-const char miscutil_rcs[] = "$Id: miscutil.c,v 1.7 2001/06/03 11:03:48 oes Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/miscutil.c,v $
*
- * Purpose : zalloc, hash_string, safe_strerror, strcmpic,
- * strncmpic, strsav, chomp, and MinGW32 strdup
- * functions.
- * These are each too small to deserve their own file
- * but don't really fit in any other file.
+ * Purpose : zalloc, hash_string, strcmpic, strncmpic, and
+ * MinGW32 strdup functions. These are each too small
+ * to deserve their own file but don't really fit in
+ * any other file.
*
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
- * IJBSWA team. http://ijbswa.sourceforge.net
+ * Copyright : Written by and Copyright (C) 2001-2022 the
+ * Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
- * by and Copyright (C) 1997 Anonymous Coders and
+ * by and Copyright (C) 1997 Anonymous Coders and
* Junkbusters Corporation. http://www.junkbusters.com
*
- * This program is free software; you can redistribute it
+ * The timegm replacement function was taken from GnuPG,
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * 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
* or write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Revisions :
- * $Log: miscutil.c,v $
- * Revision 1.7 2001/06/03 11:03:48 oes
- * Makefile/in
- *
- * introduced cgi.c
- *
- * actions.c:
- *
- * adapted to new enlist_unique arg format
- *
- * conf loadcfg.c
- *
- * introduced confdir option
- *
- * filters.c filtrers.h
- *
- * extracted-CGI relevant stuff
- *
- * jbsockets.c
- *
- * filled comment
- *
- * jcc.c
- *
- * support for new cgi mechansim
- *
- * list.c list.h
- *
- * functions for new list type: "map"
- * extended enlist_unique
- *
- * miscutil.c .h
- * introduced bindup()
- *
- * parsers.c parsers.h
- *
- * deleted const struct interceptors
- *
- * pcrs.c
- * added FIXME
- *
- * project.h
- *
- * added struct map
- * added struct http_response
- * changes struct interceptors to struct cgi_dispatcher
- * moved HTML stuff to cgi.h
- *
- * re_filterfile:
- *
- * changed
- *
- * showargs.c
- * NO TIME LEFT
- *
- * Revision 1.6 2001/06/01 18:14:49 jongfoster
- * Changing the calls to strerr() to check HAVE_STRERR (which is defined
- * in config.h if appropriate) rather than the NO_STRERR macro.
- *
- * Revision 1.5 2001/06/01 10:31:51 oes
- * Added character class matching to trivimatch; renamed to simplematch
- *
- * Revision 1.4 2001/05/31 17:32:31 oes
- *
- * - Enhanced domain part globbing with infix and prefix asterisk
- * matching and optional unanchored operation
- *
- * Revision 1.3 2001/05/29 23:10:09 oes
- *
- *
- * - Introduced chomp()
- * - Moved strsav() from showargs to miscutil
- *
- * Revision 1.2 2001/05/29 09:50:24 jongfoster
- * Unified blocklist/imagelist/permissionslist.
- * File format is still under discussion, but the internal changes
- * are (mostly) done.
- *
- * Also modified interceptor behaviour:
- * - We now intercept all URLs beginning with one of the following
- * prefixes (and *only* these prefixes):
- * * http://i.j.b/
- * * http://ijbswa.sf.net/config/
- * * http://ijbswa.sourceforge.net/config/
- * - New interceptors "home page" - go to http://i.j.b/ to see it.
- * - Internal changes so that intercepted and fast redirect pages
- * are not replaced with an image.
- * - Interceptors now have the option to send a binary page direct
- * to the client. (i.e. ijb-send-banner uses this)
- * - Implemented show-url-info interceptor. (Which is why I needed
- * the above interceptors changes - a typical URL is
- * "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
- * The previous mechanism would not have intercepted that, and
- * if it had been intercepted then it then it would have replaced
- * it with an image.)
- *
- * Revision 1.1.1.1 2001/05/15 13:59:00 oes
- * Initial import of version 2.9.3 source tree
- *
- *
*********************************************************************/
-\f
+
#include "config.h"
#include <stdio.h>
+#include <sys/types.h>
#include <stdlib.h>
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif /* #if !defined(_WIN32) */
#include <string.h>
-#include <malloc.h>
#include <ctype.h>
+#include <assert.h>
+#if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV)
+#include <time.h>
+#endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */
+
+#include "project.h"
#include "miscutil.h"
+#include "jcc.h"
#include "errlog.h"
-const char miscutil_h_rcs[] = MISCUTIL_H_VERSION;
-
-/* Fix a problem with Solaris. There should be no effect on other
- * platforms.
- * Solaris's isspace() is a macro which uses it's argument directly
- * as an array index. Therefore we need to make sure that high-bit
- * characters generate +ve values, and ideally we also want to make
- * the argument match the declared parameter type of "int".
- */
-#define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
-#define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
-
/*********************************************************************
*
* Function : zalloc
*
- * Description : Malloc some memory and set it to '\0'.
- * The way calloc() ought to be -acjc
+ * Description : Returns allocated memory that is initialized
+ * with zeros.
*
* Parameters :
* 1 : size = Size of memory chunk to return.
*
- * Returns : Pointer to newly malloc'd memory chunk.
+ * Returns : Pointer to newly alloc'd memory chunk.
*
*********************************************************************/
-void *zalloc(int size)
+void *zalloc(size_t size)
{
void * ret;
+#ifdef HAVE_CALLOC
+ ret = calloc(1, size);
+#else
+#warning calloc appears to be unavailable. Your platform will become unsupported in the future
if ((ret = (void *)malloc(size)) != NULL)
{
memset(ret, 0, size);
}
+#endif
return(ret);
+
}
/*********************************************************************
*
- * Function : hash_string
+ * Function : zalloc_or_die
+ *
+ * Description : zalloc wrapper that either succeeds or causes
+ * program termination.
*
- * Description : Take a string and compute a (hopefuly) unique numeric
- * integer value. This has several uses, but being able
- * to "switch" a string the one of my favorites.
+ * Useful in situations were the string length is
+ * "small" and zalloc() failures couldn't be handled
+ * better anyway. In case of debug builds, failures
+ * trigger an assert().
*
* Parameters :
- * 1 : s : string to be hashed.
+ * 1 : size = Size of memory chunk to return.
*
- * Returns : an unsigned long variable with the hashed value.
+ * Returns : Pointer to newly malloc'd memory chunk.
*
*********************************************************************/
-unsigned long hash_string( const char* s )
+void *zalloc_or_die(size_t size)
{
- unsigned long h = 0ul;
+ void *buffer;
- for ( ; *s; ++s )
+ buffer = zalloc(size);
+ if (buffer == NULL)
{
- h = 5 * h + *s;
+ assert(buffer != NULL);
+ log_error(LOG_LEVEL_FATAL, "Out of memory in zalloc_or_die().");
+ exit(1);
}
- return (h);
+ return(buffer);
}
-
-#ifdef __MINGW32__
/*********************************************************************
*
- * Function : strdup
+ * Function : strdup_or_die
+ *
+ * Description : strdup wrapper that either succeeds or causes
+ * program termination.
*
- * Description : For some reason (which is beyond me), gcc and WIN32
- * don't like strdup. When a "free" is executed on a
- * strdup'd ptr, it can at times freez up! So I just
- * replaced it and problem was solved.
+ * Useful in situations were the string length is
+ * "small" and strdup() failures couldn't be handled
+ * better anyway. In case of debug builds, failures
+ * trigger an assert().
*
* Parameters :
- * 1 : s = string to duplicate
+ * 1 : str = String to duplicate
*
- * Returns : Pointer to newly malloc'ed copy of the string.
+ * Returns : Pointer to newly strdup'd copy of the string.
*
*********************************************************************/
-char *strdup( const char *s )
+char *strdup_or_die(const char *str)
{
- char * result = (char *)malloc( strlen(s)+1 );
+ char *new_str;
- if (result != NULL)
+ new_str = strdup(str);
+
+ if (new_str == NULL)
{
- strcpy( result, s );
+ assert(new_str != NULL);
+ log_error(LOG_LEVEL_FATAL, "Out of memory in strdup_or_die().");
+ exit(1);
}
- return( result );
+ return(new_str);
+
}
-#endif /* def __MINGW32__ */
+/*********************************************************************
+ *
+ * Function : malloc_or_die
+ *
+ * Description : malloc wrapper that either succeeds or causes
+ * program termination.
+ *
+ * Useful in situations were the buffer size is "small"
+ * and malloc() failures couldn't be handled better
+ * anyway. In case of debug builds, failures trigger
+ * an assert().
+ *
+ * Parameters :
+ * 1 : buffer_size = Size of the space to allocate
+ *
+ * Returns : Pointer to newly malloc'd memory
+ *
+ *********************************************************************/
+void *malloc_or_die(size_t buffer_size)
+{
+ char *new_buf;
+
+ if (buffer_size == 0)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "malloc_or_die() called with buffer size 0");
+ assert(buffer_size != 0);
+ buffer_size = 4096;
+ }
+
+ new_buf = malloc(buffer_size);
+
+ if (new_buf == NULL)
+ {
+ assert(new_buf != NULL);
+ log_error(LOG_LEVEL_FATAL, "Out of memory in malloc_or_die().");
+ exit(1);
+ }
+
+ return(new_buf);
+
+}
+#if defined(unix)
/*********************************************************************
*
- * Function : safe_strerror
+ * Function : write_pid_file
*
- * Description : Variant of the library routine strerror() which will
- * work on systems without the library routine, and
- * which should never return NULL.
+ * Description : Writes a pid file with the pid of the main process.
+ * Exits if the file can't be opened
*
* Parameters :
- * 1 : err = the `errno' of the last operation.
+ * 1 : pid_file = Path of the pid file that gets created.
*
- * Returns : An "English" string of the last `errno'. Allocated
- * with strdup(), so caller frees. May be NULL if the
- * system is out of memory.
+ * Returns : N/A
*
*********************************************************************/
-char *safe_strerror(int err)
+void write_pid_file(const char *pid_file)
{
- char *s = NULL;
- char buf[BUFSIZ];
+ FILE *fp;
+ if ((fp = fopen(pid_file, "w")) == NULL)
+ {
+ log_error(LOG_LEVEL_FATAL, "can't open pid file '%s': %E", pid_file);
+ }
+ else
+ {
+ fprintf(fp, "%u\n", (unsigned int) getpid());
+ fclose (fp);
+ }
+ return;
-#ifdef HAVE_STRERROR
- s = strerror(err);
-#endif /* HAVE_STRERROR */
+}
+#endif /* def unix */
+
+
+/*********************************************************************
+ *
+ * Function : hash_string
+ *
+ * Description : Take a string and compute a (hopefully) unique numeric
+ * integer value. This is useful to "switch" a string.
+ *
+ * Parameters :
+ * 1 : s : string to be hashed.
+ *
+ * Returns : The string's hash
+ *
+ *********************************************************************/
+unsigned int hash_string(const char* s)
+{
+ unsigned int h = 0;
- if (s == NULL)
+ for (; *s; ++s)
{
- sprintf(buf, "(errno = %d)", err);
- s = buf;
+ h = 5 * h + (unsigned int)*s;
}
- return(strdup(s));
+ return (h);
}
*********************************************************************/
int strcmpic(const char *s1, const char *s2)
{
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+
while (*s1 && *s2)
{
- if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
+ if ((*s1 != *s2) && (privoxy_tolower(*s1) != privoxy_tolower(*s2)))
{
break;
}
s1++, s2++;
}
- return(ijb_tolower(*s1) - ijb_tolower(*s2));
+ return(privoxy_tolower(*s1) - privoxy_tolower(*s2));
}
*
* Function : strncmpic
*
- * Description : Case insensitive string comparison (upto n characters)
+ * Description : Case insensitive string comparison (up to n characters)
*
* Parameters :
* 1 : s1 = string 1 to compare
*********************************************************************/
int strncmpic(const char *s1, const char *s2, size_t n)
{
- if (n <= 0) return(0);
+ if (n <= (size_t)0) return(0);
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
while (*s1 && *s2)
{
- if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
+ if ((*s1 != *s2) && (privoxy_tolower(*s1) != privoxy_tolower(*s2)))
{
break;
}
- if (--n <= 0) break;
+ if (--n <= (size_t)0) break;
s1++, s2++;
}
- return(ijb_tolower(*s1) - ijb_tolower(*s2));
+ return(privoxy_tolower(*s1) - privoxy_tolower(*s2));
}
{
char *p, *q, *r;
- /*
+ /*
* strip trailing whitespace
*/
p = string + strlen(string);
- while (p > string && ijb_isspace(*(p-1)))
+ while (p > string && privoxy_isspace(*(p-1)))
{
p--;
}
*p = '\0';
- /*
- * find end of leading whitespace
+ /*
+ * find end of leading whitespace
*/
q = r = string;
- while (*q && ijb_isspace(*q))
+ while (*q && privoxy_isspace(*q))
{
q++;
}
}
+
/*********************************************************************
*
- * Function : strsav
+ * Function : string_append
+ *
+ * Description : Reallocate target_string and append text to it.
+ * This makes it easier to append to malloc'd strings.
+ * This is similar to the (removed) strsav(), but
+ * running out of memory isn't catastrophic.
+ *
+ * Programming style:
*
- * Description : Reallocate "old" and append text to it. This makes
- * it easier to append to malloc'd strings.
+ * The following style provides sufficient error
+ * checking for this routine, with minimal clutter
+ * in the source code. It is recommended if you
+ * have many calls to this function:
+ *
+ * char * s = strdup(...); // don't check for error
+ * string_append(&s, ...); // don't check for error
+ * string_append(&s, ...); // don't check for error
+ * string_append(&s, ...); // don't check for error
+ * if (NULL == s) { ... handle error ... }
+ *
+ * OR, equivalently:
+ *
+ * char * s = strdup(...); // don't check for error
+ * string_append(&s, ...); // don't check for error
+ * string_append(&s, ...); // don't check for error
+ * if (string_append(&s, ...)) {... handle error ...}
*
* Parameters :
- * 1 : old = Old text that is to be extended. Will be
- * free()d by this routine.
+ * 1 : target_string = Pointer to old text that is to be
+ * extended. *target_string will be free()d by this
+ * routine. target_string must be non-NULL.
+ * If *target_string is NULL, this routine will
+ * do nothing and return with an error - this allows
+ * you to make many calls to this routine and only
+ * check for errors after the last one.
* 2 : text_to_append = Text to be appended to old.
+ * Must not be NULL.
*
- * Returns : Pointer to newly malloc'ed appended string.
- * If there is no text to append, return old. Caller
- * must free().
+ * Returns : JB_ERR_OK on success, and sets *target_string
+ * to newly malloc'ed appended string. Caller
+ * must free(*target_string).
+ * JB_ERR_MEMORY on out-of-memory. (And free()s
+ * *target_string and sets it to NULL).
+ * JB_ERR_MEMORY if *target_string is NULL.
*
*********************************************************************/
-char *strsav(char *old, const char *text_to_append)
+jb_err string_append(char **target_string, const char *text_to_append)
{
- int old_len, new_len;
- char *p;
+ size_t old_len;
+ char *new_string;
+ size_t new_size;
- if (( text_to_append == NULL) || (*text_to_append == '\0'))
+ assert(target_string);
+ assert(text_to_append);
+
+ if (*target_string == NULL)
{
- return(old);
+ return JB_ERR_MEMORY;
}
- if (NULL != old)
+ if (*text_to_append == '\0')
{
- old_len = strlen(old);
+ return JB_ERR_OK;
}
- else
+
+ old_len = strlen(*target_string);
+
+ new_size = strlen(text_to_append) + old_len + 1;
+
+ if (NULL == (new_string = realloc(*target_string, new_size)))
{
- old_len = 0;
+ free(*target_string);
+
+ *target_string = NULL;
+ return JB_ERR_MEMORY;
}
- new_len = old_len + strlen(text_to_append) + 1;
+ strlcpy(new_string + old_len, text_to_append, new_size - old_len);
+
+ *target_string = new_string;
+ return JB_ERR_OK;
+}
+
+
+/*********************************************************************
+ *
+ * Function : string_join
+ *
+ * Description : Join two strings together. Frees BOTH the original
+ * strings. If either or both input strings are NULL,
+ * fails as if it had run out of memory.
+ *
+ * For comparison, string_append requires that the
+ * second string is non-NULL, and doesn't free it.
+ *
+ * Rationale: Too often, we want to do
+ * string_append(s, html_encode(s2)). That assert()s
+ * if s2 is NULL or if html_encode() runs out of memory.
+ * It also leaks memory. Proper checking is cumbersome.
+ * The solution: string_join(s, html_encode(s2)) is safe,
+ * and will free the memory allocated by html_encode().
+ *
+ * Parameters :
+ * 1 : target_string = Pointer to old text that is to be
+ * extended. *target_string will be free()d by this
+ * routine. target_string must be non-NULL.
+ * 2 : text_to_append = Text to be appended to old.
+ *
+ * Returns : JB_ERR_OK on success, and sets *target_string
+ * to newly malloc'ed appended string. Caller
+ * must free(*target_string).
+ * JB_ERR_MEMORY on out-of-memory, or if
+ * *target_string or text_to_append is NULL. (In
+ * this case, frees *target_string and text_to_append,
+ * sets *target_string to NULL).
+ *
+ *********************************************************************/
+jb_err string_join(char **target_string, char *text_to_append)
+{
+ jb_err err;
- if (old)
+ assert(target_string);
+
+ if (text_to_append == NULL)
{
- if ((p = realloc(old, new_len)) == NULL)
- {
- log_error(LOG_LEVEL_FATAL, "realloc(%d) bytes failed!", new_len);
- /* Never get here - LOG_LEVEL_FATAL causes program exit */
- }
+ freez(*target_string);
+ return JB_ERR_MEMORY;
}
- else
+
+ err = string_append(target_string, text_to_append);
+
+ freez(text_to_append);
+
+ return err;
+}
+
+
+/*********************************************************************
+ *
+ * Function : string_toupper
+ *
+ * Description : Produce a copy of string with all convertible
+ * characters converted to uppercase.
+ *
+ * Parameters :
+ * 1 : string = string to convert
+ *
+ * Returns : Uppercase copy of string if possible,
+ * NULL on out-of-memory or if string was NULL.
+ *
+ *********************************************************************/
+char *string_toupper(const char *string)
+{
+ char *result, *p;
+ const char *q;
+
+ if (!string || ((result = (char *) zalloc(strlen(string) + 1)) == NULL))
{
- if ((p = (char *)malloc(new_len)) == NULL)
- {
- log_error(LOG_LEVEL_FATAL, "malloc(%d) bytes failed!", new_len);
- /* Never get here - LOG_LEVEL_FATAL causes program exit */
- }
+ return NULL;
+ }
+
+ q = string;
+ p = result;
+
+ while (*q != '\0')
+ {
+ *p++ = (char)toupper((int) *q++);
}
- strcpy(p + old_len, text_to_append);
- return(p);
+ return result;
}
/*********************************************************************
*
- * Function : simplematch
+ * Function : string_tolower
*
- * Description : String matching, with a (greedy) '*' wildcard that
- * stands for zero or more arbitrary characters and
- * character classes in [], which take both enumerations
- * and ranges.
+ * Description : Produce a copy of string with all convertible
+ * characters converted to lowercase.
*
* Parameters :
- * 1 : pattern = pattern for matching
- * 2 : text = text to be matched
+ * 1 : string = string to convert
*
- * Returns : 0 if match, else nonzero
+ * Returns : Lowercase copy of string if possible,
+ * NULL on out-of-memory or if string was NULL.
*
*********************************************************************/
-int simplematch(char *pattern, char *text)
+char *string_tolower(const char *string)
{
- char *fallback;
- char *pat = pattern;
- char *txt = text;
- int wildcard = 0;
-
- char lastchar = 'a';
- unsigned i;
- unsigned char charmap[32];
-
-
- while (*txt)
- {
-
- /* EOF pattern but !EOF text? */
- if (*pat == '\0')
+ char *result, *p;
+ const char *q;
+
+ if (!string || ((result = (char *)zalloc(strlen(string) + 1)) == NULL))
+ {
+ return NULL;
+ }
+
+ q = string;
+ p = result;
+
+ while (*q != '\0')
+ {
+ *p++ = (char)privoxy_tolower(*q++);
+ }
+
+ return result;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : string_move
+ *
+ * Description : memmove wrapper to move the last part of a string
+ * towards the beginning, overwriting the part in
+ * the middle. strlcpy() can't be used here as the
+ * strings overlap.
+ *
+ * Parameters :
+ * 1 : dst = Destination to overwrite
+ * 2 : src = Source to move.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+void string_move(char *dst, char *src)
+{
+ assert(dst < src);
+
+ /* +1 to copy the terminating nul as well. */
+ memmove(dst, src, strlen(src)+1);
+}
+
+
+/*********************************************************************
+ *
+ * Function : bindup
+ *
+ * Description : Duplicate the first n characters of a string that may
+ * contain '\0' characters.
+ *
+ * Parameters :
+ * 1 : string = string to be duplicated
+ * 2 : len = number of bytes to duplicate
+ *
+ * Returns : pointer to copy, or NULL if failure
+ *
+ *********************************************************************/
+char *bindup(const char *string, size_t len)
+{
+ char *duplicate;
+
+ duplicate = (char *)malloc(len);
+ if (NULL != duplicate)
+ {
+ memcpy(duplicate, string, len);
+ }
+
+ return duplicate;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : make_path
+ *
+ * Description : Takes a directory name and a file name, returns
+ * the complete path. Handles windows/unix differences.
+ * If the file name is already an absolute path, or if
+ * the directory name is NULL or empty, it returns
+ * the filename.
+ *
+ * Parameters :
+ * 1 : dir: Name of directory or NULL for none.
+ * 2 : file: Name of file. Should not be NULL or empty.
+ *
+ * Returns : "dir/file" (Or on windows, "dir\file").
+ * It allocates the string on the heap. Caller frees.
+ * Returns NULL in error (i.e. NULL file or out of
+ * memory)
+ *
+ *********************************************************************/
+char * make_path(const char * dir, const char * file)
+{
+ if ((file == NULL) || (*file == '\0'))
+ {
+ return NULL; /* Error */
+ }
+
+ if ((dir == NULL) || (*dir == '\0') /* No directory specified */
+#if defined(_WIN32)
+ || (*file == '\\') || (file[1] == ':') /* Absolute path (DOS) */
+#else /* ifndef _WIN32 */
+ || (*file == '/') /* Absolute path (U*ix) */
+#endif /* ifndef _WIN32 */
+ )
+ {
+ return strdup(file);
+ }
+ else
+ {
+ char * path;
+ size_t path_size = strlen(dir) + strlen(file) + 2; /* +2 for trailing (back)slash and \0 */
+
+#if defined(unix)
+ if (*dir != '/' && basedir && *basedir)
{
- return 1;
+ /*
+ * Relative path, so start with the base directory.
+ */
+ path_size += strlen(basedir) + 1; /* +1 for the slash */
+ path = malloc_or_die(path_size);
+ strlcpy(path, basedir, path_size);
+ strlcat(path, "/", path_size);
+ strlcat(path, dir, path_size);
}
-
- /* '*' in the pattern? */
- if (*pat == '*')
+ else
+#endif /* defined unix */
{
-
- /* The pattern ends afterwards? Speed up the return. */
- if (*++pat == '\0')
- {
- return 0;
- }
-
- /* Else, set wildcard mode and remember position after '*' */
- wildcard = 1;
- fallback = pat;
+ path = malloc_or_die(path_size);
+ strlcpy(path, dir, path_size);
}
- /* Character range specification? */
- if (*pat == '[')
+ assert(NULL != path);
+#if defined(_WIN32)
+ if (path[strlen(path)-1] != '\\')
{
- memset(charmap, '\0', sizeof(charmap));
-
- while (*++pat != ']')
- {
- if (!*pat)
- {
- return 1;
- }
- else if (*pat == '-')
- {
- if ((*++pat == ']') || *pat == '\0')
- {
- return(1);
- }
- for(i = lastchar; i <= *pat; i++)
- {
- charmap[i / 8] |= (1 << (i % 8));
- }
- }
- else
- {
- charmap[*pat / 8] |= (1 << (*pat % 8));
- lastchar = *pat;
- }
- }
- } /* -END- if Character range specification */
-
-
- /* Compare: Char match, or char range match*/
- if ((*pat == *txt)
- || ((*pat == ']') && (charmap[*txt / 8] & (1 << (*txt % 8)))) )
- {
- /* Sucess, go ahead */
- pat++;
+ strlcat(path, "\\", path_size);
}
- else
+#else /* ifndef _WIN32 */
+ if (path[strlen(path)-1] != '/')
{
- /* In wildcard mode, just try again after failiure */
- if(wildcard)
- {
- pat = fallback;
- }
-
- /* Else, bad luck */
- else
- {
- return 1;
- }
+ strlcat(path, "/", path_size);
}
- txt++;
+#endif /* ifndef _WIN32 */
+ strlcat(path, file, path_size);
+
+ return path;
}
+}
+
- /* Cut off extra '*'s */
- if(*pat == '*') pat++;
+/*********************************************************************
+ *
+ * Function : pick_from_range
+ *
+ * Description : Pick a positive number out of a given range.
+ * Should only be used if randomness would be nice,
+ * but isn't really necessary.
+ *
+ * Parameters :
+ * 1 : range: Highest possible number to pick.
+ *
+ * Returns : Picked number.
+ *
+ *********************************************************************/
+long int pick_from_range(long int range)
+{
+ long int number;
+#ifdef _WIN32
+ static unsigned long seed = 0;
+#endif /* def _WIN32 */
+
+ assert(range != 0);
+ assert(range > 0);
+
+ if (range <= 0) return 0;
+
+#ifdef HAVE_ARC4RANDOM
+ number = arc4random() % range + 1;
+#elif defined(HAVE_RANDOM)
+ number = random() % range + 1;
+#elif defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_lock(&rand_mutex);
+#ifdef _WIN32
+ if (!seed)
+ {
+ seed = (unsigned long)(GetCurrentThreadId()+GetTickCount());
+ }
+ srand(seed);
+ seed = (unsigned long)((rand() << 16) + rand());
+#endif /* def _WIN32 */
+ number = (unsigned long)((rand() << 16) + (rand())) % (unsigned long)(range + 1);
+ privoxy_mutex_unlock(&rand_mutex);
+#else
+ /*
+ * XXX: Which platforms reach this and are there
+ * better options than just using rand() and hoping
+ * that it's safe?
+ */
+ log_error(LOG_LEVEL_INFO, "No thread-safe PRNG available? Header time randomization "
+ "might cause crashes, predictable results or even combine these fine options.");
+ number = rand() % (long int)(range + 1);
- /* If this is the pattern's end, fine! */
- return(*pat);
+#endif /* (def HAVE_ARC4RANDOM) */
+ return number;
}
+#ifdef USE_PRIVOXY_STRLCPY
/*********************************************************************
*
- * Function : bindup
+ * Function : privoxy_strlcpy
*
- * Description : Duplicate the first n characters of a string that may
- * contain '\0' characters.
+ * Description : strlcpy(3) look-alike for those without decent libc.
*
* Parameters :
- * 1 : string = string to be duplicated
- * 2 : n = number of bytes to duplicate
+ * 1 : destination: buffer to copy into.
+ * 2 : source: String to copy.
+ * 3 : size: Size of destination buffer.
*
- * Returns : pointer to copy, or NULL if failiure
+ * Returns : The length of the string that privoxy_strlcpy() tried to create.
*
*********************************************************************/
-char *bindup(const char *string, int n)
+size_t privoxy_strlcpy(char *destination, const char *source, const size_t size)
{
- char *dup;
+ if (0 < size)
+ {
+ snprintf(destination, size, "%s", source);
+ /*
+ * Platforms that lack strlcpy() also tend to have
+ * a broken snprintf implementation that doesn't
+ * guarantee nul termination.
+ *
+ * XXX: the configure script should detect and reject those.
+ */
+ destination[size-1] = '\0';
+ }
+ return strlen(source);
+}
+#endif /* def USE_PRIVOXY_STRLCPY */
- if (NULL == (dup = (char *)malloc(n)))
+
+#ifndef HAVE_STRLCAT
+/*********************************************************************
+ *
+ * Function : privoxy_strlcat
+ *
+ * Description : strlcat(3) look-alike for those without decent libc.
+ *
+ * Parameters :
+ * 1 : destination: C string.
+ * 2 : source: String to copy.
+ * 3 : size: Size of destination buffer.
+ *
+ * Returns : The length of the string that privoxy_strlcat() tried to create.
+ *
+ *********************************************************************/
+size_t privoxy_strlcat(char *destination, const char *source, const size_t size)
+{
+ const size_t old_length = strlen(destination);
+ return old_length + strlcpy(destination + old_length, source, size - old_length);
+}
+#endif /* ndef HAVE_STRLCAT */
+
+
+/*********************************************************************
+ *
+ * Function : privoxy_millisleep
+ *
+ * Description : Sleep a number of milliseconds
+ *
+ * Parameters :
+ * 1 : delay: Number of milliseconds to sleep
+ *
+ * Returns : -1 on error, 0 otherwise
+ *
+ *********************************************************************/
+int privoxy_millisleep(unsigned milliseconds)
+{
+#ifdef HAVE_NANOSLEEP
+ struct timespec rqtp = {0};
+ struct timespec rmtp = {0};
+
+ rqtp.tv_sec = milliseconds / 1000;
+ rqtp.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
+
+ return nanosleep(&rqtp, &rmtp);
+#elif defined (_WIN32)
+ Sleep(milliseconds);
+
+ return 0;
+#else
+#warning Missing privoxy_milisleep() implementation. delay-response{} will not work.
+
+ return -1;
+#endif /* def HAVE_NANOSLEEP */
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : privoxy_gmtime_r
+ *
+ * Description : Behave like gmtime_r() and convert a
+ * time_t to a struct tm.
+ *
+ * Parameters :
+ * 1 : time_spec: The time to convert
+ * 2 : result: The struct tm to use as storage
+ *
+ * Returns : Pointer to the result or NULL on error.
+ *
+ *********************************************************************/
+struct tm *privoxy_gmtime_r(const time_t *time_spec, struct tm *result)
+{
+ struct tm *timeptr;
+
+#ifdef HAVE_GMTIME_R
+ timeptr = gmtime_r(time_spec, result);
+#elif defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_lock(&gmtime_mutex);
+ timeptr = gmtime(time_spec);
+#else
+#warning Using unlocked gmtime()
+ timeptr = gmtime(time_spec);
+#endif
+
+ if (timeptr == NULL)
+ {
+#if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
+ return NULL;
+ }
+
+#if !defined(HAVE_GMTIME_R)
+ *result = *timeptr;
+ timeptr = result;
+#ifdef MUTEX_LOCKS_AVAILABLE
+ privoxy_mutex_unlock(&gmtime_mutex);
+#endif
+#endif
+
+ return timeptr;
+}
+
+#if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV)
+/*********************************************************************
+ *
+ * Function : timegm
+ *
+ * Description : libc replacement function for the inverse of gmtime().
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * Code originally copied from GnuPG, modifications done
+ * for Privoxy: style changed, #ifdefs for _WIN32 added
+ * to have it work on mingw32.
+ *
+ * XXX: It's very unlikely to happen, but if the malloc()
+ * call fails the time zone will be permanently set to UTC.
+ *
+ * Parameters :
+ * 1 : tm: Broken-down time struct.
+ *
+ * Returns : tm converted into time_t seconds.
+ *
+ *********************************************************************/
+time_t timegm(struct tm *tm)
+{
+ time_t answer;
+ char *zone;
+
+ zone = getenv("TZ");
+ putenv("TZ=UTC");
+ tzset();
+ answer = mktime(tm);
+ if (zone)
{
- return NULL;
- }
+ char *old_zone;
+
+ old_zone = malloc(3 + strlen(zone) + 1);
+ if (old_zone)
+ {
+ strcpy(old_zone, "TZ=");
+ strcat(old_zone, zone);
+ putenv(old_zone);
+#ifdef _WIN32
+ /* http://man7.org/linux/man-pages/man3/putenv.3.html
+ * int putenv(char *string);
+ * The string pointed to by string becomes part of the environment, so altering the
+ * string changes the environment.
+ * In other words, the memory pointed to by *string is used until
+ * a) another call to putenv() with the same e-var name
+ * b) the program exits
+ *
+ * Windows e-vars don't work that way, so let's not leak memory.
+ */
+ free(old_zone);
+#endif /* def _WIN32 */
+ }
+ }
else
- {
- memcpy(dup, string, n);
- }
+ {
+#ifdef HAVE_UNSETENV
+ unsetenv("TZ");
+#elif defined(_WIN32)
+ putenv("TZ=");
+#else
+ putenv("TZ");
+#endif
+ }
+ tzset();
+
+ return answer;
+}
+#endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */
+
- return dup;
+/*********************************************************************
+ *
+ * Function : host_is_ip_address
+ *
+ * Description : Checks whether or not a host is specified by
+ * IP address. Does not actually validate the
+ * address.
+ *
+ * Parameters :
+ * 1 : host = The host name to check
+ *
+ * Returns : 1 => Yes
+ * 0 => No
+ *
+ *********************************************************************/
+extern int host_is_ip_address(const char *host)
+{
+ const char *p;
+
+ if (NULL != strstr(host, ":"))
+ {
+ /* Assume an IPv6 address. */
+ return 1;
+ }
+
+ for (p = host; *p; p++)
+ {
+ if ((*p != '.') && !privoxy_isdigit(*p))
+ {
+ /* Not a dot or digit so it can't be an IPv4 address. */
+ return 0;
+ }
+ }
+
+ /*
+ * Host only consists of dots and digits so
+ * assume that is an IPv4 address.
+ */
+ return 1;
}