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