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