Initial checkin of directory structure and source code of the java Activity
[privoxy.git] / src / miscutil.c
1 const char miscutil_rcs[] = "$Id: miscutil.c,v 2.3 2002/09/25 13:00:41 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa//current/src/miscutil.c,v $
5  *
6  * Purpose     :  zalloc, hash_string, safe_strerror, strcmpic,
7  *                strncmpic, chomp, and MinGW32 strdup
8  *                functions. 
9  *                These are each too small to deserve their own file
10  *                but don't really fit in any other file.
11  *
12  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
13  *                Privoxy team. http://www.privoxy.org/
14  *
15  *                Based on the Internet Junkbuster originally written
16  *                by and Copyright (C) 1997 Anonymous Coders and 
17  *                Junkbusters Corporation.  http://www.junkbusters.com
18  *
19  *                This program is free software; you can redistribute it 
20  *                and/or modify it under the terms of the GNU General
21  *                Public License as published by the Free Software
22  *                Foundation; either version 2 of the License, or (at
23  *                your option) any later version.
24  *
25  *                This program is distributed in the hope that it will
26  *                be useful, but WITHOUT ANY WARRANTY; without even the
27  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
28  *                PARTICULAR PURPOSE.  See the GNU General Public
29  *                License for more details.
30  *
31  *                The GNU General Public License should be included with
32  *                this file.  If not, you can view it at
33  *                http://www.gnu.org/copyleft/gpl.html
34  *                or write to the Free Software Foundation, Inc., 59
35  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  *
37  * Revisions   :
38  *    $Log: miscutil.c,v $
39  *    Revision 2.3  2002/09/25 13:00:41  oes
40  *    Made strcmpic and strncmpic safe against NULL arguments
41  *    (which are now treated as empty strings).
42  *
43  *    Revision 2.2  2002/08/26 11:16:33  sarantis
44  *    Fix typo.
45  *
46  *    Revision 2.1  2002/06/04 17:22:37  jongfoster
47  *    Adding comments
48  *
49  *    Revision 2.0  2002/06/04 14:34:21  jongfoster
50  *    Moving source files to src/
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  :  string = 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   
774    while (*txt)
775    {
776
777       /* EOF pattern but !EOF text? */
778       if (*pat == '\0')
779       {
780          return 1;
781       }
782
783       /* '*' in the pattern?  */
784       if (*pat == '*') 
785       {
786      
787          /* The pattern ends afterwards? Speed up the return. */
788          if (*++pat == '\0')
789          {
790             return 0;
791          }
792      
793          /* Else, set wildcard mode and remember position after '*' */
794          wildcard = 1;
795          fallback = pat;
796       }
797
798       /* Character range specification? */
799       if (*pat == '[')
800       {
801          memset(charmap, '\0', sizeof(charmap));
802
803          while (*++pat != ']')
804          {
805             if (!*pat)
806             { 
807                return 1;
808             }
809             else if (*pat == '-')
810             {
811                if ((*++pat == ']') || *pat == '\0')
812                {
813                   return(1);
814                }
815                for(i = lastchar; i <= *pat; i++)
816                {
817                   charmap[i / 8] |= (1 << (i % 8));
818                } 
819             }
820             else
821             {
822                charmap[*pat / 8] |= (1 << (*pat % 8));
823                lastchar = *pat;
824             }
825          }
826       } /* -END- if Character range specification */
827
828
829       /* Compare: Char match, or char range match*/
830       if ((*pat == *txt)  
831       || ((*pat == ']') && (charmap[*txt / 8] & (1 << (*txt % 8)))) )
832       {
833          /* 
834           * Sucess: Go ahead
835           */
836          pat++;
837       }
838       else if (!wildcard)
839       {
840          /* 
841           * No match && no wildcard: No luck
842           */
843          return 1;
844       }
845       else if (pat != fallback)
846       {
847          /*
848           * Wildcard mode && nonmatch beyond fallback: Rewind pattern
849           */
850          pat = fallback;
851          continue;
852       }
853       txt++;
854    } 
855
856    /* Cut off extra '*'s */
857    if(*pat == '*')  pat++;
858
859    /* If this is the pattern's end, fine! */
860    return(*pat);
861
862 }
863
864
865 /*********************************************************************
866  *
867  * Function    :  bindup
868  *
869  * Description :  Duplicate the first n characters of a string that may
870  *                contain '\0' characters.
871  *
872  * Parameters  :
873  *          1  :  string = string to be duplicated
874  *          2  :  len = number of bytes to duplicate
875  *
876  * Returns     :  pointer to copy, or NULL if failure
877  *
878  *********************************************************************/
879 char *bindup(const char *string, size_t len)
880 {
881    char *duplicate;
882
883    if (NULL == (duplicate = (char *)malloc(len)))
884    {
885       return NULL;
886    }
887    else
888    {
889      memcpy(duplicate, string, len);
890    }
891
892    return duplicate;
893
894 }
895
896
897 /*********************************************************************
898  *
899  * Function    :  make_path
900  *
901  * Description :  Takes a directory name and a file name, returns 
902  *                the complete path.  Handles windows/unix differences.
903  *                If the file name is already an absolute path, or if
904  *                the directory name is NULL or empty, it returns 
905  *                the filename. 
906  *
907  * Parameters  :
908  *          1  :  dir = Name of directory or NULL for none.
909  *          2  :  file = Name of file.  Should not be NULL or empty.
910  *
911  * Returns     :  "dir/file" (Or on windows, "dir\file").
912  *                It allocates the string on the heap.  Caller frees.
913  *                Returns NULL in error (i.e. NULL file or out of
914  *                memory) 
915  *
916  *********************************************************************/
917 char * make_path(const char * dir, const char * file)
918 {
919 #ifdef AMIGA
920    char path[512];
921
922    if(dir)
923    {
924       if(dir[0] == '.')
925       {
926          if(dir[1] == '/')
927          {
928             strncpy(path,dir+2,512);
929          }
930          else
931          {
932             strncpy(path,dir+1,512);
933          }
934       }
935       else
936       {
937          strncpy(path,dir,512);
938       }
939       path[511]=0;
940    } else {
941       path[0]=0;
942    }
943    if(AddPart(path,file,512))
944    {
945       return strdup(path);
946    } else {
947       return NULL;
948    }
949 #else /* ndef AMIGA */
950
951    if ((file == NULL) || (*file == '\0'))
952    {
953       return NULL; /* Error */
954    }
955
956    if ((dir == NULL) || (*dir == '\0') /* No directory specified */
957 #if defined(_WIN32) || defined(__OS2__)
958       || (*file == '\\') || (file[1] == ':') /* Absolute path (DOS) */
959 #else /* ifndef _WIN32 || __OS2__ */
960       || (*file == '/') /* Absolute path (U*ix) */
961 #endif /* ifndef _WIN32 || __OS2__  */
962       )
963    {
964       return strdup(file);
965    }
966    else
967    {
968       char * path;
969
970 #if defined(unix)
971       if ( *dir != '/' && basedir && *basedir )
972       {
973          path = malloc( strlen( basedir ) + strlen(dir) + strlen(file) + 3);
974          if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
975          strcpy(path, basedir);
976          strcat(path, "/");
977          strcat(path, dir);
978       }
979       else
980       {
981          path = malloc(strlen(dir) + strlen(file) + 2);
982          if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
983          strcpy(path, dir);
984       }
985 #else
986
987       path = malloc(strlen(dir) + strlen(file) + 2);
988       if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
989       strcpy(path, dir);
990
991 #endif /* defined unix */
992
993 #if defined(_WIN32) || defined(__OS2__)
994       if(path[strlen(path)-1] != '\\')
995       {
996          strcat(path, "\\");
997       }
998 #else /* ifndef _WIN32 || __OS2__ */
999       if(path[strlen(path)-1] != '/')
1000       {
1001          strcat(path, "/");
1002       }
1003 #endif /* ifndef _WIN32 || __OS2__ */
1004       strcat(path, file);
1005
1006       return path;
1007    }
1008 #endif /* ndef AMIGA */
1009 }
1010
1011
1012 /*
1013  * What follows is a portable snprintf routine, written by Mark Martinec.
1014  * See: http://www.ijs.si/software/snprintf/
1015  * Anyone who needs it can add a define for themselves... so far, only 
1016  * OS/2 (native) lacks snprintf.
1017
1018                                   snprintf.c
1019                    - a portable implementation of snprintf,
1020        including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf
1021                                        
1022    snprintf is a routine to convert numeric and string arguments to
1023    formatted strings. It is similar to sprintf(3) provided in a system's
1024    C library, yet it requires an additional argument - the buffer size -
1025    and it guarantees never to store anything beyond the given buffer,
1026    regardless of the format or arguments to be formatted. Some newer
1027    operating systems do provide snprintf in their C library, but many do
1028    not or do provide an inadequate (slow or idiosyncratic) version, which
1029    calls for a portable implementation of this routine.
1030
1031 Author
1032
1033    Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000
1034    Copyright Â© 1999, Mark Martinec
1035
1036  */
1037
1038 #ifdef __OS2__
1039
1040 #define PORTABLE_SNPRINTF_VERSION_MAJOR 2
1041 #define PORTABLE_SNPRINTF_VERSION_MINOR 2
1042
1043 #if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF)
1044 # if defined(NEED_SNPRINTF_ONLY)
1045 # undef NEED_SNPRINTF_ONLY
1046 # endif
1047 # if !defined(PREFER_PORTABLE_SNPRINTF)
1048 # define PREFER_PORTABLE_SNPRINTF
1049 # endif
1050 #endif
1051
1052 #if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE)
1053 #define SOLARIS_COMPATIBLE
1054 #endif
1055
1056 #if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
1057 #define HPUX_COMPATIBLE
1058 #endif
1059
1060 #if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE)
1061 #define DIGITAL_UNIX_COMPATIBLE
1062 #endif
1063
1064 #if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE)
1065 #define PERL_COMPATIBLE
1066 #endif
1067
1068 #if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE)
1069 #define LINUX_COMPATIBLE
1070 #endif
1071
1072 #include <sys/types.h>
1073 #include <string.h>
1074 #include <stdlib.h>
1075 #include <stdio.h>
1076 #include <stdarg.h>
1077 #include <assert.h>
1078 #include <errno.h>
1079
1080 #ifdef isdigit
1081 #undef isdigit
1082 #endif
1083 #define isdigit(c) ((c) >= '0' && (c) <= '9')
1084
1085 /* For copying strings longer or equal to 'breakeven_point'
1086  * it is more efficient to call memcpy() than to do it inline.
1087  * The value depends mostly on the processor architecture,
1088  * but also on the compiler and its optimization capabilities.
1089  * The value is not critical, some small value greater than zero
1090  * will be just fine if you don't care to squeeze every drop
1091  * of performance out of the code.
1092  *
1093  * Small values favor memcpy, large values favor inline code.
1094  */
1095 #if defined(__alpha__) || defined(__alpha)
1096 #  define breakeven_point   2    /* AXP (DEC Alpha)     - gcc or cc or egcs */
1097 #endif
1098 #if defined(__i386__)  || defined(__i386)
1099 #  define breakeven_point  12    /* Intel Pentium/Linux - gcc 2.96 */
1100 #endif
1101 #if defined(__hppa)
1102 #  define breakeven_point  10    /* HP-PA               - gcc */
1103 #endif
1104 #if defined(__sparc__) || defined(__sparc)
1105 #  define breakeven_point  33    /* Sun Sparc 5         - gcc 2.8.1 */
1106 #endif
1107
1108 /* some other values of possible interest: */
1109 /* #define breakeven_point  8 */ /* VAX 4000          - vaxc */
1110 /* #define breakeven_point 19 */ /* VAX 4000          - gcc 2.7.0 */
1111
1112 #ifndef breakeven_point
1113 #  define breakeven_point   6    /* some reasonable one-size-fits-all value */
1114 #endif
1115
1116 #define fast_memcpy(d,s,n) \
1117   { register size_t nn = (size_t)(n); \
1118     if (nn >= breakeven_point) memcpy((d), (s), nn); \
1119     else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
1120       register char *dd; register const char *ss; \
1121       for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
1122
1123 #define fast_memset(d,c,n) \
1124   { register size_t nn = (size_t)(n); \
1125     if (nn >= breakeven_point) memset((d), (int)(c), nn); \
1126     else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
1127       register char *dd; register const int cc=(int)(c); \
1128       for (dd=(d); nn>0; nn--) *dd++ = cc; } }
1129
1130 /* prototypes */
1131
1132 #if defined(NEED_ASPRINTF)
1133 int asprintf   (char **ptr, const char *fmt, /*args*/ ...);
1134 #endif
1135 #if defined(NEED_VASPRINTF)
1136 int vasprintf  (char **ptr, const char *fmt, va_list ap);
1137 #endif
1138 #if defined(NEED_ASNPRINTF)
1139 int asnprintf  (char **ptr, size_t str_m, const char *fmt, /*args*/ ...);
1140 #endif
1141 #if defined(NEED_VASNPRINTF)
1142 int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap);
1143 #endif
1144
1145 #if defined(HAVE_SNPRINTF)
1146 /* declare our portable snprintf  routine under name portable_snprintf  */
1147 /* declare our portable vsnprintf routine under name portable_vsnprintf */
1148 #else
1149 /* declare our portable routines under names snprintf and vsnprintf */
1150 #define portable_snprintf snprintf
1151 #if !defined(NEED_SNPRINTF_ONLY)
1152 #define portable_vsnprintf vsnprintf
1153 #endif
1154 #endif
1155
1156 #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
1157 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...);
1158 #if !defined(NEED_SNPRINTF_ONLY)
1159 int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
1160 #endif
1161 #endif
1162
1163 /* declarations */
1164
1165 static char credits[] = "\n\
1166 @(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
1167 @(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
1168 @(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
1169
1170 #if defined(NEED_ASPRINTF)
1171 int asprintf(char **ptr, const char *fmt, /*args*/ ...) {
1172   va_list ap;
1173   size_t str_m;
1174   int str_l;
1175
1176   *ptr = NULL;
1177   va_start(ap, fmt);                            /* measure the required size */
1178   str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
1179   va_end(ap);
1180   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1181   *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
1182   if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1183   else {
1184     int str_l2;
1185     va_start(ap, fmt);
1186     str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1187     va_end(ap);
1188     assert(str_l2 == str_l);
1189   }
1190   return str_l;
1191 }
1192 #endif
1193
1194 #if defined(NEED_VASPRINTF)
1195 int vasprintf(char **ptr, const char *fmt, va_list ap) {
1196   size_t str_m;
1197   int str_l;
1198
1199   *ptr = NULL;
1200   { va_list ap2;
1201     va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
1202     str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
1203     va_end(ap2);
1204   }
1205   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1206   *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
1207   if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1208   else {
1209     int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1210     assert(str_l2 == str_l);
1211   }
1212   return str_l;
1213 }
1214 #endif
1215
1216 #if defined(NEED_ASNPRINTF)
1217 int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
1218   va_list ap;
1219   int str_l;
1220
1221   *ptr = NULL;
1222   va_start(ap, fmt);                            /* measure the required size */
1223   str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
1224   va_end(ap);
1225   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1226   if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
1227   /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
1228   if (str_m == 0) {  /* not interested in resulting string, just return size */
1229   } else {
1230     *ptr = (char *) malloc(str_m);
1231     if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1232     else {
1233       int str_l2;
1234       va_start(ap, fmt);
1235       str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1236       va_end(ap);
1237       assert(str_l2 == str_l);
1238     }
1239   }
1240   return str_l;
1241 }
1242 #endif
1243
1244 #if defined(NEED_VASNPRINTF)
1245 int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
1246   int str_l;
1247
1248   *ptr = NULL;
1249   { va_list ap2;
1250     va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
1251     str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
1252     va_end(ap2);
1253   }
1254   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1255   if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
1256   /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
1257   if (str_m == 0) {  /* not interested in resulting string, just return size */
1258   } else {
1259     *ptr = (char *) malloc(str_m);
1260     if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1261     else {
1262       int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1263       assert(str_l2 == str_l);
1264     }
1265   }
1266   return str_l;
1267 }
1268 #endif
1269
1270 /*
1271  * If the system does have snprintf and the portable routine is not
1272  * specifically required, this module produces no code for snprintf/vsnprintf.
1273  */
1274 #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
1275
1276 #if !defined(NEED_SNPRINTF_ONLY)
1277 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
1278   va_list ap;
1279   int str_l;
1280
1281   va_start(ap, fmt);
1282   str_l = portable_vsnprintf(str, str_m, fmt, ap);
1283   va_end(ap);
1284   return str_l;
1285 }
1286 #endif
1287
1288 #if defined(NEED_SNPRINTF_ONLY)
1289 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
1290 #else
1291 int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
1292 #endif
1293
1294 #if defined(NEED_SNPRINTF_ONLY)
1295   va_list ap;
1296 #endif
1297   size_t str_l = 0;
1298   const char *p = fmt;
1299
1300 /* In contrast with POSIX, the ISO C99 now says
1301  * that str can be NULL and str_m can be 0.
1302  * This is more useful than the old:  if (str_m < 1) return -1; */
1303
1304 #if defined(NEED_SNPRINTF_ONLY)
1305   va_start(ap, fmt);
1306 #endif
1307   if (!p) p = "";
1308   while (*p) {
1309     if (*p != '%') {
1310    /* if (str_l < str_m) str[str_l++] = *p++;    -- this would be sufficient */
1311    /* but the following code achieves better performance for cases
1312     * where format string is long and contains few conversions */
1313       const char *q = strchr(p+1,'%');
1314       size_t n = !q ? strlen(p) : (q-p);
1315       if (str_l < str_m) {
1316         size_t avail = str_m-str_l;
1317         fast_memcpy(str+str_l, p, (n>avail?avail:n));
1318       }
1319       p += n; str_l += n;
1320     } else {
1321       const char *starting_p;
1322       size_t min_field_width = 0, precision = 0;
1323       int zero_padding = 0, precision_specified = 0, justify_left = 0;
1324       int alternate_form = 0, force_sign = 0;
1325       int space_for_positive = 1; /* If both the ' ' and '+' flags appear,
1326                                      the ' ' flag should be ignored. */
1327       char length_modifier = '\0';            /* allowed values: \0, h, l, L */
1328       char tmp[32];/* temporary buffer for simple numeric->string conversion */
1329
1330       const char *str_arg;      /* string address in case of string argument */
1331       size_t str_arg_l;         /* natural field width of arg without padding
1332                                    and sign */
1333       unsigned char uchar_arg;
1334         /* unsigned char argument value - only defined for c conversion.
1335            N.B. standard explicitly states the char argument for
1336            the c conversion is unsigned */
1337
1338       size_t number_of_zeros_to_pad = 0;
1339         /* number of zeros to be inserted for numeric conversions
1340            as required by the precision or minimal field width */
1341
1342       size_t zero_padding_insertion_ind = 0;
1343         /* index into tmp where zero padding is to be inserted */
1344
1345       char fmt_spec = '\0';
1346         /* current conversion specifier character */
1347
1348       str_arg = credits;/* just to make compiler happy (defined but not used)*/
1349       str_arg = NULL;
1350       starting_p = p; p++;  /* skip '%' */
1351    /* parse flags */
1352       while (*p == '0' || *p == '-' || *p == '+' ||
1353              *p == ' ' || *p == '#' || *p == '\'') {
1354         switch (*p) {
1355         case '0': zero_padding = 1; break;
1356         case '-': justify_left = 1; break;
1357         case '+': force_sign = 1; space_for_positive = 0; break;
1358         case ' ': force_sign = 1;
1359      /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
1360 #ifdef PERL_COMPATIBLE
1361      /* ... but in Perl the last of ' ' and '+' applies */
1362                   space_for_positive = 1;
1363 #endif
1364                   break;
1365         case '#': alternate_form = 1; break;
1366         case '\'': break;
1367         }
1368         p++;
1369       }
1370    /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
1371
1372    /* parse field width */
1373       if (*p == '*') {
1374         int j;
1375         p++; j = va_arg(ap, int);
1376         if (j >= 0) min_field_width = j;
1377         else { min_field_width = -j; justify_left = 1; }
1378       } else if (isdigit((int)(*p))) {
1379         /* size_t could be wider than unsigned int;
1380            make sure we treat argument like common implementations do */
1381         unsigned int uj = *p++ - '0';
1382         while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
1383         min_field_width = uj;
1384       }
1385    /* parse precision */
1386       if (*p == '.') {
1387         p++; precision_specified = 1;
1388         if (*p == '*') {
1389           int j = va_arg(ap, int);
1390           p++;
1391           if (j >= 0) precision = j;
1392           else {
1393             precision_specified = 0; precision = 0;
1394          /* NOTE:
1395           *   Solaris 2.6 man page claims that in this case the precision
1396           *   should be set to 0.  Digital Unix 4.0, HPUX 10 and BSD man page
1397           *   claim that this case should be treated as unspecified precision,
1398           *   which is what we do here.
1399           */
1400           }
1401         } else if (isdigit((int)(*p))) {
1402           /* size_t could be wider than unsigned int;
1403              make sure we treat argument like common implementations do */
1404           unsigned int uj = *p++ - '0';
1405           while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
1406           precision = uj;
1407         }
1408       }
1409    /* parse 'h', 'l' and 'll' length modifiers */
1410       if (*p == 'h' || *p == 'l') {
1411         length_modifier = *p; p++;
1412         if (length_modifier == 'l' && *p == 'l') {   /* double l = long long */
1413 #ifdef SNPRINTF_LONGLONG_SUPPORT
1414           length_modifier = '2';                  /* double l encoded as '2' */
1415 #else
1416           length_modifier = 'l';                 /* treat it as a single 'l' */
1417 #endif
1418           p++;
1419         }
1420       }
1421       fmt_spec = *p;
1422    /* common synonyms: */
1423       switch (fmt_spec) {
1424       case 'i': fmt_spec = 'd'; break;
1425       case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
1426       case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
1427       case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
1428       default: break;
1429       }
1430    /* get parameter value, do initial processing */
1431       switch (fmt_spec) {
1432       case '%': /* % behaves similar to 's' regarding flags and field widths */
1433       case 'c': /* c behaves similar to 's' regarding flags and field widths */
1434       case 's':
1435         length_modifier = '\0';          /* wint_t and wchar_t not supported */
1436      /* the result of zero padding flag with non-numeric conversion specifier*/
1437      /* is undefined. Solaris and HPUX 10 does zero padding in this case,    */
1438      /* Digital Unix and Linux does not. */
1439 #if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
1440         zero_padding = 0;    /* turn zero padding off for string conversions */
1441 #endif
1442         str_arg_l = 1;
1443         switch (fmt_spec) {
1444         case '%':
1445           str_arg = p; break;
1446         case 'c': {
1447           int j = va_arg(ap, int);
1448           uchar_arg = (unsigned char) j;   /* standard demands unsigned char */
1449           str_arg = (const char *) &uchar_arg;
1450           break;
1451         }
1452         case 's':
1453           str_arg = va_arg(ap, const char *);
1454           if (!str_arg) str_arg_l = 0;
1455        /* make sure not to address string beyond the specified precision !!! */
1456           else if (!precision_specified) str_arg_l = strlen(str_arg);
1457        /* truncate string if necessary as requested by precision */
1458           else if (precision == 0) str_arg_l = 0;
1459           else {
1460        /* memchr on HP does not like n > 2^31  !!! */
1461             const char *q = memchr(str_arg, '\0',
1462                              precision <= 0x7fffffff ? precision : 0x7fffffff);
1463             str_arg_l = !q ? precision : (q-str_arg);
1464           }
1465           break;
1466         default: break;
1467         }
1468         break;
1469       case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
1470         /* NOTE: the u, o, x, X and p conversion specifiers imply
1471                  the value is unsigned;  d implies a signed value */
1472
1473         int arg_sign = 0;
1474           /* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
1475             +1 if greater than zero (or nonzero for unsigned arguments),
1476             -1 if negative (unsigned argument is never negative) */
1477
1478         int int_arg = 0;  unsigned int uint_arg = 0;
1479           /* only defined for length modifier h, or for no length modifiers */
1480
1481         long int long_arg = 0;  unsigned long int ulong_arg = 0;
1482           /* only defined for length modifier l */
1483
1484         void *ptr_arg = NULL;
1485           /* pointer argument value -only defined for p conversion */
1486
1487 #ifdef SNPRINTF_LONGLONG_SUPPORT
1488         long long int long_long_arg = 0;
1489         unsigned long long int ulong_long_arg = 0;
1490           /* only defined for length modifier ll */
1491 #endif
1492         if (fmt_spec == 'p') {
1493         /* HPUX 10: An l, h, ll or L before any other conversion character
1494          *   (other than d, i, u, o, x, or X) is ignored.
1495          * Digital Unix:
1496          *   not specified, but seems to behave as HPUX does.
1497          * Solaris: If an h, l, or L appears before any other conversion
1498          *   specifier (other than d, i, u, o, x, or X), the behavior
1499          *   is undefined. (Actually %hp converts only 16-bits of address
1500          *   and %llp treats address as 64-bit data which is incompatible
1501          *   with (void *) argument on a 32-bit system).
1502          */
1503 #ifdef SOLARIS_COMPATIBLE
1504 #  ifdef SOLARIS_BUG_COMPATIBLE
1505           /* keep length modifiers even if it represents 'll' */
1506 #  else
1507           if (length_modifier == '2') length_modifier = '\0';
1508 #  endif
1509 #else
1510           length_modifier = '\0';
1511 #endif
1512           ptr_arg = va_arg(ap, void *);
1513           if (ptr_arg != NULL) arg_sign = 1;
1514         } else if (fmt_spec == 'd') {  /* signed */
1515           switch (length_modifier) {
1516           case '\0':
1517           case 'h':
1518          /* It is non-portable to specify a second argument of char or short
1519           * to va_arg, because arguments seen by the called function
1520           * are not char or short.  C converts char and short arguments
1521           * to int before passing them to a function.
1522           */
1523             int_arg = va_arg(ap, int);
1524             if      (int_arg > 0) arg_sign =  1;
1525             else if (int_arg < 0) arg_sign = -1;
1526             break;
1527           case 'l':
1528             long_arg = va_arg(ap, long int);
1529             if      (long_arg > 0) arg_sign =  1;
1530             else if (long_arg < 0) arg_sign = -1;
1531             break;
1532 #ifdef SNPRINTF_LONGLONG_SUPPORT
1533           case '2':
1534             long_long_arg = va_arg(ap, long long int);
1535             if      (long_long_arg > 0) arg_sign =  1;
1536             else if (long_long_arg < 0) arg_sign = -1;
1537             break;
1538 #endif
1539           }
1540         } else {  /* unsigned */
1541           switch (length_modifier) {
1542           case '\0':
1543           case 'h':
1544             uint_arg = va_arg(ap, unsigned int);
1545             if (uint_arg) arg_sign = 1;
1546             break;
1547           case 'l':
1548             ulong_arg = va_arg(ap, unsigned long int);
1549             if (ulong_arg) arg_sign = 1;
1550             break;
1551 #ifdef SNPRINTF_LONGLONG_SUPPORT
1552           case '2':
1553             ulong_long_arg = va_arg(ap, unsigned long long int);
1554             if (ulong_long_arg) arg_sign = 1;
1555             break;
1556 #endif
1557           }
1558         }
1559         str_arg = tmp; str_arg_l = 0;
1560      /* NOTE:
1561       *   For d, i, u, o, x, and X conversions, if precision is specified,
1562       *   the '0' flag should be ignored. This is so with Solaris 2.6,
1563       *   Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
1564       */
1565 #ifndef PERL_COMPATIBLE
1566         if (precision_specified) zero_padding = 0;
1567 #endif
1568         if (fmt_spec == 'd') {
1569           if (force_sign && arg_sign >= 0)
1570             tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
1571          /* leave negative numbers for sprintf to handle,
1572             to avoid handling tricky cases like (short int)(-32768) */
1573 #ifdef LINUX_COMPATIBLE
1574         } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
1575           tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
1576 #endif
1577         } else if (alternate_form) {
1578           if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
1579             { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
1580          /* alternate form should have no effect for p conversion, but ... */
1581 #ifdef HPUX_COMPATIBLE
1582           else if (fmt_spec == 'p'
1583          /* HPUX 10: for an alternate form of p conversion,
1584           *          a nonzero result is prefixed by 0x. */
1585 #ifndef HPUX_BUG_COMPATIBLE
1586          /* Actually it uses 0x prefix even for a zero value. */
1587                    && arg_sign != 0
1588 #endif
1589                   ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
1590 #endif
1591         }
1592         zero_padding_insertion_ind = str_arg_l;
1593         if (!precision_specified) precision = 1;   /* default precision is 1 */
1594         if (precision == 0 && arg_sign == 0
1595 #if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
1596             && fmt_spec != 'p'
1597          /* HPUX 10 man page claims: With conversion character p the result of
1598           * converting a zero value with a precision of zero is a null string.
1599           * Actually HP returns all zeroes, and Linux returns "(nil)". */
1600 #endif
1601         ) {
1602          /* converted to null string */
1603          /* When zero value is formatted with an explicit precision 0,
1604             the resulting formatted string is empty (d, i, u, o, x, X, p).   */
1605         } else {
1606           char f[5]; int f_l = 0;
1607           f[f_l++] = '%';    /* construct a simple format string for sprintf */
1608           if (!length_modifier) { }
1609           else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
1610           else f[f_l++] = length_modifier;
1611           f[f_l++] = fmt_spec; f[f_l++] = '\0';
1612           if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
1613           else if (fmt_spec == 'd') {  /* signed */
1614             switch (length_modifier) {
1615             case '\0':
1616             case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg);  break;
1617             case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
1618 #ifdef SNPRINTF_LONGLONG_SUPPORT
1619             case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
1620 #endif
1621             }
1622           } else {  /* unsigned */
1623             switch (length_modifier) {
1624             case '\0':
1625             case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg);  break;
1626             case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
1627 #ifdef SNPRINTF_LONGLONG_SUPPORT
1628             case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
1629 #endif
1630             }
1631           }
1632          /* include the optional minus sign and possible "0x"
1633             in the region before the zero padding insertion point */
1634           if (zero_padding_insertion_ind < str_arg_l &&
1635               tmp[zero_padding_insertion_ind] == '-') {
1636             zero_padding_insertion_ind++;
1637           }
1638           if (zero_padding_insertion_ind+1 < str_arg_l &&
1639               tmp[zero_padding_insertion_ind]   == '0' &&
1640              (tmp[zero_padding_insertion_ind+1] == 'x' ||
1641               tmp[zero_padding_insertion_ind+1] == 'X') ) {
1642             zero_padding_insertion_ind += 2;
1643           }
1644         }
1645         { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
1646           if (alternate_form && fmt_spec == 'o'
1647 #ifdef HPUX_COMPATIBLE                                  /* ("%#.o",0) -> ""  */
1648               && (str_arg_l > 0)
1649 #endif
1650 #ifdef DIGITAL_UNIX_BUG_COMPATIBLE                      /* ("%#o",0) -> "00" */
1651 #else
1652               /* unless zero is already the first character */
1653               && !(zero_padding_insertion_ind < str_arg_l
1654                    && tmp[zero_padding_insertion_ind] == '0')
1655 #endif
1656           ) {        /* assure leading zero for alternate-form octal numbers */
1657             if (!precision_specified || precision < num_of_digits+1) {
1658              /* precision is increased to force the first character to be zero,
1659                 except if a zero value is formatted with an explicit precision
1660                 of zero */
1661               precision = num_of_digits+1; precision_specified = 1;
1662             }
1663           }
1664        /* zero padding to specified precision? */
1665           if (num_of_digits < precision) 
1666             number_of_zeros_to_pad = precision - num_of_digits;
1667         }
1668      /* zero padding to specified minimal field width? */
1669         if (!justify_left && zero_padding) {
1670           int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1671           if (n > 0) number_of_zeros_to_pad += n;
1672         }
1673         break;
1674       }
1675       default: /* unrecognized conversion specifier, keep format string as-is*/
1676         zero_padding = 0;  /* turn zero padding off for non-numeric convers. */
1677 #ifndef DIGITAL_UNIX_COMPATIBLE
1678         justify_left = 1; min_field_width = 0;                /* reset flags */
1679 #endif
1680 #if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
1681      /* keep the entire format string unchanged */
1682         str_arg = starting_p; str_arg_l = p - starting_p;
1683      /* well, not exactly so for Linux, which does something inbetween,
1684       * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y"  */
1685 #else
1686      /* discard the unrecognized conversion, just keep *
1687       * the unrecognized conversion character          */
1688         str_arg = p; str_arg_l = 0;
1689 #endif
1690         if (*p) str_arg_l++;  /* include invalid conversion specifier unchanged
1691                                  if not at end-of-string */
1692         break;
1693       }
1694       if (*p) p++;      /* step over the just processed conversion specifier */
1695    /* insert padding to the left as requested by min_field_width;
1696       this does not include the zero padding in case of numerical conversions*/
1697       if (!justify_left) {                /* left padding with blank or zero */
1698         int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1699         if (n > 0) {
1700           if (str_l < str_m) {
1701             size_t avail = str_m-str_l;
1702             fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
1703           }
1704           str_l += n;
1705         }
1706       }
1707    /* zero padding as requested by the precision or by the minimal field width
1708     * for numeric conversions required? */
1709       if (number_of_zeros_to_pad <= 0) {
1710      /* will not copy first part of numeric right now, *
1711       * force it to be copied later in its entirety    */
1712         zero_padding_insertion_ind = 0;
1713       } else {
1714      /* insert first part of numerics (sign or '0x') before zero padding */
1715         int n = zero_padding_insertion_ind;
1716         if (n > 0) {
1717           if (str_l < str_m) {
1718             size_t avail = str_m-str_l;
1719             fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
1720           }
1721           str_l += n;
1722         }
1723      /* insert zero padding as requested by the precision or min field width */
1724         n = number_of_zeros_to_pad;
1725         if (n > 0) {
1726           if (str_l < str_m) {
1727             size_t avail = str_m-str_l;
1728             fast_memset(str+str_l, '0', (n>avail?avail:n));
1729           }
1730           str_l += n;
1731         }
1732       }
1733    /* insert formatted string
1734     * (or as-is conversion specifier for unknown conversions) */
1735       { int n = str_arg_l - zero_padding_insertion_ind;
1736         if (n > 0) {
1737           if (str_l < str_m) {
1738             size_t avail = str_m-str_l;
1739             fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
1740                         (n>avail?avail:n));
1741           }
1742           str_l += n;
1743         }
1744       }
1745    /* insert right padding */
1746       if (justify_left) {          /* right blank padding to the field width */
1747         int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1748         if (n > 0) {
1749           if (str_l < str_m) {
1750             size_t avail = str_m-str_l;
1751             fast_memset(str+str_l, ' ', (n>avail?avail:n));
1752           }
1753           str_l += n;
1754         }
1755       }
1756     }
1757   }
1758 #if defined(NEED_SNPRINTF_ONLY)
1759   va_end(ap);
1760 #endif
1761   if (str_m > 0) { /* make sure the string is null-terminated
1762                       even at the expense of overwriting the last character
1763                       (shouldn't happen, but just in case) */
1764     str[str_l <= str_m-1 ? str_l : str_m-1] = '\0';
1765   }
1766   /* Return the number of characters formatted (excluding trailing null
1767    * character), that is, the number of characters that would have been
1768    * written to the buffer if it were large enough.
1769    *
1770    * The value of str_l should be returned, but str_l is of unsigned type
1771    * size_t, and snprintf is int, possibly leading to an undetected
1772    * integer overflow, resulting in a negative return value, which is illegal.
1773    * Both XSH5 and ISO C99 (at least the draft) are silent on this issue.
1774    * Should errno be set to EOVERFLOW and EOF returned in this case???
1775    */
1776   return (int) str_l;
1777 }
1778 #endif
1779 #endif /* __OS2__ */
1780 /*
1781   Local Variables:
1782   tab-width: 3
1783   end:
1784 */