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