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