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
28 #ifdef HAVE_W32_SYSTEM
32 #include "libjnlib-config.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.
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
;
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
-- )
58 return (const char*)buf
;
60 s
= (const unsigned char *)sub
;
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
;
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
-- )
83 return (const char*)buf
;
84 t
= (const unsigned char *)buf
;
85 s
= (const unsigned char *)sub
;
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
100 mem2str( char *dest
, const void *src
, size_t n
)
107 dest
= jnlib_xmalloc( n
) ;
110 for(n
--; n
&& *s
; n
-- )
120 * remove leading and trailing white spaces
123 trim_spaces( char *str
)
125 char *string
, *p
, *mark
;
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
) ) {
140 *mark
= '\0' ; /* remove trailing spaces */
146 * remove trailing white spaces
149 trim_trailing_spaces( char *string
)
153 for( mark
= NULL
, p
= string
; *p
; p
++ ) {
154 if( isspace( *(byte
*)p
) ) {
169 trim_trailing_chars( byte
*line
, unsigned len
, const char *trimchars
)
174 for(mark
=NULL
, p
=line
, n
=0; n
< len
; n
++, p
++ ) {
175 if( strchr(trimchars
, *p
) ) {
191 * remove trailing white spaces and return the length of the buffer
194 trim_trailing_ws( byte
*line
, unsigned len
)
196 return trim_trailing_chars( line
, len
, " \t\r\n" );
200 length_sans_trailing_chars (const unsigned char *line
, size_t len
,
201 const char *trimchars
)
203 const unsigned char *p
, *mark
;
206 for( mark
=NULL
, p
=line
, n
=0; n
< len
; n
++, p
++ )
208 if (strchr (trimchars
, *p
))
223 * Return the length of line ignoring trailing white-space.
226 length_sans_trailing_ws (const unsigned char *line
, size_t len
)
228 return length_sans_trailing_chars (line
, len
, " \t\r\n");
234 * Extract from a given path the filename component.
238 make_basename(const char *filepath
, const char *inputpath
)
243 return riscos_make_basename(filepath
, inputpath
);
246 if ( !(p
=strrchr(filepath
, '/')) )
247 #ifdef HAVE_DRIVE_LETTERS
248 if ( !(p
=strrchr(filepath
, '\\')) )
249 if ( !(p
=strrchr(filepath
, ':')) )
252 return jnlib_xstrdup(filepath
);
255 return jnlib_xstrdup(p
+1);
261 * Extract from a given filename the path prepended to it.
262 * If their isn't a path prepended to the filename, a dot
267 make_dirname(const char *filepath
)
273 if ( !(p
=strrchr(filepath
, '/')) )
274 #ifdef HAVE_DRIVE_LETTERS
275 if ( !(p
=strrchr(filepath
, '\\')) )
276 if ( !(p
=strrchr(filepath
, ':')) )
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;
293 * Construct a filename from the NULL terminated list of parts.
294 * Tilde expansion is done here.
297 make_filename( const char *first_part
, ... )
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 *)) )
311 if( *first_part
== '~' && first_part
[1] == '/'
312 && (home
= getenv("HOME")) && *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
);
328 compare_filenames( const char *a
, const char *b
)
330 /* ? check whether this is an absolute filename and
333 #ifdef HAVE_DRIVE_LETTERS
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
)
348 if ( *s
>= '0' && *s
<= '9' )
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');
357 if ( *s
>= '0' && *s
<= '9' )
359 else if ( *s
>= 'A' && *s
<= 'F' )
361 else if ( *s
>= 'a' && *s
<= 'f' )
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. */
373 print_sanitized_buffer2 (FILE *fp
, const void *buffer
, size_t length
,
374 int delim
, int delim2
)
376 const unsigned char *p
= buffer
;
379 for (; length
; length
--, p
++, count
++)
381 /* Fixme: Check whether *p < 0xa0 is correct for utf8 encoding. */
383 || (*p
>= 0x7f && *p
< 0xa0)
386 || ((delim
|| delim2
) && *p
=='\\'))
422 fprintf (fp
, "x%02x", *p
);
436 /* Same as print_sanitized_buffer2 but with just one delimiter. */
438 print_sanitized_buffer (FILE *fp
, const void *buffer
, size_t length
,
441 return print_sanitized_buffer2 (fp
, buffer
, length
, delim
, 0);
446 print_sanitized_utf8_buffer (FILE *fp
, const void *buffer
,
447 size_t length
, int delim
)
449 const char *p
= buffer
;
452 /* We can handle plain ascii simpler, so check for it first. */
453 for (i
=0; i
< length
; i
++ )
460 char *buf
= utf8_to_native (p
, length
, delim
);
461 /*(utf8 conversion already does the control character quoting)*/
468 return print_sanitized_buffer (fp
, p
, length
, delim
);
473 print_sanitized_string2 (FILE *fp
, const char *string
, int delim
, int delim2
)
475 return string
? print_sanitized_buffer2 (fp
, string
, strlen (string
),
480 print_sanitized_string (FILE *fp
, const char *string
, int delim
)
482 return string
? print_sanitized_buffer (fp
, string
, strlen (string
), delim
):0;
486 print_sanitized_utf8_string (FILE *fp
, const char *string
, int delim
)
488 return string
? print_sanitized_utf8_buffer (fp
,
489 string
, strlen (string
),
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. */
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
;
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
)
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
=='\\')) {
527 else if( *p
== '\r' )
529 else if( *p
== '\f' )
531 else if( *p
== '\v' )
533 else if( *p
== '\b' )
538 sprintf(d
, "x%02x", *p
);
550 /****************************************************
551 ********** W32 specific functions ****************
552 ****************************************************/
554 #ifdef HAVE_W32_SYSTEM
556 w32_strerror (int ec
)
558 static char strerr
[256];
561 ec
= (int)GetLastError ();
562 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, ec
,
563 MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
),
564 strerr
, DIM (strerr
)-1, NULL
);
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';
587 ascii_toupper (int c
)
589 if (c
>= 'a' && c
<= 'z')
595 ascii_tolower (int c
)
597 if (c
>= 'A' && c
<= 'Z')
604 ascii_strcasecmp( const char *a
, const char *b
)
609 for (; *a
&& *b
; a
++, b
++) {
610 if (*a
!= *b
&& ascii_toupper(*a
) != ascii_toupper(*b
))
613 return *a
== *b
? 0 : (ascii_toupper (*a
) - ascii_toupper (*b
));
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
;
628 c1
= ascii_tolower (*p1
);
629 c2
= ascii_tolower (*p2
);
631 if ( !--n
|| c1
== '\0')
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
;
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
));
660 ascii_strcmp( const char *a
, const char *b
)
665 for (; *a
&& *b
; a
++, b
++) {
669 return *a
== *b
? 0 : (*(signed char *)a
- *(signed char *)b
);
674 ascii_memcasemem (const void *haystack
, size_t nhaystack
,
675 const void *needle
, size_t 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
;
687 if ( !ascii_memcasecmp (a
, needle
, nneedle
) )
694 /*********************************************
695 ********** missing string functions *********
696 *********************************************/
700 stpcpy(char *a
,const char *b
)
711 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
713 strsep (char **stringp
, const char *delim
)
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')
734 else if (*begin
== '\0')
737 end
= strchr (begin
+ 1, ch
);
741 /* Find the end of the token. */
742 end
= strpbrk (begin
, delim
);
746 /* Terminate the token and set *STRINGP past NUL character. */
751 /* No more delimiters; this is the last token. */
756 #endif /*HAVE_STRSEP*/
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
) )
779 return *(const byte
*)a
- *(const byte
*)b
;
785 * mingw32/cpd has a 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
;
801 memrchr (const void *buffer
, int c
, size_t n
)
803 const unsigned char *p
= buffer
;
805 for (p
+= n
; n
; n
--)
810 #endif /*HAVE_MEMRCHR*/