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