summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2007-10-31 17:11:00 +0100
committerSebastien Helleu <flashcode@flashtux.org>2007-10-31 17:11:00 +0100
commit886b5bc8dd0e309c642e7478a7f8208343ea11ea (patch)
tree0497943320bbcdda0de587470e1581c5672fad6a
parenta664e70488d3b76c7ade51cb2e0ddc20024f2913 (diff)
downloadweechat-886b5bc8dd0e309c642e7478a7f8208343ea11ea.zip
Added some string functions
-rw-r--r--src/core/wee-string.c710
-rw-r--r--src/core/wee-string.h42
2 files changed, 752 insertions, 0 deletions
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 <flashcode@flashtux.org>
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* wee-string.c: string functions for WeeChat */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#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 <flashcode@flashtux.org>
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#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 */