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