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