Re-implemented GPG's --passwd command and improved it.
[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.
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_DOSISH_SYSTEM
52   char *p;
53
54   if (strchr (name, '\\'))
55     {
56       for (p=name; *p; p++)
57         if (*p == '/')
58           *p = '\\';
59     }
60 #endif /*HAVE_DOSISH_SYSTEM*/
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_DOSISH_SYSTEM
277         if ( !(p=strrchr(filepath, '\\')) )
278 #endif
279 #ifdef HAVE_DRIVE_LETTERS
280             if ( !(p=strrchr(filepath, ':')) )
281 #endif
282               {
283                 return jnlib_xstrdup(filepath);
284               }
285
286     return jnlib_xstrdup(p+1);
287 #endif
288 }
289
290
291
292 /*
293  * Extract from a given filename the path prepended to it.  If there
294  * isn't a path prepended to the filename, a dot is returned ('.').
295  * This function terminates the process on memory shortage.
296  */
297 char *
298 make_dirname(const char *filepath)
299 {
300     char *dirname;
301     int  dirname_length;
302     char *p;
303
304     if ( !(p=strrchr(filepath, '/')) )
305 #ifdef HAVE_DOSISH_SYSTEM
306         if ( !(p=strrchr(filepath, '\\')) )
307 #endif
308 #ifdef HAVE_DRIVE_LETTERS
309             if ( !(p=strrchr(filepath, ':')) )
310 #endif
311               {
312                 return jnlib_xstrdup(".");
313               }
314
315     dirname_length = p-filepath;
316     dirname = jnlib_xmalloc(dirname_length+1);
317     strncpy(dirname, filepath, dirname_length);
318     dirname[dirname_length] = 0;
319
320     return dirname;
321 }
322
323
324 \f
325 static char *
326 get_pwdir (int xmode, const char *name)
327 {
328   char *result = NULL;
329 #ifdef HAVE_PWD_H
330   struct passwd *pwd = NULL;
331
332   if (name)
333     {
334 #ifdef HAVE_GETPWNAM
335       /* Fixme: We should use getpwnam_r if available.  */
336       pwd = getpwnam (name);
337 #endif
338     }
339   else
340     {
341 #ifdef HAVE_GETPWUID
342       /* Fixme: We should use getpwuid_r if available.  */
343       pwd = getpwuid (getuid());
344 #endif
345     }
346   if (pwd)
347     {
348       if (xmode)
349         result = jnlib_xstrdup (pwd->pw_dir);
350       else
351         result = jnlib_strdup (pwd->pw_dir);
352     }
353 #else /*!HAVE_PWD_H*/
354   /* No support at all.  */
355   (void)xmode;
356   (void)name;
357 #endif /*HAVE_PWD_H*/
358   return result;
359 }
360
361 static char *
362 do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
363 {
364   const char *argv[32];
365   int argc;
366   size_t n; 
367   int skip = 1;
368   char *home_buffer = NULL;
369   char *name, *home, *p;                           
370        
371   n = strlen (first_part) + 1;                     
372   argc = 0;
373   while ( (argv[argc] = va_arg (arg_ptr, const char *)) )   
374     {
375       n += strlen (argv[argc]) + 1;                        
376       if (argc >= DIM (argv)-1)
377         {
378           if (xmode)
379             BUG ();
380           jnlib_set_errno (EINVAL);
381           return NULL;
382         }
383       argc++; 
384     }
385   n++;
386   
387   home = NULL;                                     
388   if (*first_part == '~')
389     {
390       if (first_part[1] == '/' || !first_part[1])
391         {
392           /* This is the "~/" or "~" case.  */
393           home = getenv("HOME");
394           if (!home)
395             home = home_buffer = get_pwdir (xmode, NULL);
396           if (home && *home)
397             n += strlen (home);                            
398         }
399       else
400         {
401           /* This is the "~username/" or "~username" case.  */
402           char *user;
403     
404           if (xmode)
405             user = jnlib_xstrdup (first_part+1);
406           else
407             {
408               user = jnlib_strdup (first_part+1);
409               if (!user)
410                 return NULL;
411             }
412           p = strchr (user, '/');
413           if (p)
414             *p = 0;
415           skip = 1 + strlen (user);
416           
417           home = home_buffer = get_pwdir (xmode, user);
418           jnlib_free (user);
419           if (home)
420             n += strlen (home);
421           else
422             skip = 1;
423         }
424     }
425
426   if (xmode)
427     name = jnlib_xmalloc (n);
428   else
429     {
430       name = jnlib_malloc (n);
431       if (!name)
432         {
433           jnlib_free (home_buffer);
434           return NULL;
435         }
436     }
437   
438   if (home)
439     p = stpcpy (stpcpy (name, home), first_part + skip);
440   else
441     p = stpcpy (name, first_part);
442
443   jnlib_free (home_buffer);
444
445   for (argc=0; argv[argc]; argc++)
446     p = stpcpy (stpcpy (p, "/"), argv[argc]);
447
448   return change_slashes (name);
449 }
450
451 /* Construct a filename from the NULL terminated list of parts.  Tilde
452    expansion is done for the first argument.  This function terminates
453    the process on memory shortage. */
454 char *
455 make_filename (const char *first_part, ... )
456 {
457   va_list arg_ptr;
458   char *result;
459
460   va_start (arg_ptr, first_part);
461   result = do_make_filename (1, first_part, arg_ptr);
462   va_end (arg_ptr);
463   return result;
464 }
465
466 /* Construct a filename from the NULL terminated list of parts.  Tilde
467    expansion is done for the first argument.  This function may return
468    NULL on error. */
469 char *
470 make_filename_try (const char *first_part, ... )
471 {
472   va_list arg_ptr;
473   char *result;
474
475   va_start (arg_ptr, first_part);
476   result = do_make_filename (0, first_part, arg_ptr);
477   va_end (arg_ptr);
478   return result;
479 }
480
481
482 \f
483 /* Compare whether the filenames are identical.  This is a
484    special version of strcmp() taking the semantics of filenames in
485    account.  Note that this function works only on the supplied names
486    without considering any context like the current directory.  See
487    also same_file_p(). */
488 int
489 compare_filenames (const char *a, const char *b)
490 {
491 #ifdef HAVE_DOSISH_SYSTEM
492   for ( ; *a && *b; a++, b++ ) 
493     {
494       if (*a != *b 
495           && (toupper (*(const unsigned char*)a)
496               != toupper (*(const unsigned char*)b) )
497           && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
498         break;
499     }
500   if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
501     return 0;
502   else
503     return (toupper (*(const unsigned char*)a) 
504             - toupper (*(const unsigned char*)b));
505 #else
506     return strcmp(a,b);
507 #endif
508 }
509
510
511 /* Convert 2 hex characters at S to a byte value.  Return this value
512    or -1 if there is an error. */
513 int
514 hextobyte (const char *s)
515 {
516   int c;
517
518   if ( *s >= '0' && *s <= '9' )
519     c = 16 * (*s - '0');
520   else if ( *s >= 'A' && *s <= 'F' )
521     c = 16 * (10 + *s - 'A');
522   else if ( *s >= 'a' && *s <= 'f' )
523     c = 16 * (10 + *s - 'a');
524   else
525     return -1;
526   s++;
527   if ( *s >= '0' && *s <= '9' )
528     c += *s - '0';
529   else if ( *s >= 'A' && *s <= 'F' )
530     c += 10 + *s - 'A';
531   else if ( *s >= 'a' && *s <= 'f' )
532     c += 10 + *s - 'a';
533   else
534     return -1;
535   return c;
536 }
537
538
539 /* Print a BUFFER to stream FP while replacing all control characters
540    and the characters DELIM and DELIM2 with standard C escape
541    sequences.  Returns the number of characters printed. */
542 size_t 
543 print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
544                          int delim, int delim2)
545 {
546   const unsigned char *p = buffer;
547   size_t count = 0;
548
549   for (; length; length--, p++, count++)
550     {
551       if (*p < 0x20 
552           || *p == 0x7f
553           || *p == delim 
554           || *p == delim2
555           || ((delim || delim2) && *p=='\\'))
556         {
557           putc ('\\', fp);
558           count++;
559           if (*p == '\n')
560             {
561               putc ('n', fp);
562               count++;
563             }
564           else if (*p == '\r')
565             {
566               putc ('r', fp);
567               count++;
568             }
569           else if (*p == '\f')
570             {
571               putc ('f', fp);
572               count++;
573             }
574           else if (*p == '\v')
575             {
576               putc ('v', fp);
577               count++;
578             }
579           else if (*p == '\b')
580             {
581               putc ('b', fp);
582               count++;
583             }
584           else if (!*p)
585             {
586               putc('0', fp);
587               count++;
588             }
589           else
590             {
591               fprintf (fp, "x%02x", *p);
592               count += 3;
593             }
594         }
595       else
596         {
597           putc (*p, fp);
598           count++;
599         }
600     }
601
602   return count;
603 }
604
605 /* Same as print_sanitized_buffer2 but with just one delimiter. */
606 size_t 
607 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
608                         int delim)
609 {
610   return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
611 }
612
613
614 size_t 
615 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
616                              size_t length, int delim)
617 {
618   const char *p = buffer;
619   size_t i;
620
621   /* We can handle plain ascii simpler, so check for it first. */
622   for (i=0; i < length; i++ ) 
623     {
624       if ( (p[i] & 0x80) )
625         break;
626     }
627   if (i < length)
628     {
629         char *buf = utf8_to_native (p, length, delim);
630         /*(utf8 conversion already does the control character quoting)*/
631         i = strlen (buf);
632         fputs (buf, fp);
633         jnlib_free (buf);
634         return i;
635     }
636   else
637     return print_sanitized_buffer (fp, p, length, delim);
638 }
639
640
641 size_t 
642 print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
643 {
644   return string? print_sanitized_buffer2 (fp, string, strlen (string),
645                                           delim, delim2):0;
646 }
647
648 size_t 
649 print_sanitized_string (FILE *fp, const char *string, int delim)
650 {
651   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
652 }
653
654 size_t 
655 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
656 {
657   return string? print_sanitized_utf8_buffer (fp,
658                                               string, strlen (string),
659                                               delim) : 0;
660 }
661
662 /* Create a string from the buffer P_ARG of length N which is suitable
663    for printing.  Caller must release the created string using xfree.
664    This function terminates the process on memory shortage.  */
665 char *
666 sanitize_buffer (const void *p_arg, size_t n, int delim)
667 {
668   const unsigned char *p = p_arg;
669   size_t save_n, buflen;
670   const unsigned char *save_p;
671   char *buffer, *d;
672
673   /* First count length. */
674   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
675     {
676       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
677         {
678           if ( *p=='\n' || *p=='\r' || *p=='\f'
679                || *p=='\v' || *p=='\b' || !*p )
680             buflen += 2;
681           else
682             buflen += 5;
683         }
684       else
685         buflen++;
686     }
687   p = save_p;
688   n = save_n;
689   /* And now make the string */
690   d = buffer = jnlib_xmalloc( buflen );
691   for ( ; n; n--, p++ )
692     {
693       if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
694         *d++ = '\\';
695         if( *p == '\n' )
696           *d++ = 'n';
697         else if( *p == '\r' )
698           *d++ = 'r';
699         else if( *p == '\f' )
700           *d++ = 'f';
701         else if( *p == '\v' )
702           *d++ = 'v';
703         else if( *p == '\b' )
704           *d++ = 'b';
705         else if( !*p )
706           *d++ = '0';
707         else {
708           sprintf(d, "x%02x", *p );
709           d += 3;
710         }
711       }
712       else
713         *d++ = *p;
714     }
715   *d = 0;
716   return buffer;
717 }
718
719
720 /* Given a string containing an UTF-8 encoded text, return the number
721    of characters in this string.  It differs from strlen in that it
722    only counts complete UTF-8 characters.  Note, that this function
723    does not take combined characters into account.  */
724 size_t
725 utf8_charcount (const char *s)
726 {
727   size_t n;
728
729   for (n=0; *s; s++)
730     if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
731       n++;
732
733   return n;
734 }
735
736
737 /****************************************************
738  **********  W32 specific functions  ****************
739  ****************************************************/
740
741 #ifdef HAVE_W32_SYSTEM
742 const char *
743 w32_strerror (int ec)
744 {
745   static char strerr[256];
746   
747   if (ec == -1)
748     ec = (int)GetLastError ();
749 #ifdef HAVE_W32CE_SYSTEM
750   /* There is only a wchar_t FormatMessage.  It does not make much
751      sense to play the conversion game; we print only the code.  */
752   snprintf (strerr, sizeof strerr, "ec=%d", (int)GetLastError ());
753 #else
754   FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
755                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
756                  strerr, DIM (strerr)-1, NULL);
757 #endif
758   return strerr;    
759 }
760 #endif /*HAVE_W32_SYSTEM*/
761
762
763 /****************************************************
764  ******** Locale insensitive ctype functions ********
765  ****************************************************/
766 /* FIXME: replace them by a table lookup and macros */
767 int
768 ascii_isupper (int c)
769 {
770     return c >= 'A' && c <= 'Z';
771 }
772
773 int
774 ascii_islower (int c)
775 {
776     return c >= 'a' && c <= 'z';
777 }
778
779 int 
780 ascii_toupper (int c)
781 {
782     if (c >= 'a' && c <= 'z')
783         c &= ~0x20;
784     return c;
785 }
786
787 int 
788 ascii_tolower (int c)
789 {
790     if (c >= 'A' && c <= 'Z')
791         c |= 0x20;
792     return c;
793 }
794
795
796 int
797 ascii_strcasecmp( const char *a, const char *b )
798 {
799     if (a == b)
800         return 0;
801
802     for (; *a && *b; a++, b++) {
803         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
804             break;
805     }
806     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
807 }
808
809 int 
810 ascii_strncasecmp (const char *a, const char *b, size_t n)
811 {
812   const unsigned char *p1 = (const unsigned char *)a;
813   const unsigned char *p2 = (const unsigned char *)b;
814   unsigned char c1, c2;
815
816   if (p1 == p2 || !n )
817     return 0;
818
819   do
820     {
821       c1 = ascii_tolower (*p1);
822       c2 = ascii_tolower (*p2);
823
824       if ( !--n || c1 == '\0')
825         break;
826
827       ++p1;
828       ++p2;
829     }
830   while (c1 == c2);
831   
832   return c1 - c2;
833 }
834
835
836 int
837 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
838 {
839   const char *a = a_arg;
840   const char *b = b_arg;
841
842   if (a == b)
843     return 0;
844   for ( ; n; n--, a++, b++ )
845     {
846       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
847         return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
848     }
849   return 0;
850 }
851
852 int
853 ascii_strcmp( const char *a, const char *b )
854 {
855     if (a == b)
856         return 0;
857
858     for (; *a && *b; a++, b++) {
859         if (*a != *b )
860             break;
861     }
862     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
863 }
864
865
866 void *
867 ascii_memcasemem (const void *haystack, size_t nhaystack,
868                   const void *needle, size_t nneedle)
869 {
870
871   if (!nneedle)
872     return (void*)haystack; /* finding an empty needle is really easy */
873   if (nneedle <= nhaystack)
874     {
875       const char *a = haystack;
876       const char *b = a + nhaystack - nneedle;
877       
878       for (; a <= b; a++)
879         {
880           if ( !ascii_memcasecmp (a, needle, nneedle) )
881             return (void *)a;
882         }
883     }
884   return NULL;
885 }
886
887 /*********************************************
888  ********** missing string functions *********
889  *********************************************/
890
891 #ifndef HAVE_STPCPY
892 char *
893 stpcpy(char *a,const char *b)
894 {
895     while( *b )
896         *a++ = *b++;
897     *a = 0;
898
899     return (char*)a;
900 }
901 #endif
902
903 #ifndef HAVE_STRSEP
904 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
905 char *
906 strsep (char **stringp, const char *delim)
907 {
908   char *begin, *end;
909
910   begin = *stringp;
911   if (begin == NULL)
912     return NULL;
913
914   /* A frequent case is when the delimiter string contains only one
915      character.  Here we don't need to call the expensive `strpbrk'
916      function and instead work using `strchr'.  */
917   if (delim[0] == '\0' || delim[1] == '\0')
918     {
919       char ch = delim[0];
920
921       if (ch == '\0')
922         end = NULL;
923       else
924         {
925           if (*begin == ch)
926             end = begin;
927           else if (*begin == '\0')
928             end = NULL;
929           else
930             end = strchr (begin + 1, ch);
931         }
932     }
933   else
934     /* Find the end of the token.  */
935     end = strpbrk (begin, delim);
936
937   if (end)
938     {
939       /* Terminate the token and set *STRINGP past NUL character.  */
940       *end++ = '\0';
941       *stringp = end;
942     }
943   else
944     /* No more delimiters; this is the last token.  */
945     *stringp = NULL;
946
947   return begin;
948 }
949 #endif /*HAVE_STRSEP*/
950
951
952 #ifndef HAVE_STRLWR
953 char *
954 strlwr(char *s)
955 {
956     char *p;
957     for(p=s; *p; p++ )
958         *p = tolower(*p);
959     return s;
960 }
961 #endif
962
963
964 #ifndef HAVE_STRCASECMP
965 int
966 strcasecmp( const char *a, const char *b )
967 {
968     for( ; *a && *b; a++, b++ ) {
969         if( *a != *b && toupper(*a) != toupper(*b) )
970             break;
971     }
972     return *(const byte*)a - *(const byte*)b;
973 }
974 #endif
975
976
977 /****************
978  * mingw32/cpd has a memicmp()
979  */
980 #ifndef HAVE_MEMICMP
981 int
982 memicmp( const char *a, const char *b, size_t n )
983 {
984     for( ; n; n--, a++, b++ )
985         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
986             return *(const byte *)a - *(const byte*)b;
987     return 0;
988 }
989 #endif
990
991
992 #ifndef HAVE_MEMRCHR
993 void *
994 memrchr (const void *buffer, int c, size_t n)
995 {
996   const unsigned char *p = buffer;
997
998   for (p += n; n ; n--)
999     if (*--p == c)
1000       return (void *)p;
1001   return NULL;
1002 }
1003 #endif /*HAVE_MEMRCHR*/
1004
1005 \f
1006 /* Percent-escape the string STR by replacing colons with '%3a'.  If
1007    EXTRA is not NULL all characters in EXTRA are also escaped.  */
1008 static char *
1009 do_percent_escape (const char *str, const char *extra, int die)
1010 {
1011   int i, j;
1012   char *ptr;
1013
1014   if (!str)
1015     return NULL;
1016
1017   for (i=j=0; str[i]; i++)
1018     if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
1019       j++;
1020   if (die)
1021     ptr = jnlib_xmalloc (i + 2 * j + 1);
1022   else
1023     {
1024       ptr = jnlib_malloc (i + 2 * j + 1);
1025       if (!ptr)
1026         return NULL;
1027     }
1028   i = 0;
1029   while (*str)
1030     {
1031       if (*str == ':')
1032         {
1033           ptr[i++] = '%';
1034           ptr[i++] = '3';
1035           ptr[i++] = 'a';
1036         }
1037       else if (*str == '%')
1038         {
1039           ptr[i++] = '%';
1040           ptr[i++] = '2';
1041           ptr[i++] = '5';
1042         }
1043       else if (extra && strchr (extra, *str))
1044         {
1045           ptr[i++] = '%';
1046           ptr[i++] = tohex_lower ((*str>>4)&15);
1047           ptr[i++] = tohex_lower (*str&15);
1048         }
1049       else
1050         ptr[i++] = *str;
1051       str++;
1052     }
1053   ptr[i] = '\0';
1054
1055   return ptr;
1056 }
1057
1058 /* Percent-escape the string STR by replacing colons with '%3a'.  If
1059    EXTRA is not NULL all characters in EXTRA are also escaped.  This
1060    function terminates the process on memory shortage.  */
1061 char *
1062 percent_escape (const char *str, const char *extra)
1063 {
1064   return do_percent_escape (str, extra, 1);
1065 }
1066
1067 /* Same as percent_escape but return NULL instead of exiting on memory
1068    error. */
1069 char *
1070 try_percent_escape (const char *str, const char *extra)
1071 {
1072   return do_percent_escape (str, extra, 0);
1073 }
1074
1075
1076
1077 static char *
1078 do_strconcat (const char *s1, va_list arg_ptr)
1079 {
1080   const char *argv[48];
1081   size_t argc;
1082   size_t needed;
1083   char *buffer, *p;
1084
1085   argc = 0;
1086   argv[argc++] = s1;
1087   needed = strlen (s1);
1088   while (((argv[argc] = va_arg (arg_ptr, const char *))))
1089     {
1090       needed += strlen (argv[argc]);
1091       if (argc >= DIM (argv)-1)
1092         {
1093           jnlib_set_errno (EINVAL);
1094           return NULL;
1095         }
1096       argc++;
1097     }
1098   needed++;
1099   buffer = jnlib_malloc (needed);
1100   if (buffer)
1101     {
1102       for (p = buffer, argc=0; argv[argc]; argc++)
1103         p = stpcpy (p, argv[argc]);
1104     }
1105   return buffer;
1106 }
1107
1108
1109 /* Concatenate the string S1 with all the following strings up to a
1110    NULL.  Returns a malloced buffer with the new string or NULL on a
1111    malloc error or if too many arguments are given.  */
1112 char *
1113 strconcat (const char *s1, ...)
1114 {
1115   va_list arg_ptr;
1116   char *result;
1117
1118   if (!s1)
1119     result = jnlib_strdup ("");
1120   else
1121     {
1122       va_start (arg_ptr, s1);
1123       result = do_strconcat (s1, arg_ptr);
1124       va_end (arg_ptr);
1125     }
1126   return result;
1127 }
1128
1129 /* Same as strconcat but terminate the process with an error message
1130    if something goes wrong.  */
1131 char *
1132 xstrconcat (const char *s1, ...)
1133 {
1134   va_list arg_ptr;
1135   char *result;
1136
1137   if (!s1)
1138     result = jnlib_xstrdup ("");
1139   else
1140     {
1141       va_start (arg_ptr, s1);
1142       result = do_strconcat (s1, arg_ptr);
1143       va_end (arg_ptr);
1144     }
1145   if (!result)
1146     {
1147       if (errno == EINVAL)
1148         fputs ("\nfatal: too many args for xstrconcat\n", stderr);
1149       else
1150         fputs ("\nfatal: out of memory\n", stderr);
1151       exit (2);
1152     }
1153   return result;
1154 }
1155