2006-10-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / jnlib / stringhelp.c
blob1731dd9460ebb7b1b80cdb09ab16cf48b58ff97f
1 /* stringhelp.c - standard string helper functions
2 * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
3 * 2006 Free Software Foundation, Inc.
5 * This file is part of JNLIB.
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.
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.
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.
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
32 #include "libjnlib-config.h"
33 #include "utf8conv.h"
34 #include "stringhelp.h"
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.
42 const char *
43 memistr (const void *buffer, size_t buflen, const char *sub)
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;
50 for ( ; n ; t++, n-- )
52 if ( toupper (*t) == toupper (*s) )
54 for ( buf=t++, buflen = n--, s++;
55 n && toupper (*t) == toupper (*s); t++, s++, n-- )
57 if (!*s)
58 return (const char*)buf;
59 t = buf;
60 s = (const unsigned char *)sub ;
61 n = buflen;
64 return NULL;
67 const char *
68 ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
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;
75 for ( ; n ; t++, n-- )
77 if (ascii_toupper (*t) == ascii_toupper (*s) )
79 for ( buf=t++, buflen = n--, s++;
80 n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- )
82 if (!*s)
83 return (const char*)buf;
84 t = (const unsigned char *)buf;
85 s = (const unsigned char *)sub ;
86 n = buflen;
89 return NULL;
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.
99 char *
100 mem2str( char *dest , const void *src , size_t n )
102 char *d;
103 const char *s;
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' ;
115 return dest ;
119 /****************
120 * remove leading and trailing white spaces
122 char *
123 trim_spaces( char *str )
125 char *string, *p, *mark;
127 string = str;
128 /* find first non space character */
129 for( p=string; *p && isspace( *(byte*)p ) ; p++ )
131 /* move characters */
132 for( (mark = NULL); (*string = *p); string++, p++ )
133 if( isspace( *(byte*)p ) ) {
134 if( !mark )
135 mark = string ;
137 else
138 mark = NULL ;
139 if( mark )
140 *mark = '\0' ; /* remove trailing spaces */
142 return str ;
145 /****************
146 * remove trailing white spaces
148 char *
149 trim_trailing_spaces( char *string )
151 char *p, *mark;
153 for( mark = NULL, p = string; *p; p++ ) {
154 if( isspace( *(byte*)p ) ) {
155 if( !mark )
156 mark = p;
158 else
159 mark = NULL;
161 if( mark )
162 *mark = '\0' ;
164 return string ;
168 unsigned
169 trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
171 byte *p, *mark;
172 unsigned n;
174 for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
175 if( strchr(trimchars, *p ) ) {
176 if( !mark )
177 mark = p;
179 else
180 mark = NULL;
183 if( mark ) {
184 *mark = 0;
185 return mark - line;
187 return len;
190 /****************
191 * remove trailing white spaces and return the length of the buffer
193 unsigned
194 trim_trailing_ws( byte *line, unsigned len )
196 return trim_trailing_chars( line, len, " \t\r\n" );
199 size_t
200 length_sans_trailing_chars (const unsigned char *line, size_t len,
201 const char *trimchars )
203 const unsigned char *p, *mark;
204 size_t n;
206 for( mark=NULL, p=line, n=0; n < len; n++, p++ )
208 if (strchr (trimchars, *p ))
210 if( !mark )
211 mark = p;
213 else
214 mark = NULL;
217 if (mark)
218 return mark - line;
219 return len;
223 * Return the length of line ignoring trailing white-space.
225 size_t
226 length_sans_trailing_ws (const unsigned char *line, size_t len)
228 return length_sans_trailing_chars (line, len, " \t\r\n");
233 /***************
234 * Extract from a given path the filename component.
237 char *
238 make_basename(const char *filepath, const char *inputpath)
240 char *p;
242 #ifdef __riscos__
243 return riscos_make_basename(filepath, inputpath);
244 #endif
246 if ( !(p=strrchr(filepath, '/')) )
247 #ifdef HAVE_DRIVE_LETTERS
248 if ( !(p=strrchr(filepath, '\\')) )
249 if ( !(p=strrchr(filepath, ':')) )
250 #endif
252 return jnlib_xstrdup(filepath);
255 return jnlib_xstrdup(p+1);
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 ('.').
266 char *
267 make_dirname(const char *filepath)
269 char *dirname;
270 int dirname_length;
271 char *p;
273 if ( !(p=strrchr(filepath, '/')) )
274 #ifdef HAVE_DRIVE_LETTERS
275 if ( !(p=strrchr(filepath, '\\')) )
276 if ( !(p=strrchr(filepath, ':')) )
277 #endif
279 return jnlib_xstrdup(".");
282 dirname_length = p-filepath;
283 dirname = jnlib_xmalloc(dirname_length+1);
284 strncpy(dirname, filepath, dirname_length);
285 dirname[dirname_length] = 0;
287 return dirname;
292 /****************
293 * Construct a filename from the NULL terminated list of parts.
294 * Tilde expansion is done here.
296 char *
297 make_filename( const char *first_part, ... )
299 va_list arg_ptr ;
300 size_t n;
301 const char *s;
302 char *name, *home, *p;
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);
310 home = NULL;
311 if( *first_part == '~' && first_part[1] == '/'
312 && (home = getenv("HOME")) && *home )
313 n += strlen(home);
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);
323 return name;
328 compare_filenames( const char *a, const char *b )
330 /* ? check whether this is an absolute filename and
331 * resolve symlinks?
333 #ifdef HAVE_DRIVE_LETTERS
334 return stricmp(a,b);
335 #else
336 return strcmp(a,b);
337 #endif
341 /* Convert 2 hex characters at S to a byte value. Return this value
342 or -1 if there is an error. */
344 hextobyte (const char *s)
346 int c;
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;
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)
376 const unsigned char *p = buffer;
377 size_t count = 0;
379 for (; length; length--, p++, count++)
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=='\\'))
388 putc ('\\', fp);
389 count++;
390 if (*p == '\n')
392 putc ('n', fp);
393 count++;
395 else if (*p == '\r')
397 putc ('r', fp);
398 count++;
400 else if (*p == '\f')
402 putc ('f', fp);
403 count++;
405 else if (*p == '\v')
407 putc ('v', fp);
408 count++;
410 else if (*p == '\b')
412 putc ('b', fp);
413 count++;
415 else if (!*p)
417 putc('0', fp);
418 count++;
420 else
422 fprintf (fp, "x%02x", *p);
423 count += 3;
426 else
428 putc (*p, fp);
429 count++;
433 return count;
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)
441 return print_sanitized_buffer2 (fp, buffer, length, delim, 0);
445 size_t
446 print_sanitized_utf8_buffer (FILE *fp, const void *buffer,
447 size_t length, int delim)
449 const char *p = buffer;
450 size_t i;
452 /* We can handle plain ascii simpler, so check for it first. */
453 for (i=0; i < length; i++ )
455 if ( (p[i] & 0x80) )
456 break;
458 if (i < length)
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;
467 else
468 return print_sanitized_buffer (fp, p, length, delim);
472 size_t
473 print_sanitized_string2 (FILE *fp, const char *string, int delim, int delim2)
475 return string? print_sanitized_buffer2 (fp, string, strlen (string),
476 delim, delim2):0;
479 size_t
480 print_sanitized_string (FILE *fp, const char *string, int delim)
482 return string? print_sanitized_buffer (fp, string, strlen (string), delim):0;
485 size_t
486 print_sanitized_utf8_string (FILE *fp, const char *string, int delim)
488 return string? print_sanitized_utf8_buffer (fp,
489 string, strlen (string),
490 delim) : 0;
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)
498 const unsigned char *p = p_arg;
499 size_t save_n, buflen;
500 const unsigned char *save_p;
501 char *buffer, *d;
503 /* First count length. */
504 for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
506 if ( *p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\'))
508 if ( *p=='\n' || *p=='\r' || *p=='\f'
509 || *p=='\v' || *p=='\b' || !*p )
510 buflen += 2;
511 else
512 buflen += 5;
514 else
515 buflen++;
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++ )
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;
542 else
543 *d++ = *p;
545 *d = 0;
546 return buffer;
550 /****************************************************
551 ********** W32 specific functions ****************
552 ****************************************************/
554 #ifdef HAVE_W32_SYSTEM
555 const char *
556 w32_strerror (int ec)
558 static char strerr[256];
560 if (ec == -1)
561 ec = (int)GetLastError ();
562 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
563 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
564 strerr, DIM (strerr)-1, NULL);
565 return strerr;
567 #endif /*HAVE_W32_SYSTEM*/
570 /****************************************************
571 ******** Locale insensitive ctype functions ********
572 ****************************************************/
573 /* FIXME: replace them by a table lookup and macros */
575 ascii_isupper (int c)
577 return c >= 'A' && c <= 'Z';
581 ascii_islower (int c)
583 return c >= 'a' && c <= 'z';
586 int
587 ascii_toupper (int c)
589 if (c >= 'a' && c <= 'z')
590 c &= ~0x20;
591 return c;
594 int
595 ascii_tolower (int c)
597 if (c >= 'A' && c <= 'Z')
598 c |= 0x20;
599 return c;
604 ascii_strcasecmp( const char *a, const char *b )
606 if (a == b)
607 return 0;
609 for (; *a && *b; a++, b++) {
610 if (*a != *b && ascii_toupper(*a) != ascii_toupper(*b))
611 break;
613 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
616 int
617 ascii_strncasecmp (const char *a, const char *b, size_t n)
619 const unsigned char *p1 = (const unsigned char *)a;
620 const unsigned char *p2 = (const unsigned char *)b;
621 unsigned char c1, c2;
623 if (p1 == p2 || !n )
624 return 0;
628 c1 = ascii_tolower (*p1);
629 c2 = ascii_tolower (*p2);
631 if ( !--n || c1 == '\0')
632 break;
634 ++p1;
635 ++p2;
637 while (c1 == c2);
639 return c1 - c2;
644 ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n )
646 const char *a = a_arg;
647 const char *b = b_arg;
649 if (a == b)
650 return 0;
651 for ( ; n; n--, a++, b++ )
653 if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) )
654 return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b));
656 return 0;
660 ascii_strcmp( const char *a, const char *b )
662 if (a == b)
663 return 0;
665 for (; *a && *b; a++, b++) {
666 if (*a != *b )
667 break;
669 return *a == *b? 0 : (*(signed char *)a - *(signed char *)b);
673 void *
674 ascii_memcasemem (const void *haystack, size_t nhaystack,
675 const void *needle, size_t nneedle)
678 if (!nneedle)
679 return (void*)haystack; /* finding an empty needle is really easy */
680 if (nneedle <= nhaystack)
682 const char *a = haystack;
683 const char *b = a + nhaystack - nneedle;
685 for (; a <= b; a++)
687 if ( !ascii_memcasecmp (a, needle, nneedle) )
688 return (void *)a;
691 return NULL;
694 /*********************************************
695 ********** missing string functions *********
696 *********************************************/
698 #ifndef HAVE_STPCPY
699 char *
700 stpcpy(char *a,const char *b)
702 while( *b )
703 *a++ = *b++;
704 *a = 0;
706 return (char*)a;
708 #endif
710 #ifndef HAVE_STRSEP
711 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
712 char *
713 strsep (char **stringp, const char *delim)
715 char *begin, *end;
717 begin = *stringp;
718 if (begin == NULL)
719 return NULL;
721 /* A frequent case is when the delimiter string contains only one
722 character. Here we don't need to call the expensive `strpbrk'
723 function and instead work using `strchr'. */
724 if (delim[0] == '\0' || delim[1] == '\0')
726 char ch = delim[0];
728 if (ch == '\0')
729 end = NULL;
730 else
732 if (*begin == ch)
733 end = begin;
734 else if (*begin == '\0')
735 end = NULL;
736 else
737 end = strchr (begin + 1, ch);
740 else
741 /* Find the end of the token. */
742 end = strpbrk (begin, delim);
744 if (end)
746 /* Terminate the token and set *STRINGP past NUL character. */
747 *end++ = '\0';
748 *stringp = end;
750 else
751 /* No more delimiters; this is the last token. */
752 *stringp = NULL;
754 return begin;
756 #endif /*HAVE_STRSEP*/
759 #ifndef HAVE_STRLWR
760 char *
761 strlwr(char *s)
763 char *p;
764 for(p=s; *p; p++ )
765 *p = tolower(*p);
766 return s;
768 #endif
771 #ifndef HAVE_STRCASECMP
773 strcasecmp( const char *a, const char *b )
775 for( ; *a && *b; a++, b++ ) {
776 if( *a != *b && toupper(*a) != toupper(*b) )
777 break;
779 return *(const byte*)a - *(const byte*)b;
781 #endif
784 /****************
785 * mingw32/cpd has a memicmp()
787 #ifndef HAVE_MEMICMP
789 memicmp( const char *a, const char *b, size_t n )
791 for( ; n; n--, a++, b++ )
792 if( *a != *b && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
793 return *(const byte *)a - *(const byte*)b;
794 return 0;
796 #endif
799 #ifndef HAVE_MEMRCHR
800 void *
801 memrchr (const void *buffer, int c, size_t n)
803 const unsigned char *p = buffer;
805 for (p += n; n ; n--)
806 if (*--p == c)
807 return p;
808 return NULL;
810 #endif /*HAVE_MEMRCHR*/