pcrs: Use the D flag to disable JIT-compilation
[privoxy.git] / miscutil.c
1 /*********************************************************************
2  *
3  * File        :  $Source: /cvsroot/ijbswa/current/miscutil.c,v $
4  *
5  * Purpose     :  zalloc, hash_string, strcmpic, strncmpic, and
6  *                MinGW32 strdup functions.  These are each too small
7  *                to deserve their own file but don't really fit in
8  *                any other file.
9  *
10  * Copyright   :  Written by and Copyright (C) 2001-2020 the
11  *                Privoxy team. https://www.privoxy.org/
12  *
13  *                Based on the Internet Junkbuster originally written
14  *                by and Copyright (C) 1997 Anonymous Coders and
15  *                Junkbusters Corporation.  http://www.junkbusters.com
16  *
17  *                The timegm replacement function was taken from GnuPG,
18  *                Copyright (C) 2004 Free Software Foundation, Inc.
19  *
20  *                This program is free software; you can redistribute it
21  *                and/or modify it under the terms of the GNU General
22  *                Public License as published by the Free Software
23  *                Foundation; either version 2 of the License, or (at
24  *                your option) any later version.
25  *
26  *                This program is distributed in the hope that it will
27  *                be useful, but WITHOUT ANY WARRANTY; without even the
28  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
29  *                PARTICULAR PURPOSE.  See the GNU General Public
30  *                License for more details.
31  *
32  *                The GNU General Public License should be included with
33  *                this file.  If not, you can view it at
34  *                http://www.gnu.org/copyleft/gpl.html
35  *                or write to the Free Software Foundation, Inc., 59
36  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
37  *
38  *********************************************************************/
39
40
41 #include "config.h"
42
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include <stdlib.h>
46 #if !defined(_WIN32)
47 #include <unistd.h>
48 #endif /* #if !defined(_WIN32) */
49 #include <string.h>
50 #include <ctype.h>
51 #include <assert.h>
52
53 #if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV)
54 #include <time.h>
55 #endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */
56
57 #include "project.h"
58 #include "miscutil.h"
59 #include "jcc.h"
60 #include "errlog.h"
61
62 /*********************************************************************
63  *
64  * Function    :  zalloc
65  *
66  * Description :  Returns allocated memory that is initialized
67  *                with zeros.
68  *
69  * Parameters  :
70  *          1  :  size = Size of memory chunk to return.
71  *
72  * Returns     :  Pointer to newly alloc'd memory chunk.
73  *
74  *********************************************************************/
75 void *zalloc(size_t size)
76 {
77    void * ret;
78
79 #ifdef HAVE_CALLOC
80    ret = calloc(1, size);
81 #else
82 #warning calloc appears to be unavailable. Your platform will become unsupported in the future
83    if ((ret = (void *)malloc(size)) != NULL)
84    {
85       memset(ret, 0, size);
86    }
87 #endif
88
89    return(ret);
90
91 }
92
93
94 /*********************************************************************
95  *
96  * Function    :  zalloc_or_die
97  *
98  * Description :  zalloc wrapper that either succeeds or causes
99  *                program termination.
100  *
101  *                Useful in situations were the string length is
102  *                "small" and zalloc() failures couldn't be handled
103  *                better anyway. In case of debug builds, failures
104  *                trigger an assert().
105  *
106  * Parameters  :
107  *          1  :  size = Size of memory chunk to return.
108  *
109  * Returns     :  Pointer to newly malloc'd memory chunk.
110  *
111  *********************************************************************/
112 void *zalloc_or_die(size_t size)
113 {
114    void *buffer;
115
116    buffer = zalloc(size);
117    if (buffer == NULL)
118    {
119       assert(buffer != NULL);
120       log_error(LOG_LEVEL_FATAL, "Out of memory in zalloc_or_die().");
121       exit(1);
122    }
123
124    return(buffer);
125
126 }
127
128 /*********************************************************************
129  *
130  * Function    :  strdup_or_die
131  *
132  * Description :  strdup wrapper that either succeeds or causes
133  *                program termination.
134  *
135  *                Useful in situations were the string length is
136  *                "small" and strdup() failures couldn't be handled
137  *                better anyway. In case of debug builds, failures
138  *                trigger an assert().
139  *
140  * Parameters  :
141  *          1  :  str = String to duplicate
142  *
143  * Returns     :  Pointer to newly strdup'd copy of the string.
144  *
145  *********************************************************************/
146 char *strdup_or_die(const char *str)
147 {
148    char *new_str;
149
150    new_str = strdup(str);
151
152    if (new_str == NULL)
153    {
154       assert(new_str != NULL);
155       log_error(LOG_LEVEL_FATAL, "Out of memory in strdup_or_die().");
156       exit(1);
157    }
158
159    return(new_str);
160
161 }
162
163
164 /*********************************************************************
165  *
166  * Function    :  malloc_or_die
167  *
168  * Description :  malloc wrapper that either succeeds or causes
169  *                program termination.
170  *
171  *                Useful in situations were the buffer size is "small"
172  *                and malloc() failures couldn't be handled better
173  *                anyway. In case of debug builds, failures trigger
174  *                an assert().
175  *
176  * Parameters  :
177  *          1  :  buffer_size = Size of the space to allocate
178  *
179  * Returns     :  Pointer to newly malloc'd memory
180  *
181  *********************************************************************/
182 void *malloc_or_die(size_t buffer_size)
183 {
184    char *new_buf;
185
186    if (buffer_size == 0)
187    {
188       log_error(LOG_LEVEL_ERROR,
189          "malloc_or_die() called with buffer size 0");
190       assert(buffer_size != 0);
191       buffer_size = 4096;
192    }
193
194    new_buf = malloc(buffer_size);
195
196    if (new_buf == NULL)
197    {
198       assert(new_buf != NULL);
199       log_error(LOG_LEVEL_FATAL, "Out of memory in malloc_or_die().");
200       exit(1);
201    }
202
203    return(new_buf);
204
205 }
206
207
208 #if defined(unix)
209 /*********************************************************************
210  *
211  * Function    :  write_pid_file
212  *
213  * Description :  Writes a pid file with the pid of the main process.
214  *                Exits if the file can't be opened
215  *
216  * Parameters  :
217  *          1  :  pid_file = Path of the pid file that gets created.
218  *
219  * Returns     :  N/A
220  *
221  *********************************************************************/
222 void write_pid_file(const char *pid_file)
223 {
224    FILE   *fp;
225
226    if ((fp = fopen(pid_file, "w")) == NULL)
227    {
228       log_error(LOG_LEVEL_FATAL, "can't open pid file '%s': %E", pid_file);
229    }
230    else
231    {
232       fprintf(fp, "%u\n", (unsigned int) getpid());
233       fclose (fp);
234    }
235    return;
236
237 }
238 #endif /* def unix */
239
240
241 /*********************************************************************
242  *
243  * Function    :  hash_string
244  *
245  * Description :  Take a string and compute a (hopefuly) unique numeric
246  *                integer value. This is useful to "switch" a string.
247  *
248  * Parameters  :
249  *          1  :  s : string to be hashed.
250  *
251  * Returns     :  The string's hash
252  *
253  *********************************************************************/
254 unsigned int hash_string(const char* s)
255 {
256    unsigned int h = 0;
257
258    for (; *s; ++s)
259    {
260       h = 5 * h + (unsigned int)*s;
261    }
262
263    return (h);
264
265 }
266
267
268 /*********************************************************************
269  *
270  * Function    :  strcmpic
271  *
272  * Description :  Case insensitive string comparison
273  *
274  * Parameters  :
275  *          1  :  s1 = string 1 to compare
276  *          2  :  s2 = string 2 to compare
277  *
278  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
279  *
280  *********************************************************************/
281 int strcmpic(const char *s1, const char *s2)
282 {
283    if (!s1) s1 = "";
284    if (!s2) s2 = "";
285
286    while (*s1 && *s2)
287    {
288       if ((*s1 != *s2) && (privoxy_tolower(*s1) != privoxy_tolower(*s2)))
289       {
290          break;
291       }
292       s1++, s2++;
293    }
294    return(privoxy_tolower(*s1) - privoxy_tolower(*s2));
295
296 }
297
298
299 /*********************************************************************
300  *
301  * Function    :  strncmpic
302  *
303  * Description :  Case insensitive string comparison (up to n characters)
304  *
305  * Parameters  :
306  *          1  :  s1 = string 1 to compare
307  *          2  :  s2 = string 2 to compare
308  *          3  :  n = maximum characters to compare
309  *
310  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
311  *
312  *********************************************************************/
313 int strncmpic(const char *s1, const char *s2, size_t n)
314 {
315    if (n <= (size_t)0) return(0);
316    if (!s1) s1 = "";
317    if (!s2) s2 = "";
318
319    while (*s1 && *s2)
320    {
321       if ((*s1 != *s2) && (privoxy_tolower(*s1) != privoxy_tolower(*s2)))
322       {
323          break;
324       }
325
326       if (--n <= (size_t)0) break;
327
328       s1++, s2++;
329    }
330    return(privoxy_tolower(*s1) - privoxy_tolower(*s2));
331
332 }
333
334
335 /*********************************************************************
336  *
337  * Function    :  chomp
338  *
339  * Description :  In-situ-eliminate all leading and trailing whitespace
340  *                from a string.
341  *
342  * Parameters  :
343  *          1  :  s : string to be chomped.
344  *
345  * Returns     :  chomped string
346  *
347  *********************************************************************/
348 char *chomp(char *string)
349 {
350    char *p, *q, *r;
351
352    /*
353     * strip trailing whitespace
354     */
355    p = string + strlen(string);
356    while (p > string && privoxy_isspace(*(p-1)))
357    {
358       p--;
359    }
360    *p = '\0';
361
362    /*
363     * find end of leading whitespace
364     */
365    q = r = string;
366    while (*q && privoxy_isspace(*q))
367    {
368       q++;
369    }
370
371    /*
372     * if there was any, move the rest forwards
373     */
374    if (q != string)
375    {
376       while (q <= p)
377       {
378          *r++ = *q++;
379       }
380    }
381
382    return(string);
383
384 }
385
386
387 /*********************************************************************
388  *
389  * Function    :  string_append
390  *
391  * Description :  Reallocate target_string and append text to it.
392  *                This makes it easier to append to malloc'd strings.
393  *                This is similar to the (removed) strsav(), but
394  *                running out of memory isn't catastrophic.
395  *
396  *                Programming style:
397  *
398  *                The following style provides sufficient error
399  *                checking for this routine, with minimal clutter
400  *                in the source code.  It is recommended if you
401  *                have many calls to this function:
402  *
403  *                char * s = strdup(...); // don't check for error
404  *                string_append(&s, ...);  // don't check for error
405  *                string_append(&s, ...);  // don't check for error
406  *                string_append(&s, ...);  // don't check for error
407  *                if (NULL == s) { ... handle error ... }
408  *
409  *                OR, equivalently:
410  *
411  *                char * s = strdup(...); // 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 (string_append(&s, ...)) {... handle error ...}
415  *
416  * Parameters  :
417  *          1  :  target_string = Pointer to old text that is to be
418  *                extended.  *target_string will be free()d by this
419  *                routine.  target_string must be non-NULL.
420  *                If *target_string is NULL, this routine will
421  *                do nothing and return with an error - this allows
422  *                you to make many calls to this routine and only
423  *                check for errors after the last one.
424  *          2  :  text_to_append = Text to be appended to old.
425  *                Must not be NULL.
426  *
427  * Returns     :  JB_ERR_OK on success, and sets *target_string
428  *                   to newly malloc'ed appended string.  Caller
429  *                   must free(*target_string).
430  *                JB_ERR_MEMORY on out-of-memory.  (And free()s
431  *                   *target_string and sets it to NULL).
432  *                JB_ERR_MEMORY if *target_string is NULL.
433  *
434  *********************************************************************/
435 jb_err string_append(char **target_string, const char *text_to_append)
436 {
437    size_t old_len;
438    char *new_string;
439    size_t new_size;
440
441    assert(target_string);
442    assert(text_to_append);
443
444    if (*target_string == NULL)
445    {
446       return JB_ERR_MEMORY;
447    }
448
449    if (*text_to_append == '\0')
450    {
451       return JB_ERR_OK;
452    }
453
454    old_len = strlen(*target_string);
455
456    new_size = strlen(text_to_append) + old_len + 1;
457
458    if (NULL == (new_string = realloc(*target_string, new_size)))
459    {
460       free(*target_string);
461
462       *target_string = NULL;
463       return JB_ERR_MEMORY;
464    }
465
466    strlcpy(new_string + old_len, text_to_append, new_size - old_len);
467
468    *target_string = new_string;
469    return JB_ERR_OK;
470 }
471
472
473 /*********************************************************************
474  *
475  * Function    :  string_join
476  *
477  * Description :  Join two strings together.  Frees BOTH the original
478  *                strings.  If either or both input strings are NULL,
479  *                fails as if it had run out of memory.
480  *
481  *                For comparison, string_append requires that the
482  *                second string is non-NULL, and doesn't free it.
483  *
484  *                Rationale: Too often, we want to do
485  *                string_append(s, html_encode(s2)).  That assert()s
486  *                if s2 is NULL or if html_encode() runs out of memory.
487  *                It also leaks memory.  Proper checking is cumbersome.
488  *                The solution: string_join(s, html_encode(s2)) is safe,
489  *                and will free the memory allocated by html_encode().
490  *
491  * Parameters  :
492  *          1  :  target_string = Pointer to old text that is to be
493  *                extended.  *target_string will be free()d by this
494  *                routine.  target_string must be non-NULL.
495  *          2  :  text_to_append = Text to be appended to old.
496  *
497  * Returns     :  JB_ERR_OK on success, and sets *target_string
498  *                   to newly malloc'ed appended string.  Caller
499  *                   must free(*target_string).
500  *                JB_ERR_MEMORY on out-of-memory, or if
501  *                   *target_string or text_to_append is NULL.  (In
502  *                   this case, frees *target_string and text_to_append,
503  *                   sets *target_string to NULL).
504  *
505  *********************************************************************/
506 jb_err string_join(char **target_string, char *text_to_append)
507 {
508    jb_err err;
509
510    assert(target_string);
511
512    if (text_to_append == NULL)
513    {
514       freez(*target_string);
515       return JB_ERR_MEMORY;
516    }
517
518    err = string_append(target_string, text_to_append);
519
520    freez(text_to_append);
521
522    return err;
523 }
524
525
526 /*********************************************************************
527  *
528  * Function    :  string_toupper
529  *
530  * Description :  Produce a copy of string with all convertible
531  *                characters converted to uppercase.
532  *
533  * Parameters  :
534  *          1  :  string = string to convert
535  *
536  * Returns     :  Uppercase copy of string if possible,
537  *                NULL on out-of-memory or if string was NULL.
538  *
539  *********************************************************************/
540 char *string_toupper(const char *string)
541 {
542    char *result, *p;
543    const char *q;
544
545    if (!string || ((result = (char *) zalloc(strlen(string) + 1)) == NULL))
546    {
547       return NULL;
548    }
549
550    q = string;
551    p = result;
552
553    while (*q != '\0')
554    {
555       *p++ = (char)toupper((int) *q++);
556    }
557
558    return result;
559
560 }
561
562
563 /*********************************************************************
564  *
565  * Function    :  string_move
566  *
567  * Description :  memmove wrapper to move the last part of a string
568  *                towards the beginning, overwriting the part in
569  *                the middle. strlcpy() can't be used here as the
570  *                strings overlap.
571  *
572  * Parameters  :
573  *          1  :  dst = Destination to overwrite
574  *          2  :  src = Source to move.
575  *
576  * Returns     :  N/A
577  *
578  *********************************************************************/
579 void string_move(char *dst, char *src)
580 {
581    assert(dst < src);
582
583    /* +1 to copy the terminating nul as well. */
584    memmove(dst, src, strlen(src)+1);
585 }
586
587
588 /*********************************************************************
589  *
590  * Function    :  bindup
591  *
592  * Description :  Duplicate the first n characters of a string that may
593  *                contain '\0' characters.
594  *
595  * Parameters  :
596  *          1  :  string = string to be duplicated
597  *          2  :  len = number of bytes to duplicate
598  *
599  * Returns     :  pointer to copy, or NULL if failiure
600  *
601  *********************************************************************/
602 char *bindup(const char *string, size_t len)
603 {
604    char *duplicate;
605
606    duplicate = (char *)malloc(len);
607    if (NULL != duplicate)
608    {
609       memcpy(duplicate, string, len);
610    }
611
612    return duplicate;
613
614 }
615
616
617 /*********************************************************************
618  *
619  * Function    :  make_path
620  *
621  * Description :  Takes a directory name and a file name, returns
622  *                the complete path.  Handles windows/unix differences.
623  *                If the file name is already an absolute path, or if
624  *                the directory name is NULL or empty, it returns
625  *                the filename.
626  *
627  * Parameters  :
628  *          1  :  dir: Name of directory or NULL for none.
629  *          2  :  file: Name of file.  Should not be NULL or empty.
630  *
631  * Returns     :  "dir/file" (Or on windows, "dir\file").
632  *                It allocates the string on the heap.  Caller frees.
633  *                Returns NULL in error (i.e. NULL file or out of
634  *                memory)
635  *
636  *********************************************************************/
637 char * make_path(const char * dir, const char * file)
638 {
639    if ((file == NULL) || (*file == '\0'))
640    {
641       return NULL; /* Error */
642    }
643
644    if ((dir == NULL) || (*dir == '\0') /* No directory specified */
645 #if defined(_WIN32)
646       || (*file == '\\') || (file[1] == ':') /* Absolute path (DOS) */
647 #else /* ifndef _WIN32 */
648       || (*file == '/') /* Absolute path (U*ix) */
649 #endif /* ifndef _WIN32 */
650       )
651    {
652       return strdup(file);
653    }
654    else
655    {
656       char * path;
657       size_t path_size = strlen(dir) + strlen(file) + 2; /* +2 for trailing (back)slash and \0 */
658
659 #if defined(unix)
660       if (*dir != '/' && basedir && *basedir)
661       {
662          /*
663           * Relative path, so start with the base directory.
664           */
665          path_size += strlen(basedir) + 1; /* +1 for the slash */
666          path = malloc(path_size);
667          if (!path) log_error(LOG_LEVEL_FATAL, "malloc failed!");
668          strlcpy(path, basedir, path_size);
669          strlcat(path, "/", path_size);
670          strlcat(path, dir, path_size);
671       }
672       else
673 #endif /* defined unix */
674       {
675          path = malloc(path_size);
676          if (!path) log_error(LOG_LEVEL_FATAL, "malloc failed!");
677          strlcpy(path, dir, path_size);
678       }
679
680       assert(NULL != path);
681 #if defined(_WIN32)
682       if (path[strlen(path)-1] != '\\')
683       {
684          strlcat(path, "\\", path_size);
685       }
686 #else /* ifndef _WIN32 */
687       if (path[strlen(path)-1] != '/')
688       {
689          strlcat(path, "/", path_size);
690       }
691 #endif /* ifndef _WIN32 */
692       strlcat(path, file, path_size);
693
694       return path;
695    }
696 }
697
698
699 /*********************************************************************
700  *
701  * Function    :  pick_from_range
702  *
703  * Description :  Pick a positive number out of a given range.
704  *                Should only be used if randomness would be nice,
705  *                but isn't really necessary.
706  *
707  * Parameters  :
708  *          1  :  range: Highest possible number to pick.
709  *
710  * Returns     :  Picked number.
711  *
712  *********************************************************************/
713 long int pick_from_range(long int range)
714 {
715    long int number;
716 #ifdef _WIN32
717    static unsigned long seed = 0;
718 #endif /* def _WIN32 */
719
720    assert(range != 0);
721    assert(range > 0);
722
723    if (range <= 0) return 0;
724
725 #ifdef HAVE_ARC4RANDOM
726    number = arc4random() % range + 1;
727 #elif defined(HAVE_RANDOM)
728    number = random() % range + 1;
729 #elif defined(MUTEX_LOCKS_AVAILABLE)
730    privoxy_mutex_lock(&rand_mutex);
731 #ifdef _WIN32
732    if (!seed)
733    {
734       seed = (unsigned long)(GetCurrentThreadId()+GetTickCount());
735    }
736    srand(seed);
737    seed = (unsigned long)((rand() << 16) + rand());
738 #endif /* def _WIN32 */
739    number = (unsigned long)((rand() << 16) + (rand())) % (unsigned long)(range + 1);
740    privoxy_mutex_unlock(&rand_mutex);
741 #else
742    /*
743     * XXX: Which platforms reach this and are there
744     * better options than just using rand() and hoping
745     * that it's safe?
746     */
747    log_error(LOG_LEVEL_INFO, "No thread-safe PRNG available? Header time randomization "
748       "might cause crashes, predictable results or even combine these fine options.");
749    number = rand() % (long int)(range + 1);
750
751 #endif /* (def HAVE_ARC4RANDOM) */
752
753    return number;
754 }
755
756
757 #ifdef USE_PRIVOXY_STRLCPY
758 /*********************************************************************
759  *
760  * Function    :  privoxy_strlcpy
761  *
762  * Description :  strlcpy(3) look-alike for those without decent libc.
763  *
764  * Parameters  :
765  *          1  :  destination: buffer to copy into.
766  *          2  :  source: String to copy.
767  *          3  :  size: Size of destination buffer.
768  *
769  * Returns     :  The length of the string that privoxy_strlcpy() tried to create.
770  *
771  *********************************************************************/
772 size_t privoxy_strlcpy(char *destination, const char *source, const size_t size)
773 {
774    if (0 < size)
775    {
776       snprintf(destination, size, "%s", source);
777       /*
778        * Platforms that lack strlcpy() also tend to have
779        * a broken snprintf implementation that doesn't
780        * guarantee nul termination.
781        *
782        * XXX: the configure script should detect and reject those.
783        */
784       destination[size-1] = '\0';
785    }
786    return strlen(source);
787 }
788 #endif /* def USE_PRIVOXY_STRLCPY */
789
790
791 #ifndef HAVE_STRLCAT
792 /*********************************************************************
793  *
794  * Function    :  privoxy_strlcat
795  *
796  * Description :  strlcat(3) look-alike for those without decent libc.
797  *
798  * Parameters  :
799  *          1  :  destination: C string.
800  *          2  :  source: String to copy.
801  *          3  :  size: Size of destination buffer.
802  *
803  * Returns     :  The length of the string that privoxy_strlcat() tried to create.
804  *
805  *********************************************************************/
806 size_t privoxy_strlcat(char *destination, const char *source, const size_t size)
807 {
808    const size_t old_length = strlen(destination);
809    return old_length + strlcpy(destination + old_length, source, size - old_length);
810 }
811 #endif /* ndef HAVE_STRLCAT */
812
813
814 /*********************************************************************
815  *
816  * Function    :  privoxy_millisleep
817  *
818  * Description :  Sleep a number of milliseconds
819  *
820  * Parameters  :
821  *          1  :  delay: Number of milliseconds to sleep
822  *
823  * Returns     :  -1 on error, 0 otherwise
824  *
825  *********************************************************************/
826 int privoxy_millisleep(unsigned milliseconds)
827 {
828 #ifdef HAVE_NANOSLEEP
829    struct timespec rqtp = {0};
830    struct timespec rmtp = {0};
831
832    rqtp.tv_sec = milliseconds / 1000;
833    rqtp.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
834
835    return nanosleep(&rqtp, &rmtp);
836 #elif defined (_WIN32)
837    Sleep(milliseconds);
838
839    return 0;
840 #else
841 #warning Missing privoxy_milisleep() implementation. delay-response{} will not work.
842
843    return -1;
844 #endif /* def HAVE_NANOSLEEP */
845
846 }
847
848
849 /*********************************************************************
850  *
851  * Function    :  privoxy_gmtime_r
852  *
853  * Description :  Behave like gmtime_r() and convert a
854  *                time_t to a struct tm.
855  *
856  * Parameters  :
857  *          1  :  time_spec: The time to convert
858  *          2  :  result: The struct tm to use as storage
859  *
860  * Returns     :  Pointer to the result or NULL on error.
861  *
862  *********************************************************************/
863 struct tm *privoxy_gmtime_r(const time_t *time_spec, struct tm *result)
864 {
865    struct tm *timeptr;
866
867 #ifdef HAVE_GMTIME_R
868    timeptr = gmtime_r(time_spec, result);
869 #elif defined(MUTEX_LOCKS_AVAILABLE)
870    privoxy_mutex_lock(&gmtime_mutex);
871    timeptr = gmtime(time_spec);
872 #else
873 #warning Using unlocked gmtime()
874    timeptr = gmtime(time_spec);
875 #endif
876
877    if (timeptr == NULL)
878    {
879 #if !defined(HAVE_GMTIME_R) && defined(MUTEX_LOCKS_AVAILABLE)
880       privoxy_mutex_unlock(&gmtime_mutex);
881 #endif
882       return NULL;
883    }
884
885 #if !defined(HAVE_GMTIME_R)
886    *result = *timeptr;
887    timeptr = result;
888 #ifdef MUTEX_LOCKS_AVAILABLE
889    privoxy_mutex_unlock(&gmtime_mutex);
890 #endif
891 #endif
892
893    return timeptr;
894 }
895
896 #if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV)
897 /*********************************************************************
898  *
899  * Function    :  timegm
900  *
901  * Description :  libc replacement function for the inverse of gmtime().
902  *                Copyright (C) 2004 Free Software Foundation, Inc.
903  *
904  *                Code originally copied from GnuPG, modifications done
905  *                for Privoxy: style changed, #ifdefs for _WIN32 added
906  *                to have it work on mingw32.
907  *
908  *                XXX: It's very unlikely to happen, but if the malloc()
909  *                call fails the time zone will be permanently set to UTC.
910  *
911  * Parameters  :
912  *          1  :  tm: Broken-down time struct.
913  *
914  * Returns     :  tm converted into time_t seconds.
915  *
916  *********************************************************************/
917 time_t timegm(struct tm *tm)
918 {
919    time_t answer;
920    char *zone;
921
922    zone = getenv("TZ");
923    putenv("TZ=UTC");
924    tzset();
925    answer = mktime(tm);
926    if (zone)
927    {
928       char *old_zone;
929
930       old_zone = malloc(3 + strlen(zone) + 1);
931       if (old_zone)
932       {
933          strcpy(old_zone, "TZ=");
934          strcat(old_zone, zone);
935          putenv(old_zone);
936 #ifdef _WIN32
937          /* http://man7.org/linux/man-pages/man3/putenv.3.html
938           *   int putenv(char *string);
939           *     The string pointed to by string becomes part of the environment, so altering the
940           *     string changes the environment.
941           * In other words, the memory pointed to by *string is used until
942           *   a) another call to putenv() with the same e-var name
943           *   b) the program exits
944           *
945           * Windows e-vars don't work that way, so let's not leak memory.
946           */
947          free(old_zone);
948 #endif /* def _WIN32 */
949       }
950    }
951    else
952    {
953 #ifdef HAVE_UNSETENV
954       unsetenv("TZ");
955 #elif defined(_WIN32)
956       putenv("TZ=");
957 #else
958       putenv("TZ");
959 #endif
960    }
961    tzset();
962
963    return answer;
964 }
965 #endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */
966
967
968 /*
969   Local Variables:
970   tab-width: 3
971   end:
972 */