Still merging 1.4.3 code back
[gnupg.git] / jnlib / stringhelp.c
1 /* stringhelp.c -  standard string helper functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003,
3  *               2004, 2005  Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27 #ifdef HAVE_W32_SYSTEM
28 #include <windows.h>
29 #endif
30
31 #include "libjnlib-config.h"
32 #include "utf8conv.h"
33 #include "stringhelp.h"
34
35
36 /*
37  * Look for the substring SUB in buffer and return a pointer to that
38  * substring in BUFFER or NULL if not found.
39  * Comparison is case-insensitive.
40  */
41 const char *
42 memistr (const void *buffer, size_t buflen, const char *sub)
43 {
44   const unsigned char *buf = buffer;
45   const unsigned char *t = (const unsigned char *)buffer;
46   const unsigned char *s = (const unsigned char *)sub;
47   size_t n = buflen;
48
49   for ( ; n ; t++, n-- )
50     {
51       if ( toupper (*t) == toupper (*s) )
52         {
53           for ( buf=t++, buflen = n--, s++;
54                 n && toupper (*t) == toupper (*s); t++, s++, n-- )
55             ;
56           if (!*s)
57             return (const char*)buf;
58           t = buf;
59           s = (const unsigned char *)sub ;
60           n = buflen;
61         }
62     }
63   return NULL;
64 }
65
66 const char *
67 ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
68 {
69   const unsigned char *buf = buffer;
70   const unsigned char *t = (const unsigned char *)buf;
71   const unsigned char *s = (const unsigned char *)sub;
72   size_t n = buflen;
73
74   for ( ; n ; t++, n-- )
75     {
76       if (ascii_toupper (*t) == ascii_toupper (*s) )
77         {
78           for ( buf=t++, buflen = n--, s++;
79                 n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
80             ;
81           if (!*s)
82             return (const char*)buf;
83           t = (const unsigned char *)buf;
84           s = (const unsigned char *)sub ;
85           n = buflen;
86         }
87     }
88   return NULL;
89 }
90
91 /* This function is similar to strncpy().  However it won't copy more
92    than N - 1 characters and makes sure that a '\0' is appended. With
93    N given as 0, nothing will happen.  With DEST given as NULL, memory
94    will be allocated using jnlib_xmalloc (i.e. if it runs out of core
95    the function terminates).  Returns DES or a pointer to the
96    allocated memory.
97  */
98 char *
99 mem2str( char *dest , const void *src , size_t n )
100 {
101     char *d;
102     const char *s;
103
104     if( n ) {
105         if( !dest )
106             dest = jnlib_xmalloc( n ) ;
107         d = dest;
108         s = src ;
109         for(n--; n && *s; n-- )
110             *d++ = *s++;
111         *d = '\0' ;
112     }
113
114     return dest ;
115 }
116
117
118 /****************
119  * remove leading and trailing white spaces
120  */
121 char *
122 trim_spaces( char *str )
123 {
124     char *string, *p, *mark;
125
126     string = str;
127     /* find first non space character */
128     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
129         ;
130     /* move characters */
131     for( (mark = NULL); (*string = *p); string++, p++ )
132         if( isspace( *(byte*)p ) ) {
133             if( !mark )
134                 mark = string ;
135         }
136         else
137             mark = NULL ;
138     if( mark )
139         *mark = '\0' ;  /* remove trailing spaces */
140
141     return str ;
142 }
143
144 /****************
145  * remove trailing white spaces
146  */
147 char *
148 trim_trailing_spaces( char *string )
149 {
150     char *p, *mark;
151
152     for( mark = NULL, p = string; *p; p++ ) {
153         if( isspace( *(byte*)p ) ) {
154             if( !mark )
155                 mark = p;
156         }
157         else
158             mark = NULL;
159     }
160     if( mark )
161         *mark = '\0' ;
162
163     return string ;
164 }
165
166
167 unsigned
168 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
169 {
170     byte *p, *mark;
171     unsigned n;
172
173     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
174         if( strchr(trimchars, *p ) ) {
175             if( !mark )
176                 mark = p;
177         }
178         else
179             mark = NULL;
180     }
181
182     if( mark ) {
183         *mark = 0;
184         return mark - line;
185     }
186     return len;
187 }
188
189 /****************
190  * remove trailing white spaces and return the length of the buffer
191  */
192 unsigned
193 trim_trailing_ws( byte *line, unsigned len )
194 {
195     return trim_trailing_chars( line, len, " \t\r\n" );
196 }
197
198 size_t
199 length_sans_trailing_chars (const unsigned char *line, size_t len,
200                             const char *trimchars )
201 {
202   const unsigned char *p, *mark;
203   size_t n;
204   
205   for( mark=NULL, p=line, n=0; n < len; n++, p++ )
206     {
207       if (strchr (trimchars, *p ))
208         {
209           if( !mark )
210             mark = p;
211         }
212       else
213         mark = NULL;
214     }
215   
216   if (mark) 
217     return mark - line;
218   return len;
219 }
220
221 /****************
222  * remove trailing white spaces and return the length of the buffer
223  */
224 size_t
225 length_sans_trailing_ws (const unsigned char *line, size_t len)
226 {
227   return length_sans_trailing_chars (line, len, " \t\r\n");
228 }
229
230
231
232 /***************
233  * Extract from a given path the filename component.
234  *
235  */
236 char *
237 make_basename(const char *filepath, const char *inputpath)
238 {
239     char *p;
240
241 #ifdef __riscos__
242     return riscos_make_basename(filepath, inputpath);
243 #endif
244
245     if ( !(p=strrchr(filepath, '/')) )
246 #ifdef HAVE_DRIVE_LETTERS
247         if ( !(p=strrchr(filepath, '\\')) )
248             if ( !(p=strrchr(filepath, ':')) )
249 #endif
250               {
251                 return jnlib_xstrdup(filepath);
252               }
253
254     return jnlib_xstrdup(p+1);
255 }
256
257
258
259 /***************
260  * Extract from a given filename the path prepended to it.
261  * If their isn't a path prepended to the filename, a dot
262  * is returned ('.').
263  *
264  */
265 char *
266 make_dirname(const char *filepath)
267 {
268     char *dirname;
269     int  dirname_length;
270     char *p;
271
272     if ( !(p=strrchr(filepath, '/')) )
273       #ifdef HAVE_DRIVE_LETTERS
274         if ( !(p=strrchr(filepath, '\\')) )
275             if ( !(p=strrchr(filepath, ':')) )
276       #endif
277               {
278                 return jnlib_xstrdup(".");
279               }
280
281     dirname_length = p-filepath;
282     dirname = jnlib_xmalloc(dirname_length+1);
283     strncpy(dirname, filepath, dirname_length);
284     dirname[dirname_length] = 0;
285
286     return dirname;
287 }
288
289
290
291 /****************
292  * Construct a filename from the NULL terminated list of parts.
293  * Tilde expansion is done here.
294  */
295 char *
296 make_filename( const char *first_part, ... )
297 {
298     va_list arg_ptr ;
299     size_t n;
300     const char *s;
301     char *name, *home, *p;
302
303     va_start( arg_ptr, first_part ) ;
304     n = strlen(first_part)+1;
305     while( (s=va_arg(arg_ptr, const char *)) )
306         n += strlen(s) + 1;
307     va_end(arg_ptr);
308
309     home = NULL;
310     if( *first_part == '~' && first_part[1] == '/'
311                            && (home = getenv("HOME")) && *home )
312         n += strlen(home);
313
314     name = jnlib_xmalloc(n);
315     p = home ? stpcpy(stpcpy(name,home), first_part+1)
316              : stpcpy(name, first_part);
317     va_start( arg_ptr, first_part ) ;
318     while( (s=va_arg(arg_ptr, const char *)) )
319         p = stpcpy(stpcpy(p,"/"), s);
320     va_end(arg_ptr);
321
322     return name;
323 }
324
325
326 int
327 compare_filenames( const char *a, const char *b )
328 {
329     /* ? check whether this is an absolute filename and
330      * resolve symlinks?
331      */
332 #ifdef HAVE_DRIVE_LETTERS
333     return stricmp(a,b);
334 #else
335     return strcmp(a,b);
336 #endif
337 }
338
339 /* Print a BUFFER to stream FP while replacing all control characters
340    and the character DELIM with standard C escape sequences.  Returns
341    the number of characters printed. */
342 size_t 
343 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
344                         int delim)
345 {
346   const unsigned char *p = buffer;
347   size_t count = 0;
348
349   for (; length; length--, p++, count++)
350     {
351       if (*p < 0x20 || *p == 0x7f || *p == delim)
352         {
353           putc ('\\', fp);
354           count++;
355           if (*p == '\n')
356             putc ('n', fp);
357           else if (*p == '\r')
358             putc ('r', fp);
359           else if (*p == '\f')
360             putc ('f', fp);
361           else if (*p == '\v')
362             putc ('v', fp);
363           else if (*p == '\b')
364             putc ('b', fp);
365           else if (!*p)
366             putc('0', fp);
367           else
368             {
369               fprintf (fp, "x%02x", *p);
370               count += 2;
371             }
372         }
373       else
374         putc (*p, fp);
375     }
376
377   return count;
378 }
379
380 size_t 
381 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
382                              size_t length, int delim)
383 {
384   const char *p = buffer;
385   size_t i;
386
387   /* We can handle plain ascii simpler, so check for it first. */
388   for (i=0; i < length; i++ ) 
389     {
390       if ( (p[i] & 0x80) )
391         break;
392     }
393   if (i < length)
394     {
395         char *buf = utf8_to_native (p, length, delim);
396         /*(utf8 conversion already does the control character quoting)*/
397         i = strlen (buf);
398         fputs (buf, fp);
399         jnlib_free (buf);
400         return i;
401     }
402   else
403     return print_sanitized_buffer (fp, p, length, delim);
404 }
405
406
407 size_t 
408 print_sanitized_string (FILE *fp, const char *string, int delim)
409 {
410   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
411 }
412
413 size_t 
414 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
415 {
416   return string? print_sanitized_utf8_buffer (fp,
417                                               string, strlen (string),
418                                               delim) : 0;
419 }
420
421 /* Create a string from the buffer P_ARG of length N which is suitable for
422    printing.  Caller must release the created string using xfree. */
423 char *
424 sanitize_buffer (const void *p_arg, size_t n, int delim)
425 {
426   const unsigned char *p = p_arg;
427   size_t save_n, buflen;
428   const unsigned char *save_p;
429   char *buffer, *d;
430
431   /* first count length */
432   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
433     {
434       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
435         {
436           if ( *p=='\n' || *p=='\r' || *p=='\f'
437                || *p=='\v' || *p=='\b' || !*p )
438             buflen += 2;
439           else
440             buflen += 4;
441         }
442       else
443         buflen++;
444     }
445   p = save_p;
446   n = save_n;
447   /* and now make the string */
448   d = buffer = jnlib_xmalloc( buflen );
449   for ( ; n; n--, p++ )
450     {
451       if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
452         *d++ = '\\';
453         if( *p == '\n' )
454           *d++ = 'n';
455         else if( *p == '\r' )
456           *d++ = 'r';
457         else if( *p == '\f' )
458           *d++ = 'f';
459         else if( *p == '\v' )
460           *d++ = 'v';
461         else if( *p == '\b' )
462           *d++ = 'b';
463         else if( !*p )
464           *d++ = '0';
465         else {
466           sprintf(d, "x%02x", *p );
467           d += 2;
468         }
469       }
470       else
471         *d++ = *p;
472     }
473   *d = 0;
474   return buffer;
475 }
476
477
478 /****************************************************
479  **********  W32 specific functions  ****************
480  ****************************************************/
481
482 #ifdef HAVE_W32_SYSTEM
483 const char *
484 w32_strerror (int ec)
485 {
486   static char strerr[256];
487   
488   if (ec == -1)
489     ec = (int)GetLastError ();
490   FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
491                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
492                  strerr, DIM (strerr)-1, NULL);
493   return strerr;    
494 }
495 #endif /*HAVE_W32_SYSTEM*/
496
497
498 /****************************************************
499  ******** Locale insensitive ctype functions ********
500  ****************************************************/
501 /* FIXME: replace them by a table lookup and macros */
502 int
503 ascii_isupper (int c)
504 {
505     return c >= 'A' && c <= 'Z';
506 }
507
508 int
509 ascii_islower (int c)
510 {
511     return c >= 'a' && c <= 'z';
512 }
513
514 int 
515 ascii_toupper (int c)
516 {
517     if (c >= 'a' && c <= 'z')
518         c &= ~0x20;
519     return c;
520 }
521
522 int 
523 ascii_tolower (int c)
524 {
525     if (c >= 'A' && c <= 'Z')
526         c |= 0x20;
527     return c;
528 }
529
530
531 int
532 ascii_strcasecmp( const char *a, const char *b )
533 {
534     if (a == b)
535         return 0;
536
537     for (; *a && *b; a++, b++) {
538         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
539             break;
540     }
541     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
542 }
543
544 int 
545 ascii_strncasecmp (const char *a, const char *b, size_t n)
546 {
547   const unsigned char *p1 = (const unsigned char *)a;
548   const unsigned char *p2 = (const unsigned char *)b;
549   unsigned char c1, c2;
550
551   if (p1 == p2 || !n )
552     return 0;
553
554   do
555     {
556       c1 = ascii_tolower (*p1);
557       c2 = ascii_tolower (*p2);
558
559       if ( !--n || c1 == '\0')
560         break;
561
562       ++p1;
563       ++p2;
564     }
565   while (c1 == c2);
566   
567   return c1 - c2;
568 }
569
570
571 int
572 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
573 {
574   const char *a = a_arg;
575   const char *b = b_arg;
576
577   if (a == b)
578     return 0;
579   for ( ; n; n--, a++, b++ )
580     {
581       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
582         return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
583     }
584   return 0;
585 }
586
587 int
588 ascii_strcmp( const char *a, const char *b )
589 {
590     if (a == b)
591         return 0;
592
593     for (; *a && *b; a++, b++) {
594         if (*a != *b )
595             break;
596     }
597     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
598 }
599
600
601 void *
602 ascii_memcasemem (const void *haystack, size_t nhaystack,
603                   const void *needle, size_t nneedle)
604 {
605
606   if (!nneedle)
607     return (void*)haystack; /* finding an empty needle is really easy */
608   if (nneedle <= nhaystack)
609     {
610       const char *a = haystack;
611       const char *b = a + nhaystack - nneedle;
612       
613       for (; a <= b; a++)
614         {
615           if ( !ascii_memcasecmp (a, needle, nneedle) )
616             return (void *)a;
617         }
618     }
619   return NULL;
620 }
621
622 /*********************************************
623  ********** missing string functions *********
624  *********************************************/
625
626 #ifndef HAVE_STPCPY
627 char *
628 stpcpy(char *a,const char *b)
629 {
630     while( *b )
631         *a++ = *b++;
632     *a = 0;
633
634     return (char*)a;
635 }
636 #endif
637
638 #ifndef HAVE_STRLWR
639 char *
640 strlwr(char *s)
641 {
642     char *p;
643     for(p=s; *p; p++ )
644         *p = tolower(*p);
645     return s;
646 }
647 #endif
648
649
650 #ifndef HAVE_STRCASECMP
651 int
652 strcasecmp( const char *a, const char *b )
653 {
654     for( ; *a && *b; a++, b++ ) {
655         if( *a != *b && toupper(*a) != toupper(*b) )
656             break;
657     }
658     return *(const byte*)a - *(const byte*)b;
659 }
660 #endif
661
662
663 /****************
664  * mingw32/cpd has a memicmp()
665  */
666 #ifndef HAVE_MEMICMP
667 int
668 memicmp( const char *a, const char *b, size_t n )
669 {
670     for( ; n; n--, a++, b++ )
671         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
672             return *(const byte *)a - *(const byte*)b;
673     return 0;
674 }
675 #endif
676
677