jnlib/
[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  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 2.1 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, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  */
22
23 #include <config.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #ifdef HAVE_W32_SYSTEM
29 #include <windows.h>
30 #endif
31
32 #include "libjnlib-config.h"
33 #include "utf8conv.h"
34 #include "stringhelp.h"
35
36
37 /*
38  * Look for the substring SUB in buffer and return a pointer to that
39  * substring in BUFFER or NULL if not found.
40  * Comparison is case-insensitive.
41  */
42 const char *
43 memistr (const void *buffer, size_t buflen, const char *sub)
44 {
45   const unsigned char *buf = buffer;
46   const unsigned char *t = (const unsigned char *)buffer;
47   const unsigned char *s = (const unsigned char *)sub;
48   size_t n = buflen;
49
50   for ( ; n ; t++, n-- )
51     {
52       if ( toupper (*t) == toupper (*s) )
53         {
54           for ( buf=t++, buflen = n--, s++;
55                 n && toupper (*t) == toupper (*s); t++, s++, n-- )
56             ;
57           if (!*s)
58             return (const char*)buf;
59           t = buf;
60           s = (const unsigned char *)sub ;
61           n = buflen;
62         }
63     }
64   return NULL;
65 }
66
67 const char *
68 ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
69 {
70   const unsigned char *buf = buffer;
71   const unsigned char *t = (const unsigned char *)buf;
72   const unsigned char *s = (const unsigned char *)sub;
73   size_t n = buflen;
74
75   for ( ; n ; t++, n-- )
76     {
77       if (ascii_toupper (*t) == ascii_toupper (*s) )
78         {
79           for ( buf=t++, buflen = n--, s++;
80                 n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
81             ;
82           if (!*s)
83             return (const char*)buf;
84           t = (const unsigned char *)buf;
85           s = (const unsigned char *)sub ;
86           n = buflen;
87         }
88     }
89   return NULL;
90 }
91
92 /* This function is similar to strncpy().  However it won't copy more
93    than N - 1 characters and makes sure that a '\0' is appended. With
94    N given as 0, nothing will happen.  With DEST given as NULL, memory
95    will be allocated using jnlib_xmalloc (i.e. if it runs out of core
96    the function terminates).  Returns DES or a pointer to the
97    allocated memory.
98  */
99 char *
100 mem2str( char *dest , const void *src , size_t n )
101 {
102     char *d;
103     const char *s;
104
105     if( n ) {
106         if( !dest )
107             dest = jnlib_xmalloc( n ) ;
108         d = dest;
109         s = src ;
110         for(n--; n && *s; n-- )
111             *d++ = *s++;
112         *d = '\0' ;
113     }
114
115     return dest ;
116 }
117
118
119 /****************
120  * remove leading and trailing white spaces
121  */
122 char *
123 trim_spaces( char *str )
124 {
125     char *string, *p, *mark;
126
127     string = str;
128     /* find first non space character */
129     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
130         ;
131     /* move characters */
132     for( (mark = NULL); (*string = *p); string++, p++ )
133         if( isspace( *(byte*)p ) ) {
134             if( !mark )
135                 mark = string ;
136         }
137         else
138             mark = NULL ;
139     if( mark )
140         *mark = '\0' ;  /* remove trailing spaces */
141
142     return str ;
143 }
144
145 /****************
146  * remove trailing white spaces
147  */
148 char *
149 trim_trailing_spaces( char *string )
150 {
151     char *p, *mark;
152
153     for( mark = NULL, p = string; *p; p++ ) {
154         if( isspace( *(byte*)p ) ) {
155             if( !mark )
156                 mark = p;
157         }
158         else
159             mark = NULL;
160     }
161     if( mark )
162         *mark = '\0' ;
163
164     return string ;
165 }
166
167
168 unsigned
169 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
170 {
171     byte *p, *mark;
172     unsigned n;
173
174     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
175         if( strchr(trimchars, *p ) ) {
176             if( !mark )
177                 mark = p;
178         }
179         else
180             mark = NULL;
181     }
182
183     if( mark ) {
184         *mark = 0;
185         return mark - line;
186     }
187     return len;
188 }
189
190 /****************
191  * remove trailing white spaces and return the length of the buffer
192  */
193 unsigned
194 trim_trailing_ws( byte *line, unsigned len )
195 {
196     return trim_trailing_chars( line, len, " \t\r\n" );
197 }
198
199 size_t
200 length_sans_trailing_chars (const unsigned char *line, size_t len,
201                             const char *trimchars )
202 {
203   const unsigned char *p, *mark;
204   size_t n;
205   
206   for( mark=NULL, p=line, n=0; n < len; n++, p++ )
207     {
208       if (strchr (trimchars, *p ))
209         {
210           if( !mark )
211             mark = p;
212         }
213       else
214         mark = NULL;
215     }
216   
217   if (mark) 
218     return mark - line;
219   return len;
220 }
221
222 /*
223  *  Return the length of line ignoring trailing white-space.
224  */
225 size_t
226 length_sans_trailing_ws (const unsigned char *line, size_t len)
227 {
228   return length_sans_trailing_chars (line, len, " \t\r\n");
229 }
230
231
232
233 /***************
234  * Extract from a given path the filename component.
235  *
236  */
237 char *
238 make_basename(const char *filepath, const char *inputpath)
239 {
240     char *p;
241
242 #ifdef __riscos__
243     return riscos_make_basename(filepath, inputpath);
244 #endif
245
246     if ( !(p=strrchr(filepath, '/')) )
247 #ifdef HAVE_DRIVE_LETTERS
248         if ( !(p=strrchr(filepath, '\\')) )
249             if ( !(p=strrchr(filepath, ':')) )
250 #endif
251               {
252                 return jnlib_xstrdup(filepath);
253               }
254
255     return jnlib_xstrdup(p+1);
256 }
257
258
259
260 /***************
261  * Extract from a given filename the path prepended to it.
262  * If their isn't a path prepended to the filename, a dot
263  * is returned ('.').
264  *
265  */
266 char *
267 make_dirname(const char *filepath)
268 {
269     char *dirname;
270     int  dirname_length;
271     char *p;
272
273     if ( !(p=strrchr(filepath, '/')) )
274       #ifdef HAVE_DRIVE_LETTERS
275         if ( !(p=strrchr(filepath, '\\')) )
276             if ( !(p=strrchr(filepath, ':')) )
277       #endif
278               {
279                 return jnlib_xstrdup(".");
280               }
281
282     dirname_length = p-filepath;
283     dirname = jnlib_xmalloc(dirname_length+1);
284     strncpy(dirname, filepath, dirname_length);
285     dirname[dirname_length] = 0;
286
287     return dirname;
288 }
289
290
291
292 /****************
293  * Construct a filename from the NULL terminated list of parts.
294  * Tilde expansion is done here.
295  */
296 char *
297 make_filename( const char *first_part, ... )
298 {
299     va_list arg_ptr ;
300     size_t n;
301     const char *s;
302     char *name, *home, *p;
303
304     va_start( arg_ptr, first_part ) ;
305     n = strlen(first_part)+1;
306     while( (s=va_arg(arg_ptr, const char *)) )
307         n += strlen(s) + 1;
308     va_end(arg_ptr);
309
310     home = NULL;
311     if( *first_part == '~' && first_part[1] == '/'
312                            && (home = getenv("HOME")) && *home )
313         n += strlen(home);
314
315     name = jnlib_xmalloc(n);
316     p = home ? stpcpy(stpcpy(name,home), first_part+1)
317              : stpcpy(name, first_part);
318     va_start( arg_ptr, first_part ) ;
319     while( (s=va_arg(arg_ptr, const char *)) )
320         p = stpcpy(stpcpy(p,"/"), s);
321     va_end(arg_ptr);
322
323     return name;
324 }
325
326
327 int
328 compare_filenames( const char *a, const char *b )
329 {
330     /* ? check whether this is an absolute filename and
331      * resolve symlinks?
332      */
333 #ifdef HAVE_DRIVE_LETTERS
334     return stricmp(a,b);
335 #else
336     return strcmp(a,b);
337 #endif
338 }
339
340
341 /* Convert 2 hex characters at S to a byte value.  Return this value
342    or -1 if there is an error. */
343 int
344 hextobyte (const char *s)
345 {
346   int c;
347
348   if ( *s >= '0' && *s <= '9' )
349     c = 16 * (*s - '0');
350   else if ( *s >= 'A' && *s <= 'F' )
351     c = 16 * (10 + *s - 'A');
352   else if ( *s >= 'a' && *s <= 'f' )
353     c = 16 * (10 + *s - 'a');
354   else
355     return -1;
356   s++;
357   if ( *s >= '0' && *s <= '9' )
358     c += *s - '0';
359   else if ( *s >= 'A' && *s <= 'F' )
360     c += 10 + *s - 'A';
361   else if ( *s >= 'a' && *s <= 'f' )
362     c += 10 + *s - 'a';
363   else
364     return -1;
365   return c;
366 }
367
368
369 /* Print a BUFFER to stream FP while replacing all control characters
370    and the characters DELIM and DELIM2 with standard C escape
371    sequences.  Returns the number of characters printed. */
372 size_t 
373 print_sanitized_buffer2 (FILE *fp, const void *buffer, size_t length,
374                          int delim, int delim2)
375 {
376   const unsigned char *p = buffer;
377   size_t count = 0;
378
379   for (; length; length--, p++, count++)
380     {
381       /* Fixme: Check whether *p < 0xa0 is correct for utf8 encoding. */
382       if (*p < 0x20 
383           || (*p >= 0x7f && *p < 0xa0)
384           || *p == delim 
385           || *p == delim2
386           || ((delim || delim2) && *p=='\\'))
387         {
388           putc ('\\', fp);
389           count++;
390           if (*p == '\n')
391             {
392               putc ('n', fp);
393               count++;
394             }
395           else if (*p == '\r')
396             {
397               putc ('r', fp);
398               count++;
399             }
400           else if (*p == '\f')
401             {
402               putc ('f', fp);
403               count++;
404             }
405           else if (*p == '\v')
406             {
407               putc ('v', fp);
408               count++;
409             }
410           else if (*p == '\b')
411             {
412               putc ('b', fp);
413               count++;
414             }
415           else if (!*p)
416             {
417               putc('0', fp);
418               count++;
419             }
420           else
421             {
422               fprintf (fp, "x%02x", *p);
423               count += 3;
424             }
425         }
426       else
427         {
428           putc (*p, fp);
429           count++;
430         }
431     }
432
433   return count;
434 }
435
436 /* Same as print_sanitized_buffer2 but with just one delimiter. */
437 size_t 
438 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
439                         int delim)
440 {
441   return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
442 }
443
444
445 size_t 
446 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
447                              size_t length, int delim)
448 {
449   const char *p = buffer;
450   size_t i;
451
452   /* We can handle plain ascii simpler, so check for it first. */
453   for (i=0; i < length; i++ ) 
454     {
455       if ( (p[i] & 0x80) )
456         break;
457     }
458   if (i < length)
459     {
460         char *buf = utf8_to_native (p, length, delim);
461         /*(utf8 conversion already does the control character quoting)*/
462         i = strlen (buf);
463         fputs (buf, fp);
464         jnlib_free (buf);
465         return i;
466     }
467   else
468     return print_sanitized_buffer (fp, p, length, delim);
469 }
470
471
472 size_t 
473 print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
474 {
475   return string? print_sanitized_buffer2 (fp, string, strlen (string),
476                                           delim, delim2):0;
477 }
478
479 size_t 
480 print_sanitized_string (FILE *fp, const char *string, int delim)
481 {
482   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
483 }
484
485 size_t 
486 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
487 {
488   return string? print_sanitized_utf8_buffer (fp,
489                                               string, strlen (string),
490                                               delim) : 0;
491 }
492
493 /* Create a string from the buffer P_ARG of length N which is suitable for
494    printing.  Caller must release the created string using xfree. */
495 char *
496 sanitize_buffer (const void *p_arg, size_t n, int delim)
497 {
498   const unsigned char *p = p_arg;
499   size_t save_n, buflen;
500   const unsigned char *save_p;
501   char *buffer, *d;
502
503   /* First count length. */
504   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
505     {
506       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
507         {
508           if ( *p=='\n' || *p=='\r' || *p=='\f'
509                || *p=='\v' || *p=='\b' || !*p )
510             buflen += 2;
511           else
512             buflen += 5;
513         }
514       else
515         buflen++;
516     }
517   p = save_p;
518   n = save_n;
519   /* And now make the string */
520   d = buffer = jnlib_xmalloc( buflen );
521   for ( ; n; n--, p++ )
522     {
523       if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
524         *d++ = '\\';
525         if( *p == '\n' )
526           *d++ = 'n';
527         else if( *p == '\r' )
528           *d++ = 'r';
529         else if( *p == '\f' )
530           *d++ = 'f';
531         else if( *p == '\v' )
532           *d++ = 'v';
533         else if( *p == '\b' )
534           *d++ = 'b';
535         else if( !*p )
536           *d++ = '0';
537         else {
538           sprintf(d, "x%02x", *p );
539           d += 3;
540         }
541       }
542       else
543         *d++ = *p;
544     }
545   *d = 0;
546   return buffer;
547 }
548
549
550 /* Given a string containing an UTF-8 encoded text, return the number
551    of characters in this string.  It differs from strlen in that it
552    only counts complete UTF-8 characters.  Note, that this function
553    does not take combined characters into account.  */
554 size_t
555 utf8_charcount (const char *s)
556 {
557   size_t n;
558
559   for (n=0; *s; s++)
560     if ( (*s&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
561       n++;
562
563   return n;
564 }
565
566
567 /****************************************************
568  **********  W32 specific functions  ****************
569  ****************************************************/
570
571 #ifdef HAVE_W32_SYSTEM
572 const char *
573 w32_strerror (int ec)
574 {
575   static char strerr[256];
576   
577   if (ec == -1)
578     ec = (int)GetLastError ();
579   FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
580                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
581                  strerr, DIM (strerr)-1, NULL);
582   return strerr;    
583 }
584 #endif /*HAVE_W32_SYSTEM*/
585
586
587 /****************************************************
588  ******** Locale insensitive ctype functions ********
589  ****************************************************/
590 /* FIXME: replace them by a table lookup and macros */
591 int
592 ascii_isupper (int c)
593 {
594     return c >= 'A' && c <= 'Z';
595 }
596
597 int
598 ascii_islower (int c)
599 {
600     return c >= 'a' && c <= 'z';
601 }
602
603 int 
604 ascii_toupper (int c)
605 {
606     if (c >= 'a' && c <= 'z')
607         c &= ~0x20;
608     return c;
609 }
610
611 int 
612 ascii_tolower (int c)
613 {
614     if (c >= 'A' && c <= 'Z')
615         c |= 0x20;
616     return c;
617 }
618
619
620 int
621 ascii_strcasecmp( const char *a, const char *b )
622 {
623     if (a == b)
624         return 0;
625
626     for (; *a && *b; a++, b++) {
627         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
628             break;
629     }
630     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
631 }
632
633 int 
634 ascii_strncasecmp (const char *a, const char *b, size_t n)
635 {
636   const unsigned char *p1 = (const unsigned char *)a;
637   const unsigned char *p2 = (const unsigned char *)b;
638   unsigned char c1, c2;
639
640   if (p1 == p2 || !n )
641     return 0;
642
643   do
644     {
645       c1 = ascii_tolower (*p1);
646       c2 = ascii_tolower (*p2);
647
648       if ( !--n || c1 == '\0')
649         break;
650
651       ++p1;
652       ++p2;
653     }
654   while (c1 == c2);
655   
656   return c1 - c2;
657 }
658
659
660 int
661 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
662 {
663   const char *a = a_arg;
664   const char *b = b_arg;
665
666   if (a == b)
667     return 0;
668   for ( ; n; n--, a++, b++ )
669     {
670       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
671         return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
672     }
673   return 0;
674 }
675
676 int
677 ascii_strcmp( const char *a, const char *b )
678 {
679     if (a == b)
680         return 0;
681
682     for (; *a && *b; a++, b++) {
683         if (*a != *b )
684             break;
685     }
686     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
687 }
688
689
690 void *
691 ascii_memcasemem (const void *haystack, size_t nhaystack,
692                   const void *needle, size_t nneedle)
693 {
694
695   if (!nneedle)
696     return (void*)haystack; /* finding an empty needle is really easy */
697   if (nneedle <= nhaystack)
698     {
699       const char *a = haystack;
700       const char *b = a + nhaystack - nneedle;
701       
702       for (; a <= b; a++)
703         {
704           if ( !ascii_memcasecmp (a, needle, nneedle) )
705             return (void *)a;
706         }
707     }
708   return NULL;
709 }
710
711 /*********************************************
712  ********** missing string functions *********
713  *********************************************/
714
715 #ifndef HAVE_STPCPY
716 char *
717 stpcpy(char *a,const char *b)
718 {
719     while( *b )
720         *a++ = *b++;
721     *a = 0;
722
723     return (char*)a;
724 }
725 #endif
726
727 #ifndef HAVE_STRSEP
728 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
729 char *
730 strsep (char **stringp, const char *delim)
731 {
732   char *begin, *end;
733
734   begin = *stringp;
735   if (begin == NULL)
736     return NULL;
737
738   /* A frequent case is when the delimiter string contains only one
739      character.  Here we don't need to call the expensive `strpbrk'
740      function and instead work using `strchr'.  */
741   if (delim[0] == '\0' || delim[1] == '\0')
742     {
743       char ch = delim[0];
744
745       if (ch == '\0')
746         end = NULL;
747       else
748         {
749           if (*begin == ch)
750             end = begin;
751           else if (*begin == '\0')
752             end = NULL;
753           else
754             end = strchr (begin + 1, ch);
755         }
756     }
757   else
758     /* Find the end of the token.  */
759     end = strpbrk (begin, delim);
760
761   if (end)
762     {
763       /* Terminate the token and set *STRINGP past NUL character.  */
764       *end++ = '\0';
765       *stringp = end;
766     }
767   else
768     /* No more delimiters; this is the last token.  */
769     *stringp = NULL;
770
771   return begin;
772 }
773 #endif /*HAVE_STRSEP*/
774
775
776 #ifndef HAVE_STRLWR
777 char *
778 strlwr(char *s)
779 {
780     char *p;
781     for(p=s; *p; p++ )
782         *p = tolower(*p);
783     return s;
784 }
785 #endif
786
787
788 #ifndef HAVE_STRCASECMP
789 int
790 strcasecmp( const char *a, const char *b )
791 {
792     for( ; *a && *b; a++, b++ ) {
793         if( *a != *b && toupper(*a) != toupper(*b) )
794             break;
795     }
796     return *(const byte*)a - *(const byte*)b;
797 }
798 #endif
799
800
801 /****************
802  * mingw32/cpd has a memicmp()
803  */
804 #ifndef HAVE_MEMICMP
805 int
806 memicmp( const char *a, const char *b, size_t n )
807 {
808     for( ; n; n--, a++, b++ )
809         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
810             return *(const byte *)a - *(const byte*)b;
811     return 0;
812 }
813 #endif
814
815
816 #ifndef HAVE_MEMRCHR
817 void *
818 memrchr (const void *buffer, int c, size_t n)
819 {
820   const unsigned char *p = buffer;
821
822   for (p += n; n ; n--)
823     if (*--p == c)
824       return (void *)p;
825   return NULL;
826 }
827 #endif /*HAVE_MEMRCHR*/
828
829 \f
830 /* Percent-escape the string STR by replacing colons with '%3a'.  */
831 char *
832 percent_escape (const char *str)
833 {
834   int i = 0;
835   int j = 0;
836   char *ptr;
837
838   if (!str)
839     return NULL;
840
841   while (str[i])
842     if (str[i++] == ':')
843       j++;
844   ptr = jnlib_xmalloc (i + 2 * j + 1);
845   i = 0;
846   while (*str)
847     {
848       if (*str == ':')
849         {
850           ptr[i++] = '%';
851           ptr[i++] = '3';
852           ptr[i++] = 'a';
853         }
854       else
855         ptr[i++] = *str;
856       str++;
857     }
858   ptr[i] = '\0';
859
860   return ptr;
861 }