- Back to timegm() using GnuPG's replacement if necessary.
[privoxy.git] / miscutil.c
1 const char miscutil_rcs[] = "$Id: miscutil.c,v 1.39 2006/07/18 14:48:46 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, 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  *                Privoxy team. http://www.privoxy.org/
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.39  2006/07/18 14:48:46  david__schmidt
40  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
41  *    with what was really the latest development (the v_3_0_branch branch)
42  *
43  *    Revision 1.37.2.4  2003/12/01 14:45:14  oes
44  *    Fixed two more problems with wildcarding in simplematch()
45  *
46  *    Revision 1.37.2.3  2003/11/20 11:39:24  oes
47  *    Bugfix: The "?" wildcard for domain names had never been implemented. Ooops\!
48  *
49  *    Revision 1.37.2.2  2002/11/12 14:28:18  oes
50  *    Proper backtracking in simplematch; fixes bug #632888
51  *
52  *    Revision 1.37.2.1  2002/09/25 12:58:51  oes
53  *    Made strcmpic and strncmpic safe against NULL arguments
54  *    (which are now treated as empty strings).
55  *
56  *    Revision 1.37  2002/04/26 18:29:43  jongfoster
57  *    Fixing this Visual C++ warning:
58  *    miscutil.c(710) : warning C4090: '=' : different 'const' qualifiers
59  *
60  *    Revision 1.36  2002/04/26 12:55:38  oes
61  *    New function string_toupper
62  *
63  *    Revision 1.35  2002/03/26 22:29:55  swa
64  *    we have a new homepage!
65  *
66  *    Revision 1.34  2002/03/24 13:25:43  swa
67  *    name change related issues
68  *
69  *    Revision 1.33  2002/03/07 03:46:53  oes
70  *    Fixed compiler warnings etc
71  *
72  *    Revision 1.32  2002/03/06 23:02:57  jongfoster
73  *    Removing tabs
74  *
75  *    Revision 1.31  2002/03/05 04:52:42  oes
76  *    Deleted non-errlog debugging code
77  *
78  *    Revision 1.30  2002/03/04 18:27:42  oes
79  *    - Deleted deletePidFile
80  *    - Made write_pid_file use the --pidfile option value
81  *      (or no PID file, if the option was absent)
82  *    - Played styleguide police
83  *
84  *    Revision 1.29  2002/03/04 02:08:02  david__schmidt
85  *    Enable web editing of actions file on OS/2 (it had been broken all this time!)
86  *
87  *    Revision 1.28  2002/03/03 09:18:03  joergs
88  *    Made jumbjuster work on AmigaOS again.
89  *
90  *    Revision 1.27  2002/01/21 00:52:32  jongfoster
91  *    Adding string_join()
92  *
93  *    Revision 1.26  2001/12/30 14:07:32  steudten
94  *    - Add signal handling (unix)
95  *    - Add SIGHUP handler (unix)
96  *    - Add creation of pidfile (unix)
97  *    - Add action 'top' in rc file (RH)
98  *    - Add entry 'SIGNALS' to manpage
99  *    - Add exit message to logfile (unix)
100  *
101  *    Revision 1.25  2001/11/13 00:16:38  jongfoster
102  *    Replacing references to malloc.h with the standard stdlib.h
103  *    (See ANSI or K&R 2nd Ed)
104  *
105  *    Revision 1.24  2001/11/05 21:41:43  steudten
106  *    Add changes to be a real daemon just for unix os.
107  *    (change cwd to /, detach from controlling tty, set
108  *    process group and session leader to the own process.
109  *    Add DBG() Macro.
110  *    Add some fatal-error log message for failed malloc().
111  *    Add '-d' if compiled with 'configure --with-debug' to
112  *    enable debug output.
113  *
114  *    Revision 1.23  2001/10/29 03:48:10  david__schmidt
115  *    OS/2 native needed a snprintf() routine.  Added one to miscutil, brackedted
116  *    by and __OS2__ ifdef.
117  *
118  *    Revision 1.22  2001/10/26 17:39:38  oes
119  *    Moved ijb_isspace and ijb_tolower to project.h
120  *
121  *    Revision 1.21  2001/10/23 21:27:50  jongfoster
122  *    Standardising error codes in string_append
123  *    make_path() no longer adds '\\' if the dir already ends in '\\' (this
124  *    is just copying a UNIX-specific fix to the Windows-specific part)
125  *
126  *    Revision 1.20  2001/10/22 15:33:56  david__schmidt
127  *    Special-cased OS/2 out of the Netscape-abort-on-404-in-js problem in
128  *    filters.c.  Added a FIXME in front of the offending code.  I'll gladly
129  *    put in a better/more robust fix for all parties if one is presented...
130  *    It seems that just returning 200 instead of 404 would pretty much fix
131  *    it for everyone, but I don't know all the history of the problem.
132  *
133  *    Revision 1.19  2001/10/14 22:02:57  jongfoster
134  *    New function string_append() which is like strsav(), but running
135  *    out of memory isn't automatically FATAL.
136  *
137  *    Revision 1.18  2001/09/20 13:33:43  steudten
138  *
139  *    change long to int as return value in hash_string(). Remember the wraparound
140  *    for int = long = sizeof(4) - thats maybe not what we want.
141  *
142  *    Revision 1.17  2001/09/13 20:51:29  jongfoster
143  *    Fixing potential problems with characters >=128 in simplematch()
144  *    This was also a compiler warning.
145  *
146  *    Revision 1.16  2001/09/10 10:56:59  oes
147  *    Silenced compiler warnings
148  *
149  *    Revision 1.15  2001/07/13 14:02:24  oes
150  *    Removed vim-settings
151  *
152  *    Revision 1.14  2001/06/29 21:45:41  oes
153  *    Indentation, CRLF->LF, Tab-> Space
154  *
155  *    Revision 1.13  2001/06/29 13:32:14  oes
156  *    Removed logentry from cancelled commit
157  *
158  *    Revision 1.12  2001/06/09 10:55:28  jongfoster
159  *    Changing BUFSIZ ==> BUFFER_SIZE
160  *
161  *    Revision 1.11  2001/06/07 23:09:19  jongfoster
162  *    Cosmetic indentation changes.
163  *
164  *    Revision 1.10  2001/06/07 14:51:38  joergs
165  *    make_path() no longer adds '/' if the dir already ends in '/'.
166  *
167  *    Revision 1.9  2001/06/07 14:43:17  swa
168  *    slight mistake in make_path, unix path style is /.
169  *
170  *    Revision 1.8  2001/06/05 22:32:01  jongfoster
171  *    New function make_path() to splice directory and file names together.
172  *
173  *    Revision 1.7  2001/06/03 19:12:30  oes
174  *    introduced bindup()
175  *
176  *    Revision 1.6  2001/06/01 18:14:49  jongfoster
177  *    Changing the calls to strerr() to check HAVE_STRERR (which is defined
178  *    in config.h if appropriate) rather than the NO_STRERR macro.
179  *
180  *    Revision 1.5  2001/06/01 10:31:51  oes
181  *    Added character class matching to trivimatch; renamed to simplematch
182  *
183  *    Revision 1.4  2001/05/31 17:32:31  oes
184  *
185  *     - Enhanced domain part globbing with infix and prefix asterisk
186  *       matching and optional unanchored operation
187  *
188  *    Revision 1.3  2001/05/29 23:10:09  oes
189  *
190  *
191  *     - Introduced chomp()
192  *     - Moved strsav() from showargs to miscutil
193  *
194  *    Revision 1.2  2001/05/29 09:50:24  jongfoster
195  *    Unified blocklist/imagelist/permissionslist.
196  *    File format is still under discussion, but the internal changes
197  *    are (mostly) done.
198  *
199  *    Also modified interceptor behaviour:
200  *    - We now intercept all URLs beginning with one of the following
201  *      prefixes (and *only* these prefixes):
202  *        * http://i.j.b/
203  *        * http://ijbswa.sf.net/config/
204  *        * http://ijbswa.sourceforge.net/config/
205  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
206  *    - Internal changes so that intercepted and fast redirect pages
207  *      are not replaced with an image.
208  *    - Interceptors now have the option to send a binary page direct
209  *      to the client. (i.e. ijb-send-banner uses this)
210  *    - Implemented show-url-info interceptor.  (Which is why I needed
211  *      the above interceptors changes - a typical URL is
212  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
213  *      The previous mechanism would not have intercepted that, and
214  *      if it had been intercepted then it then it would have replaced
215  *      it with an image.)
216  *
217  *    Revision 1.1.1.1  2001/05/15 13:59:00  oes
218  *    Initial import of version 2.9.3 source tree
219  *
220  *
221  *********************************************************************/
222 \f
223
224 #include "config.h"
225
226 #include <stdio.h>
227 #include <sys/types.h>
228 #include <stdlib.h>
229 #if !defined(_WIN32) && !defined(__OS2__)
230 #include <unistd.h>
231 #endif /* #if !defined(_WIN32) && !defined(__OS2__) */
232 #include <string.h>
233 #include <ctype.h>
234 #include <assert.h>
235
236 #ifndef HAVE_TIMEGM
237 #include <time.h>
238 #endif /* #ifndef HAVE_TIMEGM */
239
240 #include "project.h"
241 #include "miscutil.h"
242 #include "errlog.h"
243 #include "jcc.h"
244
245 const char miscutil_h_rcs[] = MISCUTIL_H_VERSION;
246
247 /*********************************************************************
248  *
249  * Function    :  zalloc
250  *
251  * Description :  Malloc some memory and set it to '\0'.
252  *                The way calloc() ought to be -acjc
253  *
254  * Parameters  :
255  *          1  :  size = Size of memory chunk to return.
256  *
257  * Returns     :  Pointer to newly malloc'd memory chunk.
258  *
259  *********************************************************************/
260 void *zalloc(size_t size)
261 {
262    void * ret;
263
264    if ((ret = (void *)malloc(size)) != NULL)
265    {
266       memset(ret, 0, size);
267    }
268
269    return(ret);
270
271 }
272
273
274 #if defined(unix)
275 /*********************************************************************
276  *
277  * Function    :  write_pid_file 
278  *
279  * Description :  Writes a pid file with the pid of the main process 
280  *
281  * Parameters  :  None
282  *
283  * Returns     :  N/A 
284  *
285  *********************************************************************/
286 void write_pid_file(void)
287 {
288    FILE   *fp;
289    
290    /*
291     * If no --pidfile option was given,
292     * we can live without one.
293     */
294    if (pidfile == NULL) return;
295
296    if ((fp = fopen(pidfile, "w")) == NULL)
297    {
298       log_error(LOG_LEVEL_INFO, "can't open pidfile '%s': %E", pidfile);
299    }
300    else
301    {
302       fprintf(fp, "%u\n", (unsigned int) getpid());
303       fclose (fp);
304    }
305    return;
306
307 }
308 #endif /* def unix */
309
310
311 /*********************************************************************
312  *
313  * Function    :  hash_string
314  *
315  * Description :  Take a string and compute a (hopefuly) unique numeric
316  *                integer value.  This has several uses, but being able
317  *                to "switch" a string the one of my favorites.
318  *
319  * Parameters  :
320  *          1  :  s : string to be hashed.
321  *
322  * Returns     :  an unsigned long variable with the hashed value.
323  *
324  *********************************************************************/
325 unsigned int hash_string( const char* s )
326 {
327    unsigned int h = 0; 
328
329    for ( ; *s; ++s )
330    {
331       h = 5 * h + *s;
332    }
333
334    return (h);
335
336 }
337
338
339 #ifdef __MINGW32__
340 /*********************************************************************
341  *
342  * Function    :  strdup
343  *
344  * Description :  For some reason (which is beyond me), gcc and WIN32
345  *                don't like strdup.  When a "free" is executed on a
346  *                strdup'd ptr, it can at times freez up!  So I just
347  *                replaced it and problem was solved.
348  *
349  * Parameters  :
350  *          1  :  s = string to duplicate
351  *
352  * Returns     :  Pointer to newly malloc'ed copy of the string.
353  *
354  *********************************************************************/
355 char *strdup( const char *s )
356 {
357    char * result = (char *)malloc( strlen(s)+1 );
358
359    if (result != NULL)
360    {
361       strcpy( result, s );
362    }
363
364    return( result );
365 }
366
367 #endif /* def __MINGW32__ */
368
369
370
371 /*********************************************************************
372  *
373  * Function    :  safe_strerror
374  *
375  * Description :  Variant of the library routine strerror() which will
376  *                work on systems without the library routine, and
377  *                which should never return NULL.
378  *
379  * Parameters  :
380  *          1  :  err = the `errno' of the last operation.
381  *
382  * Returns     :  An "English" string of the last `errno'.  Allocated
383  *                with strdup(), so caller frees.  May be NULL if the
384  *                system is out of memory.
385  *
386  *********************************************************************/
387 char *safe_strerror(int err)
388 {
389    char *s = NULL;
390    char buf[BUFFER_SIZE];
391
392
393 #ifdef HAVE_STRERROR
394    s = strerror(err);
395 #endif /* HAVE_STRERROR */
396
397    if (s == NULL)
398    {
399       sprintf(buf, "(errno = %d)", err);
400       s = buf;
401    }
402
403    return(strdup(s));
404
405 }
406
407
408 /*********************************************************************
409  *
410  * Function    :  strcmpic
411  *
412  * Description :  Case insensitive string comparison
413  *
414  * Parameters  :
415  *          1  :  s1 = string 1 to compare
416  *          2  :  s2 = string 2 to compare
417  *
418  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
419  *
420  *********************************************************************/
421 int strcmpic(const char *s1, const char *s2)
422 {
423    if (!s1) s1 = "";
424    if (!s2) s2 = "";
425
426    while (*s1 && *s2)
427    {
428       if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
429       {
430          break;
431       }
432       s1++, s2++;
433    }
434    return(ijb_tolower(*s1) - ijb_tolower(*s2));
435
436 }
437
438
439 /*********************************************************************
440  *
441  * Function    :  strncmpic
442  *
443  * Description :  Case insensitive string comparison (upto n characters)
444  *
445  * Parameters  :
446  *          1  :  s1 = string 1 to compare
447  *          2  :  s2 = string 2 to compare
448  *          3  :  n = maximum characters to compare
449  *
450  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
451  *
452  *********************************************************************/
453 int strncmpic(const char *s1, const char *s2, size_t n)
454 {
455    if (n <= 0) return(0);
456    if (!s1) s1 = "";
457    if (!s2) s2 = "";
458    
459    while (*s1 && *s2)
460    {
461       if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
462       {
463          break;
464       }
465
466       if (--n <= 0) break;
467
468       s1++, s2++;
469    }
470    return(ijb_tolower(*s1) - ijb_tolower(*s2));
471
472 }
473
474
475 /*********************************************************************
476  *
477  * Function    :  chomp
478  *
479  * Description :  In-situ-eliminate all leading and trailing whitespace
480  *                from a string.
481  *
482  * Parameters  :
483  *          1  :  s : string to be chomped.
484  *
485  * Returns     :  chomped string
486  *
487  *********************************************************************/
488 char *chomp(char *string)
489 {
490    char *p, *q, *r;
491
492    /* 
493     * strip trailing whitespace
494     */
495    p = string + strlen(string);
496    while (p > string && ijb_isspace(*(p-1)))
497    {
498       p--;
499    }
500    *p = '\0';
501
502    /* 
503     * find end of leading whitespace 
504     */
505    q = r = string;
506    while (*q && ijb_isspace(*q))
507    {
508       q++;
509    }
510
511    /*
512     * if there was any, move the rest forwards
513     */
514    if (q != string)
515    {
516       while (q <= p)
517       {
518          *r++ = *q++;
519       }
520    }
521
522    return(string);
523
524 }
525
526
527 /*********************************************************************
528  *
529  * Function    :  strsav
530  *
531  * Description :  Reallocate "old" and append text to it.  This makes
532  *                it easier to append to malloc'd strings.
533  *                Running out of memory is a FATAL error.
534  *
535  * Parameters  :
536  *          1  :  old = Old text that is to be extended.  Will be
537  *                free()d by this routine.  May be NULL.
538  *          2  :  text_to_append = Text to be appended to old.
539  *                May be NULL.
540  *
541  * Returns     :  Pointer to newly malloc'ed appended string.
542  *                If there is no text to append, return old.  Caller
543  *                must free().
544  *
545  *********************************************************************/
546 char *strsav(char *old, const char *text_to_append)
547 {
548    size_t old_len, new_len = 0;
549    char *p;
550
551    if ((text_to_append == NULL) || (*text_to_append == '\0'))
552    {
553       return(old);
554    }
555
556    if (NULL == old)
557    {
558       if ((p = strdup(text_to_append)) == NULL)
559       {
560          log_error(LOG_LEVEL_FATAL, "strdup() failed!");
561          /* Never get here - LOG_LEVEL_FATAL causes program exit */
562       }
563       return p;
564    }
565
566    old_len = strlen(old);
567    new_len = old_len + strlen(text_to_append) + 1;
568
569    if ((p = realloc(old, new_len)) == NULL)
570    {
571       log_error(LOG_LEVEL_FATAL, "realloc(%d) bytes failed!", new_len);
572       /* Never get here - LOG_LEVEL_FATAL causes program exit */
573    }
574
575    strcpy(p + old_len, text_to_append);
576    return(p);
577 }
578
579
580 /*********************************************************************
581  *
582  * Function    :  string_append
583  *
584  * Description :  Reallocate target_string and append text to it.  
585  *                This makes it easier to append to malloc'd strings.
586  *                This is similar to the (removed) strsav(), but
587  *                running out of memory isn't catastrophic.
588  *
589  *                Programming style:
590  *
591  *                The following style provides sufficient error
592  *                checking for this routine, with minimal clutter
593  *                in the source code.  It is recommended if you
594  *                have many calls to this function:
595  *
596  *                char * s = strdup(...); // don't check for error
597  *                string_append(&s, ...);  // don't check for error
598  *                string_append(&s, ...);  // don't check for error
599  *                string_append(&s, ...);  // don't check for error
600  *                if (NULL == s) { ... handle error ... }
601  *
602  *                OR, equivalently:
603  *
604  *                char * s = strdup(...); // don't check for error
605  *                string_append(&s, ...);  // don't check for error
606  *                string_append(&s, ...);  // don't check for error
607  *                if (string_append(&s, ...)) {... handle error ...}
608  *
609  * Parameters  :
610  *          1  :  target_string = Pointer to old text that is to be
611  *                extended.  *target_string will be free()d by this
612  *                routine.  target_string must be non-NULL.
613  *                If *target_string is NULL, this routine will
614  *                do nothing and return with an error - this allows
615  *                you to make many calls to this routine and only
616  *                check for errors after the last one.
617  *          2  :  text_to_append = Text to be appended to old.
618  *                Must not be NULL.
619  *
620  * Returns     :  JB_ERR_OK on success, and sets *target_string
621  *                   to newly malloc'ed appended string.  Caller
622  *                   must free(*target_string).
623  *                JB_ERR_MEMORY on out-of-memory.  (And free()s
624  *                   *target_string and sets it to NULL).
625  *                JB_ERR_MEMORY if *target_string is NULL.
626  *
627  *********************************************************************/
628 jb_err string_append(char **target_string, const char *text_to_append)
629 {
630    size_t old_len;
631    char *new_string;
632
633    assert(target_string);
634    assert(text_to_append);
635
636    if (*target_string == NULL)
637    {
638       return JB_ERR_MEMORY;
639    }
640
641    if (*text_to_append == '\0')
642    {
643       return JB_ERR_OK;
644    }
645
646    old_len = strlen(*target_string);
647
648    if (NULL == (new_string = realloc(*target_string,
649           strlen(text_to_append) + old_len + 1)))
650    {
651       free(*target_string);
652
653       *target_string = NULL;
654       return JB_ERR_MEMORY;
655    }
656
657    strcpy(new_string + old_len, text_to_append);
658
659    *target_string = new_string;
660    return JB_ERR_OK;
661 }
662
663
664 /*********************************************************************
665  *
666  * Function    :  string_join
667  *
668  * Description :  Join two strings together.  Frees BOTH the original
669  *                strings.  If either or both input strings are NULL,
670  *                fails as if it had run out of memory.
671  *
672  *                For comparison, string_append requires that the
673  *                second string is non-NULL, and doesn't free it.
674  *
675  *                Rationale: Too often, we want to do
676  *                string_append(s, html_encode(s2)).  That assert()s
677  *                if s2 is NULL or if html_encode() runs out of memory.
678  *                It also leaks memory.  Proper checking is cumbersome.
679  *                The solution: string_join(s, html_encode(s2)) is safe,
680  *                and will free the memory allocated by html_encode().
681  *
682  * Parameters  :
683  *          1  :  target_string = Pointer to old text that is to be
684  *                extended.  *target_string will be free()d by this
685  *                routine.  target_string must be non-NULL.
686  *          2  :  text_to_append = Text to be appended to old.
687  *
688  * Returns     :  JB_ERR_OK on success, and sets *target_string
689  *                   to newly malloc'ed appended string.  Caller
690  *                   must free(*target_string).
691  *                JB_ERR_MEMORY on out-of-memory, or if
692  *                   *target_string or text_to_append is NULL.  (In
693  *                   this case, frees *target_string and text_to_append,
694  *                   sets *target_string to NULL).
695  *
696  *********************************************************************/
697 jb_err string_join(char **target_string, char *text_to_append)
698 {
699    jb_err err;
700
701    assert(target_string);
702
703    if (text_to_append == NULL)
704    {
705       freez(*target_string);
706       return JB_ERR_MEMORY;
707    }
708
709    err = string_append(target_string, text_to_append);
710
711    free(text_to_append);
712
713    return err;
714 }
715
716
717 /*********************************************************************
718  *
719  * Function    :  string_toupper
720  *
721  * Description :  Produce a copy of string with all convertible
722  *                characters converted to uppercase.
723  *
724  * Parameters  :
725  *          1  :  string = string to convert
726  *
727  * Returns     :  Uppercase copy of string if possible, 
728  *                NULL on out-of-memory or if string was NULL.
729  *
730  *********************************************************************/
731 char *string_toupper(const char *string)
732 {
733    char *result, *p;
734    const char *q;
735
736    if (!string || ((result = (char *) zalloc(strlen(string) + 1)) == NULL))
737    {
738       return NULL;
739    }
740    
741    q = string;
742    p = result;
743
744    while (*q != '\0')
745    {
746       *p++ = toupper(*q++);
747    }
748
749    return result;
750
751 }
752
753
754 /*********************************************************************
755  *
756  * Function    :  simplematch
757  *
758  * Description :  String matching, with a (greedy) '*' wildcard that
759  *                stands for zero or more arbitrary characters and
760  *                character classes in [], which take both enumerations
761  *                and ranges.
762  *
763  * Parameters  :
764  *          1  :  pattern = pattern for matching
765  *          2  :  text    = text to be matched
766  *
767  * Returns     :  0 if match, else nonzero
768  *
769  *********************************************************************/
770 int simplematch(char *pattern, char *text)
771 {
772    unsigned char *pat = (unsigned char *) pattern;
773    unsigned char *txt = (unsigned char *) text;
774    unsigned char *fallback = pat; 
775    int wildcard = 0;
776   
777    unsigned char lastchar = 'a';
778    unsigned i;
779    unsigned char charmap[32];
780   
781    while (*txt)
782    {
783
784       /* EOF pattern but !EOF text? */
785       if (*pat == '\0')
786       {
787          if (wildcard)
788          {
789             pat = fallback;
790          }
791          else
792          {
793             return 1;
794          }
795       }
796
797       /* '*' in the pattern?  */
798       if (*pat == '*') 
799       {
800      
801          /* The pattern ends afterwards? Speed up the return. */
802          if (*++pat == '\0')
803          {
804             return 0;
805          }
806      
807          /* Else, set wildcard mode and remember position after '*' */
808          wildcard = 1;
809          fallback = pat;
810       }
811
812       /* Character range specification? */
813       if (*pat == '[')
814       {
815          memset(charmap, '\0', sizeof(charmap));
816
817          while (*++pat != ']')
818          {
819             if (!*pat)
820             { 
821                return 1;
822             }
823             else if (*pat == '-')
824             {
825                if ((*++pat == ']') || *pat == '\0')
826                {
827                   return(1);
828                }
829                for(i = lastchar; i <= *pat; i++)
830                {
831                   charmap[i / 8] |= (1 << (i % 8));
832                } 
833             }
834             else
835             {
836                charmap[*pat / 8] |= (1 << (*pat % 8));
837                lastchar = *pat;
838             }
839          }
840       } /* -END- if Character range specification */
841
842
843       /* 
844        * Char match, or char range match? 
845        */
846       if ( (*pat == *txt)
847       ||   (*pat == '?')
848       ||   ((*pat == ']') && (charmap[*txt / 8] & (1 << (*txt % 8)))) )
849       {
850          /* 
851           * Sucess: Go ahead
852           */
853          pat++;
854       }
855       else if (!wildcard)
856       {
857          /* 
858           * No match && no wildcard: No luck
859           */
860          return 1;
861       }
862       else if (pat != fallback)
863       {
864          /*
865           * Wildcard mode && nonmatch beyond fallback: Rewind pattern
866           */
867          pat = fallback;
868       }
869       txt++;
870    }
871
872    /* Cut off extra '*'s */
873    if(*pat == '*')  pat++;
874
875    /* If this is the pattern's end, fine! */
876    return(*pat);
877
878 }
879
880
881 /*********************************************************************
882  *
883  * Function    :  bindup
884  *
885  * Description :  Duplicate the first n characters of a string that may
886  *                contain '\0' characters.
887  *
888  * Parameters  :
889  *          1  :  string = string to be duplicated
890  *          2  :  len = number of bytes to duplicate
891  *
892  * Returns     :  pointer to copy, or NULL if failiure
893  *
894  *********************************************************************/
895 char *bindup(const char *string, size_t len)
896 {
897    char *duplicate;
898
899    if (NULL == (duplicate = (char *)malloc(len)))
900    {
901       return NULL;
902    }
903    else
904    {
905      memcpy(duplicate, string, len);
906    }
907
908    return duplicate;
909
910 }
911
912
913 /*********************************************************************
914  *
915  * Function    :  make_path
916  *
917  * Description :  Takes a directory name and a file name, returns 
918  *                the complete path.  Handles windows/unix differences.
919  *                If the file name is already an absolute path, or if
920  *                the directory name is NULL or empty, it returns 
921  *                the filename. 
922  *
923  * Parameters  :
924  *          1  :  dir: Name of directory or NULL for none.
925  *          2  :  file: Name of file.  Should not be NULL or empty.
926  *
927  * Returns     :  "dir/file" (Or on windows, "dir\file").
928  *                It allocates the string on the heap.  Caller frees.
929  *                Returns NULL in error (i.e. NULL file or out of
930  *                memory) 
931  *
932  *********************************************************************/
933 char * make_path(const char * dir, const char * file)
934 {
935 #ifdef AMIGA
936    char path[512];
937
938    if(dir)
939    {
940       if(dir[0] == '.')
941       {
942          if(dir[1] == '/')
943          {
944             strncpy(path,dir+2,512);
945          }
946          else
947          {
948             strncpy(path,dir+1,512);
949          }
950       }
951       else
952       {
953          strncpy(path,dir,512);
954       }
955       path[511]=0;
956    } else {
957       path[0]=0;
958    }
959    if(AddPart(path,file,512))
960    {
961       return strdup(path);
962    } else {
963       return NULL;
964    }
965 #else /* ndef AMIGA */
966
967    if ((file == NULL) || (*file == '\0'))
968    {
969       return NULL; /* Error */
970    }
971
972    if ((dir == NULL) || (*dir == '\0') /* No directory specified */
973 #if defined(_WIN32) || defined(__OS2__)
974       || (*file == '\\') || (file[1] == ':') /* Absolute path (DOS) */
975 #else /* ifndef _WIN32 || __OS2__ */
976       || (*file == '/') /* Absolute path (U*ix) */
977 #endif /* ifndef _WIN32 || __OS2__  */
978       )
979    {
980       return strdup(file);
981    }
982    else
983    {
984       char * path;
985
986 #if defined(unix)
987       if ( *dir != '/' && basedir && *basedir )
988       {
989          path = malloc( strlen( basedir ) + strlen(dir) + strlen(file) + 3);
990          if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
991          strcpy(path, basedir);
992          strcat(path, "/");
993          strcat(path, dir);
994       }
995       else
996       {
997          path = malloc(strlen(dir) + strlen(file) + 2);
998          if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
999          strcpy(path, dir);
1000       }
1001 #else
1002
1003       path = malloc(strlen(dir) + strlen(file) + 2);
1004       if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
1005       strcpy(path, dir);
1006
1007 #endif /* defined unix */
1008
1009 #if defined(_WIN32) || defined(__OS2__)
1010       if(path[strlen(path)-1] != '\\')
1011       {
1012          strcat(path, "\\");
1013       }
1014 #else /* ifndef _WIN32 || __OS2__ */
1015       if(path[strlen(path)-1] != '/')
1016       {
1017          strcat(path, "/");
1018       }
1019 #endif /* ifndef _WIN32 || __OS2__ */
1020       strcat(path, file);
1021
1022       return path;
1023    }
1024 #endif /* ndef AMIGA */
1025 }
1026
1027
1028 /*********************************************************************
1029  *
1030  * Function    :  pick_from_range
1031  *
1032  * Description :  Pick a positive number out of a given range.
1033  *                Should only be used if randomness would be nice,
1034  *                but isn't really necessary.
1035  *
1036  * Parameters  :
1037  *          1  :  range: Highest possible number to pick.
1038  *
1039  * Returns     :  Picked number. 
1040  *
1041  *********************************************************************/
1042
1043 long int pick_from_range(long int range)
1044 {
1045    long int number;
1046 #ifndef HAVE_RANDOM
1047    unsigned int weak_seed;
1048
1049    weak_seed = (unsigned int)(time(NULL) | range);
1050    srand(weak_seed);
1051    /*
1052     * Some rand implementations aren't that random and return mostly
1053     * lower numbers. Low entropy doesn't matter for the header times, 
1054     * but higher "random" factors are prefered.
1055     */
1056    number = (rand() * 12345) % (long int)(range + 1);
1057    /* Overflows don't matter either, positive numbers do. */
1058    if(number<0)
1059    {
1060       number*= -1;
1061    }
1062 #else
1063    number = random() % range + 1; 
1064 #endif /* (ifndef HAVE_RANDOM) */
1065    return (number);
1066 }
1067
1068
1069 #ifndef HAVE_TIMEGM
1070 /*********************************************************************
1071  *
1072  * Function    :  timegm
1073  *
1074  * Description :  libc replacement function for the inverse of gmtime()
1075  *                Copyright (C) 2004 Free Software Foundation, Inc.
1076  *                Code copied from GnuPG with minor style changes.
1077  *
1078  * Parameters  :
1079  *          1  :  tm: Broken-down time struct.
1080  *
1081  * Returns     :  tm converted into time_t seconds. 
1082  *
1083  *********************************************************************/
1084
1085 time_t timegm(struct tm *tm)
1086 {
1087    time_t answer;
1088    char *zone;
1089
1090    zone=getenv("TZ");
1091    putenv("TZ=UTC");
1092    tzset();
1093    answer=mktime(tm);
1094    if(zone)
1095    {
1096       char *old_zone;
1097
1098       old_zone=malloc(3+strlen(zone)+1);
1099       if(old_zone)
1100       {
1101          strcpy(old_zone,"TZ=");
1102          strcat(old_zone,zone);
1103          putenv(old_zone);      
1104       }
1105    }
1106    else
1107    {
1108 #ifdef HAVE_UNSETENV
1109       unsetenv("TZ");
1110 #else
1111       putenv("TZ");
1112 #endif
1113    }
1114    tzset();
1115    return answer;
1116 }
1117 #endif /* (ifndef HAVE_TIMEGM) */
1118
1119
1120 /*
1121  * What follows is a portable snprintf routine, written by Mark Martinec.
1122  * See: http://www.ijs.si/software/snprintf/
1123  * Anyone who needs it can add a define for themselves... so far, only 
1124  * OS/2 (native) lacks snprintf.
1125
1126                                   snprintf.c
1127                    - a portable implementation of snprintf,
1128        including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf
1129                                        
1130    snprintf is a routine to convert numeric and string arguments to
1131    formatted strings. It is similar to sprintf(3) provided in a system's
1132    C library, yet it requires an additional argument - the buffer size -
1133    and it guarantees never to store anything beyond the given buffer,
1134    regardless of the format or arguments to be formatted. Some newer
1135    operating systems do provide snprintf in their C library, but many do
1136    not or do provide an inadequate (slow or idiosyncratic) version, which
1137    calls for a portable implementation of this routine.
1138
1139 Author
1140
1141    Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000
1142    Copyright Â© 1999, Mark Martinec
1143
1144  */
1145
1146 #ifdef __OS2__
1147
1148 #define PORTABLE_SNPRINTF_VERSION_MAJOR 2
1149 #define PORTABLE_SNPRINTF_VERSION_MINOR 2
1150
1151 #if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF)
1152 # if defined(NEED_SNPRINTF_ONLY)
1153 # undef NEED_SNPRINTF_ONLY
1154 # endif
1155 # if !defined(PREFER_PORTABLE_SNPRINTF)
1156 # define PREFER_PORTABLE_SNPRINTF
1157 # endif
1158 #endif
1159
1160 #if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE)
1161 #define SOLARIS_COMPATIBLE
1162 #endif
1163
1164 #if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
1165 #define HPUX_COMPATIBLE
1166 #endif
1167
1168 #if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE)
1169 #define DIGITAL_UNIX_COMPATIBLE
1170 #endif
1171
1172 #if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE)
1173 #define PERL_COMPATIBLE
1174 #endif
1175
1176 #if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE)
1177 #define LINUX_COMPATIBLE
1178 #endif
1179
1180 #include <sys/types.h>
1181 #include <string.h>
1182 #include <stdlib.h>
1183 #include <stdio.h>
1184 #include <stdarg.h>
1185 #include <assert.h>
1186 #include <errno.h>
1187
1188 #ifdef isdigit
1189 #undef isdigit
1190 #endif
1191 #define isdigit(c) ((c) >= '0' && (c) <= '9')
1192
1193 /* For copying strings longer or equal to 'breakeven_point'
1194  * it is more efficient to call memcpy() than to do it inline.
1195  * The value depends mostly on the processor architecture,
1196  * but also on the compiler and its optimization capabilities.
1197  * The value is not critical, some small value greater than zero
1198  * will be just fine if you don't care to squeeze every drop
1199  * of performance out of the code.
1200  *
1201  * Small values favor memcpy, large values favor inline code.
1202  */
1203 #if defined(__alpha__) || defined(__alpha)
1204 #  define breakeven_point   2    /* AXP (DEC Alpha)     - gcc or cc or egcs */
1205 #endif
1206 #if defined(__i386__)  || defined(__i386)
1207 #  define breakeven_point  12    /* Intel Pentium/Linux - gcc 2.96 */
1208 #endif
1209 #if defined(__hppa)
1210 #  define breakeven_point  10    /* HP-PA               - gcc */
1211 #endif
1212 #if defined(__sparc__) || defined(__sparc)
1213 #  define breakeven_point  33    /* Sun Sparc 5         - gcc 2.8.1 */
1214 #endif
1215
1216 /* some other values of possible interest: */
1217 /* #define breakeven_point  8 */ /* VAX 4000          - vaxc */
1218 /* #define breakeven_point 19 */ /* VAX 4000          - gcc 2.7.0 */
1219
1220 #ifndef breakeven_point
1221 #  define breakeven_point   6    /* some reasonable one-size-fits-all value */
1222 #endif
1223
1224 #define fast_memcpy(d,s,n) \
1225   { register size_t nn = (size_t)(n); \
1226     if (nn >= breakeven_point) memcpy((d), (s), nn); \
1227     else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
1228       register char *dd; register const char *ss; \
1229       for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
1230
1231 #define fast_memset(d,c,n) \
1232   { register size_t nn = (size_t)(n); \
1233     if (nn >= breakeven_point) memset((d), (int)(c), nn); \
1234     else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
1235       register char *dd; register const int cc=(int)(c); \
1236       for (dd=(d); nn>0; nn--) *dd++ = cc; } }
1237
1238 /* prototypes */
1239
1240 #if defined(NEED_ASPRINTF)
1241 int asprintf   (char **ptr, const char *fmt, /*args*/ ...);
1242 #endif
1243 #if defined(NEED_VASPRINTF)
1244 int vasprintf  (char **ptr, const char *fmt, va_list ap);
1245 #endif
1246 #if defined(NEED_ASNPRINTF)
1247 int asnprintf  (char **ptr, size_t str_m, const char *fmt, /*args*/ ...);
1248 #endif
1249 #if defined(NEED_VASNPRINTF)
1250 int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap);
1251 #endif
1252
1253 #if defined(HAVE_SNPRINTF)
1254 /* declare our portable snprintf  routine under name portable_snprintf  */
1255 /* declare our portable vsnprintf routine under name portable_vsnprintf */
1256 #else
1257 /* declare our portable routines under names snprintf and vsnprintf */
1258 #define portable_snprintf snprintf
1259 #if !defined(NEED_SNPRINTF_ONLY)
1260 #define portable_vsnprintf vsnprintf
1261 #endif
1262 #endif
1263
1264 #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
1265 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...);
1266 #if !defined(NEED_SNPRINTF_ONLY)
1267 int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
1268 #endif
1269 #endif
1270
1271 /* declarations */
1272
1273 static char credits[] = "\n\
1274 @(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
1275 @(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
1276 @(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
1277
1278 #if defined(NEED_ASPRINTF)
1279 int asprintf(char **ptr, const char *fmt, /*args*/ ...) {
1280   va_list ap;
1281   size_t str_m;
1282   int str_l;
1283
1284   *ptr = NULL;
1285   va_start(ap, fmt);                            /* measure the required size */
1286   str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
1287   va_end(ap);
1288   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1289   *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
1290   if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1291   else {
1292     int str_l2;
1293     va_start(ap, fmt);
1294     str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1295     va_end(ap);
1296     assert(str_l2 == str_l);
1297   }
1298   return str_l;
1299 }
1300 #endif
1301
1302 #if defined(NEED_VASPRINTF)
1303 int vasprintf(char **ptr, const char *fmt, va_list ap) {
1304   size_t str_m;
1305   int str_l;
1306
1307   *ptr = NULL;
1308   { va_list ap2;
1309     va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
1310     str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
1311     va_end(ap2);
1312   }
1313   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1314   *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
1315   if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1316   else {
1317     int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1318     assert(str_l2 == str_l);
1319   }
1320   return str_l;
1321 }
1322 #endif
1323
1324 #if defined(NEED_ASNPRINTF)
1325 int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
1326   va_list ap;
1327   int str_l;
1328
1329   *ptr = NULL;
1330   va_start(ap, fmt);                            /* measure the required size */
1331   str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
1332   va_end(ap);
1333   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1334   if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
1335   /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
1336   if (str_m == 0) {  /* not interested in resulting string, just return size */
1337   } else {
1338     *ptr = (char *) malloc(str_m);
1339     if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1340     else {
1341       int str_l2;
1342       va_start(ap, fmt);
1343       str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1344       va_end(ap);
1345       assert(str_l2 == str_l);
1346     }
1347   }
1348   return str_l;
1349 }
1350 #endif
1351
1352 #if defined(NEED_VASNPRINTF)
1353 int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
1354   int str_l;
1355
1356   *ptr = NULL;
1357   { va_list ap2;
1358     va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
1359     str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
1360     va_end(ap2);
1361   }
1362   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1363   if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
1364   /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
1365   if (str_m == 0) {  /* not interested in resulting string, just return size */
1366   } else {
1367     *ptr = (char *) malloc(str_m);
1368     if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1369     else {
1370       int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1371       assert(str_l2 == str_l);
1372     }
1373   }
1374   return str_l;
1375 }
1376 #endif
1377
1378 /*
1379  * If the system does have snprintf and the portable routine is not
1380  * specifically required, this module produces no code for snprintf/vsnprintf.
1381  */
1382 #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
1383
1384 #if !defined(NEED_SNPRINTF_ONLY)
1385 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
1386   va_list ap;
1387   int str_l;
1388
1389   va_start(ap, fmt);
1390   str_l = portable_vsnprintf(str, str_m, fmt, ap);
1391   va_end(ap);
1392   return str_l;
1393 }
1394 #endif
1395
1396 #if defined(NEED_SNPRINTF_ONLY)
1397 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
1398 #else
1399 int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
1400 #endif
1401
1402 #if defined(NEED_SNPRINTF_ONLY)
1403   va_list ap;
1404 #endif
1405   size_t str_l = 0;
1406   const char *p = fmt;
1407
1408 /* In contrast with POSIX, the ISO C99 now says
1409  * that str can be NULL and str_m can be 0.
1410  * This is more useful than the old:  if (str_m < 1) return -1; */
1411
1412 #if defined(NEED_SNPRINTF_ONLY)
1413   va_start(ap, fmt);
1414 #endif
1415   if (!p) p = "";
1416   while (*p) {
1417     if (*p != '%') {
1418    /* if (str_l < str_m) str[str_l++] = *p++;    -- this would be sufficient */
1419    /* but the following code achieves better performance for cases
1420     * where format string is long and contains few conversions */
1421       const char *q = strchr(p+1,'%');
1422       size_t n = !q ? strlen(p) : (q-p);
1423       if (str_l < str_m) {
1424         size_t avail = str_m-str_l;
1425         fast_memcpy(str+str_l, p, (n>avail?avail:n));
1426       }
1427       p += n; str_l += n;
1428     } else {
1429       const char *starting_p;
1430       size_t min_field_width = 0, precision = 0;
1431       int zero_padding = 0, precision_specified = 0, justify_left = 0;
1432       int alternate_form = 0, force_sign = 0;
1433       int space_for_positive = 1; /* If both the ' ' and '+' flags appear,
1434                                      the ' ' flag should be ignored. */
1435       char length_modifier = '\0';            /* allowed values: \0, h, l, L */
1436       char tmp[32];/* temporary buffer for simple numeric->string conversion */
1437
1438       const char *str_arg;      /* string address in case of string argument */
1439       size_t str_arg_l;         /* natural field width of arg without padding
1440                                    and sign */
1441       unsigned char uchar_arg;
1442         /* unsigned char argument value - only defined for c conversion.
1443            N.B. standard explicitly states the char argument for
1444            the c conversion is unsigned */
1445
1446       size_t number_of_zeros_to_pad = 0;
1447         /* number of zeros to be inserted for numeric conversions
1448            as required by the precision or minimal field width */
1449
1450       size_t zero_padding_insertion_ind = 0;
1451         /* index into tmp where zero padding is to be inserted */
1452
1453       char fmt_spec = '\0';
1454         /* current conversion specifier character */
1455
1456       str_arg = credits;/* just to make compiler happy (defined but not used)*/
1457       str_arg = NULL;
1458       starting_p = p; p++;  /* skip '%' */
1459    /* parse flags */
1460       while (*p == '0' || *p == '-' || *p == '+' ||
1461              *p == ' ' || *p == '#' || *p == '\'') {
1462         switch (*p) {
1463         case '0': zero_padding = 1; break;
1464         case '-': justify_left = 1; break;
1465         case '+': force_sign = 1; space_for_positive = 0; break;
1466         case ' ': force_sign = 1;
1467      /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
1468 #ifdef PERL_COMPATIBLE
1469      /* ... but in Perl the last of ' ' and '+' applies */
1470                   space_for_positive = 1;
1471 #endif
1472                   break;
1473         case '#': alternate_form = 1; break;
1474         case '\'': break;
1475         }
1476         p++;
1477       }
1478    /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
1479
1480    /* parse field width */
1481       if (*p == '*') {
1482         int j;
1483         p++; j = va_arg(ap, int);
1484         if (j >= 0) min_field_width = j;
1485         else { min_field_width = -j; justify_left = 1; }
1486       } else if (isdigit((int)(*p))) {
1487         /* size_t could be wider than unsigned int;
1488            make sure we treat argument like common implementations do */
1489         unsigned int uj = *p++ - '0';
1490         while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
1491         min_field_width = uj;
1492       }
1493    /* parse precision */
1494       if (*p == '.') {
1495         p++; precision_specified = 1;
1496         if (*p == '*') {
1497           int j = va_arg(ap, int);
1498           p++;
1499           if (j >= 0) precision = j;
1500           else {
1501             precision_specified = 0; precision = 0;
1502          /* NOTE:
1503           *   Solaris 2.6 man page claims that in this case the precision
1504           *   should be set to 0.  Digital Unix 4.0, HPUX 10 and BSD man page
1505           *   claim that this case should be treated as unspecified precision,
1506           *   which is what we do here.
1507           */
1508           }
1509         } else if (isdigit((int)(*p))) {
1510           /* size_t could be wider than unsigned int;
1511              make sure we treat argument like common implementations do */
1512           unsigned int uj = *p++ - '0';
1513           while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
1514           precision = uj;
1515         }
1516       }
1517    /* parse 'h', 'l' and 'll' length modifiers */
1518       if (*p == 'h' || *p == 'l') {
1519         length_modifier = *p; p++;
1520         if (length_modifier == 'l' && *p == 'l') {   /* double l = long long */
1521 #ifdef SNPRINTF_LONGLONG_SUPPORT
1522           length_modifier = '2';                  /* double l encoded as '2' */
1523 #else
1524           length_modifier = 'l';                 /* treat it as a single 'l' */
1525 #endif
1526           p++;
1527         }
1528       }
1529       fmt_spec = *p;
1530    /* common synonyms: */
1531       switch (fmt_spec) {
1532       case 'i': fmt_spec = 'd'; break;
1533       case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
1534       case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
1535       case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
1536       default: break;
1537       }
1538    /* get parameter value, do initial processing */
1539       switch (fmt_spec) {
1540       case '%': /* % behaves similar to 's' regarding flags and field widths */
1541       case 'c': /* c behaves similar to 's' regarding flags and field widths */
1542       case 's':
1543         length_modifier = '\0';          /* wint_t and wchar_t not supported */
1544      /* the result of zero padding flag with non-numeric conversion specifier*/
1545      /* is undefined. Solaris and HPUX 10 does zero padding in this case,    */
1546      /* Digital Unix and Linux does not. */
1547 #if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
1548         zero_padding = 0;    /* turn zero padding off for string conversions */
1549 #endif
1550         str_arg_l = 1;
1551         switch (fmt_spec) {
1552         case '%':
1553           str_arg = p; break;
1554         case 'c': {
1555           int j = va_arg(ap, int);
1556           uchar_arg = (unsigned char) j;   /* standard demands unsigned char */
1557           str_arg = (const char *) &uchar_arg;
1558           break;
1559         }
1560         case 's':
1561           str_arg = va_arg(ap, const char *);
1562           if (!str_arg) str_arg_l = 0;
1563        /* make sure not to address string beyond the specified precision !!! */
1564           else if (!precision_specified) str_arg_l = strlen(str_arg);
1565        /* truncate string if necessary as requested by precision */
1566           else if (precision == 0) str_arg_l = 0;
1567           else {
1568        /* memchr on HP does not like n > 2^31  !!! */
1569             const char *q = memchr(str_arg, '\0',
1570                              precision <= 0x7fffffff ? precision : 0x7fffffff);
1571             str_arg_l = !q ? precision : (q-str_arg);
1572           }
1573           break;
1574         default: break;
1575         }
1576         break;
1577       case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
1578         /* NOTE: the u, o, x, X and p conversion specifiers imply
1579                  the value is unsigned;  d implies a signed value */
1580
1581         int arg_sign = 0;
1582           /* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
1583             +1 if greater than zero (or nonzero for unsigned arguments),
1584             -1 if negative (unsigned argument is never negative) */
1585
1586         int int_arg = 0;  unsigned int uint_arg = 0;
1587           /* only defined for length modifier h, or for no length modifiers */
1588
1589         long int long_arg = 0;  unsigned long int ulong_arg = 0;
1590           /* only defined for length modifier l */
1591
1592         void *ptr_arg = NULL;
1593           /* pointer argument value -only defined for p conversion */
1594
1595 #ifdef SNPRINTF_LONGLONG_SUPPORT
1596         long long int long_long_arg = 0;
1597         unsigned long long int ulong_long_arg = 0;
1598           /* only defined for length modifier ll */
1599 #endif
1600         if (fmt_spec == 'p') {
1601         /* HPUX 10: An l, h, ll or L before any other conversion character
1602          *   (other than d, i, u, o, x, or X) is ignored.
1603          * Digital Unix:
1604          *   not specified, but seems to behave as HPUX does.
1605          * Solaris: If an h, l, or L appears before any other conversion
1606          *   specifier (other than d, i, u, o, x, or X), the behavior
1607          *   is undefined. (Actually %hp converts only 16-bits of address
1608          *   and %llp treats address as 64-bit data which is incompatible
1609          *   with (void *) argument on a 32-bit system).
1610          */
1611 #ifdef SOLARIS_COMPATIBLE
1612 #  ifdef SOLARIS_BUG_COMPATIBLE
1613           /* keep length modifiers even if it represents 'll' */
1614 #  else
1615           if (length_modifier == '2') length_modifier = '\0';
1616 #  endif
1617 #else
1618           length_modifier = '\0';
1619 #endif
1620           ptr_arg = va_arg(ap, void *);
1621           if (ptr_arg != NULL) arg_sign = 1;
1622         } else if (fmt_spec == 'd') {  /* signed */
1623           switch (length_modifier) {
1624           case '\0':
1625           case 'h':
1626          /* It is non-portable to specify a second argument of char or short
1627           * to va_arg, because arguments seen by the called function
1628           * are not char or short.  C converts char and short arguments
1629           * to int before passing them to a function.
1630           */
1631             int_arg = va_arg(ap, int);
1632             if      (int_arg > 0) arg_sign =  1;
1633             else if (int_arg < 0) arg_sign = -1;
1634             break;
1635           case 'l':
1636             long_arg = va_arg(ap, long int);
1637             if      (long_arg > 0) arg_sign =  1;
1638             else if (long_arg < 0) arg_sign = -1;
1639             break;
1640 #ifdef SNPRINTF_LONGLONG_SUPPORT
1641           case '2':
1642             long_long_arg = va_arg(ap, long long int);
1643             if      (long_long_arg > 0) arg_sign =  1;
1644             else if (long_long_arg < 0) arg_sign = -1;
1645             break;
1646 #endif
1647           }
1648         } else {  /* unsigned */
1649           switch (length_modifier) {
1650           case '\0':
1651           case 'h':
1652             uint_arg = va_arg(ap, unsigned int);
1653             if (uint_arg) arg_sign = 1;
1654             break;
1655           case 'l':
1656             ulong_arg = va_arg(ap, unsigned long int);
1657             if (ulong_arg) arg_sign = 1;
1658             break;
1659 #ifdef SNPRINTF_LONGLONG_SUPPORT
1660           case '2':
1661             ulong_long_arg = va_arg(ap, unsigned long long int);
1662             if (ulong_long_arg) arg_sign = 1;
1663             break;
1664 #endif
1665           }
1666         }
1667         str_arg = tmp; str_arg_l = 0;
1668      /* NOTE:
1669       *   For d, i, u, o, x, and X conversions, if precision is specified,
1670       *   the '0' flag should be ignored. This is so with Solaris 2.6,
1671       *   Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
1672       */
1673 #ifndef PERL_COMPATIBLE
1674         if (precision_specified) zero_padding = 0;
1675 #endif
1676         if (fmt_spec == 'd') {
1677           if (force_sign && arg_sign >= 0)
1678             tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
1679          /* leave negative numbers for sprintf to handle,
1680             to avoid handling tricky cases like (short int)(-32768) */
1681 #ifdef LINUX_COMPATIBLE
1682         } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
1683           tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
1684 #endif
1685         } else if (alternate_form) {
1686           if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
1687             { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
1688          /* alternate form should have no effect for p conversion, but ... */
1689 #ifdef HPUX_COMPATIBLE
1690           else if (fmt_spec == 'p'
1691          /* HPUX 10: for an alternate form of p conversion,
1692           *          a nonzero result is prefixed by 0x. */
1693 #ifndef HPUX_BUG_COMPATIBLE
1694          /* Actually it uses 0x prefix even for a zero value. */
1695                    && arg_sign != 0
1696 #endif
1697                   ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
1698 #endif
1699         }
1700         zero_padding_insertion_ind = str_arg_l;
1701         if (!precision_specified) precision = 1;   /* default precision is 1 */
1702         if (precision == 0 && arg_sign == 0
1703 #if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
1704             && fmt_spec != 'p'
1705          /* HPUX 10 man page claims: With conversion character p the result of
1706           * converting a zero value with a precision of zero is a null string.
1707           * Actually HP returns all zeroes, and Linux returns "(nil)". */
1708 #endif
1709         ) {
1710          /* converted to null string */
1711          /* When zero value is formatted with an explicit precision 0,
1712             the resulting formatted string is empty (d, i, u, o, x, X, p).   */
1713         } else {
1714           char f[5]; int f_l = 0;
1715           f[f_l++] = '%';    /* construct a simple format string for sprintf */
1716           if (!length_modifier) { }
1717           else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
1718           else f[f_l++] = length_modifier;
1719           f[f_l++] = fmt_spec; f[f_l++] = '\0';
1720           if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
1721           else if (fmt_spec == 'd') {  /* signed */
1722             switch (length_modifier) {
1723             case '\0':
1724             case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg);  break;
1725             case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
1726 #ifdef SNPRINTF_LONGLONG_SUPPORT
1727             case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
1728 #endif
1729             }
1730           } else {  /* unsigned */
1731             switch (length_modifier) {
1732             case '\0':
1733             case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg);  break;
1734             case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
1735 #ifdef SNPRINTF_LONGLONG_SUPPORT
1736             case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
1737 #endif
1738             }
1739           }
1740          /* include the optional minus sign and possible "0x"
1741             in the region before the zero padding insertion point */
1742           if (zero_padding_insertion_ind < str_arg_l &&
1743               tmp[zero_padding_insertion_ind] == '-') {
1744             zero_padding_insertion_ind++;
1745           }
1746           if (zero_padding_insertion_ind+1 < str_arg_l &&
1747               tmp[zero_padding_insertion_ind]   == '0' &&
1748              (tmp[zero_padding_insertion_ind+1] == 'x' ||
1749               tmp[zero_padding_insertion_ind+1] == 'X') ) {
1750             zero_padding_insertion_ind += 2;
1751           }
1752         }
1753         { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
1754           if (alternate_form && fmt_spec == 'o'
1755 #ifdef HPUX_COMPATIBLE                                  /* ("%#.o",0) -> ""  */
1756               && (str_arg_l > 0)
1757 #endif
1758 #ifdef DIGITAL_UNIX_BUG_COMPATIBLE                      /* ("%#o",0) -> "00" */
1759 #else
1760               /* unless zero is already the first character */
1761               && !(zero_padding_insertion_ind < str_arg_l
1762                    && tmp[zero_padding_insertion_ind] == '0')
1763 #endif
1764           ) {        /* assure leading zero for alternate-form octal numbers */
1765             if (!precision_specified || precision < num_of_digits+1) {
1766              /* precision is increased to force the first character to be zero,
1767                 except if a zero value is formatted with an explicit precision
1768                 of zero */
1769               precision = num_of_digits+1; precision_specified = 1;
1770             }
1771           }
1772        /* zero padding to specified precision? */
1773           if (num_of_digits < precision) 
1774             number_of_zeros_to_pad = precision - num_of_digits;
1775         }
1776      /* zero padding to specified minimal field width? */
1777         if (!justify_left && zero_padding) {
1778           int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1779           if (n > 0) number_of_zeros_to_pad += n;
1780         }
1781         break;
1782       }
1783       default: /* unrecognized conversion specifier, keep format string as-is*/
1784         zero_padding = 0;  /* turn zero padding off for non-numeric convers. */
1785 #ifndef DIGITAL_UNIX_COMPATIBLE
1786         justify_left = 1; min_field_width = 0;                /* reset flags */
1787 #endif
1788 #if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
1789      /* keep the entire format string unchanged */
1790         str_arg = starting_p; str_arg_l = p - starting_p;
1791      /* well, not exactly so for Linux, which does something inbetween,
1792       * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y"  */
1793 #else
1794      /* discard the unrecognized conversion, just keep *
1795       * the unrecognized conversion character          */
1796         str_arg = p; str_arg_l = 0;
1797 #endif
1798         if (*p) str_arg_l++;  /* include invalid conversion specifier unchanged
1799                                  if not at end-of-string */
1800         break;
1801       }
1802       if (*p) p++;      /* step over the just processed conversion specifier */
1803    /* insert padding to the left as requested by min_field_width;
1804       this does not include the zero padding in case of numerical conversions*/
1805       if (!justify_left) {                /* left padding with blank or zero */
1806         int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1807         if (n > 0) {
1808           if (str_l < str_m) {
1809             size_t avail = str_m-str_l;
1810             fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
1811           }
1812           str_l += n;
1813         }
1814       }
1815    /* zero padding as requested by the precision or by the minimal field width
1816     * for numeric conversions required? */
1817       if (number_of_zeros_to_pad <= 0) {
1818      /* will not copy first part of numeric right now, *
1819       * force it to be copied later in its entirety    */
1820         zero_padding_insertion_ind = 0;
1821       } else {
1822      /* insert first part of numerics (sign or '0x') before zero padding */
1823         int n = zero_padding_insertion_ind;
1824         if (n > 0) {
1825           if (str_l < str_m) {
1826             size_t avail = str_m-str_l;
1827             fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
1828           }
1829           str_l += n;
1830         }
1831      /* insert zero padding as requested by the precision or min field width */
1832         n = number_of_zeros_to_pad;
1833         if (n > 0) {
1834           if (str_l < str_m) {
1835             size_t avail = str_m-str_l;
1836             fast_memset(str+str_l, '0', (n>avail?avail:n));
1837           }
1838           str_l += n;
1839         }
1840       }
1841    /* insert formatted string
1842     * (or as-is conversion specifier for unknown conversions) */
1843       { int n = str_arg_l - zero_padding_insertion_ind;
1844         if (n > 0) {
1845           if (str_l < str_m) {
1846             size_t avail = str_m-str_l;
1847             fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
1848                         (n>avail?avail:n));
1849           }
1850           str_l += n;
1851         }
1852       }
1853    /* insert right padding */
1854       if (justify_left) {          /* right blank padding to the field width */
1855         int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1856         if (n > 0) {
1857           if (str_l < str_m) {
1858             size_t avail = str_m-str_l;
1859             fast_memset(str+str_l, ' ', (n>avail?avail:n));
1860           }
1861           str_l += n;
1862         }
1863       }
1864     }
1865   }
1866 #if defined(NEED_SNPRINTF_ONLY)
1867   va_end(ap);
1868 #endif
1869   if (str_m > 0) { /* make sure the string is null-terminated
1870                       even at the expense of overwriting the last character
1871                       (shouldn't happen, but just in case) */
1872     str[str_l <= str_m-1 ? str_l : str_m-1] = '\0';
1873   }
1874   /* Return the number of characters formatted (excluding trailing null
1875    * character), that is, the number of characters that would have been
1876    * written to the buffer if it were large enough.
1877    *
1878    * The value of str_l should be returned, but str_l is of unsigned type
1879    * size_t, and snprintf is int, possibly leading to an undetected
1880    * integer overflow, resulting in a negative return value, which is illegal.
1881    * Both XSH5 and ISO C99 (at least the draft) are silent on this issue.
1882    * Should errno be set to EOVERFLOW and EOF returned in this case???
1883    */
1884   return (int) str_l;
1885 }
1886 #endif
1887 #endif /* __OS2__ */
1888 /*
1889   Local Variables:
1890   tab-width: 3
1891   end:
1892 */