Removed some set but unused variables.
[gnupg.git] / jnlib / stringhelp.c
1 /* stringhelp.c -  standard string helper functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
3  *               2006, 2007, 2008, 2009  Free Software Foundation, Inc.
4  *
5  * This file is part of JNLIB.
6  *
7  * JNLIB is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * JNLIB is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #ifdef HAVE_PWD_H
28 # include <pwd.h>
29 #endif
30 #include <unistd.h>
31 #include <sys/types.h>
32 #ifdef HAVE_W32_SYSTEM
33 # include <windows.h>
34 #endif
35
36 #include "libjnlib-config.h"
37 #include "utf8conv.h"
38 #include "stringhelp.h"
39
40
41 #define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
42
43 /* Sometimes we want to avoid mixing slashes and backslashes on W32
44    and prefer backslashes.  There is usual no problem with mixing
45    them, however a very few W32 API calls can't grok plain slashes.
46    Printing filenames with mixed slashes also looks a bit strange.
47    This function has no effext on POSIX. */
48 static inline char *
49 change_slashes (char *name)
50 {
51 #ifdef HAVE_DRIVE_LETTERS
52   char *p;
53
54   if (strchr (name, '\\'))
55     {
56       for (p=name; *p; p++)
57         if (*p == '/')
58           *p = '\\';
59     }
60 #endif /*HAVE_DRIVE_LETTERS*/
61   return name;
62 }
63
64
65 /*
66  * Look for the substring SUB in buffer and return a pointer to that
67  * substring in BUFFER or NULL if not found.
68  * Comparison is case-insensitive.
69  */
70 const char *
71 memistr (const void *buffer, size_t buflen, const char *sub)
72 {
73   const unsigned char *buf = buffer;
74   const unsigned char *t = (const unsigned char *)buffer;
75   const unsigned char *s = (const unsigned char *)sub;
76   size_t n = buflen;
77
78   for ( ; n ; t++, n-- )
79     {
80       if ( toupper (*t) == toupper (*s) )
81         {
82           for ( buf=t++, buflen = n--, s++;
83                 n && toupper (*t) == toupper (*s); t++, s++, n-- )
84             ;
85           if (!*s)
86             return (const char*)buf;
87           t = buf;
88           s = (const unsigned char *)sub ;
89           n = buflen;
90         }
91     }
92   return NULL;
93 }
94
95 const char *
96 ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
97 {
98   const unsigned char *buf = buffer;
99   const unsigned char *t = (const unsigned char *)buf;
100   const unsigned char *s = (const unsigned char *)sub;
101   size_t n = buflen;
102
103   for ( ; n ; t++, n-- )
104     {
105       if (ascii_toupper (*t) == ascii_toupper (*s) )
106         {
107           for ( buf=t++, buflen = n--, s++;
108                 n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
109             ;
110           if (!*s)
111             return (const char*)buf;
112           t = (const unsigned char *)buf;
113           s = (const unsigned char *)sub ;
114           n = buflen;
115         }
116     }
117   return NULL;
118 }
119
120 /* This function is similar to strncpy().  However it won't copy more
121    than N - 1 characters and makes sure that a '\0' is appended. With
122    N given as 0, nothing will happen.  With DEST given as NULL, memory
123    will be allocated using jnlib_xmalloc (i.e. if it runs out of core
124    the function terminates).  Returns DES or a pointer to the
125    allocated memory.
126  */
127 char *
128 mem2str( char *dest , const void *src , size_t n )
129 {
130     char *d;
131     const char *s;
132
133     if( n ) {
134         if( !dest )
135             dest = jnlib_xmalloc( n ) ;
136         d = dest;
137         s = src ;
138         for(n--; n && *s; n-- )
139             *d++ = *s++;
140         *d = '\0' ;
141     }
142
143     return dest ;
144 }
145
146
147 /****************
148  * remove leading and trailing white spaces
149  */
150 char *
151 trim_spaces( char *str )
152 {
153     char *string, *p, *mark;
154
155     string = str;
156     /* find first non space character */
157     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
158         ;
159     /* move characters */
160     for( (mark = NULL); (*string = *p); string++, p++ )
161         if( isspace( *(byte*)p ) ) {
162             if( !mark )
163                 mark = string ;
164         }
165         else
166             mark = NULL ;
167     if( mark )
168         *mark = '\0' ;  /* remove trailing spaces */
169
170     return str ;
171 }
172
173 /****************
174  * remove trailing white spaces
175  */
176 char *
177 trim_trailing_spaces( char *string )
178 {
179     char *p, *mark;
180
181     for( mark = NULL, p = string; *p; p++ ) {
182         if( isspace( *(byte*)p ) ) {
183             if( !mark )
184                 mark = p;
185         }
186         else
187             mark = NULL;
188     }
189     if( mark )
190         *mark = '\0' ;
191
192     return string ;
193 }
194
195
196 unsigned
197 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
198 {
199     byte *p, *mark;
200     unsigned n;
201
202     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
203         if( strchr(trimchars, *p ) ) {
204             if( !mark )
205                 mark = p;
206         }
207         else
208             mark = NULL;
209     }
210
211     if( mark ) {
212         *mark = 0;
213         return mark - line;
214     }
215     return len;
216 }
217
218 /****************
219  * remove trailing white spaces and return the length of the buffer
220  */
221 unsigned
222 trim_trailing_ws( byte *line, unsigned len )
223 {
224     return trim_trailing_chars( line, len, " \t\r\n" );
225 }
226
227 size_t
228 length_sans_trailing_chars (const unsigned char *line, size_t len,
229                             const char *trimchars )
230 {
231   const unsigned char *p, *mark;
232   size_t n;
233   
234   for( mark=NULL, p=line, n=0; n < len; n++, p++ )
235     {
236       if (strchr (trimchars, *p ))
237         {
238           if( !mark )
239             mark = p;
240         }
241       else
242         mark = NULL;
243     }
244   
245   if (mark) 
246     return mark - line;
247   return len;
248 }
249
250 /*
251  *  Return the length of line ignoring trailing white-space.
252  */
253 size_t
254 length_sans_trailing_ws (const unsigned char *line, size_t len)
255 {
256   return length_sans_trailing_chars (line, len, " \t\r\n");
257 }
258
259
260
261 /*
262  * Extract from a given path the filename component.  This function
263  * terminates the process on memory shortage.
264  */
265 char *
266 make_basename(const char *filepath, const char *inputpath)
267 {
268 #ifdef __riscos__
269     return riscos_make_basename(filepath, inputpath);
270 #else
271     char *p;
272
273     (void)inputpath; /* Only required for riscos.  */
274
275     if ( !(p=strrchr(filepath, '/')) )
276 #ifdef HAVE_DRIVE_LETTERS
277         if ( !(p=strrchr(filepath, '\\')) )
278             if ( !(p=strrchr(filepath, ':')) )
279 #endif
280               {
281                 return jnlib_xstrdup(filepath);
282               }
283
284     return jnlib_xstrdup(p+1);
285 #endif
286 }
287
288
289
290 /*
291  * Extract from a given filename the path prepended to it.  If there
292  * isn't a path prepended to the filename, a dot is returned ('.').
293  * This function terminates the process on memory shortage.
294  */
295 char *
296 make_dirname(const char *filepath)
297 {
298     char *dirname;
299     int  dirname_length;
300     char *p;
301
302     if ( !(p=strrchr(filepath, '/')) )
303 #ifdef HAVE_DRIVE_LETTERS
304         if ( !(p=strrchr(filepath, '\\')) )
305             if ( !(p=strrchr(filepath, ':')) )
306 #endif
307               {
308                 return jnlib_xstrdup(".");
309               }
310
311     dirname_length = p-filepath;
312     dirname = jnlib_xmalloc(dirname_length+1);
313     strncpy(dirname, filepath, dirname_length);
314     dirname[dirname_length] = 0;
315
316     return dirname;
317 }
318
319
320 \f
321 static char *
322 get_pwdir (int xmode, const char *name)
323 {
324   char *result = NULL;
325 #ifdef HAVE_PWD_H
326   struct passwd *pwd = NULL;
327
328   if (name)
329     {
330 #ifdef HAVE_GETPWNAM
331       /* Fixme: We should use getpwnam_r if available.  */
332       pwd = getpwnam (name);
333 #endif
334     }
335   else
336     {
337 #ifdef HAVE_GETPWUID
338       /* Fixme: We should use getpwuid_r if available.  */
339       pwd = getpwuid (getuid());
340 #endif
341     }
342   if (pwd)
343     {
344       if (xmode)
345         result = jnlib_xstrdup (pwd->pw_dir);
346       else
347         result = jnlib_strdup (pwd->pw_dir);
348     }
349 #endif /*HAVE_PWD_H*/
350   return result;
351 }
352
353 static char *
354 do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
355 {
356   const char *argv[32];
357   int argc;
358   size_t n; 
359   int skip = 1;
360   char *home_buffer = NULL;
361   char *name, *home, *p;                           
362        
363   n = strlen (first_part) + 1;                     
364   argc = 0;
365   while ( (argv[argc] = va_arg (arg_ptr, const char *)) )   
366     {
367       n += strlen (argv[argc]) + 1;                        
368       if (argc >= DIM (argv)-1)
369         {
370           if (xmode)
371             BUG ();
372           errno = EINVAL;
373           return NULL;
374         }
375       argc++; 
376     }
377   n++;
378   
379   home = NULL;                                     
380   if (*first_part == '~')
381     {
382       if (first_part[1] == '/' || !first_part[1])
383         {
384           /* This is the "~/" or "~" case.  */
385           home = getenv("HOME");
386           if (!home)
387             home = home_buffer = get_pwdir (xmode, NULL);
388           if (home && *home)
389             n += strlen (home);                            
390         }
391       else
392         {
393           /* This is the "~username/" or "~username" case.  */
394           char *user;
395     
396           if (xmode)
397             user = jnlib_xstrdup (first_part+1);
398           else
399             {
400               user = jnlib_strdup (first_part+1);
401               if (!user)
402                 return NULL;
403             }
404           p = strchr (user, '/');
405           if (p)
406             *p = 0;
407           skip = 1 + strlen (user);
408           
409           home = home_buffer = get_pwdir (xmode, user);
410           jnlib_free (user);
411           if (home)
412             n += strlen (home);
413           else
414             skip = 1;
415         }
416     }
417
418   if (xmode)
419     name = jnlib_xmalloc (n);
420   else
421     {
422       name = jnlib_malloc (n);
423       if (!name)
424         {
425           jnlib_free (home_buffer);
426           return NULL;
427         }
428     }
429   
430   if (home)
431     p = stpcpy (stpcpy (name, home), first_part + skip);
432   else
433     p = stpcpy (name, first_part);
434
435   jnlib_free (home_buffer);
436
437   for (argc=0; argv[argc]; argc++)
438     p = stpcpy (stpcpy (p, "/"), argv[argc]);
439
440   return change_slashes (name);
441 }
442
443 /* Construct a filename from the NULL terminated list of parts.  Tilde
444    expansion is done for the first argument.  This function terminates
445    the process on memory shortage. */
446 char *
447 make_filename (const char *first_part, ... )
448 {
449   va_list arg_ptr;
450   char *result;
451
452   va_start (arg_ptr, first_part);
453   result = do_make_filename (1, first_part, arg_ptr);
454   va_end (arg_ptr);
455   return result;
456 }
457
458 /* Construct a filename from the NULL terminated list of parts.  Tilde
459    expansion is done for the first argument.  This function may return
460    NULL on error. */
461 char *
462 make_filename_try (const char *first_part, ... )
463 {
464   va_list arg_ptr;
465   char *result;
466
467   va_start (arg_ptr, first_part);
468   result = do_make_filename (0, first_part, arg_ptr);
469   va_end (arg_ptr);
470   return result;
471 }
472
473
474 \f
475 /* Compare whether the filenames are identical.  This is a
476    special version of strcmp() taking the semantics of filenames in
477    account.  Note that this function works only on the supplied names
478    without considereing any context like the current directory.  See
479    also same_file_p(). */
480 int
481 compare_filenames (const char *a, const char *b)
482 {
483 #ifdef HAVE_DRIVE_LETTERS
484   for ( ; *a && *b; a++, b++ ) 
485     {
486       if (*a != *b 
487           && (toupper (*(const unsigned char*)a)
488               != toupper (*(const unsigned char*)b) )
489           && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
490         break;
491     }
492   if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
493     return 0;
494   else
495     return (toupper (*(const unsigned char*)a) 
496             - toupper (*(const unsigned char*)b));
497 #else
498     return strcmp(a,b);
499 #endif
500 }
501
502
503 /* Convert 2 hex characters at S to a byte value.  Return this value
504    or -1 if there is an error. */
505 int
506 hextobyte (const char *s)
507 {
508   int c;
509
510   if ( *s >= '0' && *s <= '9' )
511     c = 16 * (*s - '0');
512   else if ( *s >= 'A' && *s <= 'F' )
513     c = 16 * (10 + *s - 'A');
514   else if ( *s >= 'a' && *s <= 'f' )
515     c = 16 * (10 + *s - 'a');
516   else
517     return -1;
518   s++;
519   if ( *s >= '0' && *s <= '9' )
520     c += *s - '0';
521   else if ( *s >= 'A' && *s <= 'F' )
522     c += 10 + *s - 'A';
523   else if ( *s >= 'a' && *s <= 'f' )
524     c += 10 + *s - 'a';
525   else
526     return -1;
527   return c;
528 }
529
530
531 /* Print a BUFFER to stream FP while replacing all control characters
532    and the characters DELIM and DELIM2 with standard C escape
533    sequences.  Returns the number of characters printed. */
534 size_t 
535 print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
536                          int delim, int delim2)
537 {
538   const unsigned char *p = buffer;
539   size_t count = 0;
540
541   for (; length; length--, p++, count++)
542     {
543       if (*p < 0x20 
544           || *p == 0x7f
545           || *p == delim 
546           || *p == delim2
547           || ((delim || delim2) && *p=='\\'))
548         {
549           putc ('\\', fp);
550           count++;
551           if (*p == '\n')
552             {
553               putc ('n', fp);
554               count++;
555             }
556           else if (*p == '\r')
557             {
558               putc ('r', fp);
559               count++;
560             }
561           else if (*p == '\f')
562             {
563               putc ('f', fp);
564               count++;
565             }
566           else if (*p == '\v')
567             {
568               putc ('v', fp);
569               count++;
570             }
571           else if (*p == '\b')
572             {
573               putc ('b', fp);
574               count++;
575             }
576           else if (!*p)
577             {
578               putc('0', fp);
579               count++;
580             }
581           else
582             {
583               fprintf (fp, "x%02x", *p);
584               count += 3;
585             }
586         }
587       else
588         {
589           putc (*p, fp);
590           count++;
591         }
592     }
593
594   return count;
595 }
596
597 /* Same as print_sanitized_buffer2 but with just one delimiter. */
598 size_t 
599 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
600                         int delim)
601 {
602   return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
603 }
604
605
606 size_t 
607 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
608                              size_t length, int delim)
609 {
610   const char *p = buffer;
611   size_t i;
612
613   /* We can handle plain ascii simpler, so check for it first. */
614   for (i=0; i < length; i++ ) 
615     {
616       if ( (p[i] & 0x80) )
617         break;
618     }
619   if (i < length)
620     {
621         char *buf = utf8_to_native (p, length, delim);
622         /*(utf8 conversion already does the control character quoting)*/
623         i = strlen (buf);
624         fputs (buf, fp);
625         jnlib_free (buf);
626         return i;
627     }
628   else
629     return print_sanitized_buffer (fp, p, length, delim);
630 }
631
632
633 size_t 
634 print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
635 {
636   return string? print_sanitized_buffer2 (fp, string, strlen (string),
637                                           delim, delim2):0;
638 }
639
640 size_t 
641 print_sanitized_string (FILE *fp, const char *string, int delim)
642 {
643   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
644 }
645
646 size_t 
647 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
648 {
649   return string? print_sanitized_utf8_buffer (fp,
650                                               string, strlen (string),
651                                               delim) : 0;
652 }
653
654 /* Create a string from the buffer P_ARG of length N which is suitable
655    for printing.  Caller must release the created string using xfree.
656    This function terminates the process on memory shortage.  */
657 char *
658 sanitize_buffer (const void *p_arg, size_t n, int delim)
659 {
660   const unsigned char *p = p_arg;
661   size_t save_n, buflen;
662   const unsigned char *save_p;
663   char *buffer, *d;
664
665   /* First count length. */
666   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
667     {
668       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
669         {
670           if ( *p=='\n' || *p=='\r' || *p=='\f'
671                || *p=='\v' || *p=='\b' || !*p )
672             buflen += 2;
673           else
674             buflen += 5;
675         }
676       else
677         buflen++;
678     }
679   p = save_p;
680   n = save_n;
681   /* And now make the string */
682   d = buffer = jnlib_xmalloc( buflen );
683   for ( ; n; n--, p++ )
684     {
685       if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
686         *d++ = '\\';
687         if( *p == '\n' )
688           *d++ = 'n';
689         else if( *p == '\r' )
690           *d++ = 'r';
691         else if( *p == '\f' )
692           *d++ = 'f';
693         else if( *p == '\v' )
694           *d++ = 'v';
695         else if( *p == '\b' )
696           *d++ = 'b';
697         else if( !*p )
698           *d++ = '0';
699         else {
700           sprintf(d, "x%02x", *p );
701           d += 3;
702         }
703       }
704       else
705         *d++ = *p;
706     }
707   *d = 0;
708   return buffer;
709 }
710
711
712 /* Given a string containing an UTF-8 encoded text, return the number
713    of characters in this string.  It differs from strlen in that it
714    only counts complete UTF-8 characters.  Note, that this function
715    does not take combined characters into account.  */
716 size_t
717 utf8_charcount (const char *s)
718 {
719   size_t n;
720
721   for (n=0; *s; s++)
722     if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
723       n++;
724
725   return n;
726 }
727
728
729 /****************************************************
730  **********  W32 specific functions  ****************
731  ****************************************************/
732
733 #ifdef HAVE_W32_SYSTEM
734 const char *
735 w32_strerror (int ec)
736 {
737   static char strerr[256];
738   
739   if (ec == -1)
740     ec = (int)GetLastError ();
741   FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
742                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
743                  strerr, DIM (strerr)-1, NULL);
744   return strerr;    
745 }
746 #endif /*HAVE_W32_SYSTEM*/
747
748
749 /****************************************************
750  ******** Locale insensitive ctype functions ********
751  ****************************************************/
752 /* FIXME: replace them by a table lookup and macros */
753 int
754 ascii_isupper (int c)
755 {
756     return c >= 'A' && c <= 'Z';
757 }
758
759 int
760 ascii_islower (int c)
761 {
762     return c >= 'a' && c <= 'z';
763 }
764
765 int 
766 ascii_toupper (int c)
767 {
768     if (c >= 'a' && c <= 'z')
769         c &= ~0x20;
770     return c;
771 }
772
773 int 
774 ascii_tolower (int c)
775 {
776     if (c >= 'A' && c <= 'Z')
777         c |= 0x20;
778     return c;
779 }
780
781
782 int
783 ascii_strcasecmp( const char *a, const char *b )
784 {
785     if (a == b)
786         return 0;
787
788     for (; *a && *b; a++, b++) {
789         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
790             break;
791     }
792     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
793 }
794
795 int 
796 ascii_strncasecmp (const char *a, const char *b, size_t n)
797 {
798   const unsigned char *p1 = (const unsigned char *)a;
799   const unsigned char *p2 = (const unsigned char *)b;
800   unsigned char c1, c2;
801
802   if (p1 == p2 || !n )
803     return 0;
804
805   do
806     {
807       c1 = ascii_tolower (*p1);
808       c2 = ascii_tolower (*p2);
809
810       if ( !--n || c1 == '\0')
811         break;
812
813       ++p1;
814       ++p2;
815     }
816   while (c1 == c2);
817   
818   return c1 - c2;
819 }
820
821
822 int
823 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
824 {
825   const char *a = a_arg;
826   const char *b = b_arg;
827
828   if (a == b)
829     return 0;
830   for ( ; n; n--, a++, b++ )
831     {
832       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
833         return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
834     }
835   return 0;
836 }
837
838 int
839 ascii_strcmp( const char *a, const char *b )
840 {
841     if (a == b)
842         return 0;
843
844     for (; *a && *b; a++, b++) {
845         if (*a != *b )
846             break;
847     }
848     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
849 }
850
851
852 void *
853 ascii_memcasemem (const void *haystack, size_t nhaystack,
854                   const void *needle, size_t nneedle)
855 {
856
857   if (!nneedle)
858     return (void*)haystack; /* finding an empty needle is really easy */
859   if (nneedle <= nhaystack)
860     {
861       const char *a = haystack;
862       const char *b = a + nhaystack - nneedle;
863       
864       for (; a <= b; a++)
865         {
866           if ( !ascii_memcasecmp (a, needle, nneedle) )
867             return (void *)a;
868         }
869     }
870   return NULL;
871 }
872
873 /*********************************************
874  ********** missing string functions *********
875  *********************************************/
876
877 #ifndef HAVE_STPCPY
878 char *
879 stpcpy(char *a,const char *b)
880 {
881     while( *b )
882         *a++ = *b++;
883     *a = 0;
884
885     return (char*)a;
886 }
887 #endif
888
889 #ifndef HAVE_STRSEP
890 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
891 char *
892 strsep (char **stringp, const char *delim)
893 {
894   char *begin, *end;
895
896   begin = *stringp;
897   if (begin == NULL)
898     return NULL;
899
900   /* A frequent case is when the delimiter string contains only one
901      character.  Here we don't need to call the expensive `strpbrk'
902      function and instead work using `strchr'.  */
903   if (delim[0] == '\0' || delim[1] == '\0')
904     {
905       char ch = delim[0];
906
907       if (ch == '\0')
908         end = NULL;
909       else
910         {
911           if (*begin == ch)
912             end = begin;
913           else if (*begin == '\0')
914             end = NULL;
915           else
916             end = strchr (begin + 1, ch);
917         }
918     }
919   else
920     /* Find the end of the token.  */
921     end = strpbrk (begin, delim);
922
923   if (end)
924     {
925       /* Terminate the token and set *STRINGP past NUL character.  */
926       *end++ = '\0';
927       *stringp = end;
928     }
929   else
930     /* No more delimiters; this is the last token.  */
931     *stringp = NULL;
932
933   return begin;
934 }
935 #endif /*HAVE_STRSEP*/
936
937
938 #ifndef HAVE_STRLWR
939 char *
940 strlwr(char *s)
941 {
942     char *p;
943     for(p=s; *p; p++ )
944         *p = tolower(*p);
945     return s;
946 }
947 #endif
948
949
950 #ifndef HAVE_STRCASECMP
951 int
952 strcasecmp( const char *a, const char *b )
953 {
954     for( ; *a && *b; a++, b++ ) {
955         if( *a != *b && toupper(*a) != toupper(*b) )
956             break;
957     }
958     return *(const byte*)a - *(const byte*)b;
959 }
960 #endif
961
962
963 /****************
964  * mingw32/cpd has a memicmp()
965  */
966 #ifndef HAVE_MEMICMP
967 int
968 memicmp( const char *a, const char *b, size_t n )
969 {
970     for( ; n; n--, a++, b++ )
971         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
972             return *(const byte *)a - *(const byte*)b;
973     return 0;
974 }
975 #endif
976
977
978 #ifndef HAVE_MEMRCHR
979 void *
980 memrchr (const void *buffer, int c, size_t n)
981 {
982   const unsigned char *p = buffer;
983
984   for (p += n; n ; n--)
985     if (*--p == c)
986       return (void *)p;
987   return NULL;
988 }
989 #endif /*HAVE_MEMRCHR*/
990
991 \f
992 /* Percent-escape the string STR by replacing colons with '%3a'.  If
993    EXTRA is not NULL all characters in EXTRA are also escaped.  */
994 static char *
995 do_percent_escape (const char *str, const char *extra, int die)
996 {
997   int i, j;
998   char *ptr;
999
1000   if (!str)
1001     return NULL;
1002
1003   for (i=j=0; str[i]; i++)
1004     if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
1005       j++;
1006   if (die)
1007     ptr = jnlib_xmalloc (i + 2 * j + 1);
1008   else
1009     {
1010       ptr = jnlib_malloc (i + 2 * j + 1);
1011       if (!ptr)
1012         return NULL;
1013     }
1014   i = 0;
1015   while (*str)
1016     {
1017       if (*str == ':')
1018         {
1019           ptr[i++] = '%';
1020           ptr[i++] = '3';
1021           ptr[i++] = 'a';
1022         }
1023       else if (*str == '%')
1024         {
1025           ptr[i++] = '%';
1026           ptr[i++] = '2';
1027           ptr[i++] = '5';
1028         }
1029       else if (extra && strchr (extra, *str))
1030         {
1031           ptr[i++] = '%';
1032           ptr[i++] = tohex_lower ((*str>>4)&15);
1033           ptr[i++] = tohex_lower (*str&15);
1034         }
1035       else
1036         ptr[i++] = *str;
1037       str++;
1038     }
1039   ptr[i] = '\0';
1040
1041   return ptr;
1042 }
1043
1044 /* Percent-escape the string STR by replacing colons with '%3a'.  If
1045    EXTRA is not NULL all characters in EXTRA are also escaped.  This
1046    function terminates the process on memory shortage.  */
1047 char *
1048 percent_escape (const char *str, const char *extra)
1049 {
1050   return do_percent_escape (str, extra, 1);
1051 }
1052
1053 /* Same as percent_escape but return NULL instead of exiting on memory
1054    error. */
1055 char *
1056 try_percent_escape (const char *str, const char *extra)
1057 {
1058   return do_percent_escape (str, extra, 0);
1059 }
1060
1061
1062
1063 static char *
1064 do_strconcat (const char *s1, va_list arg_ptr)
1065 {
1066   const char *argv[48];
1067   size_t argc;
1068   size_t needed;
1069   char *buffer, *p;
1070
1071   argc = 0;
1072   argv[argc++] = s1;
1073   needed = strlen (s1);
1074   while (((argv[argc] = va_arg (arg_ptr, const char *))))
1075     {
1076       needed += strlen (argv[argc]);
1077       if (argc >= DIM (argv)-1)
1078         {
1079           errno = EINVAL;
1080           return NULL;
1081         }
1082       argc++;
1083     }
1084   needed++;
1085   buffer = jnlib_malloc (needed);
1086   if (buffer)
1087     {
1088       for (p = buffer, argc=0; argv[argc]; argc++)
1089         p = stpcpy (p, argv[argc]);
1090     }
1091   return buffer;
1092 }
1093
1094
1095 /* Concatenate the string S1 with all the following strings up to a
1096    NULL.  Returns a malloced buffer with the new string or NULL on a
1097    malloc error or if too many arguments are given.  */
1098 char *
1099 strconcat (const char *s1, ...)
1100 {
1101   va_list arg_ptr;
1102   char *result;
1103
1104   if (!s1)
1105     result = jnlib_strdup ("");
1106   else
1107     {
1108       va_start (arg_ptr, s1);
1109       result = do_strconcat (s1, arg_ptr);
1110       va_end (arg_ptr);
1111     }
1112   return result;
1113 }
1114
1115 /* Same as strconcat but terminate the process with an error message
1116    if something goes wrong.  */
1117 char *
1118 xstrconcat (const char *s1, ...)
1119 {
1120   va_list arg_ptr;
1121   char *result;
1122
1123   if (!s1)
1124     result = jnlib_xstrdup ("");
1125   else
1126     {
1127       va_start (arg_ptr, s1);
1128       result = do_strconcat (s1, arg_ptr);
1129       va_end (arg_ptr);
1130     }
1131   if (!result)
1132     {
1133       if (errno == EINVAL)
1134         fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1135       else
1136         fputs ("\nfatal: out of memory\n", stderr);
1137       exit (2);
1138     }
1139   return result;
1140 }
1141