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