1 /* stringhelp.c - standard string helper functions
2 * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005,
3 * 2006, 2007 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 3 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, see <http://www.gnu.org/licenses/>.
26 #ifdef HAVE_W32_SYSTEM
30 #include "libjnlib-config.h"
32 #include "stringhelp.h"
35 #define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
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
);
317 ? stpcpy (stpcpy (name
,home
), first_part
+ 1)
318 : stpcpy(name
, first_part
));
320 va_start (arg_ptr
, first_part
) ;
321 while ( (s
= va_arg(arg_ptr
, const char *)) )
322 p
= stpcpy (stpcpy (p
,"/"), s
);
325 #ifdef HAVE_DRIVE_LETTERS
326 /* We better avoid mixing slashes and backslashes and prefer
327 backslashes. There is usual no problem with mixing them, however
328 a very few W32 API calls can't grok plain slashes. Printing
329 filenames with mixed slashes also looks a bit strange. */
330 if (strchr (name
, '\\'))
332 for (p
=name
; *p
; p
++)
336 #endif /*HAVE_DRIVE_LETTERS*/
341 /* Compare whether the filenames are identical. This is a
342 special version of strcmp() taking the semantics of filenames in
343 account. Note that this function works only on the supplied names
344 without considereing any context like the current directory. See
345 also same_file_p(). */
347 compare_filenames (const char *a
, const char *b
)
349 #ifdef HAVE_DRIVE_LETTERS
350 for ( ; *a
&& *b
; a
++, b
++ )
353 && (toupper (*(const unsigned char*)a
)
354 != toupper (*(const unsigned char*)b
) )
355 && !((*a
== '/' && *b
== '\\') || (*a
== '\\' && *b
== '/')))
358 if ((*a
== '/' && *b
== '\\') || (*a
== '\\' && *b
== '/'))
361 return (toupper (*(const unsigned char*)a
)
362 - toupper (*(const unsigned char*)b
));
369 /* Convert 2 hex characters at S to a byte value. Return this value
370 or -1 if there is an error. */
372 hextobyte (const char *s
)
376 if ( *s
>= '0' && *s
<= '9' )
378 else if ( *s
>= 'A' && *s
<= 'F' )
379 c
= 16 * (10 + *s
- 'A');
380 else if ( *s
>= 'a' && *s
<= 'f' )
381 c
= 16 * (10 + *s
- 'a');
385 if ( *s
>= '0' && *s
<= '9' )
387 else if ( *s
>= 'A' && *s
<= 'F' )
389 else if ( *s
>= 'a' && *s
<= 'f' )
397 /* Print a BUFFER to stream FP while replacing all control characters
398 and the characters DELIM and DELIM2 with standard C escape
399 sequences. Returns the number of characters printed. */
401 print_sanitized_buffer2 (FILE *fp
, const void *buffer
, size_t length
,
402 int delim
, int delim2
)
404 const unsigned char *p
= buffer
;
407 for (; length
; length
--, p
++, count
++)
409 /* Fixme: Check whether *p < 0xa0 is correct for utf8 encoding. */
411 || (*p
>= 0x7f && *p
< 0xa0)
414 || ((delim
|| delim2
) && *p
=='\\'))
450 fprintf (fp
, "x%02x", *p
);
464 /* Same as print_sanitized_buffer2 but with just one delimiter. */
466 print_sanitized_buffer (FILE *fp
, const void *buffer
, size_t length
,
469 return print_sanitized_buffer2 (fp
, buffer
, length
, delim
, 0);
474 print_sanitized_utf8_buffer (FILE *fp
, const void *buffer
,
475 size_t length
, int delim
)
477 const char *p
= buffer
;
480 /* We can handle plain ascii simpler, so check for it first. */
481 for (i
=0; i
< length
; i
++ )
488 char *buf
= utf8_to_native (p
, length
, delim
);
489 /*(utf8 conversion already does the control character quoting)*/
496 return print_sanitized_buffer (fp
, p
, length
, delim
);
501 print_sanitized_string2 (FILE *fp
, const char *string
, int delim
, int delim2
)
503 return string
? print_sanitized_buffer2 (fp
, string
, strlen (string
),
508 print_sanitized_string (FILE *fp
, const char *string
, int delim
)
510 return string
? print_sanitized_buffer (fp
, string
, strlen (string
), delim
):0;
514 print_sanitized_utf8_string (FILE *fp
, const char *string
, int delim
)
516 return string
? print_sanitized_utf8_buffer (fp
,
517 string
, strlen (string
),
521 /* Create a string from the buffer P_ARG of length N which is suitable for
522 printing. Caller must release the created string using xfree. */
524 sanitize_buffer (const void *p_arg
, size_t n
, int delim
)
526 const unsigned char *p
= p_arg
;
527 size_t save_n
, buflen
;
528 const unsigned char *save_p
;
531 /* First count length. */
532 for (save_n
= n
, save_p
= p
, buflen
=1 ; n
; n
--, p
++ )
534 if ( *p
< 0x20 || *p
== 0x7f || *p
== delim
|| (delim
&& *p
=='\\'))
536 if ( *p
=='\n' || *p
=='\r' || *p
=='\f'
537 || *p
=='\v' || *p
=='\b' || !*p
)
547 /* And now make the string */
548 d
= buffer
= jnlib_xmalloc( buflen
);
549 for ( ; n
; n
--, p
++ )
551 if (*p
< 0x20 || *p
== 0x7f || *p
== delim
|| (delim
&& *p
=='\\')) {
555 else if( *p
== '\r' )
557 else if( *p
== '\f' )
559 else if( *p
== '\v' )
561 else if( *p
== '\b' )
566 sprintf(d
, "x%02x", *p
);
578 /* Given a string containing an UTF-8 encoded text, return the number
579 of characters in this string. It differs from strlen in that it
580 only counts complete UTF-8 characters. Note, that this function
581 does not take combined characters into account. */
583 utf8_charcount (const char *s
)
588 if ( (*s
&0xc0) != 0x80 ) /* Exclude continuation bytes: 10xxxxxx */
595 /****************************************************
596 ********** W32 specific functions ****************
597 ****************************************************/
599 #ifdef HAVE_W32_SYSTEM
601 w32_strerror (int ec
)
603 static char strerr
[256];
606 ec
= (int)GetLastError ();
607 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, ec
,
608 MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
),
609 strerr
, DIM (strerr
)-1, NULL
);
612 #endif /*HAVE_W32_SYSTEM*/
615 /****************************************************
616 ******** Locale insensitive ctype functions ********
617 ****************************************************/
618 /* FIXME: replace them by a table lookup and macros */
620 ascii_isupper (int c
)
622 return c
>= 'A' && c
<= 'Z';
626 ascii_islower (int c
)
628 return c
>= 'a' && c
<= 'z';
632 ascii_toupper (int c
)
634 if (c
>= 'a' && c
<= 'z')
640 ascii_tolower (int c
)
642 if (c
>= 'A' && c
<= 'Z')
649 ascii_strcasecmp( const char *a
, const char *b
)
654 for (; *a
&& *b
; a
++, b
++) {
655 if (*a
!= *b
&& ascii_toupper(*a
) != ascii_toupper(*b
))
658 return *a
== *b
? 0 : (ascii_toupper (*a
) - ascii_toupper (*b
));
662 ascii_strncasecmp (const char *a
, const char *b
, size_t n
)
664 const unsigned char *p1
= (const unsigned char *)a
;
665 const unsigned char *p2
= (const unsigned char *)b
;
666 unsigned char c1
, c2
;
673 c1
= ascii_tolower (*p1
);
674 c2
= ascii_tolower (*p2
);
676 if ( !--n
|| c1
== '\0')
689 ascii_memcasecmp (const void *a_arg
, const void *b_arg
, size_t n
)
691 const char *a
= a_arg
;
692 const char *b
= b_arg
;
696 for ( ; n
; n
--, a
++, b
++ )
698 if( *a
!= *b
&& ascii_toupper (*a
) != ascii_toupper (*b
) )
699 return *a
== *b
? 0 : (ascii_toupper (*a
) - ascii_toupper (*b
));
705 ascii_strcmp( const char *a
, const char *b
)
710 for (; *a
&& *b
; a
++, b
++) {
714 return *a
== *b
? 0 : (*(signed char *)a
- *(signed char *)b
);
719 ascii_memcasemem (const void *haystack
, size_t nhaystack
,
720 const void *needle
, size_t nneedle
)
724 return (void*)haystack
; /* finding an empty needle is really easy */
725 if (nneedle
<= nhaystack
)
727 const char *a
= haystack
;
728 const char *b
= a
+ nhaystack
- nneedle
;
732 if ( !ascii_memcasecmp (a
, needle
, nneedle
) )
739 /*********************************************
740 ********** missing string functions *********
741 *********************************************/
745 stpcpy(char *a
,const char *b
)
756 /* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c. */
758 strsep (char **stringp
, const char *delim
)
766 /* A frequent case is when the delimiter string contains only one
767 character. Here we don't need to call the expensive `strpbrk'
768 function and instead work using `strchr'. */
769 if (delim
[0] == '\0' || delim
[1] == '\0')
779 else if (*begin
== '\0')
782 end
= strchr (begin
+ 1, ch
);
786 /* Find the end of the token. */
787 end
= strpbrk (begin
, delim
);
791 /* Terminate the token and set *STRINGP past NUL character. */
796 /* No more delimiters; this is the last token. */
801 #endif /*HAVE_STRSEP*/
816 #ifndef HAVE_STRCASECMP
818 strcasecmp( const char *a
, const char *b
)
820 for( ; *a
&& *b
; a
++, b
++ ) {
821 if( *a
!= *b
&& toupper(*a
) != toupper(*b
) )
824 return *(const byte
*)a
- *(const byte
*)b
;
830 * mingw32/cpd has a memicmp()
834 memicmp( const char *a
, const char *b
, size_t n
)
836 for( ; n
; n
--, a
++, b
++ )
837 if( *a
!= *b
&& toupper(*(const byte
*)a
) != toupper(*(const byte
*)b
) )
838 return *(const byte
*)a
- *(const byte
*)b
;
846 memrchr (const void *buffer
, int c
, size_t n
)
848 const unsigned char *p
= buffer
;
850 for (p
+= n
; n
; n
--)
855 #endif /*HAVE_MEMRCHR*/
858 /* Percent-escape the string STR by replacing colons with '%3a'. If
859 EXTRA is not NULL all characters in EXTRA are also escaped. */
861 do_percent_escape (const char *str
, const char *extra
, int die
)
869 for (i
=j
=0; str
[i
]; i
++)
870 if (str
[i
] == ':' || str
[i
] == '%' || (extra
&& strchr (extra
, str
[i
])))
873 ptr
= jnlib_xmalloc (i
+ 2 * j
+ 1);
876 ptr
= jnlib_malloc (i
+ 2 * j
+ 1);
889 else if (*str
== '%')
895 else if (extra
&& strchr (extra
, *str
))
898 ptr
[i
++] = tohex_lower ((*str
>>4)&15);
899 ptr
[i
++] = tohex_lower (*str
&15);
910 /* Percent-escape the string STR by replacing colons with '%3a'. If
911 EXTRA is not NULL all characters in EXTRA are also escaped. */
913 percent_escape (const char *str
, const char *extra
)
915 return do_percent_escape (str
, extra
, 1);
918 /* Same as percent_escape but return NULL instead of exiting on memory
921 try_percent_escape (const char *str
, const char *extra
)
923 return do_percent_escape (str
, extra
, 0);