/* Jungle Monkey * Copyright (C) 1999, 2000 The Regents of the University of Michigan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include /* These are here so MIN/MAX don't get redefined */ #include "util.h" #include static gboolean is_blankpathname (const gchar* path, gboolean (*func)(const gchar*)); /* **************************************** */ time_t get_time_gmt(void) { time_t current_time; time(¤t_time); g_assert(gmtime(¤t_time) != NULL); return current_time; } unsigned int millitime (void) { struct timeval tv; g_assert (gettimeofday (&tv, NULL) == 0); return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)); } /* **************************************** */ void rand_timer_set (guint* timer, guint time, guint delay, GSourceFunc func, gpointer user_data) { g_return_if_fail (timer); g_return_if_fail (func); if (!*timer) { if (delay) time += rand() % delay; *timer = g_timeout_add (time, func, user_data); } } void rand_timer_cancel (guint* timer) { g_return_if_fail (timer); if (*timer) { g_assert (g_source_remove(*timer)); *timer = 0; } } void rand_timer_reset (guint* timer, guint time, guint delay, GSourceFunc func, gpointer user_data) { rand_timer_cancel (timer); rand_timer_set (timer, time, delay, func, user_data); } /* **************************************** */ char* strcasestr(const char* haystack, const char* needle) { unsigned int i, j; g_return_val_if_fail (haystack != NULL, NULL); g_return_val_if_fail (needle != NULL, NULL); if (needle[0] == '\0') return (gchar*) haystack; for (i = 0; haystack[i] != '\0'; ++i) { for (j = 0; needle[j] != '\0'; ++j) { if (tolower(haystack[i + j]) != tolower(needle[j])) goto next; } return (gchar*) &haystack[i]; next: ; } return NULL; } char* strtokq (char* s, const char* delim, char** next) { gchar* start = NULL; gchar last_char = 0; gboolean is_quote = 0; gint i; /* Set s if necessary */ if (s == NULL) s = *next; /* Find the beginning of the next token */ for (;;) { if (*s == '\0') break; /* Try to find a skipable character */ for (i = 0; delim[i] != *s && delim[i] != '\0'; ++i); /* We found non-skippable character - break */ if (delim[i] == '\0') break; /* Check if it's a quote */ if (delim[i] == '\"') { /* If it's not part of a \", break */ if (last_char != '\\') { is_quote = TRUE; ++s; break; } } /* Skip it */ last_char = *s++; } /* Return NULL if we're done */ if (*s == '\0') { *next = (gchar*) s; return NULL; } /* Read the token */ start = s; last_char = '\0'; for (;;) { if (*s == '\0') break; /* Try to find a skipable character */ for (i = 0; delim[i] != *s && delim[i] != '\0'; ++i); /* Check if we found a quote (endquote or otherwise, it doesn't matter) */ if (delim[i] == '\"' && last_char != '\\') break; /* Check if we found a skippable character */ else if (is_quote == FALSE && delim[i] != '\0') break; /* This character is part of the token, continue */ last_char = *s++; } /* If we didn't hit the end, write '\0' and update next. Otherwise, set next to the end so that the next call returns NULL */ if (*s != '\0') { *s++ = '\0'; *next = s; } else *next = s; /* This causes next call to return NULL */ return start; } char* stresc (const char* s, const char* esc, char escc) { char* start; char* r; size_t size; size = 1 + strlen(s) + strchrcount(s, esc); if (!strchr(esc, escc)) for (r = (char*) s; *r; r++) if (*r == escc) ++size; start = r = g_malloc (size); while (*s) { if (strchr(esc, *s) || *s == escc) *r++ = escc; *r++ = *s++; } *r = '\0'; return start; } char* strunesc (const char* s, const char* esc, char escc) { char* start; char* r; start = r = g_malloc (strlen(s)+1); while (*s) { if (*s == escc && s[1] && (s[1] == escc || (esc && strchr(esc, s[1]))) ) s++; *r++ = *s++; } *r = '\0'; return start; } char* strescape (const char* s) { gchar escextra; gchar* r; gchar* start; int size; size = 1 + strlen(s) + strchrcount(s, "\a\b\f\n\r\t\v\\\'\""); size += strchrcount(s, "&") * 3; start = r = g_new(gchar, size); for (;;) { switch (*s) { case '\a': { escextra = 'a'; goto esc_extra; } case '\b': { escextra = 'b'; goto esc_extra; } case '\f': { escextra = 'f'; goto esc_extra; } case '\n': { escextra = 'n'; goto esc_extra; } case '\r': { escextra = 'r'; goto esc_extra; } case '\t': { escextra = 't'; goto esc_extra; } case '\v': { escextra = 'v'; goto esc_extra; } case '\\' : { escextra = '\\'; goto esc_extra; } case '\'' : { escextra = '\''; goto esc_extra; } case '\"' : { escextra = '\"'; goto esc_extra; } { esc_extra: *r++ = '\\'; *r++ = escextra; ++s; break; } case '\0': { *r = *s; return start; } case '&': { *r++ = *s++; *r++ = 'a'; *r++ = 'm'; *r++ = 'p'; } default: { *r++ = *s++; } } } g_assert_not_reached(); return NULL; } char* strunescape (const char* s) { char* r; char* start; int size; size = 1 + strlen(s); /* This is an overestimate */ start = r = g_new(gchar, size); for (;;) { switch (*s) { case '\\': { switch (*++s) { case 'a': { *r++ = '\a'; break; } case 'b': { *r++ = '\b'; break; } case 'f': { *r++ = '\f'; break; } case 'n': { *r++ = '\n'; break; } case 'r': { *r++ = '\r'; break; } case 't': { *r++ = '\t'; break; } case 'v': { *r++ = '\v'; break; } case '\\' : { *r++ = '\\'; break; } case '\'' : { *r++ = '\''; break; } case '\"' : { *r++ = '\"'; break; } case '\0': { *r = '\0'; return start; } default: { *r++ = '\\'; *r++ = *s; } } ++s; break; } case '&': { *r++ = *s++; if (strncmp("amp", s, 3) == 0) s += 3; } case '\0': { *r = '\0'; return start; } default: { *r++ = *s++; } } } g_assert_not_reached(); return NULL; } int strchrcount (const char* s, const char* chars) { int i; int count = 0; for (; *s != '\0'; ++s) { for (i = 0; chars[i] != '\0'; ++i) { if (chars[i] == *s) { ++count; goto next; } } next:; } return count; } int strsuffixcmp (const char* s1, const char* s2) { int l_s1 = strlen(s1); int l_s2 = strlen(s2); if (l_s1 > l_s2) return strcmp(&s1[l_s1 - l_s2], s2); else return strcmp(s1, &s2[l_s2 - l_s1]); g_assert_not_reached(); } static char bits2hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; char* strtoreadable (const char* s) { gint length = 0; const gchar* p = s; gchar* str; gint i; g_return_val_if_fail (s, NULL); for (p = s; *p; ++p) { if (((guint) *p < 32) || ((guint) *p > 127)) length += 3; else ++length; } ++length; str = g_new(gchar, length); for (i = 0, p = s; *p; ++p) { if (((guint) *p < 32) || ((guint) *p > 127)) { str[i++] = '\\'; str[i++] = bits2hex[(*p & 0xF0) >> 4]; str[i++] = bits2hex[(*p & 0x0F)]; } else { str[i++] = *p; } } str[i] = '\0'; return str; } size_t strnlen (const char* s, size_t len) { size_t l = 0; const char* end = s + len; while (s < end && *s) { ++s; ++l; } return l; } /* **************************************** */ char* filesize_to_string(int size) { gchar* str; g_return_val_if_fail (size >= 0, NULL); if (size < 1024) str = g_strdup_printf("%d bytes", size); else if (size < (1024 * 1024)) str = g_strdup_printf("%.1fk", (double) size / 1024.0); else str = g_strdup_printf("%.1fM", (double) size / 1048576.0); return str; } char* filesize_fraction_to_string(int offset, int size) { char* str; g_return_val_if_fail (offset >= 0, NULL); g_return_val_if_fail (size >= 0, NULL); if (size < 1024) str = g_strdup_printf("%d/%d bytes", offset, size); else if (size < (1024 * 1024)) str = g_strdup_printf("%.1f/%.1fk", (double) offset / 1024.0, (double) size / 1024.0); else str = g_strdup_printf("%.1f/%.1fM", (double) offset / 1048576.0, (double) size / 1048576.0); return str; } int file_exists (const char* path) { struct stat s; g_return_val_if_fail (path, FALSE); if (stat (path, &s)) return FALSE; return TRUE; } int file_size (const char* path) { struct stat s; g_return_val_if_fail (path, -1); if (stat (path, &s)) return -1; return s.st_size; } int FILE_size (FILE* file) { struct stat s; if (fstat(fileno(file), &s)) return -1; return s.st_size; } char* tilde_expand (const char* path) { char* str = NULL; g_return_val_if_fail (path, NULL); if (*path == '~') { char* home; home = g_getenv ("HOME"); g_assert (home); str = g_strconcat (home, G_DIR_SEPARATOR_S, &path[1], NULL); g_free (home); } else { str = g_strdup (path); } return str; } int is_file (const char* path) { struct stat filestat; if (stat(path, &filestat) == 0) return (S_ISREG(filestat.st_mode) != 0); return FALSE; } int is_dir (const char* path) { struct stat filestat; if (stat(path, &filestat) == 0) return (S_ISDIR(filestat.st_mode) != 0); return FALSE; } gboolean mkdirr(const gchar* path, gint mode) { gchar* parent; gboolean rv; /* Try to make the directory as given */ if (mkdir(path, mode) == 0 || errno == EEXIST) return TRUE; /* Failed - try to make the parent directory */ parent = g_dirname(path); rv = mkdirr(parent, mode); g_free(parent); /* Try to make the directory again if we created the parent. We check EEXIST because the original path may have ended with a directory separator. */ if (rv) return (mkdir(path, mode) == 0 || errno == EEXIST); return FALSE; } gboolean is_okfilename (const gchar* name) { g_return_val_if_fail (name != NULL, FALSE); /* Skip any whitespace */ while (isspace((int) *name)) ++name; /* Can't be blank */ if (name[0] == '\0') return FALSE; /* The name can't be . or .. */ if (name[0] == '.') { if (name[1] == '\0') return FALSE; else if (name[1] == '.' && name[2] == '\0') return FALSE; } /* The name can't have [/\|;:] in it */ while (*name) { if (*name == '/' || *name == '\\' || *name == '|' || *name == ',' || *name == ';' || *name == ':') return FALSE; ++name; } return TRUE; } gboolean is_okpathname (const gchar* path) { return is_blankpathname (path, is_okfilename); } gboolean is_goodfilename (const gchar* name) { int i = 0; g_return_val_if_fail (name != NULL, FALSE); /* Skip any whitespace */ while (isspace((int) *name)) ++name; /* Good file names begin with an alphanumerical character */ if (name[0] == '\0' || !isalnum((int) name[i])) return FALSE; /* Good names have alpha-num characters and certain punctuation only */ /* We start at 0 to weed out names that begin with weird punctuation (like /) */ for (i = 0; name[i] != '\0'; ++i) { /* Don't allow /,\, or : because the are directory seperators on some systems. */ if (isalnum((int) name[i]) || name[i] == '.' || name[i] == '-' || name[i] == '_' || name[i] == ' ' || name[i] == '!' || name[i] == '\'' || name[i] == '(' || name[i] == ')' || name[i] == '&' || name[i] == ',' || name[i] == '\"' || name[i] == '+') continue; return FALSE; } return TRUE; } gboolean is_goodpathname (const gchar* path) { return is_blankpathname(path, is_goodfilename); } gboolean is_blankpathname (const gchar* path, gboolean (*func)(const gchar*)) { gchar** tokens; guint i; gboolean rv = FALSE; g_return_val_if_fail(path != NULL, FALSE); g_return_val_if_fail(func != NULL, FALSE); /* Skip leading '/' */ if (path[0] == G_DIR_SEPARATOR) path = &path[1]; tokens = g_strsplit(path, G_DIR_SEPARATOR_S, 0); if (tokens == NULL || tokens[0] == NULL) goto done; for (i = 0; tokens[i] != NULL; ++i) if (!func(tokens[i])) goto done; rv = TRUE; done: g_strfreev(tokens); return rv; } void my_error (const gchar* format, ...) { va_list args; va_start (args, format); g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args); va_end (args); exit (EXIT_FAILURE); } gboolean remove_by_value_hrfunc (gpointer key, gpointer value, gpointer user_data) { if (value == user_data) return TRUE; return FALSE; }