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