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