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