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