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