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