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