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