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