/* * ircaux.c: some extra routines... not specific to irc... that I needed * * Written By Michael Sandrof * * Copyright(c) 1990, 1991 * * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "irc.h" #include "expr.h" #include "log.h" #include "misc.h" #include "vars.h" #include "screen.h" #include #include #include "ircaux.h" #include "output.h" #include "ircterm.h" /* * These are used by the malloc routines. We actually ask for an int-size * more of memory, and in that extra int we store the malloc size. Very * handy for debugging and other hackeries. */ /*#include */ #define alloc_start(ptr) (((char *)(ptr)) - sizeof(void *) - sizeof(void *)) #define alloc_size(ptr) (*(int *)( alloc_start((ptr)) + sizeof(void *))) #define alloc_magic(ptr) (*(int *)( alloc_start((ptr)) )) #define FREED_VAL -3 #define ALLOC_MAGIC 0xafbdce70 /* * really_new_malloc is the general interface to the malloc(3) call. * It is only called by way of the ``new_malloc'' #define. * It wont ever return NULL. */ /* * Malloc allocator with size caching. */ void *n_malloc(size_t size, char *file, int line) { char *ptr; if (!(ptr = (char *) calloc(1, size + sizeof(void *) + sizeof(void *)))) { yell("Malloc() failed, giving up!"); term_reset(); exit(1); } /* Store the size of the allocation in the buffer. */ ptr += sizeof(void *) + sizeof(void *); alloc_magic(ptr) = ALLOC_MAGIC; alloc_size(ptr) = size; return ptr; } /* * new_free: Why do this? Why not? Saves me a bit of trouble here and there */ void *n_free(void **ptr, char *file, int line) { if (*ptr) { #ifdef XARIC_DEBUG if (alloc_magic(*ptr) != ALLOC_MAGIC) abort(); /* Check to make sure its not been freed before */ if (alloc_size(*ptr) == FREED_VAL) abort(); #endif alloc_size(*ptr) = FREED_VAL; free((void *) alloc_start(*ptr)); *ptr = NULL; } return (*ptr); } void *n_realloc(void **ptr, size_t size, char *file, int line) { char *ptr2 = NULL; if (*ptr) { if (size) { size_t msize = alloc_size(*ptr); if (msize >= size) return *ptr; ptr2 = new_malloc(size); memmove(ptr2, *ptr, msize); new_free(ptr); return ((*ptr = ptr2)); } new_free(ptr); return NULL; } else if (size) ptr2 = new_malloc(size); return ((*ptr = ptr2)); } /* * malloc_strcpy: Mallocs enough space for src to be copied in to where * ptr points to. * * Never call this with ptr pointinng to an uninitialised string, as the * call to new_free() might crash the client... - phone, jan, 1993. */ char *malloc_strcpy(char **ptr, const char *src) { if (!src) return new_free(ptr); if (ptr && *ptr) { if (*ptr == src) return *ptr; if (alloc_size(*ptr) > strlen(src)) return strcpy(*ptr, src); new_free(ptr); } *ptr = new_malloc(strlen(src) + 1); return strcpy(*ptr, src); return *ptr; } /* malloc_strcat: Yeah, right */ char *malloc_strcat(char **ptr, const char *src) { size_t msize; if (*ptr) { if (!src) return *ptr; msize = strlen(*ptr) + strlen(src) + 1; RESIZE(*ptr, char, msize); return strcat(*ptr, src); } return (*ptr = m_strdup(src)); } char *malloc_str2cpy(char **ptr, const char *src1, const char *src2) { if (!src1 && !src2) return new_free(ptr); if (*ptr) { if (alloc_size(*ptr) > strlen(src1) + strlen(src2)) return strcat(strcpy(*ptr, src1), src2); new_free(ptr); } *ptr = new_malloc(strlen(src1) + strlen(src2) + 1); return strcat(strcpy(*ptr, src1), src2); } char *m_3dup(const char *str1, const char *str2, const char *str3) { size_t msize = strlen(str1) + strlen(str2) + strlen(str3) + 1; return strcat(strcat(strcpy((char *) new_malloc(msize), str1), str2), str3); } char *m_opendup(const char *str1, ...) { va_list args; int size; char *this_arg = NULL; char *retval = NULL; size = strlen(str1); va_start(args, str1); while ((this_arg = va_arg(args, char *))) size += strlen(this_arg); retval = (char *) new_malloc(size + 1); strcpy(retval, str1); va_start(args, str1); while ((this_arg = va_arg(args, char *))) strcat(retval, this_arg); va_end(args); return retval; } char *m_strdup(const char *str) { char *ptr; if (!str) str = empty_str; ptr = (char *) new_malloc(strlen(str) + 1); return strcpy(ptr, str); } char *m_s3cat(char **one, const char *maybe, const char *definitely) { if (*one && **one) return m_3cat(one, maybe, definitely); return *one = m_strdup(definitely); } char *m_s3cat_s(char **one, const char *maybe, const char *ifthere) { if (ifthere && *ifthere) return m_3cat(one, maybe, ifthere); return *one; } char *m_3cat(char **one, const char *two, const char *three) { int len = 0; char *str; if (*one) len = strlen(*one); if (two) len += strlen(two); if (three) len += strlen(three); len += 1; str = (char *) new_malloc(len); if (*one) strcpy(str, *one); if (two) strcat(str, two); if (three) strcat(str, three); new_free(one); return ((*one = str)); } char *upper(char *str) { register char *ptr = NULL; if (str) { ptr = str; for (; *str; str++) { if (islower(*str)) *str = toupper(*str); } } return (ptr); } char *lower(char *str) { register char *ptr = NULL; if (str) { ptr = str; for (; *str; str++) { if (isupper(*str)) *str = tolower(*str); } } return (ptr); } char *malloc_sprintf(char **to, const char *pattern, ...) { char booya[BIG_BUFFER_SIZE * 10 + 1]; *booya = 0; if (pattern) { va_list args; va_start(args, pattern); vsnprintf(booya, BIG_BUFFER_SIZE * 10, pattern, args); va_end(args); } malloc_strcpy(to, booya); return *to; } /* same thing, different variation */ char *m_sprintf(const char *pattern, ...) { char booya[BIG_BUFFER_SIZE * 10 + 1]; *booya = 0; if (pattern) { va_list args; va_start(args, pattern); vsnprintf(booya, BIG_BUFFER_SIZE * 10, pattern, args); va_end(args); } return m_strdup(booya); } /* case insensitive string searching */ char *stristr(char *source, char *search) { int x = 0; if (!source || !*source || !search || !*search || strlen(source) < strlen(search)) return NULL; while (*source) { if (source[x] && toupper(source[x]) == toupper(search[x])) x++; else if (search[x]) source++, x = 0; else return source; } return NULL; } /* * word_count: Efficient way to find out how many words are in * a given string. Relies on isspace() not being broken. */ extern int word_count(char *str) { int cocs = 0; int isv = 1; register char *foo = str; if (!foo) return 0; while (*foo) { if (*foo == '"' && isv) { while (*(foo + 1) && *++foo != '"') ; isv = 0; cocs++; } if (!my_isspace(*foo) != !isv) { isv = my_isspace(*foo); cocs++; } foo++; } return (cocs + 1) / 2; } char *next_arg(char *str, char **new_ptr) { char *ptr; /* added by Sheik (kilau@prairie.nodak.edu) -- sanity */ if (!str || !*str) return NULL; if ((ptr = sindex(str, "^ ")) != NULL) { if ((str = sindex(ptr, " ")) != NULL) *str++ = (char) 0; else str = empty_str; } else str = empty_str; if (new_ptr) *new_ptr = str; return ptr; } extern char *remove_trailing_spaces(char *foo) { char *end; if (!*foo) return foo; end = foo + strlen(foo) - 1; while (my_isspace(*end)) end--; end[1] = 0; return foo; } /* * yanks off the last word from 'src' * kinda the opposite of next_arg */ char *last_arg(char **src) { char *ptr; if (!src || !*src) return NULL; remove_trailing_spaces(*src); ptr = *src + strlen(*src) - 1; if (*ptr == '"') { for (ptr--;; ptr--) { if (*ptr == '"') { if (ptr == *src) break; if (ptr[-1] == ' ') { ptr--; break; } } if (ptr == *src) break; } } else { for (;; ptr--) { if (*ptr == ' ') break; if (ptr == *src) break; } } if (ptr == *src) { ptr = *src; *src = empty_str; } else { *ptr++ = 0; remove_trailing_spaces(*src); } return ptr; } char *new_next_arg(char *str, char **new_ptr) { char *ptr, *start; if (!str || !*str) return NULL; if ((ptr = sindex(str, "^ \t")) != NULL) { if (*ptr == '"') { start = ++ptr; while ((str = sindex(ptr, "\"\\")) != NULL) { switch (*str) { case '"': *str++ = '\0'; if (*str == ' ') str++; if (new_ptr) *new_ptr = str; return (start); case '\\': if (*(str + 1) == '"') strcpy(str, str + 1); ptr = str + 1; } } str = empty_str; } else { if ((str = sindex(ptr, " \t")) != NULL) *str++ = '\0'; else str = empty_str; } } else str = empty_str; if (new_ptr) *new_ptr = str; return ptr; } char *new_new_next_arg(char *str, char **new_ptr, char *type) { char *ptr, *start; if (!str || !*str) return NULL; if ((ptr = sindex(str, "^ \t")) != NULL) { if ((*ptr == '"') || (*ptr == '\'')) { char blah[3]; blah[0] = *ptr; blah[1] = '\\'; blah[2] = '\0'; *type = *ptr; start = ++ptr; while ((str = sindex(ptr, blah)) != NULL) { switch (*str) { case '\'': case '"': *str++ = '\0'; if (*str == ' ') str++; if (new_ptr) *new_ptr = str; return (start); case '\\': if (str[1] == *type) strcpy(str, str + 1); ptr = str + 1; } } str = empty_str; } else { *type = '\"'; if ((str = sindex(ptr, " \t")) != NULL) *str++ = '\0'; else str = empty_str; } } else str = empty_str; if (new_ptr) *new_ptr = str; return ptr; } unsigned char stricmp_table[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }; /* my_stricmp: case insensitive version of strcmp */ int my_stricmp(register const char *str1, register const char *str2) { while (*str1 && *str2 && (stricmp_table[(unsigned short) *str1] == stricmp_table[(unsigned short) *str2])) str1++, str2++; return (*str1 - *str2); #if 0 int xor; for (; *str1 || *str2; str1++, str2++) { if (!*str1 || !*str2) return (*str1 - *str2); if (isalpha(*str1) && isalpha(*str2)) { xor = *str1 ^ *str2; if (xor != 32 && xor != 0) return (*str1 - *str2); } else { if (*str1 != *str2) return (*str1 - *str2); } } return 0; #endif } /* my_strnicmp: case insensitive version of strncmp */ int my_strnicmp(register const char *str1, register const char *str2, register int n) { while (n && *str1 && *str2 && (stricmp_table[(unsigned short) *str1] == stricmp_table[(unsigned short) *str2])) str1++, str2++, n--; return (n) ? (*str1 - *str2) : 0; } /* chop -- chops off the last character. capiche? */ char *chop(char *stuff, int nchar) { *(stuff + strlen(stuff) - nchar) = 0; return stuff; } /* * strext: Makes a copy of the string delmited by two char pointers and * returns it in malloced memory. Useful when you dont want to munge up * the original string with a null. end must be one place beyond where * you want to copy, ie, its the first character you dont want to copy. */ char *strext(char *start, char *end) { char *ptr, *retval; ptr = retval = (char *) new_malloc(end - start + 1); while (start < end) *ptr++ = *start++; *ptr = 0; return retval; } /* * strmcpy: Well, it's like this, strncpy doesn't append a trailing null if * strlen(str) == maxlen. strmcpy always makes sure there is a trailing null */ char *strmcpy(char *dest, const char *src, int maxlen) { strncpy(dest, src, maxlen); dest[maxlen] = '\0'; return dest; } /* * strmcat: like strcat, but truncs the dest string to maxlen (thus the dest * should be able to handle maxlen+1 (for the null)) */ char *strmcat(char *dest, const char *src, int maxlen) { int srclen, len; len = strlen(dest); srclen = strlen(src); if ((len + srclen) > maxlen) strncat(dest, src, maxlen - len); else strcat(dest, src); return dest; } /* * strmcat_ue: like strcat, but truncs the dest string to maxlen (thus the dest * should be able to handle maxlen + 1 (for the null)). Also unescapes * backslashes. */ char *strmcat_ue(char *dest, const char *src, int maxlen) { int dstlen; dstlen = strlen(dest); dest += dstlen; maxlen -= dstlen; while (*src && maxlen > 0) { if (*src == '\\') { if (strchr("npr0", src[1])) *dest++ = '\020'; else if (*(src + 1)) *dest++ = *++src; else *dest++ = '\\'; } else *dest++ = *src; src++; } *dest = '\0'; return dest; } /* * m_strcat_ues: Given two strings, concatenate the 2nd string to * the end of the first one, but if the "unescape" argument is 1, do * unescaping (like in strmcat_ue). * (Malloc_STRCAT_UnEscape Special, in case you were wondering. ;-)) * * This uses a cheating, "not-as-efficient-as-possible" algorithm, * but it works with negligible cpu lossage. */ char *m_strcat_ues(char **dest, char *src, int unescape) { int total_length; char *ptr, *ptr2; int z; if (!unescape) { malloc_strcat(dest, src); return *dest; } z = total_length = (*dest) ? strlen(*dest) : 0; total_length += strlen(src); RESIZE(*dest, char, total_length + 2); if (z == 0) **dest = 0; ptr2 = *dest + z; for (ptr = src; *ptr; ptr++) { if (*ptr == '\\') { switch (*++ptr) { case 'n': case 'p': case 'r': case '0': *ptr2++ = '\020'; break; case (char) 0: *ptr2++ = '\\'; goto end_strcat_ues; break; default: *ptr2++ = *ptr; } } else *ptr2++ = *ptr; } end_strcat_ues: *ptr2 = '\0'; return *dest; } /* * scanstr: looks for an occurrence of str in source. If not found, returns * 0. If it is found, returns the position in source (1 being the first * position). Not the best way to handle this, but what the hell */ extern int scanstr(char *str, char *source) { int i, max, len; len = strlen(str); max = strlen(source) - len; for (i = 0; i <= max; i++, source++) { if (!my_strnicmp(source, str, len)) return (i + 1); } return (0); } /* expand_twiddle: expands ~ in pathnames. */ char *expand_twiddle(char *str) { char buffer[BIG_BUFFER_SIZE + 1]; char *str2; if (*str == '~') { str++; if (*str == '/' || !*str) { strmcpy(buffer, my_path, BIG_BUFFER_SIZE); strmcat(buffer, str, BIG_BUFFER_SIZE); } else { char *rest; struct passwd *entry; if ((rest = strchr(str, '/')) != NULL) *rest++ = '\0'; if ((entry = getpwnam(str)) != NULL) { strmcpy(buffer, entry->pw_dir, BIG_BUFFER_SIZE); if (rest) { strmcat(buffer, "/", BIG_BUFFER_SIZE); strmcat(buffer, rest, BIG_BUFFER_SIZE); } } else return (char *) NULL; } } else strmcpy(buffer, str, BIG_BUFFER_SIZE); /* This isnt legal! */ str2 = NULL; malloc_strcpy(&str2, buffer); return (str2); } /* islegal: true if c is a legal nickname char anywhere but first char */ #define islegal(c) ((((c) >= 'A') && ((c) <= '}')) || \ (((c) >= '0') && ((c) <= '9')) || \ ((c) == '-') || ((c) == '_')) /* * check_nickname: checks is a nickname is legal. If the first character is * bad new, null is returned. If the first character is bad, the string is * truncd down to only legal characters and returned * * rewritten, with help from do_nick_name() from the server code (2.8.5), * phone, april 1993. */ char *check_nickname(char *nick) { char *s; if (!nick || *nick == '-' || isdigit(*nick)) return NULL; for (s = nick; *s && (s - nick) < NICKNAME_LEN; s++) if (!islegal(*s) || my_isspace(*s)) break; *s = '\0'; return *nick ? nick : NULL; } /* * sindex: much like index(), but it looks for a match of any character in * the group, and returns that position. If the first character is a ^, then * this will match the first occurence not in that group. */ char *sindex(char *string, char *group) { char *ptr; if (!string || !group) return (char *) NULL; if (*group == '^') { group++; for (; *string; string++) { for (ptr = group; *ptr; ptr++) { if (*ptr == *string) break; } if (*ptr == '\0') return string; } } else { for (; *string; string++) { for (ptr = group; *ptr; ptr++) { if (*ptr == *string) return string; } } } return (char *) NULL; } /* * rsindex: much like rindex(), but it looks for a match of any character in * the group, and returns that position. If the first character is a ^, then * this will match the first occurence not in that group. */ char *rsindex(char *string, char *start, char *group) { char *ptr; char *retval = NULL; if (string && start && group && start <= string) { if (*group == '^') { group++; for (ptr = start; ptr <= string; ptr++) { if (!strchr(group, *ptr)) retval = ptr; } } else { for (ptr = start; ptr <= string; ptr++) { if (strchr(group, *ptr)) retval = ptr; } } } return retval; } /* is_number: returns true if the given string is a number, false otherwise */ int is_number(char *str) { while (*str == ' ') str++; if (*str == '-') str++; if (*str) { for (; *str; str++) { if (!isdigit((*str))) return (0); } return 1; } else return 0; } /* rfgets: exactly like fgets, cept it works backwards through a file! */ char *rfgets(char *buffer, int size, FILE * file) { char *ptr; off_t pos; if (fseek(file, -2L, SEEK_CUR)) return NULL; do { switch (fgetc(file)) { case EOF: return NULL; case '\n': pos = ftell(file); ptr = fgets(buffer, size, file); fseek(file, pos, 0); return ptr; } } while (fseek(file, -2L, SEEK_CUR) == 0); rewind(file); pos = 0L; ptr = fgets(buffer, size, file); fseek(file, pos, 0); return ptr; } /* * path_search: given a file called name, this will search each element of * the given path to locate the file. If found in an element of path, the * full path name of the file is returned in a static string. If not, null * is returned. Path is a colon separated list of directories */ char *path_search(char *name, char *path) { static char buffer[BIG_BUFFER_SIZE + 1]; char *ptr, *free_path = NULL; /* A "relative" path is valid if the file exists */ /* A "relative" path is searched in the path if the filename doesnt really exist from where we are */ if (strchr(name, '/')) if (!access(name, F_OK)) return name; /* an absolute path is always checked, never searched */ if (name[0] == '/') return (access(name, F_OK) ? (char *) 0 : name); /* This is cheating. >;-) */ free_path = path = m_strdup(path); while (path) { if ((ptr = strchr(path, ':')) != NULL) *(ptr++) = '\0'; strcpy(buffer, empty_str); if (path[0] == '~') { strmcat(buffer, my_path, BIG_BUFFER_SIZE); path++; } strmcat(buffer, path, BIG_BUFFER_SIZE); strmcat(buffer, "/", BIG_BUFFER_SIZE); strmcat(buffer, name, BIG_BUFFER_SIZE); if (access(buffer, F_OK) == 0) break; path = ptr; } new_free(&free_path); return (path != NULL) ? buffer : NULL; } /* * double_quote: Given a str of text, this will quote any character in the * set stuff with the QUOTE_CHAR. It returns a malloced quoted, null * terminated string */ char *double_quote(const char *str, const char *stuff, char *buffer) { char c; int pos; *buffer = 0; if (!stuff) return buffer; for (pos = 0; (c = *str); str++) { if (strchr(stuff, c)) { if (c == '$') buffer[pos++] = '$'; else buffer[pos++] = '\\'; } buffer[pos++] = c; } buffer[pos] = '\0'; return buffer; } void ircpanic(char *format, ...) { char buffer[10 * BIG_BUFFER_SIZE + 1]; static int recursion = 0; if (recursion++) abort(); if (format) { va_list arglist; va_start(arglist, format); vsnprintf(buffer, BIG_BUFFER_SIZE, format, arglist); va_end(arglist); } yell("An unrecoverable logic error has occured."); yell("Please email laeos@ptw.com with the following message"); yell(" "); yell("Panic: [%s] %s", PACKAGE_VERSION, buffer); irc_exit("Xaric panic... Could it possibly be a bug? Nahhhh...", NULL); } /* Not very complicated, but very handy function to have */ int end_strcmp(const char *one, const char *two, int bytes) { if (bytes <= strlen(one)) return (strcmp(one + strlen(one) - (size_t) bytes, two)); else return -1; } /* beep_em: Not hard to figure this one out */ void beep_em(int beeps) { int cnt, i; for (cnt = beeps, i = 0; i < cnt; i++) term_beep(); } FILE *open_compression(char *executable, char *filename) { FILE *file_pointer; int pipes[2]; pipes[0] = -1; pipes[1] = -1; if (pipe(pipes) == -1) { bitchsay("Cannot start decompression: %s\n", strerror(errno)); if (pipes[0] != -1) { close(pipes[0]); close(pipes[1]); } return NULL; } switch (fork()) { case -1: { bitchsay("Cannot start decompression: %s\n", strerror(errno)); return NULL; } case 0: { dup2(pipes[1], 1); close(pipes[0]); close(2); /* we dont want to see errors */ setuid(getuid()); setgid(getgid()); #ifdef ZARGS execl(executable, executable, "-c", ZARGS, filename, NULL); #else execl(executable, executable, "-c", filename, NULL); #endif _exit(0); } default: { close(pipes[1]); if ((file_pointer = fdopen(pipes[0], "r")) == NULL) { bitchsay("Cannot start decompression: %s\n", strerror(errno)); return NULL; } break; } } return file_pointer; } /* Front end to fopen() that will open ANY file, compressed or not, and * is relatively smart about looking for the possibilities, and even * searches a path for you! ;-) */ FILE *uzfopen(char **filename, char *path) { static int setup = 0; int ok_to_decompress = 0; char *filename_path; char filename_trying[256]; char *filename_blah; static char path_to_gunzip[513]; static char path_to_uncompress[513]; FILE *doh = NULL; if (setup == 0) { char *gzip = path_search("gunzip", getenv("PATH")); char *compress = path_search("uncompress", getenv("PATH")); if (gzip) strcpy(path_to_gunzip, path_search("gunzip", getenv("PATH"))); if (compress) strcpy(path_to_uncompress, path_search("uncompress", getenv("PATH"))); setup = 1; } /* It is allowed to pass to this function either a true filename with the compression extention, or to pass it the base name of * the filename, and this will look to see if there is a compressed file that matches the base name */ /* Start with what we were given as an initial guess */ /* kev asked me to call expand_twiddle here */ filename_blah = expand_twiddle(*filename); strcpy(filename_trying, filename_blah ? filename_blah : *filename); new_free(&filename_blah); /* Look to see if the passed filename is a full compressed filename */ if ((!end_strcmp(filename_trying, ".gz", 3)) || (!end_strcmp(filename_trying, ".z", 2))) { if (*path_to_gunzip) { ok_to_decompress = 1; filename_path = path_search(filename_trying, path); } else { bitchsay("Cannot open file %s because gunzip was not found", filename_trying); new_free(filename); return NULL; } } else if (!end_strcmp(filename_trying, ".Z", 2)) { if (*path_to_gunzip || *path_to_uncompress) { ok_to_decompress = 1; filename_path = path_search(filename_trying, path); } else { bitchsay("Cannot open file %s becuase uncompress was not found", filename_trying); new_free(filename); return NULL; } } /* Right now it doesnt look like the file is a full compressed fn */ else { struct stat file_info; /* Trivially, see if the file we were passed exists */ filename_path = path_search(filename_trying, path); /* Nope. it doesnt exist. */ if (!filename_path) { /* Is there a "filename.gz"? */ strcpy(filename_trying, *filename); strcat(filename_trying, ".gz"); filename_path = path_search(filename_trying, path); /* Nope. no "filename.gz" */ if (!filename_path) { /* Is there a "filename.Z"? */ strcpy(filename_trying, *filename); strcat(filename_trying, ".Z"); filename_path = path_search(filename_trying, path); /* Nope. no "filename.Z" */ if (!filename_path) { /* Is there a "filename.z"? */ strcpy(filename_trying, *filename); strcat(filename_trying, ".z"); filename_path = path_search(filename_trying, path); /* Nope. No more guesses? then punt */ if (!filename_path) { yell("File not found: %s", *filename); new_free(filename); return NULL; } /* Yep. there's a "filename.z" */ else ok_to_decompress = 2; } /* Yep. there's a "filename.Z" */ else ok_to_decompress = 1; } /* Yep. There's a "filename.gz" */ else ok_to_decompress = 2; } /* Imagine that! the file exists as-is (no decompression) */ else ok_to_decompress = 0; stat(filename_path, &file_info); if (file_info.st_mode & S_IFDIR) { bitchsay("%s is a directory", filename_trying); new_free(filename); return NULL; } if (file_info.st_mode & 0111) { bitchsay("Cannot open %s -- executable file", filename_trying); new_free(filename); return NULL; } } malloc_strcpy(filename, filename_path); /* at this point, we should have a filename in the variable filename_trying, and it should exist. If ok_to_decompress is one, * then we can gunzip the file if guzip is available, else we uncompress the file */ if (ok_to_decompress) { if (*path_to_gunzip) return open_compression(path_to_gunzip, filename_path); else if ((ok_to_decompress == 1) && *path_to_uncompress) return open_compression(path_to_uncompress, filename_path); bitchsay("Cannot open compressed file %s becuase no uncompressor was found", filename_trying); new_free(filename); return NULL; } /* Its not a compressed file... Try to open it regular-like. */ if ((doh = fopen(filename_path, "r")) != NULL) ; return doh; /* nope.. we just cant seem to open this file... */ bitchsay("Cannot open file %s: %s", filename_path, strerror(errno)); new_free(filename); return NULL; } /* From: carlson@Xylogics.COM (James Carlson) Newsgroups: comp.terminals Subject: Re: Need to skip VT100 codes, any help? Date: 1 Dec 1994 15:38:48 GMT */ /* This function returns 1 if the character passed is NOT printable, it * returns 0 if the character IS printable. It doesnt actually do anything * with the character, though. */ int vt100_decode(register unsigned char chr) { static enum { Normal, Escape, SCS, CSI, DCS, DCSData, DCSEscape } vtstate = Normal; if (chr == 0x1B) { /* ASCII ESC */ if (vtstate == DCSData || vtstate == DCSEscape) vtstate = DCSEscape; else { vtstate = Escape; return 1; } } else if (chr == 0x18 || chr == 0x1A) /* ASCII CAN & SUB */ vtstate = Normal; else if (chr == 0xE || chr == 0xF) /* ASCII SO & SI */ ; /* C0 codes are dispatched without changing machine state! Oh, my! */ else if (chr < 0x20) return 0; switch (vtstate) { case Normal: return 0; break; case Escape: switch (chr) { case '[': vtstate = CSI; break; case 'P': vtstate = DCS; break; case '(': case ')': vtstate = SCS; break; default: vtstate = Normal; } return 1; break; case SCS: vtstate = Normal; break; case CSI: if (isalpha(chr)) vtstate = Normal; break; case DCS: if (chr >= 0x40 && chr <= 0x7E) vtstate = DCSData; break; case DCSData: break; case DCSEscape: vtstate = Normal; break; } return 1; } /* Gets the time in second/usecond if you can, second/0 if you cant. */ struct timeval get_time(struct timeval *timer) { static struct timeval timer2; #ifdef HAVE_GETTIMEOFDAY if (timer) { gettimeofday(timer, NULL); return *timer; } gettimeofday(&timer2, NULL); return timer2; #else time_t time2 = time(NULL); if (timer) { timer.tv_sec = time2; timer.tv_usec = 0; return *timer; } timer2.tv_sec = time2; timer2.tv_usec = 0; return timer2; #endif } /* * calculates the time elapsed between 'one' and 'two' where they were * gotten probably with a call to get_time. 'one' should be the older * timer and 'two' should be the most recent timer. */ double time_diff(struct timeval one, struct timeval two) { struct timeval td; td.tv_sec = two.tv_sec - one.tv_sec; td.tv_usec = two.tv_usec - one.tv_usec; return (double) td.tv_sec + ((double) td.tv_usec / 1000000.0); } int time_to_next_minute(void) { time_t now = time(NULL); static int which = 0; if (which == 1) return 60 - now % 60; else { struct tm *now_tm = gmtime(&now); if (!which) { if (now_tm->tm_sec == now % 60) which = 1; else which = 2; } return 60 - now_tm->tm_sec; } } char *plural(int number) { return (number != 1) ? "s" : empty_str; } char *my_ctime(time_t when) { return chop(ctime(&when), 1); } char *ltoa(long foo) { static char buffer[BIG_BUFFER_SIZE + 1]; char *pos = buffer + BIG_BUFFER_SIZE - 1; unsigned long absv; int negative; absv = (foo < 0) ? (unsigned long) -foo : (unsigned long) foo; negative = (foo < 0) ? 1 : 0; buffer[BIG_BUFFER_SIZE] = 0; for (; absv > 9; absv /= 10) *pos-- = (absv % 10) + '0'; *pos = (absv) + '0'; if (negative) *--pos = '-'; return pos; } /* * Formats "src" into "dest" using the given length. If "length" is * negative, then the string is right-justified. If "length" is * zero, nothing happens. Sure, i cheat, but its cheaper then doing * two sprintf's. */ char *strformat(char *dest, char *src, int length, char pad_char) { char *ptr1 = dest, *ptr2 = src; int tmplen = length; int abslen; char padc; abslen = (length >= 0 ? length : -length); if (pad_char) padc = pad_char; else padc = (char) get_int_var(PAD_CHAR_VAR); if (!padc) padc = ' '; /* Cheat by spacing out 'dest' */ for (tmplen = abslen - 1; tmplen >= 0; tmplen--) dest[tmplen] = padc; dest[abslen] = 0; /* Then cheat further by deciding where the string should go. */ if (length > 0) { /* left justified */ while ((length-- > 0) && *ptr2) *ptr1++ = *ptr2++; } else if (length < 0) { /* right justified */ length = -length; ptr1 = dest; ptr2 = src; if (strlen(src) < length) ptr1 += length - strlen(src); while ((length-- > 0) && *ptr2) *ptr1++ = *ptr2++; } return dest; } /* MatchingBracket returns the next unescaped bracket of the given type */ extern char *MatchingBracket(char *string, char left, char right) { int bracket_count = 1; while (*string && bracket_count) { if (*string == left) bracket_count++; else if (*string == right) { if (!--bracket_count) return string; } else if (*string == '\\' && string[1]) string++; string++; } return NULL; } /* * parse_number: returns the next number found in a string and moves the * string pointer beyond that point in the string. Here's some examples: * * "123harhar" returns 123 and str as "harhar" * * while: * * "hoohar" returns -1 and str as "hoohar" */ extern int parse_number(char **str) { long ret; char *ptr = *str; /* sigh */ ret = strtol(ptr, str, 10); if (*str == ptr) ret = -1; return (int) ret; } extern int splitw(char *str, char ***to) { int numwords = word_count(str); int counter; *to = (char **) new_malloc(sizeof(char *) * numwords); for (counter = 0; counter < numwords; counter++) (*to)[counter] = new_next_arg(str, &str); return numwords; } extern char *unsplitw(char **str, int howmany) { char *retval = NULL; while (howmany) { m_s3cat(&retval, " ", *str); str++, howmany--; } return retval; } char *m_2dup(const char *str1, const char *str2) { size_t msize = strlen(str1) + strlen(str2) + 1; return strcat(strcpy((char *) new_malloc(msize), str1), str2); } char *on_off(int var) { if (var) return ("On"); return ("Off"); } extern char *strfill(char c, int num) { static char buffer[BIG_BUFFER_SIZE + 1]; int i = 0; if (num > BIG_BUFFER_SIZE) num = BIG_BUFFER_SIZE; for (i = 0; i < num; i++) buffer[i] = c; buffer[num] = '\0'; return buffer; } extern int empty(const char *str) { while (str && *str && *str == ' ') str++; if (str && *str) return 0; return 1; } /* makes foo[one][two] look like tmp.one.two -- got it? */ char *remove_brackets(char *name, char *args, int *arg_flag) { char *ptr, *right, *result1, *rptr, *retval = NULL; /* XXXX - ugh. */ rptr = m_strdup(name); while ((ptr = strchr(rptr, '['))) { *ptr++ = 0; right = ptr; if ((ptr = MatchingBracket(right, '[', ']'))) *ptr++ = 0; if (args) result1 = expand_alias(right, args, arg_flag, NULL); else result1 = right; retval = m_3dup(rptr, ".", result1); if (ptr) malloc_strcat(&retval, ptr); if (args) new_free(&result1); if (rptr) new_free(&rptr); rptr = retval; } return upper(rptr); } long my_atol(char *str) { if (str) return (long) strtol(str, NULL, 0); else return 0L; } char *m_dupchar(int i) { char c = (char) i; /* blah */ char *ret = (char *) new_malloc(2); ret[0] = c; ret[1] = 0; return ret; } #ifndef HAVE_VSNPRINTF int vsnprintf(char *str, size_t size, const char *format, va_list ap) { int ret = vsprintf(str, format, ap); /* If the string ended up overflowing, just give up. */ if (strlen(str) > size) ircpanic("Buffer overflow in vsnprintf"); return ret; } #endif #ifndef HAVE_SNPRINTF int snprintf(char *str, size_t size, const char *format, ...) { int ret; va_list args; va_start(args, format); ret = vsnprintf(str, size, format, args); va_end(args); return ret; } #endif char *strmopencat(char *dest, int maxlen, ...) { va_list args; int size; char *this_arg = NULL; int this_len; size = strlen(dest); va_start(args, maxlen); while (size < maxlen) { if (!(this_arg = va_arg(args, char *))) break; if (size + ((this_len = strlen(this_arg))) > maxlen) strncat(dest, this_arg, maxlen - size); else strcat(dest, this_arg); size += this_len; } va_end(args); return dest; } char *next_in_comma_list(char *str, char **after) { *after = str; while (*after && **after && **after != ',') (*after)++; if (*after && **after == ',') { **after = 0; (*after)++; } return str; } /* * Checks if ansi string only sets colors/attributes * ^[[m won't work anymore !!!! */ void FixColorAnsi(char *str) { register char *tmpstr; register char *tmpstr1 = NULL; int what = 0; int numbers = 0; int val = 0; tmpstr = str; while (*tmpstr) { if ((*tmpstr >= '0' && *tmpstr <= '9')) { numbers = 1; val = val * 10 + (*tmpstr - '0'); } else if (*tmpstr == ';') numbers = 1, val = 0; else if (!(*tmpstr == 'm' || *tmpstr == 'C')) numbers = val = 0; if (*tmpstr == 0x1B) { if (what && tmpstr1) *tmpstr1 += 64; what = 1; tmpstr1 = tmpstr; } else if (*tmpstr == 0x18 || *tmpstr == 0x0E) *tmpstr += 64; if (what && numbers && (val > 130)) { what = numbers = val = 0; *tmpstr1 += 64; } if (what && *tmpstr == 'm') { if (!numbers || (val == 12)) { *tmpstr1 += 64; tmpstr1 = tmpstr; } what = 0; numbers = val = 0; } else if (what && *tmpstr == 'C') { if (!numbers) { *tmpstr1 += 64; tmpstr1 = tmpstr; } what = 0; numbers = val = 0; } else if (what && *tmpstr == 'J') { val = numbers = 0; *tmpstr1 += 64; tmpstr1 = tmpstr; what = 0; } else if (what && *tmpstr == '(') what = 2; else if (what == 2 && (*tmpstr == 'U' || *tmpstr == 'B')) what = 0; tmpstr++; } if (what && tmpstr1 && *tmpstr1) *tmpstr1 += 64; } /* how many ansi escape chars do we have in string? if len -1 count full string, otherwise, count len chars */ int count_ansi(register const char *str, const int len) { register int count = 0; register int c = len; /* FixColorAnsi(str); */ for (; *str && c; str++, c--) if (vt100_decode(*str)) count++; return count; }