760398b0c4b330c7b1521b489546fa313a64cb0f
[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)
238 {
239     char *p;
240
241     if ( !(p=strrchr(filepath, '/')) )
242       #ifdef HAVE_DRIVE_LETTERS
243         if ( !(p=strrchr(filepath, '\\')) )
244             if ( !(p=strrchr(filepath, ':')) )
245       #endif
246               {
247                 return jnlib_xstrdup(filepath);
248               }
249
250     return jnlib_xstrdup(p+1);
251 }
252
253
254
255 /***************
256  * Extract from a given filename the path prepended to it.
257  * If their isn't a path prepended to the filename, a dot
258  * is returned ('.').
259  *
260  */
261 char *
262 make_dirname(const char *filepath)
263 {
264     char *dirname;
265     int  dirname_length;
266     char *p;
267
268     if ( !(p=strrchr(filepath, '/')) )
269       #ifdef HAVE_DRIVE_LETTERS
270         if ( !(p=strrchr(filepath, '\\')) )
271             if ( !(p=strrchr(filepath, ':')) )
272       #endif
273               {
274                 return jnlib_xstrdup(".");
275               }
276
277     dirname_length = p-filepath;
278     dirname = jnlib_xmalloc(dirname_length+1);
279     strncpy(dirname, filepath, dirname_length);
280     dirname[dirname_length] = 0;
281
282     return dirname;
283 }
284
285
286
287 /****************
288  * Construct a filename from the NULL terminated list of parts.
289  * Tilde expansion is done here.
290  */
291 char *
292 make_filename( const char *first_part, ... )
293 {
294     va_list arg_ptr ;
295     size_t n;
296     const char *s;
297     char *name, *home, *p;
298
299     va_start( arg_ptr, first_part ) ;
300     n = strlen(first_part)+1;
301     while( (s=va_arg(arg_ptr, const char *)) )
302         n += strlen(s) + 1;
303     va_end(arg_ptr);
304
305     home = NULL;
306     if( *first_part == '~' && first_part[1] == '/'
307                            && (home = getenv("HOME")) && *home )
308         n += strlen(home);
309
310     name = jnlib_xmalloc(n);
311     p = home ? stpcpy(stpcpy(name,home), first_part+1)
312              : stpcpy(name, first_part);
313     va_start( arg_ptr, first_part ) ;
314     while( (s=va_arg(arg_ptr, const char *)) )
315         p = stpcpy(stpcpy(p,"/"), s);
316     va_end(arg_ptr);
317
318     return name;
319 }
320
321
322 int
323 compare_filenames( const char *a, const char *b )
324 {
325     /* ? check whether this is an absolute filename and
326      * resolve symlinks?
327      */
328 #ifdef HAVE_DRIVE_LETTERS
329     return stricmp(a,b);
330 #else
331     return strcmp(a,b);
332 #endif
333 }
334
335 /* Print a BUFFER to stream FP while replacing all control characters
336    and the character DELIM with standard C escape sequences.  Returns
337    the number of characters printed. */
338 size_t 
339 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length,
340                         int delim)
341 {
342   const unsigned char *p = buffer;
343   size_t count = 0;
344
345   for (; length; length--, p++, count++)
346     {
347       if (*p < 0x20 || *p == 0x7f || *p == delim)
348         {
349           putc ('\\', fp);
350           count++;
351           if (*p == '\n')
352             putc ('n', fp);
353           else if (*p == '\r')
354             putc ('r', fp);
355           else if (*p == '\f')
356             putc ('f', fp);
357           else if (*p == '\v')
358             putc ('v', fp);
359           else if (*p == '\b')
360             putc ('b', fp);
361           else if (!*p)
362             putc('0', fp);
363           else
364             {
365               fprintf (fp, "x%02x", *p);
366               count += 2;
367             }
368         }
369       else
370         putc (*p, fp);
371     }
372
373   return count;
374 }
375
376 size_t 
377 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
378                              size_t length, int delim)
379 {
380   const char *p = buffer;
381   size_t i;
382
383   /* We can handle plain ascii simpler, so check for it first. */
384   for (i=0; i < length; i++ ) 
385     {
386       if ( (p[i] & 0x80) )
387         break;
388     }
389   if (i < length)
390     {
391         char *buf = utf8_to_native (p, length, delim);
392         /*(utf8 conversion already does the control character quoting)*/
393         i = strlen (buf);
394         fputs (buf, fp);
395         jnlib_free (buf);
396         return i;
397     }
398   else
399     return print_sanitized_buffer (fp, p, length, delim);
400 }
401
402
403 size_t 
404 print_sanitized_string (FILE *fp, const char *string, int delim)
405 {
406   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
407 }
408
409 size_t 
410 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
411 {
412   return string? print_sanitized_utf8_buffer (fp,
413                                               string, strlen (string),
414                                               delim) : 0;
415 }
416
417 /* Create a string from the buffer P_ARG of length N which is suitable for
418    printing.  Caller must release the created string using xfree. */
419 char *
420 sanitize_buffer (const void *p_arg, size_t n, int delim)
421 {
422   const unsigned char *p = p_arg;
423   size_t save_n, buflen;
424   const unsigned char *save_p;
425   char *buffer, *d;
426
427   /* first count length */
428   for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ ) 
429     {
430       if ( *p < 0x20 || *p == 0x7f || *p == delim  || (delim && *p=='\\'))
431         {
432           if ( *p=='\n' || *p=='\r' || *p=='\f'
433                || *p=='\v' || *p=='\b' || !*p )
434             buflen += 2;
435           else
436             buflen += 4;
437         }
438       else
439         buflen++;
440     }
441   p = save_p;
442   n = save_n;
443   /* and now make the string */
444   d = buffer = jnlib_xmalloc( buflen );
445   for ( ; n; n--, p++ )
446     {
447       if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
448         *d++ = '\\';
449         if( *p == '\n' )
450           *d++ = 'n';
451         else if( *p == '\r' )
452           *d++ = 'r';
453         else if( *p == '\f' )
454           *d++ = 'f';
455         else if( *p == '\v' )
456           *d++ = 'v';
457         else if( *p == '\b' )
458           *d++ = 'b';
459         else if( !*p )
460           *d++ = '0';
461         else {
462           sprintf(d, "x%02x", *p );
463           d += 2;
464         }
465       }
466       else
467         *d++ = *p;
468     }
469   *d = 0;
470   return buffer;
471 }
472
473
474 /****************************************************
475  **********  W32 specific functions  ****************
476  ****************************************************/
477
478 #ifdef HAVE_W32_SYSTEM
479 const char *
480 w32_strerror (int ec)
481 {
482   static char strerr[256];
483   
484   if (ec == -1)
485     ec = (int)GetLastError ();
486   FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
487                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
488                  strerr, DIM (strerr)-1, NULL);
489   return strerr;    
490 }
491 #endif /*HAVE_W32_SYSTEM*/
492
493
494 /****************************************************
495  ******** Locale insensitive ctype functions ********
496  ****************************************************/
497 /* FIXME: replace them by a table lookup and macros */
498 int
499 ascii_isupper (int c)
500 {
501     return c >= 'A' && c <= 'Z';
502 }
503
504 int
505 ascii_islower (int c)
506 {
507     return c >= 'a' && c <= 'z';
508 }
509
510 int 
511 ascii_toupper (int c)
512 {
513     if (c >= 'a' && c <= 'z')
514         c &= ~0x20;
515     return c;
516 }
517
518 int 
519 ascii_tolower (int c)
520 {
521     if (c >= 'A' && c <= 'Z')
522         c |= 0x20;
523     return c;
524 }
525
526
527 int
528 ascii_strcasecmp( const char *a, const char *b )
529 {
530     if (a == b)
531         return 0;
532
533     for (; *a && *b; a++, b++) {
534         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
535             break;
536     }
537     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
538 }
539
540 int 
541 ascii_strncasecmp (const char *a, const char *b, size_t n)
542 {
543   const unsigned char *p1 = (const unsigned char *)a;
544   const unsigned char *p2 = (const unsigned char *)b;
545   unsigned char c1, c2;
546
547   if (p1 == p2 || !n )
548     return 0;
549
550   do
551     {
552       c1 = ascii_tolower (*p1);
553       c2 = ascii_tolower (*p2);
554
555       if ( !--n || c1 == '\0')
556         break;
557
558       ++p1;
559       ++p2;
560     }
561   while (c1 == c2);
562   
563   return c1 - c2;
564 }
565
566
567 int
568 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
569 {
570   const char *a = a_arg;
571   const char *b = b_arg;
572
573   if (a == b)
574     return 0;
575   for ( ; n; n--, a++, b++ )
576     {
577       if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
578         return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
579     }
580   return 0;
581 }
582
583 int
584 ascii_strcmp( const char *a, const char *b )
585 {
586     if (a == b)
587         return 0;
588
589     for (; *a && *b; a++, b++) {
590         if (*a != *b )
591             break;
592     }
593     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
594 }
595
596
597 void *
598 ascii_memcasemem (const void *haystack, size_t nhaystack,
599                   const void *needle, size_t nneedle)
600 {
601
602   if (!nneedle)
603     return (void*)haystack; /* finding an empty needle is really easy */
604   if (nneedle <= nhaystack)
605     {
606       const char *a = haystack;
607       const char *b = a + nhaystack - nneedle;
608       
609       for (; a <= b; a++)
610         {
611           if ( !ascii_memcasecmp (a, needle, nneedle) )
612             return (void *)a;
613         }
614     }
615   return NULL;
616 }
617
618 /*********************************************
619  ********** missing string functions *********
620  *********************************************/
621
622 #ifndef HAVE_STPCPY
623 char *
624 stpcpy(char *a,const char *b)
625 {
626     while( *b )
627         *a++ = *b++;
628     *a = 0;
629
630     return (char*)a;
631 }
632 #endif
633
634 #ifndef HAVE_STRLWR
635 char *
636 strlwr(char *s)
637 {
638     char *p;
639     for(p=s; *p; p++ )
640         *p = tolower(*p);
641     return s;
642 }
643 #endif
644
645
646 #ifndef HAVE_STRCASECMP
647 int
648 strcasecmp( const char *a, const char *b )
649 {
650     for( ; *a && *b; a++, b++ ) {
651         if( *a != *b && toupper(*a) != toupper(*b) )
652             break;
653     }
654     return *(const byte*)a - *(const byte*)b;
655 }
656 #endif
657
658
659 /****************
660  * mingw32/cpd has a memicmp()
661  */
662 #ifndef HAVE_MEMICMP
663 int
664 memicmp( const char *a, const char *b, size_t n )
665 {
666     for( ; n; n--, a++, b++ )
667         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
668             return *(const byte *)a - *(const byte*)b;
669     return 0;
670 }
671 #endif
672
673