Merging ACL and forward files into config file.
[privoxy.git] / miscutil.c
1 /* vim:ts=3: */
2 const char miscutil_rcs[] = "$Id: miscutil.c,v 1.10 2001/06/07 14:51:38 joergs Exp $";
3 /*********************************************************************
4  *
5  * File        :  $Source: /cvsroot/ijbswa/current/miscutil.c,v $
6  *
7  * Purpose     :  zalloc, hash_string, safe_strerror, strcmpic,
8  *                strncmpic, strsav, chomp, and MinGW32 strdup
9  *                functions. 
10  *                These are each too small to deserve their own file
11  *                but don't really fit in any other file.
12  *
13  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
14  *                IJBSWA team.  http://ijbswa.sourceforge.net
15  *
16  *                Based on the Internet Junkbuster originally written
17  *                by and Copyright (C) 1997 Anonymous Coders and 
18  *                Junkbusters Corporation.  http://www.junkbusters.com
19  *
20  *                This program is free software; you can redistribute it 
21  *                and/or modify it under the terms of the GNU General
22  *                Public License as published by the Free Software
23  *                Foundation; either version 2 of the License, or (at
24  *                your option) any later version.
25  *
26  *                This program is distributed in the hope that it will
27  *                be useful, but WITHOUT ANY WARRANTY; without even the
28  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
29  *                PARTICULAR PURPOSE.  See the GNU General Public
30  *                License for more details.
31  *
32  *                The GNU General Public License should be included with
33  *                this file.  If not, you can view it at
34  *                http://www.gnu.org/copyleft/gpl.html
35  *                or write to the Free Software Foundation, Inc., 59
36  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
37  *
38  * Revisions   :
39  *    $Log: miscutil.c,v $
40  *    Revision 1.10  2001/06/07 14:51:38  joergs
41  *    make_path() no longer adds '/' if the dir already ends in '/'.
42  *
43  *    Revision 1.9  2001/06/07 14:43:17  swa
44  *    slight mistake in make_path, unix path style is /.
45  *
46  *    Revision 1.8  2001/06/05 22:32:01  jongfoster
47  *    New function make_path() to splice directory and file names together.
48  *
49  *    Revision 1.7  2001/06/03 19:12:30  oes
50  *    introduced bindup()
51  *
52  *    Revision 1.7  2001/06/03 11:03:48  oes
53  *    Makefile/in
54  *
55  *    introduced cgi.c
56  *
57  *    actions.c:
58  *
59  *    adapted to new enlist_unique arg format
60  *
61  *    conf loadcfg.c
62  *
63  *    introduced confdir option
64  *
65  *    filters.c filtrers.h
66  *
67  *     extracted-CGI relevant stuff
68  *
69  *    jbsockets.c
70  *
71  *     filled comment
72  *
73  *    jcc.c
74  *
75  *     support for new cgi mechansim
76  *
77  *    list.c list.h
78  *
79  *    functions for new list type: "map"
80  *    extended enlist_unique
81  *
82  *    miscutil.c .h
83  *    introduced bindup()
84  *
85  *    parsers.c parsers.h
86  *
87  *    deleted const struct interceptors
88  *
89  *    pcrs.c
90  *    added FIXME
91  *
92  *    project.h
93  *
94  *    added struct map
95  *    added struct http_response
96  *    changes struct interceptors to struct cgi_dispatcher
97  *    moved HTML stuff to cgi.h
98  *
99  *    re_filterfile:
100  *
101  *    changed
102  *
103  *    showargs.c
104  *    NO TIME LEFT
105  *
106  *    Revision 1.6  2001/06/01 18:14:49  jongfoster
107  *    Changing the calls to strerr() to check HAVE_STRERR (which is defined
108  *    in config.h if appropriate) rather than the NO_STRERR macro.
109  *
110  *    Revision 1.5  2001/06/01 10:31:51  oes
111  *    Added character class matching to trivimatch; renamed to simplematch
112  *
113  *    Revision 1.4  2001/05/31 17:32:31  oes
114  *
115  *     - Enhanced domain part globbing with infix and prefix asterisk
116  *       matching and optional unanchored operation
117  *
118  *    Revision 1.3  2001/05/29 23:10:09  oes
119  *
120  *
121  *     - Introduced chomp()
122  *     - Moved strsav() from showargs to miscutil
123  *
124  *    Revision 1.2  2001/05/29 09:50:24  jongfoster
125  *    Unified blocklist/imagelist/permissionslist.
126  *    File format is still under discussion, but the internal changes
127  *    are (mostly) done.
128  *
129  *    Also modified interceptor behaviour:
130  *    - We now intercept all URLs beginning with one of the following
131  *      prefixes (and *only* these prefixes):
132  *        * http://i.j.b/
133  *        * http://ijbswa.sf.net/config/
134  *        * http://ijbswa.sourceforge.net/config/
135  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
136  *    - Internal changes so that intercepted and fast redirect pages
137  *      are not replaced with an image.
138  *    - Interceptors now have the option to send a binary page direct
139  *      to the client. (i.e. ijb-send-banner uses this)
140  *    - Implemented show-url-info interceptor.  (Which is why I needed
141  *      the above interceptors changes - a typical URL is
142  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
143  *      The previous mechanism would not have intercepted that, and
144  *      if it had been intercepted then it then it would have replaced
145  *      it with an image.)
146  *
147  *    Revision 1.1.1.1  2001/05/15 13:59:00  oes
148  *    Initial import of version 2.9.3 source tree
149  *
150  *
151  *********************************************************************/
152 \f
153
154 #include "config.h"
155
156 #include <stdio.h>
157 #include <stdlib.h>
158 #include <string.h>
159 #include <malloc.h>
160 #include <ctype.h>
161
162 #include "miscutil.h"
163 #include "errlog.h"
164
165 const char miscutil_h_rcs[] = MISCUTIL_H_VERSION;
166
167 /* Fix a problem with Solaris.  There should be no effect on other
168  * platforms.
169  * Solaris's isspace() is a macro which uses it's argument directly
170  * as an array index.  Therefore we need to make sure that high-bit
171  * characters generate +ve values, and ideally we also want to make
172  * the argument match the declared parameter type of "int".
173  */
174 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
175 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))   
176
177 /*********************************************************************
178  *
179  * Function    :  zalloc
180  *
181  * Description :  Malloc some memory and set it to '\0'.
182  *                The way calloc() ought to be -acjc
183  *
184  * Parameters  :
185  *          1  :  size = Size of memory chunk to return.
186  *
187  * Returns     :  Pointer to newly malloc'd memory chunk.
188  *
189  *********************************************************************/
190 void *zalloc(int size)
191 {
192    void * ret;
193
194    if ((ret = (void *)malloc(size)) != NULL)
195    {
196       memset(ret, 0, size);
197    }
198
199    return(ret);
200 }
201
202
203 /*********************************************************************
204  *
205  * Function    :  hash_string
206  *
207  * Description :  Take a string and compute a (hopefuly) unique numeric
208  *                integer value.  This has several uses, but being able
209  *                to "switch" a string the one of my favorites.
210  *
211  * Parameters  :
212  *          1  :  s : string to be hashed.
213  *
214  * Returns     :  an unsigned long variable with the hashed value.
215  *
216  *********************************************************************/
217 unsigned long hash_string( const char* s )
218 {
219    unsigned long h = 0ul; 
220
221    for ( ; *s; ++s )
222    {
223       h = 5 * h + *s;
224    }
225
226    return (h);
227
228 }
229
230
231 #ifdef __MINGW32__
232 /*********************************************************************
233  *
234  * Function    :  strdup
235  *
236  * Description :  For some reason (which is beyond me), gcc and WIN32
237  *                don't like strdup.  When a "free" is executed on a
238  *                strdup'd ptr, it can at times freez up!  So I just
239  *                replaced it and problem was solved.
240  *
241  * Parameters  :
242  *          1  :  s = string to duplicate
243  *
244  * Returns     :  Pointer to newly malloc'ed copy of the string.
245  *
246  *********************************************************************/
247 char *strdup( const char *s )
248 {
249    char * result = (char *)malloc( strlen(s)+1 );
250
251    if (result != NULL)
252    {
253       strcpy( result, s );
254    }
255
256    return( result );
257 }
258
259 #endif /* def __MINGW32__ */
260
261
262
263 /*********************************************************************
264  *
265  * Function    :  safe_strerror
266  *
267  * Description :  Variant of the library routine strerror() which will
268  *                work on systems without the library routine, and
269  *                which should never return NULL.
270  *
271  * Parameters  :
272  *          1  :  err = the `errno' of the last operation.
273  *
274  * Returns     :  An "English" string of the last `errno'.  Allocated
275  *                with strdup(), so caller frees.  May be NULL if the
276  *                system is out of memory.
277  *
278  *********************************************************************/
279 char *safe_strerror(int err)
280 {
281    char *s = NULL;
282    char buf[BUFSIZ];
283
284
285 #ifdef HAVE_STRERROR
286    s = strerror(err);
287 #endif /* HAVE_STRERROR */
288
289    if (s == NULL)
290    {
291       sprintf(buf, "(errno = %d)", err);
292       s = buf;
293    }
294
295    return(strdup(s));
296
297 }
298
299
300 /*********************************************************************
301  *
302  * Function    :  strcmpic
303  *
304  * Description :  Case insensitive string comparison
305  *
306  * Parameters  :
307  *          1  :  s1 = string 1 to compare
308  *          2  :  s2 = string 2 to compare
309  *
310  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
311  *
312  *********************************************************************/
313 int strcmpic(const char *s1, const char *s2)
314 {
315    while (*s1 && *s2)
316    {
317       if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
318       {
319          break;
320       }
321       s1++, s2++;
322    }
323    return(ijb_tolower(*s1) - ijb_tolower(*s2));
324
325 }
326
327
328 /*********************************************************************
329  *
330  * Function    :  strncmpic
331  *
332  * Description :  Case insensitive string comparison (upto n characters)
333  *
334  * Parameters  :
335  *          1  :  s1 = string 1 to compare
336  *          2  :  s2 = string 2 to compare
337  *          3  :  n = maximum characters to compare
338  *
339  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
340  *
341  *********************************************************************/
342 int strncmpic(const char *s1, const char *s2, size_t n)
343 {
344    if (n <= 0) return(0);
345
346    while (*s1 && *s2)
347    {
348       if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
349       {
350          break;
351       }
352
353       if (--n <= 0) break;
354
355       s1++, s2++;
356    }
357    return(ijb_tolower(*s1) - ijb_tolower(*s2));
358
359 }
360
361
362 /*********************************************************************
363  *
364  * Function    :  chomp
365  *
366  * Description :  In-situ-eliminate all leading and trailing whitespace
367  *                from a string.
368  *
369  * Parameters  :
370  *          1  :  s : string to be chomped.
371  *
372  * Returns     :  chomped string
373  *
374  *********************************************************************/
375 char *chomp(char *string)
376 {
377    char *p, *q, *r;
378
379    /* 
380     * strip trailing whitespace
381     */
382    p = string + strlen(string);
383    while (p > string && ijb_isspace(*(p-1)))
384    {
385       p--;
386    }
387    *p = '\0';
388
389    /* 
390     * find end of leading whitespace 
391     */
392    q = r = string;
393    while (*q && ijb_isspace(*q))
394    {
395       q++;
396    }
397
398    /*
399     * if there was any, move the rest forwards
400     */
401    if (q != string)
402    {
403       while (q <= p)
404       {
405          *r++ = *q++;
406       }
407    }
408
409    return(string);
410
411 }
412
413 /*********************************************************************
414  *
415  * Function    :  strsav
416  *
417  * Description :  Reallocate "old" and append text to it.  This makes
418  *                it easier to append to malloc'd strings.
419  *
420  * Parameters  :
421  *          1  :  old = Old text that is to be extended.  Will be
422  *                free()d by this routine.
423  *          2  :  text_to_append = Text to be appended to old.
424  *
425  * Returns     :  Pointer to newly malloc'ed appended string.
426  *                If there is no text to append, return old.  Caller
427  *                must free().
428  *
429  *********************************************************************/
430 char *strsav(char *old, const char *text_to_append)
431 {
432    int old_len, new_len;
433    char *p;
434
435    if (( text_to_append == NULL) || (*text_to_append == '\0'))
436    {
437       return(old);
438    }
439
440    if (NULL != old)
441    {
442       old_len = strlen(old);
443    }
444    else
445    {
446       old_len = 0;
447    }
448
449    new_len = old_len + strlen(text_to_append) + 1;
450
451    if (old)
452    {
453       if ((p = realloc(old, new_len)) == NULL)
454       {
455          log_error(LOG_LEVEL_FATAL, "realloc(%d) bytes failed!", new_len);
456          /* Never get here - LOG_LEVEL_FATAL causes program exit */
457       }
458    }
459    else
460    {
461       if ((p = (char *)malloc(new_len)) == NULL)
462       {
463          log_error(LOG_LEVEL_FATAL, "malloc(%d) bytes failed!", new_len);
464          /* Never get here - LOG_LEVEL_FATAL causes program exit */
465       }
466    }
467
468    strcpy(p + old_len, text_to_append);
469    return(p);
470
471 }
472
473
474 /*********************************************************************
475  *
476  * Function    :  simplematch
477  *
478  * Description :  String matching, with a (greedy) '*' wildcard that
479  *                stands for zero or more arbitrary characters and
480  *                character classes in [], which take both enumerations
481  *                and ranges.
482  *
483  * Parameters  :
484  *          1  :  pattern = pattern for matching
485  *          2  :  text    = text to be matched
486  *
487  * Returns     :  0 if match, else nonzero
488  *
489  *********************************************************************/
490 int simplematch(char *pattern, char *text)
491 {
492    char *fallback; 
493    char *pat = pattern;
494    char *txt = text;
495    int wildcard = 0;
496   
497    char lastchar = 'a';
498    unsigned i;
499    unsigned char charmap[32];
500   
501   
502    while (*txt)
503    {
504
505       /* EOF pattern but !EOF text? */
506       if (*pat == '\0')
507       {
508          return 1;
509       }
510
511       /* '*' in the pattern?  */
512       if (*pat == '*') 
513       {
514      
515          /* The pattern ends afterwards? Speed up the return. */
516          if (*++pat == '\0')
517          {
518             return 0;
519          }
520      
521          /* Else, set wildcard mode and remember position after '*' */
522          wildcard = 1;
523          fallback = pat;
524       }
525
526       /* Character range specification? */
527       if (*pat == '[')
528       {
529          memset(charmap, '\0', sizeof(charmap));
530
531          while (*++pat != ']')
532          {
533             if (!*pat)
534             { 
535                return 1;
536             }
537             else if (*pat == '-')
538             {
539                if ((*++pat == ']') || *pat == '\0')
540                {
541                   return(1);
542                }
543                for(i = lastchar; i <= *pat; i++)
544                {
545                   charmap[i / 8] |= (1 << (i % 8));
546                } 
547             }
548             else
549             {
550                charmap[*pat / 8] |= (1 << (*pat % 8));
551                lastchar = *pat;
552             }
553          }
554       } /* -END- if Character range specification */
555
556
557       /* Compare: Char match, or char range match*/
558       if ((*pat == *txt)  
559       || ((*pat == ']') && (charmap[*txt / 8] & (1 << (*txt % 8)))) )
560       {
561          /* Sucess, go ahead */
562          pat++;
563       }
564       else
565       {
566          /* In wildcard mode, just try again after failiure */
567          if(wildcard)
568          {
569             pat = fallback;
570          }
571
572          /* Else, bad luck */
573          else
574          {
575             return 1;
576          }
577       }
578       txt++;
579    }
580
581    /* Cut off extra '*'s */
582    if(*pat == '*')  pat++;
583
584    /* If this is the pattern's end, fine! */
585    return(*pat);
586
587 }
588
589
590 /*********************************************************************
591  *
592  * Function    :  bindup
593  *
594  * Description :  Duplicate the first n characters of a string that may
595  *                contain '\0' characters.
596  *
597  * Parameters  :
598  *          1  :  string = string to be duplicated
599  *          2  :  n = number of bytes to duplicate
600  *
601  * Returns     :  pointer to copy, or NULL if failiure
602  *
603  *********************************************************************/
604 char *bindup(const char *string, int n)
605 {
606    char *dup;
607
608    if (NULL == (dup = (char *)malloc(n)))
609    {
610            return NULL;
611         }
612    else
613         {
614           memcpy(dup, string, n);
615         }
616
617    return dup;
618
619 }
620
621
622 /*********************************************************************
623  *
624  * Function    :  make_path
625  *
626  * Description :  Takes a directory name and a file name, returns 
627  *                the complete path.  Handles windows/unix differences.
628  *                If the file name is already an absolute path, or if
629  *                the directory name is NULL or empty, it returns 
630  *                the filename. 
631  *
632  * Parameters  :
633  *          1  :  dir: Name of directory or NULL for none.
634  *          2  :  file: Name of file.  Should not be NULL or empty.
635  *
636  * Returns     :  "dir/file" (Or on windows, "dir\file").
637  *                It allocates the string on the heap.  Caller frees.
638  *                Returns NULL in error (i.e. NULL file or out of
639  *                memory) 
640  *
641  *********************************************************************/
642 char * make_path(const char * dir, const char * file)
643 {
644 #ifdef AMIGA
645    char path[512];
646
647    if(dir)
648    {
649       strncpy(path,dir,512);
650       path[511]=0;
651    } else {
652       path[0]=0;
653    }
654    if(AddPart(path,file,512))
655    {
656       return strdup(path);
657    } else {
658       return NULL;
659    }
660 #else /* ndef AMIGA */
661
662    if ((file == NULL) || (*file == '\0'))
663    {
664       return NULL; /* Error */
665    }
666
667    if ((dir == NULL) || (*dir == '\0') /* No directory specified */
668 #ifdef _WIN32
669       || (*file == '\\') || (file[1] == ':') /* Absolute path (DOS) */
670 #else /* ifndef _WIN32 */
671       || (*file == '/') /* Absolute path (U*ix) */
672 #endif /* ifndef _WIN32 */
673       )
674    {
675       return strdup(file);
676    }
677    else
678    {
679       char * path = malloc(strlen(dir) + strlen(file) + 2);
680       strcpy(path, dir);
681 #ifdef _WIN32
682       strcat(path, "\\");
683 #else /* ifndef _WIN32 */
684       if(path[strlen(path)-1] != '/') strcat(path, "/");
685 #endif /* ifndef _WIN32 */
686       strcat(path, file);
687
688       return path;
689    }
690 #endif /* ndef AMIGA */
691 }
692
693
694 /*
695   Local Variables:
696   tab-width: 3
697   end:
698 */