From 886b5bc8dd0e309c642e7478a7f8208343ea11ea Mon Sep 17 00:00:00 2001 From: Sebastien Helleu Date: Wed, 31 Oct 2007 17:11:00 +0100 Subject: Added some string functions --- src/core/wee-string.c | 710 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/core/wee-string.h | 42 +++ 2 files changed, 752 insertions(+) create mode 100644 src/core/wee-string.c create mode 100644 src/core/wee-string.h (limited to 'src/core') diff --git a/src/core/wee-string.c b/src/core/wee-string.c new file mode 100644 index 000000000..7b9e70ff7 --- /dev/null +++ b/src/core/wee-string.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2003-2007 by FlashCode + * See README for License detail, AUTHORS for developers list. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* wee-string.c: string functions for WeeChat */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_ICONV +#include +#endif + +#ifndef ICONV_CONST + #ifdef ICONV_2ARG_IS_CONST + #define ICONV_CONST const + #else + #define ICONV_CONST + #endif +#endif + +#include "weechat.h" +#include "wee-string.h" +#include "wee-utf8.h" + + +/* + * strndup: define strndup function if not existing (FreeBSD and maybe other) + */ + +#ifndef HAVE_STRNDUP +char * +strndup (char *string, int length) +{ + char *result; + + if ((int)strlen (string) < length) + return strdup (string); + + result = (char *)malloc (length + 1); + if (!result) + return NULL; + + memcpy (result, string, length); + result[length] = '\0'; + + return result; +} +#endif + +/* + * string_tolower: locale independant string conversion to lower case + */ + +void +string_tolower (char *string) +{ + while (string && string[0]) + { + if ((string[0] >= 'A') && (string[0] <= 'Z')) + string[0] += ('a' - 'A'); + string++; + } +} + +/* + * string_toupper: locale independant string conversion to upper case + */ + +void +string_toupper (char *string) +{ + while (string && string[0]) + { + if ((string[0] >= 'a') && (string[0] <= 'z')) + string[0] -= ('a' - 'A'); + string++; + } +} + +/* + * string_strcasecmp: locale and case independent string comparison + */ + +int +string_strcasecmp (char *string1, char *string2) +{ + int c1, c2; + + if (!string1 || !string2) + return (string1) ? 1 : ((string2) ? -1 : 0); + + while (string1[0] && string2[0]) + { + c1 = (int)((unsigned char) string1[0]); + c2 = (int)((unsigned char) string2[0]); + + if ((c1 >= 'A') && (c1 <= 'Z')) + c1 += ('a' - 'A'); + + if ((c2 >= 'A') && (c2 <= 'Z')) + c2 += ('a' - 'A'); + + if ((c1 - c2) != 0) + return c1 - c2; + + string1++; + string2++; + } + + return (string1[0]) ? 1 : ((string2[0]) ? -1 : 0); +} + +/* + * string_strncasecmp: locale and case independent string comparison + * with max length + */ + +int +string_strncasecmp (char *string1, char *string2, int max) +{ + int c1, c2, count; + + if (!string1 || !string2) + return (string1) ? 1 : ((string2) ? -1 : 0); + + count = 0; + while ((count < max) && string1[0] && string2[0]) + { + c1 = (int)((unsigned char) string1[0]); + c2 = (int)((unsigned char) string2[0]); + + if ((c1 >= 'A') && (c1 <= 'Z')) + c1 += ('a' - 'A'); + + if ((c2 >= 'A') && (c2 <= 'Z')) + c2 += ('a' - 'A'); + + if ((c1 - c2) != 0) + return c1 - c2; + + string1++; + string2++; + count++; + } + + if (count >= max) + return 0; + else + return (string1[0]) ? 1 : ((string2[0]) ? -1 : 0); +} + +/* + * string_strcasestr: locale and case independent string search + */ + +char * +string_strcasestr (char *string, char *search) +{ + int length_search; + + length_search = strlen (search); + + if (!string || !search || (length_search == 0)) + return NULL; + + while (string[0]) + { + if (string_strncasecmp (string, search, length_search) == 0) + return string; + + string++; + } + + return NULL; +} + +/* + * string_replace: replace a string by new one in a string + * note: returned value has to be free() after use + */ + +char * +string_replace (char *string, char *search, char *replace) +{ + char *pos, *new_string; + int length1, length2, length_new, count; + + if (!string || !search || !replace) + return NULL; + + length1 = strlen (search); + length2 = strlen (replace); + + /* count number of strings to replace */ + count = 0; + pos = string; + while (pos && pos[0] && (pos = strstr (pos, search))) + { + count++; + pos += length1; + } + + /* easy: no string to replace! */ + if (count == 0) + return strdup (string); + + /* compute needed memory for new string */ + length_new = strlen (string) - (count * length1) + (count * length2) + 1; + + /* allocate new string */ + new_string = (char *)malloc (length_new * sizeof (char)); + if (!new_string) + return strdup (string); + + /* replace all occurences */ + new_string[0] = '\0'; + while (string && string[0]) + { + pos = strstr (string, search); + if (pos) + { + strncat (new_string, string, pos - string); + strcat (new_string, replace); + pos += length1; + } + else + strcat (new_string, string); + string = pos; + } + return new_string; +} + +/* + * string_convert_hex_chars: convert hex chars (\x??) to value + */ + +char * +string_convert_hex_chars (char *string) +{ + char *output, hex_str[8], *error; + int pos_output; + long number; + + output = (char *)malloc (strlen (string) + 1); + if (output) + { + pos_output = 0; + while (string && string[0]) + { + if (string[0] == '\\') + { + string++; + switch (string[0]) + { + case '\\': + output[pos_output++] = '\\'; + string++; + break; + case 'x': + case 'X': + if (isxdigit (string[1]) + && isxdigit (string[2])) + { + snprintf (hex_str, sizeof (hex_str), + "0x%c%c", string[1], string[2]); + number = strtol (hex_str, &error, 16); + if (error && (error[0] == '\0')) + { + output[pos_output++] = number; + string += 3; + } + else + { + output[pos_output++] = '\\'; + output[pos_output++] = string[0]; + string++; + } + } + else + { + output[pos_output++] = string[0]; + string++; + } + break; + default: + output[pos_output++] = '\\'; + output[pos_output++] = string[0]; + string++; + break; + } + } + else + { + output[pos_output++] = string[0]; + string++; + } + } + output[pos_output] = '\0'; + } + + return output; +} + +/* + * string_explode: explode a string according to separators + */ + +char ** +string_explode (char *string, char *separators, int num_items_max, + int *num_items) +{ + int i, n_items; + char **array; + char *ptr, *ptr1, *ptr2; + + if (num_items != NULL) + *num_items = 0; + + if (!string || !string[0]) + return NULL; + + /* calculate number of items */ + ptr = string; + i = 1; + while ((ptr = strpbrk (ptr, separators))) + { + while (strchr (separators, ptr[0]) != NULL) + ptr++; + i++; + } + n_items = i; + + if ((num_items_max != 0) && (n_items > num_items_max)) + n_items = num_items_max; + + array = + (char **) malloc ((n_items + 1) * sizeof (char *)); + + ptr1 = string; + ptr2 = string; + + for (i = 0; i < n_items; i++) + { + while (strchr (separators, ptr1[0]) != NULL) + ptr1++; + if (i == (n_items - 1) || (ptr2 = strpbrk (ptr1, separators)) == NULL) + if ((ptr2 = strchr (ptr1, '\r')) == NULL) + if ((ptr2 = strchr (ptr1, '\n')) == NULL) + ptr2 = strchr (ptr1, '\0'); + + if ((ptr1 == NULL) || (ptr2 == NULL)) + { + array[i] = NULL; + } + else + { + if (ptr2 - ptr1 > 0) + { + array[i] = + (char *) malloc ((ptr2 - ptr1 + 1) * sizeof (char)); + array[i] = strncpy (array[i], ptr1, ptr2 - ptr1); + array[i][ptr2 - ptr1] = '\0'; + ptr1 = ++ptr2; + } + else + { + array[i] = NULL; + } + } + } + + array[i] = NULL; + if (num_items != NULL) + *num_items = i; + + return array; +} + +/* + * string_free_exploded: free an exploded string + */ + +void +string_free_exploded (char **exploded_string) +{ + int i; + + if (exploded_string) + { + for (i = 0; exploded_string[i]; i++) + free (exploded_string[i]); + free (exploded_string); + } +} + +/* + * string_split_multi_command: split a list of commands separated by 'sep' + * and ecscaped with '\' + * - empty commands are removed + * - spaces on the left of each commands are stripped + * Result must be freed with free_multi_command + */ + +char ** +string_split_multi_command (char *command, char sep) +{ + int nb_substr, arr_idx, str_idx, type; + char **array; + char *buffer, *ptr, *p; + + if (command == NULL) + return NULL; + + nb_substr = 1; + ptr = command; + while ( (p = strchr(ptr, sep)) != NULL) + { + nb_substr++; + ptr = ++p; + } + + array = (char **) malloc ((nb_substr + 1) * sizeof(char *)); + if (!array) + return NULL; + + buffer = (char *) malloc ( (strlen(command) + 1) * sizeof (char)); + if (!buffer) + { + free (array); + return NULL; + } + + ptr = command; + str_idx = 0; + arr_idx = 0; + while(*ptr != '\0') + { + type = 0; + if (*ptr == ';') + { + if (ptr == command) + type = 1; + else if ( *(ptr-1) != '\\') + type = 1; + else if ( *(ptr-1) == '\\') + type = 2; + } + if (type == 1) + { + buffer[str_idx] = '\0'; + str_idx = -1; + p = buffer; + /* strip white spaces a the begining of the line */ + while (*p == ' ') p++; + if (p && p[0]) + array[arr_idx++] = strdup (p); + } + else if (type == 2) + buffer[--str_idx] = *ptr; + else + buffer[str_idx] = *ptr; + str_idx++; + ptr++; + } + + buffer[str_idx] = '\0'; + p = buffer; + while (*p == ' ') p++; + if (p && p[0]) + array[arr_idx++] = strdup (p); + + array[arr_idx] = NULL; + + free (buffer); + + array = (char **) realloc (array, (arr_idx + 1) * sizeof(char *)); + + return array; +} + +/* + * string_free_multi_command : free a list of commands splitted + * with split_multi_command + */ + +void +string_free_multi_command (char **commands) +{ + int i; + + if (commands) + { + for (i = 0; commands[i]; i++) + free (commands[i]); + free (commands); + } +} + +/* + * string_iconv: convert string to another charset + */ + +char * +string_iconv (int from_utf8, char *from_code, char *to_code, char *string) +{ + char *outbuf; + +#ifdef HAVE_ICONV + iconv_t cd; + char *inbuf, *ptr_inbuf, *ptr_outbuf, *next_char; + char *ptr_inbuf_shift; + int done; + size_t err, inbytesleft, outbytesleft; + + if (from_code && from_code[0] && to_code && to_code[0] + && (string_strcasecmp(from_code, to_code) != 0)) + { + cd = iconv_open (to_code, from_code); + if (cd == (iconv_t)(-1)) + outbuf = strdup (string); + else + { + inbuf = strdup (string); + ptr_inbuf = inbuf; + inbytesleft = strlen (inbuf); + outbytesleft = inbytesleft * 4; + outbuf = (char *) malloc (outbytesleft + 2); + ptr_outbuf = outbuf; + ptr_inbuf_shift = NULL; + done = 0; + while (!done) + { + err = iconv (cd, (ICONV_CONST char **)(&ptr_inbuf), &inbytesleft, + &ptr_outbuf, &outbytesleft); + if (err == (size_t)(-1)) + { + switch (errno) + { + case EINVAL: + done = 1; + break; + case E2BIG: + done = 1; + break; + case EILSEQ: + if (from_utf8) + { + next_char = utf8_next_char (ptr_inbuf); + if (next_char) + { + inbytesleft -= next_char - ptr_inbuf; + ptr_inbuf = next_char; + } + else + { + inbytesleft--; + ptr_inbuf++; + } + } + else + { + ptr_inbuf++; + inbytesleft--; + } + ptr_outbuf[0] = '?'; + ptr_outbuf++; + outbytesleft--; + break; + } + } + else + { + if (!ptr_inbuf_shift) + { + ptr_inbuf_shift = ptr_inbuf; + ptr_inbuf = NULL; + inbytesleft = 0; + } + else + done = 1; + } + } + if (ptr_inbuf_shift) + ptr_inbuf = ptr_inbuf_shift; + ptr_outbuf[0] = '\0'; + free (inbuf); + iconv_close (cd); + } + } + else + outbuf = strdup (string); +#else + /* make C compiler happy */ + (void) from_utf8; + (void) from_code; + (void) to_code; + outbuf = strdup (string); +#endif /* HAVE_ICONV */ + + return outbuf; +} + +/* + * string_iconv_to_internal: convert user string (input, script, ..) to + * WeeChat internal storage charset + */ + +char * +string_iconv_to_internal (char *charset, char *string) +{ + char *input, *output; + + input = strdup (string); + + /* optimize for UTF-8: if charset is NULL => we use term charset => + if ths charset is already UTF-8, then no iconv needed */ + if (local_utf8 && (!charset || !charset[0])) + return input; + + if (input) + { + if (utf8_has_8bits (input) && utf8_is_valid (input, NULL)) + return input; + + output = string_iconv (0, + (charset && charset[0]) ? + charset : local_charset, + WEECHAT_INTERNAL_CHARSET, + input); + utf8_normalize (output, '?'); + free (input); + return output; + } + return NULL; +} + +/* + * string_iconv_from_internal: convert internal string to terminal charset, + * for display + */ + +char * +string_iconv_from_internal (char *charset, char *string) +{ + char *input, *output; + + input = strdup (string); + + /* optimize for UTF-8: if charset is NULL => we use term charset => + if ths charset is already UTF-8, then no iconv needed */ + if (local_utf8 && (!charset || !charset[0])) + return input; + + if (input) + { + utf8_normalize (input, '?'); + output = string_iconv (1, + WEECHAT_INTERNAL_CHARSET, + (charset && charset[0]) ? + charset : local_charset, + input); + free (input); + return output; + } + return NULL; +} + +/* + * string_iconv_fprintf: encode to terminal charset, then call fprintf on a file + */ + +void +string_iconv_fprintf (FILE *file, char *data, ...) +{ + va_list argptr; + static char buf[4096]; + char *buf2; + + va_start (argptr, data); + vsnprintf (buf, sizeof (buf) - 1, data, argptr); + va_end (argptr); + + buf2 = string_iconv_from_internal (NULL, buf); + fprintf (file, "%s", (buf2) ? buf2 : buf); + if (buf2) + free (buf2); +} diff --git a/src/core/wee-string.h b/src/core/wee-string.h new file mode 100644 index 000000000..c7ca959db --- /dev/null +++ b/src/core/wee-string.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2003-2007 by FlashCode + * See README for License detail, AUTHORS for developers list. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#ifndef __WEECHAT_STRING_H +#define __WEECHAT_STRING_H 1 + +#ifndef HAVE_STRNDUP +extern char *strndup (char *, int); +#endif +extern void string_tolower (char *); +extern void string_toupper (char *); +extern int string_strcasecmp (char *, char *); +extern int string_strncasecmp (char *, char *, int); +extern char *string_strcasestr (char *, char *); +extern char *string_replace (char *, char *, char *); +extern char *string_convert_hex_chars (char *); +extern char **string_explode (char *, char *, int, int *); +extern void string_free_exploded (char **); +extern char **string_split_multi_command (char *, char); +extern void string_free_multi_command (char **); +extern char *string_iconv (int, char *, char *, char *); +extern char *string_iconv_to_internal (char *, char *); +extern char *string_iconv_from_internal (char *, char *); +extern void string_iconv_fprintf (FILE *, char *, ...); + +#endif /* wee-string.h */ -- cgit v1.2.3