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