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