4 Copyright (C) 1999 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 GInputFunction function;
34 static int irssi_io_invoke(GIOChannel *source, GIOCondition condition,
37 IRSSI_INPUT_REC *rec = data;
40 if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
41 /* error, we have to call the function.. */
42 if (rec->condition & G_IO_IN)
43 icond |= G_INPUT_READ;
45 icond |= G_INPUT_WRITE;
48 if (condition & (G_IO_IN | G_IO_PRI))
49 icond |= G_INPUT_READ;
50 if (condition & G_IO_OUT)
51 icond |= G_INPUT_WRITE;
53 if (rec->condition & icond)
54 rec->function(rec->data, source, icond);
59 int g_input_add_full(GIOChannel *source, int priority, int condition,
60 GInputFunction function, void *data)
66 rec = g_new(IRSSI_INPUT_REC, 1);
67 rec->condition = condition;
68 rec->function = function;
71 cond = (GIOCondition) (G_IO_ERR|G_IO_HUP|G_IO_NVAL);
72 if (condition & G_INPUT_READ)
73 cond |= G_IO_IN|G_IO_PRI;
74 if (condition & G_INPUT_WRITE)
77 result = g_io_add_watch_full(source, priority, cond,
78 irssi_io_invoke, rec, g_free);
83 int g_input_add(GIOChannel *source, int condition,
84 GInputFunction function, void *data)
86 return g_input_add_full(source, G_PRIORITY_DEFAULT, condition,
90 /* easy way to bypass glib polling of io channel internal buffer */
91 int g_input_add_poll(int fd, int priority, int condition,
92 GInputFunction function, void *data)
94 GIOChannel *source = g_io_channel_unix_new(fd);
95 int ret = g_input_add_full(source, priority, condition, function, data);
96 g_io_channel_unref(source);
100 int g_timeval_cmp(const GTimeVal *tv1, const GTimeVal *tv2)
102 if (tv1->tv_sec < tv2->tv_sec)
104 if (tv1->tv_sec > tv2->tv_sec)
107 return tv1->tv_usec < tv2->tv_usec ? -1 :
108 tv1->tv_usec > tv2->tv_usec ? 1 : 0;
111 long get_timeval_diff(const GTimeVal *tv1, const GTimeVal *tv2)
115 secs = tv1->tv_sec - tv2->tv_sec;
116 usecs = tv1->tv_usec - tv2->tv_usec;
121 usecs = usecs/1000 + secs * 1000;
126 int find_substr(const char *list, const char *item)
130 g_return_val_if_fail(list != NULL, FALSE);
131 g_return_val_if_fail(item != NULL, FALSE);
137 while (i_isspace(*list)) list++;
138 if (*list == '\0') break;
140 ptr = strchr(list, ' ');
141 if (ptr == NULL) ptr = list+strlen(list);
143 if (g_strncasecmp(list, item, ptr-list) == 0 &&
144 item[ptr-list] == '\0')
153 int strarray_length(char **array)
157 g_return_val_if_fail(array != NULL, 0);
167 int strarray_find(char **array, const char *item)
172 g_return_val_if_fail(array != NULL, 0);
173 g_return_val_if_fail(item != NULL, 0);
176 for (tmp = array; *tmp != NULL; tmp++, index++) {
177 if (g_strcasecmp(*tmp, item) == 0)
184 GSList *gslist_find_string(GSList *list, const char *key)
186 for (list = list; list != NULL; list = list->next)
187 if (strcmp(list->data, key) == 0) return list;
192 GSList *gslist_find_icase_string(GSList *list, const char *key)
194 for (list = list; list != NULL; list = list->next)
195 if (g_strcasecmp(list->data, key) == 0) return list;
200 void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, const void *data)
204 while (list != NULL) {
205 ret = func(list->data, (void *) data);
206 if (ret != NULL) return ret;
214 /* `list' contains pointer to structure with a char* to string. */
215 char *gslistptr_to_string(GSList *list, int offset, const char *delimiter)
220 str = g_string_new(NULL);
221 while (list != NULL) {
222 data = G_STRUCT_MEMBER_P(list->data, offset);
224 if (str->len != 0) g_string_append(str, delimiter);
225 g_string_append(str, *data);
230 g_string_free(str, FALSE);
234 /* `list' contains char* */
235 char *gslist_to_string(GSList *list, const char *delimiter)
240 str = g_string_new(NULL);
241 while (list != NULL) {
242 if (str->len != 0) g_string_append(str, delimiter);
243 g_string_append(str, list->data);
249 g_string_free(str, FALSE);
253 void hash_save_key(char *key, void *value, GSList **list)
255 *list = g_slist_append(*list, key);
258 /* save all keys in hash table to linked list - you shouldn't remove any
259 items while using this list, use g_slist_free() after you're done with it */
260 GSList *hashtable_get_keys(GHashTable *hash)
265 g_hash_table_foreach(hash, (GHFunc) hash_save_key, &list);
269 GList *glist_find_string(GList *list, const char *key)
271 for (list = list; list != NULL; list = list->next)
272 if (strcmp(list->data, key) == 0) return list;
277 GList *glist_find_icase_string(GList *list, const char *key)
279 for (list = list; list != NULL; list = list->next)
280 if (g_strcasecmp(list->data, key) == 0) return list;
285 char *stristr(const char *data, const char *key)
288 int keylen, datalen, pos;
290 keylen = strlen(key);
291 datalen = strlen(data);
293 if (keylen > datalen)
296 return (char *) data;
298 max = data+datalen-keylen;
300 while (data <= max) {
301 if (key[pos] == '\0')
302 return (char *) data;
304 if (i_toupper(data[pos]) == i_toupper(key[pos]))
316 ((unsigned char) (c) < 128 && \
317 (i_isspace(c) || i_ispunct(c)))
319 static char *strstr_full_case(const char *data, const char *key, int icase)
321 const char *start, *max;
322 int keylen, datalen, pos, match;
324 keylen = strlen(key);
325 datalen = strlen(data);
327 if (keylen > datalen)
330 return (char *) data;
332 max = data+datalen-keylen;
333 start = data; pos = 0;
334 while (data <= max) {
335 if (key[pos] == '\0') {
336 if (data[pos] != '\0' && !isbound(data[pos])) {
341 return (char *) data;
344 match = icase ? (i_toupper(data[pos]) == i_toupper(key[pos])) :
345 data[pos] == key[pos];
347 if (match && (pos != 0 || data == start || isbound(data[-1])))
358 char *strstr_full(const char *data, const char *key)
360 return strstr_full_case(data, key, FALSE);
363 char *stristr_full(const char *data, const char *key)
365 return strstr_full_case(data, key, TRUE);
368 int regexp_match(const char *str, const char *regexp)
374 if (regcomp(&preg, regexp, REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
377 ret = regexec(&preg, str, 0, NULL, 0);
386 /* Create the directory and all it's parent directories */
387 int mkpath(const char *path, int mode)
393 g_return_val_if_fail(path != NULL, -1);
395 p = g_path_skip_root((char *) path);
397 /* not a full path, maybe not what we wanted
398 but continue anyway.. */
402 if (*p != G_DIR_SEPARATOR && *p != '\0') {
407 dir = g_strndup(path, (int) (p-path));
408 if (stat(dir, &statbuf) != 0) {
410 if (mkdir(dir, mode) == -1)
412 if (_mkdir(dir) == -1)
428 /* convert ~/ to $HOME */
429 char *convert_home(const char *path)
433 if (*path == '~' && (*(path+1) == '/' || *(path+1) == '\0')) {
434 home = g_get_home_dir();
438 return g_strconcat(home, path+1, NULL);
440 return g_strdup(path);
444 int g_istr_equal(gconstpointer v, gconstpointer v2)
446 return g_strcasecmp((const char *) v, (const char *) v2) == 0;
449 int g_istr_cmp(gconstpointer v, gconstpointer v2)
451 return g_strcasecmp((const char *) v, (const char *) v2);
454 /* a char* hash function from ASU */
455 unsigned int g_istr_hash(gconstpointer v)
457 const char *s = (const char *) v;
458 unsigned int h = 0, g;
461 h = (h << 4) + i_toupper(*s);
462 if ((g = h & 0xf0000000UL)) {
472 /* Find `mask' from `data', you can use * and ? wildcards. */
473 int match_wildcards(const char *cmask, const char *data)
475 char *mask, *newmask, *p1, *p2;
478 newmask = mask = g_strdup(cmask);
479 for (; *mask != '\0' && *data != '\0'; mask++) {
481 if (*mask != '?' && i_toupper(*mask) != i_toupper(*data))
488 while (*mask == '?' || *mask == '*') mask++;
490 data += strlen(data);
494 p1 = strchr(mask, '*');
495 p2 = strchr(mask, '?');
496 if (p1 == NULL || (p2 < p1 && p2 != NULL)) p1 = p2;
498 if (p1 != NULL) *p1 = '\0';
500 data = stristr(data, mask);
501 if (data == NULL) break;
503 data += strlen(mask);
504 mask += strlen(mask)-1;
506 if (p1 != NULL) *p1 = p1 == p2 ? '?' : '*';
509 while (*mask == '*') mask++;
511 ret = data != NULL && *data == '\0' && *mask == '\0';
517 /* Return TRUE if all characters in `str' are numbers.
518 Stop when `end_char' is found from string. */
519 int is_numeric(const char *str, char end_char)
521 g_return_val_if_fail(str != NULL, FALSE);
523 if (*str == '\0' || *str == end_char)
526 while (*str != '\0' && *str != end_char) {
527 if (!i_isdigit(*str)) return FALSE;
534 /* replace all `from' chars in string to `to' chars. returns `str' */
535 char *replace_chars(char *str, char from, char to)
539 for (p = str; *p != '\0'; p++) {
540 if (*p == from) *p = to;
545 int octal2dec(int octal)
558 int dec2octal(int decimal)
563 while (decimal > 0) {
564 octal += (decimal & 7)*(pos == 0 ? 1 : pos);
572 /* string -> uoff_t */
573 uoff_t str_to_uofft(const char *str)
578 while (*str != '\0') {
579 ret = ret*10 + (*str - '0');
586 /* convert all low-ascii (<32) to ^<A..> combinations */
587 char *show_lowascii(const char *str)
591 ret = p = g_malloc(strlen(str)*2+1);
592 while (*str != '\0') {
593 if ((unsigned char) *str >= 32)
606 /* Get time in human readable form with localtime() + asctime() */
607 char *my_asctime(time_t t)
614 str = g_strdup(asctime(tm));
617 if (len > 0) str[len-1] = '\0';
621 /* Returns number of columns needed to print items.
622 save_column_widths is filled with length of each column. */
623 int get_max_column_count(GSList *items, COLUMN_LEN_FUNC len_func,
624 int max_width, int max_columns,
625 int item_extra, int item_min_size,
626 int **save_column_widths, int *rows)
629 int **columns, *columns_width, *columns_rows;
630 int item_pos, items_count;
631 int ret, len, max_len, n, col;
633 items_count = g_slist_length(items);
634 if (items_count == 0) {
635 *save_column_widths = NULL;
640 len = max_width/(item_extra+item_min_size);
641 if (len <= 0) len = 1;
642 if (max_columns <= 0 || len < max_columns)
645 columns = g_new0(int *, max_columns);
646 columns_width = g_new0(int, max_columns);
647 columns_rows = g_new0(int, max_columns);
649 for (n = 1; n < max_columns; n++) {
650 columns[n] = g_new0(int, n+1);
651 columns_rows[n] = items_count <= n+1 ? 1 :
652 (items_count+n)/(n+1);
655 /* for each possible column count, save the column widths and
656 find the biggest column count that fits to screen. */
657 item_pos = 0; max_len = 0;
658 for (tmp = items; tmp != NULL; tmp = tmp->next) {
659 len = item_extra+len_func(tmp->data);
663 for (n = 1; n < max_columns; n++) {
664 if (columns_width[n] > max_width)
665 continue; /* too wide */
667 col = item_pos/columns_rows[n];
668 if (columns[n][col] < len) {
669 columns_width[n] += len-columns[n][col];
670 columns[n][col] = len;
677 for (n = max_columns-1; n >= 1; n--) {
678 if (columns_width[n] <= max_width &&
684 *save_column_widths = g_new(int, ret);
686 **save_column_widths = max_len;
689 memcpy(*save_column_widths, columns[ret-1], sizeof(int)*ret);
690 *rows = columns_rows[ret-1];
693 for (n = 1; n < max_columns; n++)
695 g_free(columns_width);
696 g_free(columns_rows);
702 /* Return a column sorted copy of a list. */
703 GSList *columns_sort_list(GSList *list, int rows)
705 GSList *tmp, *sorted;
708 if (list == NULL || rows == 0)
713 for (row = 0; row < rows; row++) {
714 tmp = g_slist_nth(list, row);
716 for (; tmp != NULL; tmp = tmp->next) {
719 sorted = g_slist_append(sorted, tmp->data);
724 g_return_val_if_fail(g_slist_length(sorted) ==
725 g_slist_length(list), sorted);
729 /* Expand escape string, the first character in data should be the
730 one after '\'. Returns the expanded character or -1 if error. */
731 int expand_escape(const char **data)
747 if (!i_isxdigit((*data)[1]) || !i_isxdigit((*data)[2]))
750 digit[0] = (*data)[1];
751 digit[1] = (*data)[2];
754 return strtol(digit, NULL, 16);
756 /* control character (\cA = ^A) */
758 return i_toupper(**data) - 64;
759 case '0': case '1': case '2': case '3':
760 case '4': case '5': case '6': case '7':
762 digit[1] = digit[2] = digit[3] = '\0';
763 digit[0] = (*data)[0];
764 if ((*data)[1] >= '0' && (*data)[1] <= '7') {
767 if ((*data)[1] >= '0' && (*data)[1] <= '7') {
772 return strtol(digit, NULL, 8);
778 /* Escape all '"', "'" and '\' chars with '\' */
779 char *escape_string(const char *str)
783 p = ret = g_malloc(strlen(str)*2+1);
784 while (*str != '\0') {
785 if (*str == '"' || *str == '\'' || *str == '\\')
794 int strocpy(char *dest, const char *src, size_t dstsize)
799 while (*src != '\0' && dstsize > 1) {
805 return *src == '\0' ? 0 : -1;
808 int nearest_power(int num)
812 while (n < num) n <<= 1;
816 int parse_time_interval(const char *time, int *msecs)
819 int number, sign, len, ret, digits;
823 /* max. return value is around 24 days */
824 number = 0; sign = 1; ret = TRUE; digits = FALSE;
825 while (i_isspace(*time))
830 while (i_isspace(*time))
834 if (i_isdigit(*time)) {
835 number = number*10 + (*time - '0');
844 /* skip punctuation */
845 while (*time != '\0' && i_ispunct(*time) && *time != '-')
848 /* get description */
849 for (len = 0, desc = time; i_isalpha(*time); time++)
852 while (i_isspace(*time))
858 *msecs += number * 1000; /* assume seconds */
863 if (g_ascii_strncasecmp(desc, "days", len) == 0) {
868 *msecs += number * 1000*3600*24;
869 } else if (g_ascii_strncasecmp(desc, "hours", len) == 0)
870 *msecs += number * 1000*3600;
871 else if (g_ascii_strncasecmp(desc, "minutes", len) == 0 ||
872 g_ascii_strncasecmp(desc, "mins", len) == 0)
873 *msecs += number * 1000*60;
874 else if (g_ascii_strncasecmp(desc, "seconds", len) == 0 ||
875 g_ascii_strncasecmp(desc, "secs", len) == 0)
876 *msecs += number * 1000;
877 else if (g_ascii_strncasecmp(desc, "milliseconds", len) == 0 ||
878 g_ascii_strncasecmp(desc, "millisecs", len) == 0 ||
879 g_ascii_strncasecmp(desc, "mseconds", len) == 0 ||
880 g_ascii_strncasecmp(desc, "msecs", len) == 0)
886 /* skip punctuation */
887 while (*time != '\0' && i_ispunct(*time) && *time != '-')
901 int parse_size(const char *size, int *bytes)
908 /* max. return value is about 1.6 years */
910 while (*size != '\0') {
911 if (i_isdigit(*size)) {
912 number = number*10 + (*size - '0');
917 /* skip punctuation */
918 while (*size != '\0' && i_ispunct(*size))
921 /* get description */
922 for (len = 0, desc = size; i_isalpha(*size); size++)
931 *bytes += number*1024; /* assume kilobytes */
935 if (g_ascii_strncasecmp(desc, "gbytes", len) == 0)
936 *bytes += number * 1024*1024*1024;
937 if (g_ascii_strncasecmp(desc, "mbytes", len) == 0)
938 *bytes += number * 1024*1024;
939 if (g_ascii_strncasecmp(desc, "kbytes", len) == 0)
940 *bytes += number * 1024;
941 if (g_ascii_strncasecmp(desc, "bytes", len) == 0)
944 /* skip punctuation */
945 while (*size != '\0' && i_ispunct(*size))
952 char *ascii_strup(char *str)
956 for (s = str; *s; s++)
957 *s = g_ascii_toupper (*s);
961 char *ascii_strdown(char *str)
965 for (s = str; *s; s++)
966 *s = g_ascii_tolower (*s);