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