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