Some sanity checks for pick_from_range().
[privoxy.git] / miscutil.c
1 const char miscutil_rcs[] = "$Id: miscutil.c,v 1.55 2007/11/03 17:34:49 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/miscutil.c,v $
5  *
6  * Purpose     :  zalloc, hash_string, safe_strerror, strcmpic,
7  *                strncmpic, chomp, and MinGW32 strdup
8  *                functions. 
9  *                These are each too small to deserve their own file
10  *                but don't really fit in any other file.
11  *
12  * Copyright   :  Written by and Copyright (C) 2001-2007
13  *                the SourceForge Privoxy team. http://www.privoxy.org/
14  *
15  *                Based on the Internet Junkbuster originally written
16  *                by and Copyright (C) 1997 Anonymous Coders and 
17  *                Junkbusters Corporation.  http://www.junkbusters.com
18  *
19  *                The timegm replacement function was taken from GnuPG,
20  *                Copyright (C) 2004 Free Software Foundation, Inc.
21  *
22  *                The snprintf replacement function is written by
23  *                Mark Martinec who also holds the copyright. It can be
24  *                used under the terms of the GPL or the terms of the
25  *                "Frontier Artistic License".
26  *
27  *                This program is free software; you can redistribute it 
28  *                and/or modify it under the terms of the GNU General
29  *                Public License as published by the Free Software
30  *                Foundation; either version 2 of the License, or (at
31  *                your option) any later version.
32  *
33  *                This program is distributed in the hope that it will
34  *                be useful, but WITHOUT ANY WARRANTY; without even the
35  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
36  *                PARTICULAR PURPOSE.  See the GNU General Public
37  *                License for more details.
38  *
39  *                The GNU General Public License should be included with
40  *                this file.  If not, you can view it at
41  *                http://www.gnu.org/copyleft/gpl.html
42  *                or write to the Free Software Foundation, Inc., 59
43  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
44  *
45  * Revisions   :
46  *    $Log: miscutil.c,v $
47  *    Revision 1.55  2007/11/03 17:34:49  fabiankeil
48  *    Log the "weak randomization factor" warning only
49  *    once for mingw32 and provide some more details.
50  *
51  *    Revision 1.54  2007/09/19 20:28:37  fabiankeil
52  *    If privoxy_strlcpy() is called with a "buffer" size
53  *    of 0, don't touch whatever destination points to.
54  *
55  *    Revision 1.53  2007/09/09 18:20:20  fabiankeil
56  *    Turn privoxy_strlcpy() into a function and try to work with
57  *    b0rked snprintf() implementations too. Reported by icmp30.
58  *
59  *    Revision 1.52  2007/08/19 12:32:34  fabiankeil
60  *    Fix a conversion warning.
61  *
62  *    Revision 1.51  2007/06/17 16:12:22  fabiankeil
63  *    #ifdef _WIN32 the last commit. According to David Shaw,
64  *    one of the gnupg developers, the changes are mingw32-specific.
65  *
66  *    Revision 1.50  2007/06/10 14:59:59  fabiankeil
67  *    Change replacement timegm() to better match our style, plug a small
68  *    but guaranteed memory leak and fix "time zone breathing" on mingw32.
69  *
70  *    Revision 1.49  2007/05/11 11:48:15  fabiankeil
71  *    - Delete strsav() which was replaced
72  *      by string_append() years ago.
73  *    - Add a strlcat() look-alike.
74  *    - Use strlcat() and strlcpy() in those parts
75  *      of the code that are run on unixes.
76  *
77  *    Revision 1.48  2007/04/09 17:48:51  fabiankeil
78  *    Check for HAVE_SNPRINTF instead of __OS2__
79  *    before including the portable snprintf() code.
80  *
81  *    Revision 1.47  2007/03/17 11:52:15  fabiankeil
82  *    - Use snprintf instead of sprintf.
83  *    - Mention copyright for the replacement
84  *      functions in the copyright header.
85  *
86  *    Revision 1.46  2007/01/18 15:03:20  fabiankeil
87  *    Don't include replacement timegm() if
88  *    putenv() or tzset() isn't available.
89  *
90  *    Revision 1.45  2006/12/26 17:31:41  fabiankeil
91  *    Mutex protect rand() if POSIX threading
92  *    is used, warn the user if that's not possible
93  *    and stop using it on _WIN32 where it could
94  *    cause crashes.
95  *
96  *    Revision 1.44  2006/11/07 12:46:43  fabiankeil
97  *    Silence compiler warning on NetBSD 3.1.
98  *
99  *    Revision 1.43  2006/09/23 13:26:38  roro
100  *    Replace TABs by spaces in source code.
101  *
102  *    Revision 1.42  2006/09/09 14:01:45  fabiankeil
103  *    Integrated Oliver Yeoh's domain pattern fix
104  *    to make sure *x matches xx. Closes Patch 1217393
105  *    and Bug 1170767.
106  *
107  *    Revision 1.41  2006/08/18 16:03:17  david__schmidt
108  *    Tweak for OS/2 build happiness.
109  *
110  *    Revision 1.40  2006/08/17 17:15:10  fabiankeil
111  *    - Back to timegm() using GnuPG's replacement if necessary.
112  *      Using mktime() and localtime() could add a on hour offset if
113  *      the randomize factor was big enough to lead to a summer/wintertime
114  *      switch.
115  *
116  *    - Removed now-useless Privoxy 3.0.3 compatibility glue.
117  *
118  *    - Moved randomization code into pick_from_range().
119  *
120  *    - Changed parse_header_time definition.
121  *      time_t isn't guaranteed to be signed and
122  *      if it isn't, -1 isn't available as error code.
123  *      Changed some variable types in client_if_modified_since()
124  *      because of the same reason.
125  *
126  *    Revision 1.39  2006/07/18 14:48:46  david__schmidt
127  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
128  *    with what was really the latest development (the v_3_0_branch branch)
129  *
130  *    Revision 1.37.2.4  2003/12/01 14:45:14  oes
131  *    Fixed two more problems with wildcarding in simplematch()
132  *
133  *    Revision 1.37.2.3  2003/11/20 11:39:24  oes
134  *    Bugfix: The "?" wildcard for domain names had never been implemented. Ooops\!
135  *
136  *    Revision 1.37.2.2  2002/11/12 14:28:18  oes
137  *    Proper backtracking in simplematch; fixes bug #632888
138  *
139  *    Revision 1.37.2.1  2002/09/25 12:58:51  oes
140  *    Made strcmpic and strncmpic safe against NULL arguments
141  *    (which are now treated as empty strings).
142  *
143  *    Revision 1.37  2002/04/26 18:29:43  jongfoster
144  *    Fixing this Visual C++ warning:
145  *    miscutil.c(710) : warning C4090: '=' : different 'const' qualifiers
146  *
147  *    Revision 1.36  2002/04/26 12:55:38  oes
148  *    New function string_toupper
149  *
150  *    Revision 1.35  2002/03/26 22:29:55  swa
151  *    we have a new homepage!
152  *
153  *    Revision 1.34  2002/03/24 13:25:43  swa
154  *    name change related issues
155  *
156  *    Revision 1.33  2002/03/07 03:46:53  oes
157  *    Fixed compiler warnings etc
158  *
159  *    Revision 1.32  2002/03/06 23:02:57  jongfoster
160  *    Removing tabs
161  *
162  *    Revision 1.31  2002/03/05 04:52:42  oes
163  *    Deleted non-errlog debugging code
164  *
165  *    Revision 1.30  2002/03/04 18:27:42  oes
166  *    - Deleted deletePidFile
167  *    - Made write_pid_file use the --pidfile option value
168  *      (or no PID file, if the option was absent)
169  *    - Played styleguide police
170  *
171  *    Revision 1.29  2002/03/04 02:08:02  david__schmidt
172  *    Enable web editing of actions file on OS/2 (it had been broken all this time!)
173  *
174  *    Revision 1.28  2002/03/03 09:18:03  joergs
175  *    Made jumbjuster work on AmigaOS again.
176  *
177  *    Revision 1.27  2002/01/21 00:52:32  jongfoster
178  *    Adding string_join()
179  *
180  *    Revision 1.26  2001/12/30 14:07:32  steudten
181  *    - Add signal handling (unix)
182  *    - Add SIGHUP handler (unix)
183  *    - Add creation of pidfile (unix)
184  *    - Add action 'top' in rc file (RH)
185  *    - Add entry 'SIGNALS' to manpage
186  *    - Add exit message to logfile (unix)
187  *
188  *    Revision 1.25  2001/11/13 00:16:38  jongfoster
189  *    Replacing references to malloc.h with the standard stdlib.h
190  *    (See ANSI or K&R 2nd Ed)
191  *
192  *    Revision 1.24  2001/11/05 21:41:43  steudten
193  *    Add changes to be a real daemon just for unix os.
194  *    (change cwd to /, detach from controlling tty, set
195  *    process group and session leader to the own process.
196  *    Add DBG() Macro.
197  *    Add some fatal-error log message for failed malloc().
198  *    Add '-d' if compiled with 'configure --with-debug' to
199  *    enable debug output.
200  *
201  *    Revision 1.23  2001/10/29 03:48:10  david__schmidt
202  *    OS/2 native needed a snprintf() routine.  Added one to miscutil, brackedted
203  *    by and __OS2__ ifdef.
204  *
205  *    Revision 1.22  2001/10/26 17:39:38  oes
206  *    Moved ijb_isspace and ijb_tolower to project.h
207  *
208  *    Revision 1.21  2001/10/23 21:27:50  jongfoster
209  *    Standardising error codes in string_append
210  *    make_path() no longer adds '\\' if the dir already ends in '\\' (this
211  *    is just copying a UNIX-specific fix to the Windows-specific part)
212  *
213  *    Revision 1.20  2001/10/22 15:33:56  david__schmidt
214  *    Special-cased OS/2 out of the Netscape-abort-on-404-in-js problem in
215  *    filters.c.  Added a FIXME in front of the offending code.  I'll gladly
216  *    put in a better/more robust fix for all parties if one is presented...
217  *    It seems that just returning 200 instead of 404 would pretty much fix
218  *    it for everyone, but I don't know all the history of the problem.
219  *
220  *    Revision 1.19  2001/10/14 22:02:57  jongfoster
221  *    New function string_append() which is like strsav(), but running
222  *    out of memory isn't automatically FATAL.
223  *
224  *    Revision 1.18  2001/09/20 13:33:43  steudten
225  *
226  *    change long to int as return value in hash_string(). Remember the wraparound
227  *    for int = long = sizeof(4) - thats maybe not what we want.
228  *
229  *    Revision 1.17  2001/09/13 20:51:29  jongfoster
230  *    Fixing potential problems with characters >=128 in simplematch()
231  *    This was also a compiler warning.
232  *
233  *    Revision 1.16  2001/09/10 10:56:59  oes
234  *    Silenced compiler warnings
235  *
236  *    Revision 1.15  2001/07/13 14:02:24  oes
237  *    Removed vim-settings
238  *
239  *    Revision 1.14  2001/06/29 21:45:41  oes
240  *    Indentation, CRLF->LF, Tab-> Space
241  *
242  *    Revision 1.13  2001/06/29 13:32:14  oes
243  *    Removed logentry from cancelled commit
244  *
245  *    Revision 1.12  2001/06/09 10:55:28  jongfoster
246  *    Changing BUFSIZ ==> BUFFER_SIZE
247  *
248  *    Revision 1.11  2001/06/07 23:09:19  jongfoster
249  *    Cosmetic indentation changes.
250  *
251  *    Revision 1.10  2001/06/07 14:51:38  joergs
252  *    make_path() no longer adds '/' if the dir already ends in '/'.
253  *
254  *    Revision 1.9  2001/06/07 14:43:17  swa
255  *    slight mistake in make_path, unix path style is /.
256  *
257  *    Revision 1.8  2001/06/05 22:32:01  jongfoster
258  *    New function make_path() to splice directory and file names together.
259  *
260  *    Revision 1.7  2001/06/03 19:12:30  oes
261  *    introduced bindup()
262  *
263  *    Revision 1.6  2001/06/01 18:14:49  jongfoster
264  *    Changing the calls to strerr() to check HAVE_STRERR (which is defined
265  *    in config.h if appropriate) rather than the NO_STRERR macro.
266  *
267  *    Revision 1.5  2001/06/01 10:31:51  oes
268  *    Added character class matching to trivimatch; renamed to simplematch
269  *
270  *    Revision 1.4  2001/05/31 17:32:31  oes
271  *
272  *     - Enhanced domain part globbing with infix and prefix asterisk
273  *       matching and optional unanchored operation
274  *
275  *    Revision 1.3  2001/05/29 23:10:09  oes
276  *
277  *
278  *     - Introduced chomp()
279  *     - Moved strsav() from showargs to miscutil
280  *
281  *    Revision 1.2  2001/05/29 09:50:24  jongfoster
282  *    Unified blocklist/imagelist/permissionslist.
283  *    File format is still under discussion, but the internal changes
284  *    are (mostly) done.
285  *
286  *    Also modified interceptor behaviour:
287  *    - We now intercept all URLs beginning with one of the following
288  *      prefixes (and *only* these prefixes):
289  *        * http://i.j.b/
290  *        * http://ijbswa.sf.net/config/
291  *        * http://ijbswa.sourceforge.net/config/
292  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
293  *    - Internal changes so that intercepted and fast redirect pages
294  *      are not replaced with an image.
295  *    - Interceptors now have the option to send a binary page direct
296  *      to the client. (i.e. ijb-send-banner uses this)
297  *    - Implemented show-url-info interceptor.  (Which is why I needed
298  *      the above interceptors changes - a typical URL is
299  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
300  *      The previous mechanism would not have intercepted that, and
301  *      if it had been intercepted then it then it would have replaced
302  *      it with an image.)
303  *
304  *    Revision 1.1.1.1  2001/05/15 13:59:00  oes
305  *    Initial import of version 2.9.3 source tree
306  *
307  *
308  *********************************************************************/
309 \f
310
311 #include "config.h"
312
313 #include <stdio.h>
314 #include <sys/types.h>
315 #include <stdlib.h>
316 #if !defined(_WIN32) && !defined(__OS2__)
317 #include <unistd.h>
318 #endif /* #if !defined(_WIN32) && !defined(__OS2__) */
319 #include <string.h>
320 #include <ctype.h>
321 #include <assert.h>
322
323 #if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV)
324 #include <time.h>
325 #endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */
326
327 #include "project.h"
328 #include "miscutil.h"
329 #include "errlog.h"
330 #include "jcc.h"
331
332 const char miscutil_h_rcs[] = MISCUTIL_H_VERSION;
333
334 /*********************************************************************
335  *
336  * Function    :  zalloc
337  *
338  * Description :  Malloc some memory and set it to '\0'.
339  *                The way calloc() ought to be -acjc
340  *
341  * Parameters  :
342  *          1  :  size = Size of memory chunk to return.
343  *
344  * Returns     :  Pointer to newly malloc'd memory chunk.
345  *
346  *********************************************************************/
347 void *zalloc(size_t size)
348 {
349    void * ret;
350
351    if ((ret = (void *)malloc(size)) != NULL)
352    {
353       memset(ret, 0, size);
354    }
355
356    return(ret);
357
358 }
359
360
361 #if defined(unix)
362 /*********************************************************************
363  *
364  * Function    :  write_pid_file 
365  *
366  * Description :  Writes a pid file with the pid of the main process 
367  *
368  * Parameters  :  None
369  *
370  * Returns     :  N/A 
371  *
372  *********************************************************************/
373 void write_pid_file(void)
374 {
375    FILE   *fp;
376    
377    /*
378     * If no --pidfile option was given,
379     * we can live without one.
380     */
381    if (pidfile == NULL) return;
382
383    if ((fp = fopen(pidfile, "w")) == NULL)
384    {
385       log_error(LOG_LEVEL_INFO, "can't open pidfile '%s': %E", pidfile);
386    }
387    else
388    {
389       fprintf(fp, "%u\n", (unsigned int) getpid());
390       fclose (fp);
391    }
392    return;
393
394 }
395 #endif /* def unix */
396
397
398 /*********************************************************************
399  *
400  * Function    :  hash_string
401  *
402  * Description :  Take a string and compute a (hopefuly) unique numeric
403  *                integer value.  This has several uses, but being able
404  *                to "switch" a string the one of my favorites.
405  *
406  * Parameters  :
407  *          1  :  s : string to be hashed.
408  *
409  * Returns     :  an unsigned long variable with the hashed value.
410  *
411  *********************************************************************/
412 unsigned int hash_string( const char* s )
413 {
414    unsigned int h = 0; 
415
416    for ( ; *s; ++s )
417    {
418       h = 5 * h + (unsigned int)*s;
419    }
420
421    return (h);
422
423 }
424
425
426 #ifdef __MINGW32__
427 /*********************************************************************
428  *
429  * Function    :  strdup
430  *
431  * Description :  For some reason (which is beyond me), gcc and WIN32
432  *                don't like strdup.  When a "free" is executed on a
433  *                strdup'd ptr, it can at times freez up!  So I just
434  *                replaced it and problem was solved.
435  *
436  * Parameters  :
437  *          1  :  s = string to duplicate
438  *
439  * Returns     :  Pointer to newly malloc'ed copy of the string.
440  *
441  *********************************************************************/
442 char *strdup( const char *s )
443 {
444    char * result = (char *)malloc( strlen(s)+1 );
445
446    if (result != NULL)
447    {
448       strcpy( result, s );
449    }
450
451    return( result );
452 }
453
454 #endif /* def __MINGW32__ */
455
456
457
458 /*********************************************************************
459  *
460  * Function    :  safe_strerror
461  *
462  * Description :  Variant of the library routine strerror() which will
463  *                work on systems without the library routine, and
464  *                which should never return NULL.
465  *
466  * Parameters  :
467  *          1  :  err = the `errno' of the last operation.
468  *
469  * Returns     :  An "English" string of the last `errno'.  Allocated
470  *                with strdup(), so caller frees.  May be NULL if the
471  *                system is out of memory.
472  *
473  *********************************************************************/
474 char *safe_strerror(int err)
475 {
476    char *s = NULL;
477    char buf[BUFFER_SIZE];
478
479
480 #ifdef HAVE_STRERROR
481    s = strerror(err);
482 #endif /* HAVE_STRERROR */
483
484    if (s == NULL)
485    {
486       snprintf(buf, sizeof(buf), "(errno = %d)", err);
487       s = buf;
488    }
489
490    return(strdup(s));
491
492 }
493
494
495 /*********************************************************************
496  *
497  * Function    :  strcmpic
498  *
499  * Description :  Case insensitive string comparison
500  *
501  * Parameters  :
502  *          1  :  s1 = string 1 to compare
503  *          2  :  s2 = string 2 to compare
504  *
505  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
506  *
507  *********************************************************************/
508 int strcmpic(const char *s1, const char *s2)
509 {
510    if (!s1) s1 = "";
511    if (!s2) s2 = "";
512
513    while (*s1 && *s2)
514    {
515       if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
516       {
517          break;
518       }
519       s1++, s2++;
520    }
521    return(ijb_tolower(*s1) - ijb_tolower(*s2));
522
523 }
524
525
526 /*********************************************************************
527  *
528  * Function    :  strncmpic
529  *
530  * Description :  Case insensitive string comparison (upto n characters)
531  *
532  * Parameters  :
533  *          1  :  s1 = string 1 to compare
534  *          2  :  s2 = string 2 to compare
535  *          3  :  n = maximum characters to compare
536  *
537  * Returns     :  0 if s1==s2, Negative if s1<s2, Positive if s1>s2
538  *
539  *********************************************************************/
540 int strncmpic(const char *s1, const char *s2, size_t n)
541 {
542    if (n <= 0) return(0);
543    if (!s1) s1 = "";
544    if (!s2) s2 = "";
545    
546    while (*s1 && *s2)
547    {
548       if ( ( *s1 != *s2 ) && ( ijb_tolower(*s1) != ijb_tolower(*s2) ) )
549       {
550          break;
551       }
552
553       if (--n <= 0) break;
554
555       s1++, s2++;
556    }
557    return(ijb_tolower(*s1) - ijb_tolower(*s2));
558
559 }
560
561
562 /*********************************************************************
563  *
564  * Function    :  chomp
565  *
566  * Description :  In-situ-eliminate all leading and trailing whitespace
567  *                from a string.
568  *
569  * Parameters  :
570  *          1  :  s : string to be chomped.
571  *
572  * Returns     :  chomped string
573  *
574  *********************************************************************/
575 char *chomp(char *string)
576 {
577    char *p, *q, *r;
578
579    /* 
580     * strip trailing whitespace
581     */
582    p = string + strlen(string);
583    while (p > string && ijb_isspace(*(p-1)))
584    {
585       p--;
586    }
587    *p = '\0';
588
589    /* 
590     * find end of leading whitespace 
591     */
592    q = r = string;
593    while (*q && ijb_isspace(*q))
594    {
595       q++;
596    }
597
598    /*
599     * if there was any, move the rest forwards
600     */
601    if (q != string)
602    {
603       while (q <= p)
604       {
605          *r++ = *q++;
606       }
607    }
608
609    return(string);
610
611 }
612
613
614 /*********************************************************************
615  *
616  * Function    :  string_append
617  *
618  * Description :  Reallocate target_string and append text to it.  
619  *                This makes it easier to append to malloc'd strings.
620  *                This is similar to the (removed) strsav(), but
621  *                running out of memory isn't catastrophic.
622  *
623  *                Programming style:
624  *
625  *                The following style provides sufficient error
626  *                checking for this routine, with minimal clutter
627  *                in the source code.  It is recommended if you
628  *                have many calls to this function:
629  *
630  *                char * s = strdup(...); // don't check for error
631  *                string_append(&s, ...);  // don't check for error
632  *                string_append(&s, ...);  // don't check for error
633  *                string_append(&s, ...);  // don't check for error
634  *                if (NULL == s) { ... handle error ... }
635  *
636  *                OR, equivalently:
637  *
638  *                char * s = strdup(...); // don't check for error
639  *                string_append(&s, ...);  // don't check for error
640  *                string_append(&s, ...);  // don't check for error
641  *                if (string_append(&s, ...)) {... handle error ...}
642  *
643  * Parameters  :
644  *          1  :  target_string = Pointer to old text that is to be
645  *                extended.  *target_string will be free()d by this
646  *                routine.  target_string must be non-NULL.
647  *                If *target_string is NULL, this routine will
648  *                do nothing and return with an error - this allows
649  *                you to make many calls to this routine and only
650  *                check for errors after the last one.
651  *          2  :  text_to_append = Text to be appended to old.
652  *                Must not be NULL.
653  *
654  * Returns     :  JB_ERR_OK on success, and sets *target_string
655  *                   to newly malloc'ed appended string.  Caller
656  *                   must free(*target_string).
657  *                JB_ERR_MEMORY on out-of-memory.  (And free()s
658  *                   *target_string and sets it to NULL).
659  *                JB_ERR_MEMORY if *target_string is NULL.
660  *
661  *********************************************************************/
662 jb_err string_append(char **target_string, const char *text_to_append)
663 {
664    size_t old_len;
665    char *new_string;
666    size_t new_size;
667
668    assert(target_string);
669    assert(text_to_append);
670
671    if (*target_string == NULL)
672    {
673       return JB_ERR_MEMORY;
674    }
675
676    if (*text_to_append == '\0')
677    {
678       return JB_ERR_OK;
679    }
680
681    old_len = strlen(*target_string);
682
683    new_size = strlen(text_to_append) + old_len + 1;
684
685    if (NULL == (new_string = realloc(*target_string, new_size)))
686    {
687       free(*target_string);
688
689       *target_string = NULL;
690       return JB_ERR_MEMORY;
691    }
692
693    strlcpy(new_string + old_len, text_to_append, new_size - old_len);
694
695    *target_string = new_string;
696    return JB_ERR_OK;
697 }
698
699
700 /*********************************************************************
701  *
702  * Function    :  string_join
703  *
704  * Description :  Join two strings together.  Frees BOTH the original
705  *                strings.  If either or both input strings are NULL,
706  *                fails as if it had run out of memory.
707  *
708  *                For comparison, string_append requires that the
709  *                second string is non-NULL, and doesn't free it.
710  *
711  *                Rationale: Too often, we want to do
712  *                string_append(s, html_encode(s2)).  That assert()s
713  *                if s2 is NULL or if html_encode() runs out of memory.
714  *                It also leaks memory.  Proper checking is cumbersome.
715  *                The solution: string_join(s, html_encode(s2)) is safe,
716  *                and will free the memory allocated by html_encode().
717  *
718  * Parameters  :
719  *          1  :  target_string = Pointer to old text that is to be
720  *                extended.  *target_string will be free()d by this
721  *                routine.  target_string must be non-NULL.
722  *          2  :  text_to_append = Text to be appended to old.
723  *
724  * Returns     :  JB_ERR_OK on success, and sets *target_string
725  *                   to newly malloc'ed appended string.  Caller
726  *                   must free(*target_string).
727  *                JB_ERR_MEMORY on out-of-memory, or if
728  *                   *target_string or text_to_append is NULL.  (In
729  *                   this case, frees *target_string and text_to_append,
730  *                   sets *target_string to NULL).
731  *
732  *********************************************************************/
733 jb_err string_join(char **target_string, char *text_to_append)
734 {
735    jb_err err;
736
737    assert(target_string);
738
739    if (text_to_append == NULL)
740    {
741       freez(*target_string);
742       return JB_ERR_MEMORY;
743    }
744
745    err = string_append(target_string, text_to_append);
746
747    free(text_to_append);
748
749    return err;
750 }
751
752
753 /*********************************************************************
754  *
755  * Function    :  string_toupper
756  *
757  * Description :  Produce a copy of string with all convertible
758  *                characters converted to uppercase.
759  *
760  * Parameters  :
761  *          1  :  string = string to convert
762  *
763  * Returns     :  Uppercase copy of string if possible, 
764  *                NULL on out-of-memory or if string was NULL.
765  *
766  *********************************************************************/
767 char *string_toupper(const char *string)
768 {
769    char *result, *p;
770    const char *q;
771
772    if (!string || ((result = (char *) zalloc(strlen(string) + 1)) == NULL))
773    {
774       return NULL;
775    }
776    
777    q = string;
778    p = result;
779
780    while (*q != '\0')
781    {
782       *p++ = (char)toupper((int) *q++);
783    }
784
785    return result;
786
787 }
788
789
790 /*********************************************************************
791  *
792  * Function    :  simplematch
793  *
794  * Description :  String matching, with a (greedy) '*' wildcard that
795  *                stands for zero or more arbitrary characters and
796  *                character classes in [], which take both enumerations
797  *                and ranges.
798  *
799  * Parameters  :
800  *          1  :  pattern = pattern for matching
801  *          2  :  text    = text to be matched
802  *
803  * Returns     :  0 if match, else nonzero
804  *
805  *********************************************************************/
806 int simplematch(char *pattern, char *text)
807 {
808    unsigned char *pat = (unsigned char *) pattern;
809    unsigned char *txt = (unsigned char *) text;
810    unsigned char *fallback = pat; 
811    int wildcard = 0;
812   
813    unsigned char lastchar = 'a';
814    unsigned i;
815    unsigned char charmap[32];
816   
817    while (*txt)
818    {
819
820       /* EOF pattern but !EOF text? */
821       if (*pat == '\0')
822       {
823          if (wildcard)
824          {
825             pat = fallback;
826          }
827          else
828          {
829             return 1;
830          }
831       }
832
833       /* '*' in the pattern?  */
834       if (*pat == '*') 
835       {
836      
837          /* The pattern ends afterwards? Speed up the return. */
838          if (*++pat == '\0')
839          {
840             return 0;
841          }
842      
843          /* Else, set wildcard mode and remember position after '*' */
844          wildcard = 1;
845          fallback = pat;
846       }
847
848       /* Character range specification? */
849       if (*pat == '[')
850       {
851          memset(charmap, '\0', sizeof(charmap));
852
853          while (*++pat != ']')
854          {
855             if (!*pat)
856             { 
857                return 1;
858             }
859             else if (*pat == '-')
860             {
861                if ((*++pat == ']') || *pat == '\0')
862                {
863                   return(1);
864                }
865                for(i = lastchar; i <= *pat; i++)
866                {
867                   charmap[i / 8] |= (1 << (i % 8));
868                } 
869             }
870             else
871             {
872                charmap[*pat / 8] |= (1 << (*pat % 8));
873                lastchar = *pat;
874             }
875          }
876       } /* -END- if Character range specification */
877
878
879       /* 
880        * Char match, or char range match? 
881        */
882       if ( (*pat == *txt)
883       ||   (*pat == '?')
884       ||   ((*pat == ']') && (charmap[*txt / 8] & (1 << (*txt % 8)))) )
885       {
886          /* 
887           * Sucess: Go ahead
888           */
889          pat++;
890       }
891       else if (!wildcard)
892       {
893          /* 
894           * No match && no wildcard: No luck
895           */
896          return 1;
897       }
898       else if (pat != fallback)
899       {
900          /*
901           * Increment text pointer if in char range matching
902           */
903          if (*pat == ']')
904          {
905             txt++;
906          }
907          /*
908           * Wildcard mode && nonmatch beyond fallback: Rewind pattern
909           */
910          pat = fallback;
911          /*
912           * Restart matching from current text pointer
913           */
914          continue;
915       }
916       txt++;
917    }
918
919    /* Cut off extra '*'s */
920    if(*pat == '*')  pat++;
921
922    /* If this is the pattern's end, fine! */
923    return(*pat);
924
925 }
926
927
928 /*********************************************************************
929  *
930  * Function    :  bindup
931  *
932  * Description :  Duplicate the first n characters of a string that may
933  *                contain '\0' characters.
934  *
935  * Parameters  :
936  *          1  :  string = string to be duplicated
937  *          2  :  len = number of bytes to duplicate
938  *
939  * Returns     :  pointer to copy, or NULL if failiure
940  *
941  *********************************************************************/
942 char *bindup(const char *string, size_t len)
943 {
944    char *duplicate;
945
946    if (NULL == (duplicate = (char *)malloc(len)))
947    {
948       return NULL;
949    }
950    else
951    {
952      memcpy(duplicate, string, len);
953    }
954
955    return duplicate;
956
957 }
958
959
960 /*********************************************************************
961  *
962  * Function    :  make_path
963  *
964  * Description :  Takes a directory name and a file name, returns 
965  *                the complete path.  Handles windows/unix differences.
966  *                If the file name is already an absolute path, or if
967  *                the directory name is NULL or empty, it returns 
968  *                the filename. 
969  *
970  * Parameters  :
971  *          1  :  dir: Name of directory or NULL for none.
972  *          2  :  file: Name of file.  Should not be NULL or empty.
973  *
974  * Returns     :  "dir/file" (Or on windows, "dir\file").
975  *                It allocates the string on the heap.  Caller frees.
976  *                Returns NULL in error (i.e. NULL file or out of
977  *                memory) 
978  *
979  *********************************************************************/
980 char * make_path(const char * dir, const char * file)
981 {
982 #ifdef AMIGA
983    char path[512];
984
985    if(dir)
986    {
987       if(dir[0] == '.')
988       {
989          if(dir[1] == '/')
990          {
991             strncpy(path,dir+2,512);
992          }
993          else
994          {
995             strncpy(path,dir+1,512);
996          }
997       }
998       else
999       {
1000          strncpy(path,dir,512);
1001       }
1002       path[511]=0;
1003    }
1004    else
1005    {
1006       path[0]=0;
1007    }
1008    if(AddPart(path,file,512))
1009    {
1010       return strdup(path);
1011    }
1012    else
1013    {
1014       return NULL;
1015    }
1016 #else /* ndef AMIGA */
1017
1018    if ((file == NULL) || (*file == '\0'))
1019    {
1020       return NULL; /* Error */
1021    }
1022
1023    if ((dir == NULL) || (*dir == '\0') /* No directory specified */
1024 #if defined(_WIN32) || defined(__OS2__)
1025       || (*file == '\\') || (file[1] == ':') /* Absolute path (DOS) */
1026 #else /* ifndef _WIN32 || __OS2__ */
1027       || (*file == '/') /* Absolute path (U*ix) */
1028 #endif /* ifndef _WIN32 || __OS2__  */
1029       )
1030    {
1031       return strdup(file);
1032    }
1033    else
1034    {
1035       char * path;
1036       size_t path_size = strlen(dir) + strlen(file) + 2; /* +2 for trailing (back)slash and \0 */
1037
1038 #if defined(unix)
1039       if ( *dir != '/' && basedir && *basedir )
1040       {
1041          /*
1042           * Relative path, so start with the base directory.
1043           */
1044          path_size += strlen(basedir) + 1; /* +1 for the slash */
1045          path = malloc(path_size);
1046          if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
1047          strlcpy(path, basedir, path_size);
1048          strlcat(path, "/", path_size);
1049          strlcat(path, dir, path_size);
1050       }
1051       else
1052 #endif /* defined unix */
1053       {
1054          path = malloc(path_size);
1055          if (!path ) log_error(LOG_LEVEL_FATAL, "malloc failed!");
1056          strlcpy(path, dir, path_size);
1057       }
1058
1059 #if defined(_WIN32) || defined(__OS2__)
1060       if(path[strlen(path)-1] != '\\')
1061       {
1062          strlcat(path, "\\", path_size);
1063       }
1064 #else /* ifndef _WIN32 || __OS2__ */
1065       if(path[strlen(path)-1] != '/')
1066       {
1067          strlcat(path, "/", path_size);
1068       }
1069 #endif /* ifndef _WIN32 || __OS2__ */
1070       strlcat(path, file, path_size);
1071
1072       return path;
1073    }
1074 #endif /* ndef AMIGA */
1075 }
1076
1077
1078 /*********************************************************************
1079  *
1080  * Function    :  pick_from_range
1081  *
1082  * Description :  Pick a positive number out of a given range.
1083  *                Should only be used if randomness would be nice,
1084  *                but isn't really necessary.
1085  *
1086  * Parameters  :
1087  *          1  :  range: Highest possible number to pick.
1088  *
1089  * Returns     :  Picked number. 
1090  *
1091  *********************************************************************/
1092 long int pick_from_range(long int range)
1093 {
1094    long int number;
1095
1096    assert(range != 0);
1097    assert(range > 0);
1098
1099    if (range <= 0) return 0;
1100
1101 #ifdef HAVE_RANDOM
1102    number = random() % range + 1; 
1103 #elif defined(FEATURE_PTHREAD)
1104    pthread_mutex_lock(&rand_mutex);
1105    number = rand() % (long int)(range + 1);
1106    pthread_mutex_unlock(&rand_mutex);
1107 #else
1108 #ifdef _WIN32
1109    /*
1110     * On Windows and mingw32 srand() has to be called in every
1111     * rand()-using thread, but can cause crashes if it's not
1112     * mutex protected.
1113     *
1114     * Currently we don't have mutexes for mingw32, and for
1115     * our purpose this cludge is probably preferable to crashes.
1116     *
1117     * The warning is shown once on startup from jcc.c.
1118     */
1119    number = (range + GetCurrentThreadId() % range) / 2;
1120 #else
1121    /*
1122     * XXX: Which platforms reach this and are there
1123     * better options than just using rand() and hoping
1124     * that it's safe?
1125     */
1126    log_error(LOG_LEVEL_INFO, "No thread-safe PRNG available? Header time randomization might cause "
1127       "crashes, predictable results or even combine these fine options.");
1128    number = rand() % (long int)(range + 1);
1129 #endif /* def _WIN32 */ 
1130
1131 #endif /* (def HAVE_RANDOM) */
1132
1133    return number;
1134 }
1135
1136
1137 #ifdef USE_PRIVOXY_STRLCPY
1138 /*********************************************************************
1139  *
1140  * Function    :  privoxy_strlcpy
1141  *
1142  * Description :  strlcpy(3) look-alike for those without decent libc.
1143  *
1144  * Parameters  :
1145  *          1  :  destination: buffer to copy into.
1146  *          2  :  source: String to copy.
1147  *          3  :  size: Size of destination buffer.
1148  *
1149  * Returns     :  The length of the string that privoxy_strlcpy() tried to create.
1150  *
1151  *********************************************************************/
1152 size_t privoxy_strlcpy(char *destination, const char *source, const size_t size)
1153 {
1154    if (0 < size)
1155    {
1156       snprintf(destination, size, "%s", source);
1157       /*
1158        * Platforms that lack strlcpy() also tend to have
1159        * a broken snprintf implementation that doesn't
1160        * guarantee nul termination.
1161        *
1162        * XXX: the configure script should detect and reject those.
1163        */
1164       destination[size-1] = '\0';
1165    }
1166    return strlen(source);
1167 }
1168 #endif /* def USE_PRIVOXY_STRLCPY */
1169
1170
1171 #ifndef HAVE_STRLCAT
1172 /*********************************************************************
1173  *
1174  * Function    :  privoxy_strlcat
1175  *
1176  * Description :  strlcat(3) look-alike for those without decent libc.
1177  *
1178  * Parameters  :
1179  *          1  :  destination: C string.
1180  *          2  :  source: String to copy.
1181  *          3  :  size: Size of destination buffer.
1182  *
1183  * Returns     :  The length of the string that privoxy_strlcat() tried to create.
1184  *
1185  *********************************************************************/
1186 size_t privoxy_strlcat(char *destination, const char *source, const size_t size)
1187 {
1188    const size_t old_length = strlen(destination);
1189    return old_length + strlcpy(destination + old_length, source, size - old_length);
1190 }
1191 #endif /* ndef HAVE_STRLCAT */
1192
1193
1194 #if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV)
1195 /*********************************************************************
1196  *
1197  * Function    :  timegm
1198  *
1199  * Description :  libc replacement function for the inverse of gmtime().
1200  *                Copyright (C) 2004 Free Software Foundation, Inc.
1201  *
1202  *                Code originally copied from GnuPG, modifications done
1203  *                for Privoxy: style changed, #ifdefs for _WIN32 added
1204  *                to have it work on mingw32.
1205  *
1206  *                XXX: It's very unlikely to happen, but if the malloc()
1207  *                call fails the time zone will be permanently set to UTC.
1208  *
1209  * Parameters  :
1210  *          1  :  tm: Broken-down time struct.
1211  *
1212  * Returns     :  tm converted into time_t seconds. 
1213  *
1214  *********************************************************************/
1215 time_t timegm(struct tm *tm)
1216 {
1217    time_t answer;
1218    char *zone;
1219
1220    zone = getenv("TZ");
1221    putenv("TZ=UTC");
1222    tzset();
1223    answer = mktime(tm);
1224    if (zone)
1225    {
1226       char *old_zone;
1227
1228       old_zone = malloc(3 + strlen(zone) + 1);
1229       if (old_zone)
1230       {
1231          strcpy(old_zone, "TZ=");
1232          strcat(old_zone, zone);
1233          putenv(old_zone);
1234 #ifdef _WIN32
1235          free(old_zone);
1236 #endif /* def _WIN32 */
1237       }
1238    }
1239    else
1240    {
1241 #ifdef HAVE_UNSETENV
1242       unsetenv("TZ");
1243 #elif defined(_WIN32)
1244       putenv("TZ=");
1245 #else
1246       putenv("TZ");
1247 #endif
1248    }
1249    tzset();
1250
1251    return answer;
1252 }
1253 #endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */
1254
1255
1256 #ifndef HAVE_SNPRINTF
1257 /*
1258  * What follows is a portable snprintf routine, written by Mark Martinec.
1259  * See: http://www.ijs.si/software/snprintf/
1260
1261                                   snprintf.c
1262                    - a portable implementation of snprintf,
1263        including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf
1264                                        
1265    snprintf is a routine to convert numeric and string arguments to
1266    formatted strings. It is similar to sprintf(3) provided in a system's
1267    C library, yet it requires an additional argument - the buffer size -
1268    and it guarantees never to store anything beyond the given buffer,
1269    regardless of the format or arguments to be formatted. Some newer
1270    operating systems do provide snprintf in their C library, but many do
1271    not or do provide an inadequate (slow or idiosyncratic) version, which
1272    calls for a portable implementation of this routine.
1273
1274 Author
1275
1276    Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000
1277    Copyright Â© 1999, Mark Martinec
1278
1279  */
1280
1281 #define PORTABLE_SNPRINTF_VERSION_MAJOR 2
1282 #define PORTABLE_SNPRINTF_VERSION_MINOR 2
1283
1284 #if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF)
1285 # if defined(NEED_SNPRINTF_ONLY)
1286 # undef NEED_SNPRINTF_ONLY
1287 # endif
1288 # if !defined(PREFER_PORTABLE_SNPRINTF)
1289 # define PREFER_PORTABLE_SNPRINTF
1290 # endif
1291 #endif
1292
1293 #if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE)
1294 #define SOLARIS_COMPATIBLE
1295 #endif
1296
1297 #if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
1298 #define HPUX_COMPATIBLE
1299 #endif
1300
1301 #if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE)
1302 #define DIGITAL_UNIX_COMPATIBLE
1303 #endif
1304
1305 #if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE)
1306 #define PERL_COMPATIBLE
1307 #endif
1308
1309 #if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE)
1310 #define LINUX_COMPATIBLE
1311 #endif
1312
1313 #include <sys/types.h>
1314 #include <string.h>
1315 #include <stdlib.h>
1316 #include <stdio.h>
1317 #include <stdarg.h>
1318 #include <assert.h>
1319 #include <errno.h>
1320
1321 #ifdef isdigit
1322 #undef isdigit
1323 #endif
1324 #define isdigit(c) ((c) >= '0' && (c) <= '9')
1325
1326 /* For copying strings longer or equal to 'breakeven_point'
1327  * it is more efficient to call memcpy() than to do it inline.
1328  * The value depends mostly on the processor architecture,
1329  * but also on the compiler and its optimization capabilities.
1330  * The value is not critical, some small value greater than zero
1331  * will be just fine if you don't care to squeeze every drop
1332  * of performance out of the code.
1333  *
1334  * Small values favor memcpy, large values favor inline code.
1335  */
1336 #if defined(__alpha__) || defined(__alpha)
1337 #  define breakeven_point   2    /* AXP (DEC Alpha)     - gcc or cc or egcs */
1338 #endif
1339 #if defined(__i386__)  || defined(__i386)
1340 #  define breakeven_point  12    /* Intel Pentium/Linux - gcc 2.96 */
1341 #endif
1342 #if defined(__hppa)
1343 #  define breakeven_point  10    /* HP-PA               - gcc */
1344 #endif
1345 #if defined(__sparc__) || defined(__sparc)
1346 #  define breakeven_point  33    /* Sun Sparc 5         - gcc 2.8.1 */
1347 #endif
1348
1349 /* some other values of possible interest: */
1350 /* #define breakeven_point  8 */ /* VAX 4000          - vaxc */
1351 /* #define breakeven_point 19 */ /* VAX 4000          - gcc 2.7.0 */
1352
1353 #ifndef breakeven_point
1354 #  define breakeven_point   6    /* some reasonable one-size-fits-all value */
1355 #endif
1356
1357 #define fast_memcpy(d,s,n) \
1358   { register size_t nn = (size_t)(n); \
1359     if (nn >= breakeven_point) memcpy((d), (s), nn); \
1360     else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
1361       register char *dd; register const char *ss; \
1362       for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
1363
1364 #define fast_memset(d,c,n) \
1365   { register size_t nn = (size_t)(n); \
1366     if (nn >= breakeven_point) memset((d), (int)(c), nn); \
1367     else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
1368       register char *dd; register const int cc=(int)(c); \
1369       for (dd=(d); nn>0; nn--) *dd++ = cc; } }
1370
1371 /* prototypes */
1372
1373 #if defined(NEED_ASPRINTF)
1374 int asprintf   (char **ptr, const char *fmt, /*args*/ ...);
1375 #endif
1376 #if defined(NEED_VASPRINTF)
1377 int vasprintf  (char **ptr, const char *fmt, va_list ap);
1378 #endif
1379 #if defined(NEED_ASNPRINTF)
1380 int asnprintf  (char **ptr, size_t str_m, const char *fmt, /*args*/ ...);
1381 #endif
1382 #if defined(NEED_VASNPRINTF)
1383 int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap);
1384 #endif
1385
1386 #if defined(HAVE_SNPRINTF)
1387 /* declare our portable snprintf  routine under name portable_snprintf  */
1388 /* declare our portable vsnprintf routine under name portable_vsnprintf */
1389 #else
1390 /* declare our portable routines under names snprintf and vsnprintf */
1391 #define portable_snprintf snprintf
1392 #if !defined(NEED_SNPRINTF_ONLY)
1393 #define portable_vsnprintf vsnprintf
1394 #endif
1395 #endif
1396
1397 #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
1398 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...);
1399 #if !defined(NEED_SNPRINTF_ONLY)
1400 int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
1401 #endif
1402 #endif
1403
1404 /* declarations */
1405
1406 static char credits[] = "\n\
1407 @(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
1408 @(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
1409 @(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
1410
1411 #if defined(NEED_ASPRINTF)
1412 int asprintf(char **ptr, const char *fmt, /*args*/ ...) {
1413   va_list ap;
1414   size_t str_m;
1415   int str_l;
1416
1417   *ptr = NULL;
1418   va_start(ap, fmt);                            /* measure the required size */
1419   str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
1420   va_end(ap);
1421   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1422   *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
1423   if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1424   else {
1425     int str_l2;
1426     va_start(ap, fmt);
1427     str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1428     va_end(ap);
1429     assert(str_l2 == str_l);
1430   }
1431   return str_l;
1432 }
1433 #endif
1434
1435 #if defined(NEED_VASPRINTF)
1436 int vasprintf(char **ptr, const char *fmt, va_list ap) {
1437   size_t str_m;
1438   int str_l;
1439
1440   *ptr = NULL;
1441   { va_list ap2;
1442     va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
1443     str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
1444     va_end(ap2);
1445   }
1446   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1447   *ptr = (char *) malloc(str_m = (size_t)str_l + 1);
1448   if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1449   else {
1450     int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1451     assert(str_l2 == str_l);
1452   }
1453   return str_l;
1454 }
1455 #endif
1456
1457 #if defined(NEED_ASNPRINTF)
1458 int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
1459   va_list ap;
1460   int str_l;
1461
1462   *ptr = NULL;
1463   va_start(ap, fmt);                            /* measure the required size */
1464   str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
1465   va_end(ap);
1466   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1467   if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
1468   /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
1469   if (str_m == 0) {  /* not interested in resulting string, just return size */
1470   } else {
1471     *ptr = (char *) malloc(str_m);
1472     if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1473     else {
1474       int str_l2;
1475       va_start(ap, fmt);
1476       str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1477       va_end(ap);
1478       assert(str_l2 == str_l);
1479     }
1480   }
1481   return str_l;
1482 }
1483 #endif
1484
1485 #if defined(NEED_VASNPRINTF)
1486 int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
1487   int str_l;
1488
1489   *ptr = NULL;
1490   { va_list ap2;
1491     va_copy(ap2, ap);  /* don't consume the original ap, we'll need it again */
1492     str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
1493     va_end(ap2);
1494   }
1495   assert(str_l >= 0);        /* possible integer overflow if str_m > INT_MAX */
1496   if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1;      /* truncate */
1497   /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
1498   if (str_m == 0) {  /* not interested in resulting string, just return size */
1499   } else {
1500     *ptr = (char *) malloc(str_m);
1501     if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
1502     else {
1503       int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
1504       assert(str_l2 == str_l);
1505     }
1506   }
1507   return str_l;
1508 }
1509 #endif
1510
1511 /*
1512  * If the system does have snprintf and the portable routine is not
1513  * specifically required, this module produces no code for snprintf/vsnprintf.
1514  */
1515 #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
1516
1517 #if !defined(NEED_SNPRINTF_ONLY)
1518 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
1519   va_list ap;
1520   int str_l;
1521
1522   va_start(ap, fmt);
1523   str_l = portable_vsnprintf(str, str_m, fmt, ap);
1524   va_end(ap);
1525   return str_l;
1526 }
1527 #endif
1528
1529 #if defined(NEED_SNPRINTF_ONLY)
1530 int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
1531 #else
1532 int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
1533 #endif
1534
1535 #if defined(NEED_SNPRINTF_ONLY)
1536   va_list ap;
1537 #endif
1538   size_t str_l = 0;
1539   const char *p = fmt;
1540
1541 /* In contrast with POSIX, the ISO C99 now says
1542  * that str can be NULL and str_m can be 0.
1543  * This is more useful than the old:  if (str_m < 1) return -1; */
1544
1545 #if defined(NEED_SNPRINTF_ONLY)
1546   va_start(ap, fmt);
1547 #endif
1548   if (!p) p = "";
1549   while (*p) {
1550     if (*p != '%') {
1551    /* if (str_l < str_m) str[str_l++] = *p++;    -- this would be sufficient */
1552    /* but the following code achieves better performance for cases
1553     * where format string is long and contains few conversions */
1554       const char *q = strchr(p+1,'%');
1555       size_t n = !q ? strlen(p) : (q-p);
1556       if (str_l < str_m) {
1557         size_t avail = str_m-str_l;
1558         fast_memcpy(str+str_l, p, (n>avail?avail:n));
1559       }
1560       p += n; str_l += n;
1561     } else {
1562       const char *starting_p;
1563       size_t min_field_width = 0, precision = 0;
1564       int zero_padding = 0, precision_specified = 0, justify_left = 0;
1565       int alternate_form = 0, force_sign = 0;
1566       int space_for_positive = 1; /* If both the ' ' and '+' flags appear,
1567                                      the ' ' flag should be ignored. */
1568       char length_modifier = '\0';            /* allowed values: \0, h, l, L */
1569       char tmp[32];/* temporary buffer for simple numeric->string conversion */
1570
1571       const char *str_arg;      /* string address in case of string argument */
1572       size_t str_arg_l;         /* natural field width of arg without padding
1573                                    and sign */
1574       unsigned char uchar_arg;
1575         /* unsigned char argument value - only defined for c conversion.
1576            N.B. standard explicitly states the char argument for
1577            the c conversion is unsigned */
1578
1579       size_t number_of_zeros_to_pad = 0;
1580         /* number of zeros to be inserted for numeric conversions
1581            as required by the precision or minimal field width */
1582
1583       size_t zero_padding_insertion_ind = 0;
1584         /* index into tmp where zero padding is to be inserted */
1585
1586       char fmt_spec = '\0';
1587         /* current conversion specifier character */
1588
1589       str_arg = credits;/* just to make compiler happy (defined but not used)*/
1590       str_arg = NULL;
1591       starting_p = p; p++;  /* skip '%' */
1592    /* parse flags */
1593       while (*p == '0' || *p == '-' || *p == '+' ||
1594              *p == ' ' || *p == '#' || *p == '\'') {
1595         switch (*p) {
1596         case '0': zero_padding = 1; break;
1597         case '-': justify_left = 1; break;
1598         case '+': force_sign = 1; space_for_positive = 0; break;
1599         case ' ': force_sign = 1;
1600      /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
1601 #ifdef PERL_COMPATIBLE
1602      /* ... but in Perl the last of ' ' and '+' applies */
1603                   space_for_positive = 1;
1604 #endif
1605                   break;
1606         case '#': alternate_form = 1; break;
1607         case '\'': break;
1608         }
1609         p++;
1610       }
1611    /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
1612
1613    /* parse field width */
1614       if (*p == '*') {
1615         int j;
1616         p++; j = va_arg(ap, int);
1617         if (j >= 0) min_field_width = j;
1618         else { min_field_width = -j; justify_left = 1; }
1619       } else if (isdigit((int)(*p))) {
1620         /* size_t could be wider than unsigned int;
1621            make sure we treat argument like common implementations do */
1622         unsigned int uj = *p++ - '0';
1623         while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
1624         min_field_width = uj;
1625       }
1626    /* parse precision */
1627       if (*p == '.') {
1628         p++; precision_specified = 1;
1629         if (*p == '*') {
1630           int j = va_arg(ap, int);
1631           p++;
1632           if (j >= 0) precision = j;
1633           else {
1634             precision_specified = 0; precision = 0;
1635          /* NOTE:
1636           *   Solaris 2.6 man page claims that in this case the precision
1637           *   should be set to 0.  Digital Unix 4.0, HPUX 10 and BSD man page
1638           *   claim that this case should be treated as unspecified precision,
1639           *   which is what we do here.
1640           */
1641           }
1642         } else if (isdigit((int)(*p))) {
1643           /* size_t could be wider than unsigned int;
1644              make sure we treat argument like common implementations do */
1645           unsigned int uj = *p++ - '0';
1646           while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
1647           precision = uj;
1648         }
1649       }
1650    /* parse 'h', 'l' and 'll' length modifiers */
1651       if (*p == 'h' || *p == 'l') {
1652         length_modifier = *p; p++;
1653         if (length_modifier == 'l' && *p == 'l') {   /* double l = long long */
1654 #ifdef SNPRINTF_LONGLONG_SUPPORT
1655           length_modifier = '2';                  /* double l encoded as '2' */
1656 #else
1657           length_modifier = 'l';                 /* treat it as a single 'l' */
1658 #endif
1659           p++;
1660         }
1661       }
1662       fmt_spec = *p;
1663    /* common synonyms: */
1664       switch (fmt_spec) {
1665       case 'i': fmt_spec = 'd'; break;
1666       case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
1667       case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
1668       case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
1669       default: break;
1670       }
1671    /* get parameter value, do initial processing */
1672       switch (fmt_spec) {
1673       case '%': /* % behaves similar to 's' regarding flags and field widths */
1674       case 'c': /* c behaves similar to 's' regarding flags and field widths */
1675       case 's':
1676         length_modifier = '\0';          /* wint_t and wchar_t not supported */
1677      /* the result of zero padding flag with non-numeric conversion specifier*/
1678      /* is undefined. Solaris and HPUX 10 does zero padding in this case,    */
1679      /* Digital Unix and Linux does not. */
1680 #if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
1681         zero_padding = 0;    /* turn zero padding off for string conversions */
1682 #endif
1683         str_arg_l = 1;
1684         switch (fmt_spec) {
1685         case '%':
1686           str_arg = p; break;
1687         case 'c': {
1688           int j = va_arg(ap, int);
1689           uchar_arg = (unsigned char) j;   /* standard demands unsigned char */
1690           str_arg = (const char *) &uchar_arg;
1691           break;
1692         }
1693         case 's':
1694           str_arg = va_arg(ap, const char *);
1695           if (!str_arg) str_arg_l = 0;
1696        /* make sure not to address string beyond the specified precision !!! */
1697           else if (!precision_specified) str_arg_l = strlen(str_arg);
1698        /* truncate string if necessary as requested by precision */
1699           else if (precision == 0) str_arg_l = 0;
1700           else {
1701        /* memchr on HP does not like n > 2^31  !!! */
1702             const char *q = memchr(str_arg, '\0',
1703                              precision <= 0x7fffffff ? precision : 0x7fffffff);
1704             str_arg_l = !q ? precision : (q-str_arg);
1705           }
1706           break;
1707         default: break;
1708         }
1709         break;
1710       case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
1711         /* NOTE: the u, o, x, X and p conversion specifiers imply
1712                  the value is unsigned;  d implies a signed value */
1713
1714         int arg_sign = 0;
1715           /* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
1716             +1 if greater than zero (or nonzero for unsigned arguments),
1717             -1 if negative (unsigned argument is never negative) */
1718
1719         int int_arg = 0;  unsigned int uint_arg = 0;
1720           /* only defined for length modifier h, or for no length modifiers */
1721
1722         long int long_arg = 0;  unsigned long int ulong_arg = 0;
1723           /* only defined for length modifier l */
1724
1725         void *ptr_arg = NULL;
1726           /* pointer argument value -only defined for p conversion */
1727
1728 #ifdef SNPRINTF_LONGLONG_SUPPORT
1729         long long int long_long_arg = 0;
1730         unsigned long long int ulong_long_arg = 0;
1731           /* only defined for length modifier ll */
1732 #endif
1733         if (fmt_spec == 'p') {
1734         /* HPUX 10: An l, h, ll or L before any other conversion character
1735          *   (other than d, i, u, o, x, or X) is ignored.
1736          * Digital Unix:
1737          *   not specified, but seems to behave as HPUX does.
1738          * Solaris: If an h, l, or L appears before any other conversion
1739          *   specifier (other than d, i, u, o, x, or X), the behavior
1740          *   is undefined. (Actually %hp converts only 16-bits of address
1741          *   and %llp treats address as 64-bit data which is incompatible
1742          *   with (void *) argument on a 32-bit system).
1743          */
1744 #ifdef SOLARIS_COMPATIBLE
1745 #  ifdef SOLARIS_BUG_COMPATIBLE
1746           /* keep length modifiers even if it represents 'll' */
1747 #  else
1748           if (length_modifier == '2') length_modifier = '\0';
1749 #  endif
1750 #else
1751           length_modifier = '\0';
1752 #endif
1753           ptr_arg = va_arg(ap, void *);
1754           if (ptr_arg != NULL) arg_sign = 1;
1755         } else if (fmt_spec == 'd') {  /* signed */
1756           switch (length_modifier) {
1757           case '\0':
1758           case 'h':
1759          /* It is non-portable to specify a second argument of char or short
1760           * to va_arg, because arguments seen by the called function
1761           * are not char or short.  C converts char and short arguments
1762           * to int before passing them to a function.
1763           */
1764             int_arg = va_arg(ap, int);
1765             if      (int_arg > 0) arg_sign =  1;
1766             else if (int_arg < 0) arg_sign = -1;
1767             break;
1768           case 'l':
1769             long_arg = va_arg(ap, long int);
1770             if      (long_arg > 0) arg_sign =  1;
1771             else if (long_arg < 0) arg_sign = -1;
1772             break;
1773 #ifdef SNPRINTF_LONGLONG_SUPPORT
1774           case '2':
1775             long_long_arg = va_arg(ap, long long int);
1776             if      (long_long_arg > 0) arg_sign =  1;
1777             else if (long_long_arg < 0) arg_sign = -1;
1778             break;
1779 #endif
1780           }
1781         } else {  /* unsigned */
1782           switch (length_modifier) {
1783           case '\0':
1784           case 'h':
1785             uint_arg = va_arg(ap, unsigned int);
1786             if (uint_arg) arg_sign = 1;
1787             break;
1788           case 'l':
1789             ulong_arg = va_arg(ap, unsigned long int);
1790             if (ulong_arg) arg_sign = 1;
1791             break;
1792 #ifdef SNPRINTF_LONGLONG_SUPPORT
1793           case '2':
1794             ulong_long_arg = va_arg(ap, unsigned long long int);
1795             if (ulong_long_arg) arg_sign = 1;
1796             break;
1797 #endif
1798           }
1799         }
1800         str_arg = tmp; str_arg_l = 0;
1801      /* NOTE:
1802       *   For d, i, u, o, x, and X conversions, if precision is specified,
1803       *   the '0' flag should be ignored. This is so with Solaris 2.6,
1804       *   Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
1805       */
1806 #ifndef PERL_COMPATIBLE
1807         if (precision_specified) zero_padding = 0;
1808 #endif
1809         if (fmt_spec == 'd') {
1810           if (force_sign && arg_sign >= 0)
1811             tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
1812          /* leave negative numbers for sprintf to handle,
1813             to avoid handling tricky cases like (short int)(-32768) */
1814 #ifdef LINUX_COMPATIBLE
1815         } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
1816           tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
1817 #endif
1818         } else if (alternate_form) {
1819           if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
1820             { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
1821          /* alternate form should have no effect for p conversion, but ... */
1822 #ifdef HPUX_COMPATIBLE
1823           else if (fmt_spec == 'p'
1824          /* HPUX 10: for an alternate form of p conversion,
1825           *          a nonzero result is prefixed by 0x. */
1826 #ifndef HPUX_BUG_COMPATIBLE
1827          /* Actually it uses 0x prefix even for a zero value. */
1828                    && arg_sign != 0
1829 #endif
1830                   ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
1831 #endif
1832         }
1833         zero_padding_insertion_ind = str_arg_l;
1834         if (!precision_specified) precision = 1;   /* default precision is 1 */
1835         if (precision == 0 && arg_sign == 0
1836 #if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
1837             && fmt_spec != 'p'
1838          /* HPUX 10 man page claims: With conversion character p the result of
1839           * converting a zero value with a precision of zero is a null string.
1840           * Actually HP returns all zeroes, and Linux returns "(nil)". */
1841 #endif
1842         ) {
1843          /* converted to null string */
1844          /* When zero value is formatted with an explicit precision 0,
1845             the resulting formatted string is empty (d, i, u, o, x, X, p).   */
1846         } else {
1847           char f[5]; int f_l = 0;
1848           f[f_l++] = '%';    /* construct a simple format string for sprintf */
1849           if (!length_modifier) { }
1850           else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
1851           else f[f_l++] = length_modifier;
1852           f[f_l++] = fmt_spec; f[f_l++] = '\0';
1853           if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
1854           else if (fmt_spec == 'd') {  /* signed */
1855             switch (length_modifier) {
1856             case '\0':
1857             case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg);  break;
1858             case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
1859 #ifdef SNPRINTF_LONGLONG_SUPPORT
1860             case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
1861 #endif
1862             }
1863           } else {  /* unsigned */
1864             switch (length_modifier) {
1865             case '\0':
1866             case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg);  break;
1867             case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
1868 #ifdef SNPRINTF_LONGLONG_SUPPORT
1869             case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
1870 #endif
1871             }
1872           }
1873          /* include the optional minus sign and possible "0x"
1874             in the region before the zero padding insertion point */
1875           if (zero_padding_insertion_ind < str_arg_l &&
1876               tmp[zero_padding_insertion_ind] == '-') {
1877             zero_padding_insertion_ind++;
1878           }
1879           if (zero_padding_insertion_ind+1 < str_arg_l &&
1880               tmp[zero_padding_insertion_ind]   == '0' &&
1881              (tmp[zero_padding_insertion_ind+1] == 'x' ||
1882               tmp[zero_padding_insertion_ind+1] == 'X') ) {
1883             zero_padding_insertion_ind += 2;
1884           }
1885         }
1886         { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
1887           if (alternate_form && fmt_spec == 'o'
1888 #ifdef HPUX_COMPATIBLE                                  /* ("%#.o",0) -> ""  */
1889               && (str_arg_l > 0)
1890 #endif
1891 #ifdef DIGITAL_UNIX_BUG_COMPATIBLE                      /* ("%#o",0) -> "00" */
1892 #else
1893               /* unless zero is already the first character */
1894               && !(zero_padding_insertion_ind < str_arg_l
1895                    && tmp[zero_padding_insertion_ind] == '0')
1896 #endif
1897           ) {        /* assure leading zero for alternate-form octal numbers */
1898             if (!precision_specified || precision < num_of_digits+1) {
1899              /* precision is increased to force the first character to be zero,
1900                 except if a zero value is formatted with an explicit precision
1901                 of zero */
1902               precision = num_of_digits+1; precision_specified = 1;
1903             }
1904           }
1905        /* zero padding to specified precision? */
1906           if (num_of_digits < precision) 
1907             number_of_zeros_to_pad = precision - num_of_digits;
1908         }
1909      /* zero padding to specified minimal field width? */
1910         if (!justify_left && zero_padding) {
1911           int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1912           if (n > 0) number_of_zeros_to_pad += n;
1913         }
1914         break;
1915       }
1916       default: /* unrecognized conversion specifier, keep format string as-is*/
1917         zero_padding = 0;  /* turn zero padding off for non-numeric convers. */
1918 #ifndef DIGITAL_UNIX_COMPATIBLE
1919         justify_left = 1; min_field_width = 0;                /* reset flags */
1920 #endif
1921 #if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
1922      /* keep the entire format string unchanged */
1923         str_arg = starting_p; str_arg_l = p - starting_p;
1924      /* well, not exactly so for Linux, which does something inbetween,
1925       * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y"  */
1926 #else
1927      /* discard the unrecognized conversion, just keep *
1928       * the unrecognized conversion character          */
1929         str_arg = p; str_arg_l = 0;
1930 #endif
1931         if (*p) str_arg_l++;  /* include invalid conversion specifier unchanged
1932                                  if not at end-of-string */
1933         break;
1934       }
1935       if (*p) p++;      /* step over the just processed conversion specifier */
1936    /* insert padding to the left as requested by min_field_width;
1937       this does not include the zero padding in case of numerical conversions*/
1938       if (!justify_left) {                /* left padding with blank or zero */
1939         int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1940         if (n > 0) {
1941           if (str_l < str_m) {
1942             size_t avail = str_m-str_l;
1943             fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
1944           }
1945           str_l += n;
1946         }
1947       }
1948    /* zero padding as requested by the precision or by the minimal field width
1949     * for numeric conversions required? */
1950       if (number_of_zeros_to_pad <= 0) {
1951      /* will not copy first part of numeric right now, *
1952       * force it to be copied later in its entirety    */
1953         zero_padding_insertion_ind = 0;
1954       } else {
1955      /* insert first part of numerics (sign or '0x') before zero padding */
1956         int n = zero_padding_insertion_ind;
1957         if (n > 0) {
1958           if (str_l < str_m) {
1959             size_t avail = str_m-str_l;
1960             fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
1961           }
1962           str_l += n;
1963         }
1964      /* insert zero padding as requested by the precision or min field width */
1965         n = number_of_zeros_to_pad;
1966         if (n > 0) {
1967           if (str_l < str_m) {
1968             size_t avail = str_m-str_l;
1969             fast_memset(str+str_l, '0', (n>avail?avail:n));
1970           }
1971           str_l += n;
1972         }
1973       }
1974    /* insert formatted string
1975     * (or as-is conversion specifier for unknown conversions) */
1976       { int n = str_arg_l - zero_padding_insertion_ind;
1977         if (n > 0) {
1978           if (str_l < str_m) {
1979             size_t avail = str_m-str_l;
1980             fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
1981                         (n>avail?avail:n));
1982           }
1983           str_l += n;
1984         }
1985       }
1986    /* insert right padding */
1987       if (justify_left) {          /* right blank padding to the field width */
1988         int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
1989         if (n > 0) {
1990           if (str_l < str_m) {
1991             size_t avail = str_m-str_l;
1992             fast_memset(str+str_l, ' ', (n>avail?avail:n));
1993           }
1994           str_l += n;
1995         }
1996       }
1997     }
1998   }
1999 #if defined(NEED_SNPRINTF_ONLY)
2000   va_end(ap);
2001 #endif
2002   if (str_m > 0) { /* make sure the string is null-terminated
2003                       even at the expense of overwriting the last character
2004                       (shouldn't happen, but just in case) */
2005     str[str_l <= str_m-1 ? str_l : str_m-1] = '\0';
2006   }
2007   /* Return the number of characters formatted (excluding trailing null
2008    * character), that is, the number of characters that would have been
2009    * written to the buffer if it were large enough.
2010    *
2011    * The value of str_l should be returned, but str_l is of unsigned type
2012    * size_t, and snprintf is int, possibly leading to an undetected
2013    * integer overflow, resulting in a negative return value, which is illegal.
2014    * Both XSH5 and ISO C99 (at least the draft) are silent on this issue.
2015    * Should errno be set to EOVERFLOW and EOF returned in this case???
2016    */
2017   return (int) str_l;
2018 }
2019 #endif
2020 #endif /* ndef HAVE_SNPRINTF */
2021 /*
2022   Local Variables:
2023   tab-width: 3
2024   end:
2025 */