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