Make use of libgpg-error
[gnupg.git] / jnlib / stringhelp.c
1 /* stringhelp.c -  standard string helper functions
2  *      Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <ctype.h>
26
27 #include "libjnlib-config.h"
28 #include "stringhelp.h"
29
30
31 /****************
32  * look for the substring SUB in buffer and return a pointer to that
33  * substring in BUF or NULL if not found.
34  * Comparison is case-insensitive.
35  */
36 const char *
37 memistr( const char *buf, size_t buflen, const char *sub )
38 {
39     const byte *t, *s ;
40     size_t n;
41
42     for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
43         if( toupper(*t) == toupper(*s) ) {
44             for( buf=t++, buflen = n--, s++;
45                  n && toupper(*t) == toupper(*s); t++, s++, n-- )
46                 ;
47             if( !*s )
48                 return buf;
49             t = buf; n = buflen; s = sub ;
50         }
51
52     return NULL ;
53 }
54
55 /****************
56  * Wie strncpy(), aber es werden maximal n-1 zeichen kopiert und ein
57  * '\0' angehängt. Ist n = 0, so geschieht nichts, ist Destination
58  * gleich NULL, so wird via jnlib_xmalloc Speicher besorgt, ist dann nicht
59  * genügend Speicher vorhanden, so bricht die funktion ab.
60  */
61 char *
62 mem2str( char *dest , const void *src , size_t n )
63 {
64     char *d;
65     const char *s;
66
67     if( n ) {
68         if( !dest )
69             dest = jnlib_xmalloc( n ) ;
70         d = dest;
71         s = src ;
72         for(n--; n && *s; n-- )
73             *d++ = *s++;
74         *d = '\0' ;
75     }
76
77     return dest ;
78 }
79
80
81 /****************
82  * remove leading and trailing white spaces
83  */
84 char *
85 trim_spaces( char *str )
86 {
87     char *string, *p, *mark;
88
89     string = str;
90     /* find first non space character */
91     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
92         ;
93     /* move characters */
94     for( (mark = NULL); (*string = *p); string++, p++ )
95         if( isspace( *(byte*)p ) ) {
96             if( !mark )
97                 mark = string ;
98         }
99         else
100             mark = NULL ;
101     if( mark )
102         *mark = '\0' ;  /* remove trailing spaces */
103
104     return str ;
105 }
106
107 /****************
108  * remove trailing white spaces
109  */
110 char *
111 trim_trailing_spaces( char *string )
112 {
113     char *p, *mark;
114
115     for( mark = NULL, p = string; *p; p++ ) {
116         if( isspace( *(byte*)p ) ) {
117             if( !mark )
118                 mark = p;
119         }
120         else
121             mark = NULL;
122     }
123     if( mark )
124         *mark = '\0' ;
125
126     return string ;
127 }
128
129
130
131 unsigned
132 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
133 {
134     byte *p, *mark;
135     unsigned n;
136
137     for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
138         if( strchr(trimchars, *p ) ) {
139             if( !mark )
140                 mark = p;
141         }
142         else
143             mark = NULL;
144     }
145
146     if( mark ) {
147         *mark = 0;
148         return mark - line;
149     }
150     return len;
151 }
152
153 /****************
154  * remove trailing white spaces and return the length of the buffer
155  */
156 unsigned
157 trim_trailing_ws( byte *line, unsigned len )
158 {
159     return trim_trailing_chars( line, len, " \t\r\n" );
160 }
161
162
163 /***************
164  * Extract from a given path the filename component.
165  *
166  */
167 char *
168 make_basename(const char *filepath)
169 {
170     char *p;
171
172     if ( !(p=strrchr(filepath, '/')) )
173       #ifdef HAVE_DRIVE_LETTERS
174         if ( !(p=strrchr(filepath, '\\')) )
175             if ( !(p=strrchr(filepath, ':')) )
176       #endif
177               {
178                 return jnlib_xstrdup(filepath);
179               }
180
181     return jnlib_xstrdup(p+1);
182 }
183
184
185
186 /***************
187  * Extract from a given filename the path prepended to it.
188  * If their isn't a path prepended to the filename, a dot
189  * is returned ('.').
190  *
191  */
192 char *
193 make_dirname(const char *filepath)
194 {
195     char *dirname;
196     int  dirname_length;
197     char *p;
198
199     if ( !(p=strrchr(filepath, '/')) )
200       #ifdef HAVE_DRIVE_LETTERS
201         if ( !(p=strrchr(filepath, '\\')) )
202             if ( !(p=strrchr(filepath, ':')) )
203       #endif
204               {
205                 return jnlib_xstrdup(".");
206               }
207
208     dirname_length = p-filepath;
209     dirname = jnlib_xmalloc(dirname_length+1);
210     strncpy(dirname, filepath, dirname_length);
211     dirname[dirname_length] = 0;
212
213     return dirname;
214 }
215
216
217
218 /****************
219  * Construct a filename from the NULL terminated list of parts.
220  * Tilde expansion is done here.
221  */
222 char *
223 make_filename( const char *first_part, ... )
224 {
225     va_list arg_ptr ;
226     size_t n;
227     const char *s;
228     char *name, *home, *p;
229
230     va_start( arg_ptr, first_part ) ;
231     n = strlen(first_part)+1;
232     while( (s=va_arg(arg_ptr, const char *)) )
233         n += strlen(s) + 1;
234     va_end(arg_ptr);
235
236     home = NULL;
237     if( *first_part == '~' && first_part[1] == '/'
238                            && (home = getenv("HOME")) && *home )
239         n += strlen(home);
240
241     name = jnlib_xmalloc(n);
242     p = home ? stpcpy(stpcpy(name,home), first_part+1)
243              : stpcpy(name, first_part);
244     va_start( arg_ptr, first_part ) ;
245     while( (s=va_arg(arg_ptr, const char *)) )
246         p = stpcpy(stpcpy(p,"/"), s);
247     va_end(arg_ptr);
248
249     return name;
250 }
251
252
253 int
254 compare_filenames( const char *a, const char *b )
255 {
256     /* ? check whether this is an absolute filename and
257      * resolve symlinks?
258      */
259   #ifdef HAVE_DRIVE_LETTERS
260     return stricmp(a,b);
261   #else
262     return strcmp(a,b);
263   #endif
264 }
265
266 /* Print a BUFFER to stream FP while replacing all control characters
267    and the character DELIM with standard C eescape sequences.  Returns
268    the number of characters printed. */
269 size_t 
270 print_sanitized_buffer (FILE *fp, const void *buffer, size_t length, int delim)
271 {
272   const unsigned char *p = buffer;
273   size_t count = 0;
274
275   for (; length; length--, p++, count++)
276     {
277       if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
278         {
279           putc ('\\', fp);
280           count++;
281           if (*p == '\n')
282             putc ('n', fp);
283           else if (*p == '\r')
284             putc ('r', fp);
285           else if (*p == '\f')
286             putc ('f', fp);
287           else if (*p == '\v')
288             putc ('v', fp);
289           else if (*p == '\b')
290             putc ('b', fp);
291           else if (!*p)
292             putc('0', fp);
293           else
294             {
295               fprintf (fp, "x%02x", *p);
296               count += 2;
297             }
298         }
299       else
300         putc (*p, fp);
301     }
302
303   return count;
304 }
305
306 size_t 
307 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
308                              size_t length, int delim)
309 {
310   /* FIXME: convert to local characterset */
311   return print_sanitized_buffer (fp, buffer, length, delim);
312 }
313
314
315 size_t 
316 print_sanitized_string (FILE *fp, const char *string, int delim)
317 {
318   return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
319 }
320
321 size_t 
322 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
323 {
324   /* FIXME: convert to local characterset */
325   return print_sanitized_string (fp, string, delim);
326 }
327
328 /****************************************************
329  ******** locale insensitive ctype functions ********
330  ****************************************************/
331 /* FIXME: replace them by a table lookup and macros */
332 int
333 ascii_isupper (int c)
334 {
335     return c >= 'A' && c <= 'Z';
336 }
337
338 int
339 ascii_islower (int c)
340 {
341     return c >= 'a' && c <= 'z';
342 }
343
344 int 
345 ascii_toupper (int c)
346 {
347     if (c >= 'a' && c <= 'z')
348         c &= ~0x20;
349     return c;
350 }
351
352 int 
353 ascii_tolower (int c)
354 {
355     if (c >= 'A' && c <= 'Z')
356         c |= 0x20;
357     return c;
358 }
359
360
361 int
362 ascii_strcasecmp( const char *a, const char *b )
363 {
364     if (a == b)
365         return 0;
366
367     for (; *a && *b; a++, b++) {
368         if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
369             break;
370     }
371     return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
372 }
373
374 int
375 ascii_memcasecmp( const char *a, const char *b, size_t n )
376 {
377     if (a == b)
378         return 0;
379     for ( ; n; n--, a++, b++ ) {
380         if( *a != *b  && ascii_toupper (*a) != ascii_toupper (*b) )
381             return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
382     }
383     return 0;
384 }
385
386 int
387 ascii_strcmp( const char *a, const char *b )
388 {
389     if (a == b)
390         return 0;
391
392     for (; *a && *b; a++, b++) {
393         if (*a != *b )
394             break;
395     }
396     return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
397 }
398
399
400 void *
401 ascii_memcasemem (const void *haystack, size_t nhaystack,
402                   const void *needle, size_t nneedle)
403 {
404
405   if (!nneedle)
406     return (void*)haystack; /* finding an empty needle is really easy */
407   if (nneedle <= nhaystack)
408     {
409       const unsigned char *a = haystack;
410       const unsigned char *b = a + nhaystack - nneedle;
411       
412       for (; a <= b; a++)
413         {
414           if ( !ascii_memcasecmp (a, needle, nneedle) )
415             return (void *)a;
416         }
417     }
418   return NULL;
419 }
420
421 /*********************************************
422  ********** missing string functions *********
423  *********************************************/
424
425 #ifndef HAVE_STPCPY
426 char *
427 stpcpy(char *a,const char *b)
428 {
429     while( *b )
430         *a++ = *b++;
431     *a = 0;
432
433     return (char*)a;
434 }
435 #endif
436
437 #ifndef HAVE_STRLWR
438 char *
439 strlwr(char *s)
440 {
441     char *p;
442     for(p=s; *p; p++ )
443         *p = tolower(*p);
444     return s;
445 }
446 #endif
447
448
449 #ifndef HAVE_STRCASECMP
450 int
451 strcasecmp( const char *a, const char *b )
452 {
453     for( ; *a && *b; a++, b++ ) {
454         if( *a != *b && toupper(*a) != toupper(*b) )
455             break;
456     }
457     return *(const byte*)a - *(const byte*)b;
458 }
459 #endif
460
461
462 /****************
463  * mingw32/cpd has a memicmp()
464  */
465 #ifndef HAVE_MEMICMP
466 int
467 memicmp( const char *a, const char *b, size_t n )
468 {
469     for( ; n; n--, a++, b++ )
470         if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
471             return *(const byte *)a - *(const byte*)b;
472     return 0;
473 }
474 #endif