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