/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
/* These are here so MIN/MAX don't get redefined */
#include "util.h"
#include <glib.h>
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;
}
syntax highlighted by Code2HTML, v. 0.9.1