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