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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 GInputFunction function;
36 static int irssi_io_invoke(GIOChannel *source, GIOCondition condition,
39 IRSSI_INPUT_REC *rec = data;
42 if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
43 /* error, we have to call the function.. */
44 if (rec->condition & G_IO_IN)
45 icond |= G_INPUT_READ;
47 icond |= G_INPUT_WRITE;
50 if (condition & (G_IO_IN | G_IO_PRI))
51 icond |= G_INPUT_READ;
52 if (condition & G_IO_OUT)
53 icond |= G_INPUT_WRITE;
55 if (rec->condition & icond)
56 rec->function(rec->data, source, icond);
61 int g_input_add_full(GIOChannel *source, int priority, int condition,
62 GInputFunction function, void *data)
68 rec = g_new(IRSSI_INPUT_REC, 1);
69 rec->condition = condition;
70 rec->function = function;
73 cond = (GIOCondition) (G_IO_ERR|G_IO_HUP|G_IO_NVAL);
74 if (condition & G_INPUT_READ)
75 cond |= G_IO_IN|G_IO_PRI;
76 if (condition & G_INPUT_WRITE)
79 result = g_io_add_watch_full(source, priority, cond,
80 irssi_io_invoke, rec, g_free);
85 int g_input_add(GIOChannel *source, int condition,
86 GInputFunction function, void *data)
88 return g_input_add_full(source, G_PRIORITY_DEFAULT, condition,
92 int g_timeval_cmp(const GTimeVal *tv1, const GTimeVal *tv2)
94 if (tv1->tv_sec < tv2->tv_sec)
96 if (tv1->tv_sec > tv2->tv_sec)
99 return tv1->tv_usec < tv2->tv_usec ? -1 :
100 tv1->tv_usec > tv2->tv_usec ? 1 : 0;
103 long get_timeval_diff(const GTimeVal *tv1, const GTimeVal *tv2)
107 secs = tv1->tv_sec - tv2->tv_sec;
108 usecs = tv1->tv_usec - tv2->tv_usec;
113 usecs = usecs/1000 + secs * 1000;
118 int find_substr(const char *list, const char *item)
122 g_return_val_if_fail(list != NULL, FALSE);
123 g_return_val_if_fail(item != NULL, FALSE);
129 while (i_isspace(*list)) list++;
130 if (*list == '\0') break;
132 ptr = strchr(list, ' ');
133 if (ptr == NULL) ptr = list+strlen(list);
135 if (g_strncasecmp(list, item, ptr-list) == 0 &&
136 item[ptr-list] == '\0')
145 int strarray_length(char **array)
149 g_return_val_if_fail(array != NULL, 0);
159 int strarray_find(char **array, const char *item)
164 g_return_val_if_fail(array != NULL, 0);
165 g_return_val_if_fail(item != NULL, 0);
168 for (tmp = array; *tmp != NULL; tmp++, index++) {
169 if (g_strcasecmp(*tmp, item) == 0)
176 int execute(const char *cmd)
183 g_return_val_if_fail(cmd != NULL, -1);
187 if (pid == -1) return FALSE;
193 args = g_strsplit(cmd, " ", -1);
194 execvp(args[0], args);
200 args = g_strsplit(cmd, " ", -1);
201 _spawnvp(_P_DETACH, args[0], args);
207 GSList *gslist_find_string(GSList *list, const char *key)
209 for (list = list; list != NULL; list = list->next)
210 if (strcmp(list->data, key) == 0) return list;
215 GSList *gslist_find_icase_string(GSList *list, const char *key)
217 for (list = list; list != NULL; list = list->next)
218 if (g_strcasecmp(list->data, key) == 0) return list;
223 void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, const void *data)
227 while (list != NULL) {
228 ret = func(list->data, (void *) data);
229 if (ret != NULL) return ret;
237 /* `list' contains pointer to structure with a char* to string. */
238 char *gslistptr_to_string(GSList *list, int offset, const char *delimiter)
243 str = g_string_new(NULL);
244 while (list != NULL) {
245 data = G_STRUCT_MEMBER_P(list->data, offset);
247 if (str->len != 0) g_string_append(str, delimiter);
248 g_string_append(str, *data);
253 g_string_free(str, FALSE);
257 /* `list' contains char* */
258 char *gslist_to_string(GSList *list, const char *delimiter)
263 str = g_string_new(NULL);
264 while (list != NULL) {
265 if (str->len != 0) g_string_append(str, delimiter);
266 g_string_append(str, list->data);
272 g_string_free(str, FALSE);
276 void hash_save_key(char *key, void *value, GSList **list)
278 *list = g_slist_append(*list, key);
281 /* save all keys in hash table to linked list - you shouldn't remove any
282 items while using this list, use g_slist_free() after you're done with it */
283 GSList *hashtable_get_keys(GHashTable *hash)
288 g_hash_table_foreach(hash, (GHFunc) hash_save_key, &list);
292 GList *glist_find_string(GList *list, const char *key)
294 for (list = list; list != NULL; list = list->next)
295 if (strcmp(list->data, key) == 0) return list;
300 GList *glist_find_icase_string(GList *list, const char *key)
302 for (list = list; list != NULL; list = list->next)
303 if (g_strcasecmp(list->data, key) == 0) return list;
308 char *stristr(const char *data, const char *key)
311 int keylen, datalen, pos;
313 keylen = strlen(key);
314 datalen = strlen(data);
316 if (keylen > datalen)
319 return (char *) data;
321 max = data+datalen-keylen;
323 while (data <= max) {
324 if (key[pos] == '\0')
325 return (char *) data;
327 if (i_toupper(data[pos]) == i_toupper(key[pos]))
339 ((unsigned char) (c) < 128 && \
340 (i_isspace(c) || i_ispunct(c)))
342 char *strstr_full_case(const char *data, const char *key, int icase)
344 const char *start, *max;
345 int keylen, datalen, pos, match;
347 keylen = strlen(key);
348 datalen = strlen(data);
350 if (keylen > datalen)
353 return (char *) data;
355 max = data+datalen-keylen;
356 start = data; pos = 0;
357 while (data <= max) {
358 if (key[pos] == '\0') {
359 if (data[pos] != '\0' && !isbound(data[pos])) {
364 return (char *) data;
367 match = icase ? (i_toupper(data[pos]) == i_toupper(key[pos])) :
368 data[pos] == key[pos];
370 if (match && (pos != 0 || data == start || isbound(data[-1])))
381 char *strstr_full(const char *data, const char *key)
383 return strstr_full_case(data, key, FALSE);
386 char *stristr_full(const char *data, const char *key)
388 return strstr_full_case(data, key, TRUE);
391 int regexp_match(const char *str, const char *regexp)
397 if (regcomp(&preg, regexp, REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
400 ret = regexec(&preg, str, 0, NULL, 0);
409 /* Create the directory and all it's parent directories */
410 int mkpath(const char *path, int mode)
416 g_return_val_if_fail(path != NULL, -1);
418 p = g_path_skip_root((char *) path);
420 /* not a full path, maybe not what we wanted
421 but continue anyway.. */
425 if (*p != G_DIR_SEPARATOR && *p != '\0') {
430 dir = g_strndup(path, (int) (p-path));
431 if (stat(dir, &statbuf) != 0) {
433 if (mkdir(dir, mode) == -1)
435 if (_mkdir(dir) == -1)
451 /* convert ~/ to $HOME */
452 char *convert_home(const char *path)
456 if (*path == '~' && (*(path+1) == '/' || *(path+1) == '\0')) {
457 home = g_get_home_dir();
461 return g_strconcat(home, path+1, NULL);
463 return g_strdup(path);
467 int g_istr_equal(gconstpointer v, gconstpointer v2)
469 return g_strcasecmp((const char *) v, (const char *) v2) == 0;
472 int g_istr_cmp(gconstpointer v, gconstpointer v2)
474 return g_strcasecmp((const char *) v, (const char *) v2);
477 /* a char* hash function from ASU */
478 unsigned int g_istr_hash(gconstpointer v)
480 const char *s = (const char *) v;
481 unsigned int h = 0, g;
484 h = (h << 4) + i_toupper(*s);
485 if ((g = h & 0xf0000000UL)) {
495 /* Find `mask' from `data', you can use * and ? wildcards. */
496 int match_wildcards(const char *cmask, const char *data)
498 char *mask, *newmask, *p1, *p2;
501 newmask = mask = g_strdup(cmask);
502 for (; *mask != '\0' && *data != '\0'; mask++) {
504 if (*mask != '?' && i_toupper(*mask) != i_toupper(*data))
511 while (*mask == '?' || *mask == '*') mask++;
513 data += strlen(data);
517 p1 = strchr(mask, '*');
518 p2 = strchr(mask, '?');
519 if (p1 == NULL || (p2 < p1 && p2 != NULL)) p1 = p2;
521 if (p1 != NULL) *p1 = '\0';
523 data = stristr(data, mask);
524 if (data == NULL) break;
526 data += strlen(mask);
527 mask += strlen(mask)-1;
529 if (p1 != NULL) *p1 = p1 == p2 ? '?' : '*';
532 while (*mask == '*') mask++;
534 ret = data != NULL && *data == '\0' && *mask == '\0';
540 /* Return TRUE if all characters in `str' are numbers.
541 Stop when `end_char' is found from string. */
542 int is_numeric(const char *str, char end_char)
544 g_return_val_if_fail(str != NULL, FALSE);
546 if (*str == '\0' || *str == end_char)
549 while (*str != '\0' && *str != end_char) {
550 if (!i_isdigit(*str)) return FALSE;
557 /* replace all `from' chars in string to `to' chars. returns `str' */
558 char *replace_chars(char *str, char from, char to)
562 for (p = str; *p != '\0'; p++) {
563 if (*p == from) *p = to;
568 int octal2dec(int octal)
581 int dec2octal(int decimal)
586 while (decimal > 0) {
587 octal += (decimal & 7)*(pos == 0 ? 1 : pos);
595 /* string -> uoff_t */
596 uoff_t str_to_uofft(const char *str)
601 while (*str != '\0') {
602 ret = ret*10 + (*str - '0');
609 /* convert all low-ascii (<32) to ^<A..> combinations */
610 char *show_lowascii(const char *channel)
614 str = p = g_malloc(strlen(channel)*2+1);
615 while (*channel != '\0') {
616 if ((unsigned char) *channel >= 32)
620 *p++ = *channel + 'A'-1;
629 /* Get time in human readable form with localtime() + asctime() */
630 char *my_asctime(time_t t)
637 str = g_strdup(asctime(tm));
640 if (len > 0) str[len-1] = '\0';
644 /* Returns number of columns needed to print items.
645 save_column_widths is filled with length of each column. */
646 int get_max_column_count(GSList *items, COLUMN_LEN_FUNC len_func,
647 int max_width, int max_columns,
648 int item_extra, int item_min_size,
649 int **save_column_widths, int *rows)
652 int **columns, *columns_width, *columns_rows;
653 int item_pos, items_count;
654 int ret, len, max_len, n, col;
656 items_count = g_slist_length(items);
657 if (items_count == 0) {
658 *save_column_widths = NULL;
663 len = max_width/(item_extra+item_min_size);
664 if (len <= 0) len = 1;
665 if (max_columns <= 0 || len < max_columns)
668 columns = g_new0(int *, max_columns);
669 columns_width = g_new0(int, max_columns);
670 columns_rows = g_new0(int, max_columns);
672 for (n = 1; n < max_columns; n++) {
673 columns[n] = g_new0(int, n+1);
674 columns_rows[n] = items_count <= n+1 ? 1 :
675 (items_count+n)/(n+1);
678 /* for each possible column count, save the column widths and
679 find the biggest column count that fits to screen. */
680 item_pos = 0; max_len = 0;
681 for (tmp = items; tmp != NULL; tmp = tmp->next) {
682 len = item_extra+len_func(tmp->data);
686 for (n = 1; n < max_columns; n++) {
687 if (columns_width[n] > max_width)
688 continue; /* too wide */
690 col = item_pos/columns_rows[n];
691 if (columns[n][col] < len) {
692 columns_width[n] += len-columns[n][col];
693 columns[n][col] = len;
700 for (n = max_columns-1; n >= 1; n--) {
701 if (columns_width[n] <= max_width &&
707 *save_column_widths = g_new(int, ret);
709 **save_column_widths = max_len;
712 memcpy(*save_column_widths, columns[ret-1], sizeof(int)*ret);
713 *rows = columns_rows[ret-1];
716 for (n = 1; n < max_columns; n++)
718 g_free(columns_width);
719 g_free(columns_rows);
725 /* Return a column sorted copy of a list. */
726 GSList *columns_sort_list(GSList *list, int rows)
728 GSList *tmp, *sorted;
731 if (list == NULL || rows == 0)
736 for (row = 0; row < rows; row++) {
737 tmp = g_slist_nth(list, row);
739 for (; tmp != NULL; tmp = tmp->next) {
742 sorted = g_slist_append(sorted, tmp->data);
747 g_return_val_if_fail(g_slist_length(sorted) ==
748 g_slist_length(list), sorted);
752 /* Expand escape string, the first character in data should be the
753 one after '\'. Returns the expanded character or -1 if error. */
754 int expand_escape(const char **data)
770 if (!i_isxdigit((*data)[1]) || !i_isxdigit((*data)[2]))
773 digit[0] = (*data)[1];
774 digit[1] = (*data)[2];
777 return strtol(digit, NULL, 16);
779 /* control character (\cA = ^A) */
781 return i_toupper(**data) - 64;
783 if (!i_isdigit(**data))
787 digit[0] = (*data)[0];
788 digit[1] = (*data)[1];
789 digit[2] = (*data)[2];
792 return strtol(digit, NULL, 8);
796 /* Escape all '"', "'" and '\' chars with '\' */
797 char *escape_string(const char *str)
801 p = ret = g_malloc(strlen(str)*2+1);
802 while (*str != '\0') {
803 if (*str == '"' || *str == '\'' || *str == '\\')