/* $Id: dynstuff.c 11259 2010-02-17 04:47:22Z borkra $ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski * Dawid Jarosz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. * * 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "gg.h" #include #include #include #include /* * list_add_sorted() * * dodaje do listy dany element. przy okazji może też skopiować zawartość. * jeśli poda się jako ostatni parametr funkcję porównującą zawartość * elementów, może posortować od razu. * * - list - wskaźnik do listy, * - data - wskaźnik do elementu, * - alloc_size - rozmiar elementu, jeśli chcemy go skopiować. * * zwraca wskaźnik zaalokowanego elementu lub NULL w przpadku błędu. */ void *list_add_sorted(list_t *list, void *data, int alloc_size, int (*comparision)(void *, void *)) { if (!list) { errno = EFAULT; return NULL; } list_t newlist = (list_t)malloc(sizeof(struct list)); newlist->data = data; newlist->next = NULL; if (alloc_size) { newlist->data = malloc(alloc_size); memcpy(newlist->data, data, alloc_size); } list_t tmp; if (!(tmp = *list)) { *list = newlist; } else { if (!comparision) { while (tmp->next) tmp = tmp->next; tmp->next = newlist; } else { list_t prev = NULL; while (comparision(newlist->data, tmp->data) > 0) { prev = tmp; tmp = tmp->next; if (!tmp) break; } if (!prev) { tmp = *list; *list = newlist; newlist->next = tmp; } else { prev->next = newlist; newlist->next = tmp; } } } return newlist->data; } /* * list_add() * * wrapper do list_add_sorted(), który zachowuje poprzednią składnię. */ void *list_add(list_t *list, void *data, int alloc_size) { return list_add_sorted(list, data, alloc_size, NULL); } /* * list_remove() * * usuwa z listy wpis z podanym elementem. * * - list - wskaźnik do listy, * - data - element, * - free_data - zwolnić pamięć po elemencie. */ int list_remove(list_t *list, void *data, int free_data) { list_t tmp, last = NULL; if (!list || !*list) { errno = EFAULT; return -1; } tmp = *list; if (tmp->data == data) { *list = tmp->next; } else { for (; tmp && tmp->data != data; tmp = tmp->next) last = tmp; if (!tmp) { errno = ENOENT; return -1; } last->next = tmp->next; } if (free_data) free(tmp->data); free(tmp); return 0; } /* * list_count() * * zwraca ilość elementów w danej liście. * * - list - lista. */ int list_count(list_t list) { int count = 0; for (; list; list = list->next) count++; return count; } /* * list_destroy() * * niszczy wszystkie elementy listy. * * - list - lista, * - free_data - czy zwalniać bufor danych? */ int list_destroy(list_t list, int free_data) { list_t tmp; while (list) { if (free_data) free(list->data); tmp = list->next; free(list); list = tmp; } return 0; } /* * string_realloc() * * upewnia się, że w stringu będzie wystarczająco dużo miejsca. * * - s - ciąg znaków, * - count - wymagana ilość znaków (bez końcowego '\0'). */ static void string_realloc(string_t s, int count) { char *tmp; if (s->str && count + 1 <= s->size) return; tmp = (char*)realloc(s->str, count + 81); if (!s->str) *tmp = 0; tmp[count + 80] = 0; s->size = count + 81; s->str = tmp; } /* * string_append_c() * * dodaje do danego ciągu jeden znak, alokując przy tym odpowiednią ilość * pamięci. * * - s - ciąg znaków. * - c - znaczek do dopisania. */ int string_append_c(string_t s, char c) { if (!s) { errno = EFAULT; return -1; } string_realloc(s, s->len + 1); s->str[s->len + 1] = 0; s->str[s->len++] = c; return 0; } /* * string_append_n() * * dodaje tekst do bufora alokując odpowiednią ilość pamięci. * * - s - ciąg znaków, * - str - tekst do dopisania, * - count - ile znaków tego tekstu dopisać? (-1 znaczy, że cały). */ int string_append_n(string_t s, const char *str, int count) { if (!s || !str) { errno = EFAULT; return -1; } if (count == -1) count = (int)strlen(str); string_realloc(s, s->len + count); s->str[s->len + count] = 0; strncpy(s->str + s->len, str, count); s->len += count; return 0; } int string_append(string_t s, const char *str) { return string_append_n(s, str, -1); } /* * string_insert_n() * * wstawia tekst w podane miejsce bufora. * * - s - ciąg znaków, * - index - miejsce, gdzie mamy wpisać (liczone od 0), * - str - tekst do dopisania, * - count - ilość znaków do dopisania (-1 znaczy, że wszystkie). */ void string_insert_n(string_t s, int index, const char *str, int count) { if (!s || !str) return; if (count == -1) count = (int)strlen(str); if (index > s->len) index = s->len; string_realloc(s, s->len + count); memmove(s->str + index + count, s->str + index, s->len + 1 - index); memmove(s->str + index, str, count); s->len += count; } void string_insert(string_t s, int index, const char *str) { string_insert_n(s, index, str, -1); } /* * string_init() * * inicjuje strukturę string. alokuje pamięć i przypisuje pierwszą wartość. * * - value - jeśli NULL, ciąg jest pusty, inaczej kopiuje tam. * * zwraca zaalokowaną strukturę `string'. */ string_t string_init(const char *value) { string_t tmp = (string_t)malloc(sizeof(struct string)); if (!value) value = ""; tmp->str = _strdup(value); tmp->len = (int)strlen(value); tmp->size = (int)strlen(value) + 1; return tmp; } /* * string_clear() * * czyści zawartość struktury `string'. * * - s - ciąg znaków. */ void string_clear(string_t s) { if (!s) return; if (s->size > 160) { s->str = (char*)realloc(s->str, 80); s->size = 80; } s->str[0] = 0; s->len = 0; } /* * string_free() * * zwalnia pamięć po strukturze string i może też zwolnić pamięć po samym * ciągu znaków. * * - s - struktura, którą wycinamy, * - free_string - zwolnić pamięć po ciągu znaków? * * jeśli free_string=0 zwraca wskaźnik do ciągu, inaczej NULL. */ char *string_free(string_t s, int free_string) { char *tmp = NULL; if (!s) return NULL; if (free_string) free(s->str); else tmp = s->str; free(s); return tmp; } /* * _itoa() * * prosta funkcja, która zwraca tekstową reprezentację liczby. w obrębie * danego wywołania jakiejś funkcji lub wyrażenia może być wywołania 10 * razy, ponieważ tyle mamy statycznych buforów. lepsze to niż ciągłe * tworzenie tymczasowych buforów na stosie i sprintf()owanie. * * - i - liczba do zamiany. * * zwraca adres do bufora, którego _NIE_NALEŻY_ zwalniać. */ const char *ditoa(long int i) { static char bufs[10][16]; static int index = 0; char *tmp = bufs[index++]; if (index > 9) index = 0; mir_snprintf(tmp, 16, "%ld", i); return tmp; } /* * array_make() * * tworzy tablicę tekstów z jednego, rozdzielonego podanymi znakami. * * - string - tekst wejściowy, * - sep - lista elementów oddzielających, * - max - maksymalna ilość elementów tablicy. jeśli równe 0, nie ma * ograniczeń rozmiaru tablicy. * - trim - czy większą ilość elementów oddzielających traktować jako * jeden (na przykład spacje, tabulacja itp.) * - quotes - czy pola mogą być zapisywane w cudzysłowiach lub * apostrofach z escapowanymi znakami. * * zaalokowaną tablicę z zaalokowanymi ciągami znaków, którą należy * zwolnić funkcją array_free() */ char **array_make(const char *string, const char *sep, int max, int trim, int quotes) { const char *p, *q; char **result = NULL; int items = 0, last = 0; if (!string || !sep) goto failure; for (p = string; ; ) { int len = 0; char *token = NULL; if (max && items >= max - 1) last = 1; if (trim) { while (*p && strchr(sep, *p)) p++; if (!*p) break; } if (!last && quotes && (*p == '\'' || *p == '\"')) { char sep = *p; for (q = p + 1, len = 0; *q; q++, len++) { if (*q == '\\') { q++; if (!*q) break; } else if (*q == sep) break; } if ((token = (char*)calloc(1, len + 1))) { char *r = token; for (q = p + 1; *q; q++, r++) { if (*q == '\\') { q++; if (!*q) break; switch (*q) { case 'n': *r = '\n'; break; case 'r': *r = '\r'; break; case 't': *r = '\t'; break; default: *r = *q; } } else if (*q == sep) { break; } else *r = *q; } *r = 0; } p = (*q) ? q + 1 : q; } else { for (q = p, len = 0; *q && (last || !strchr(sep, *q)); q++, len++); token = (char*)calloc(1, len + 1); strncpy(token, p, len); token[len] = 0; p = q; } result = (char**)realloc(result, (items + 2) * sizeof(char*)); result[items] = token; result[++items] = NULL; if (!*p) break; p++; } failure: if (!items) result = (char**)calloc(1, sizeof(char*)); return result; } /* * array_count() * * zwraca ilość elementów tablicy. */ int array_count(char **array) { int result = 0; if (!array) return 0; while (*array) { result++; array++; } return result; } /* * array_add() * * dodaje element do tablicy. */ void array_add(char ***array, char *string) { int count = array_count(*array); *array = (char**)realloc(*array, (count + 2) * sizeof(char*)); (*array)[count + 1] = NULL; (*array)[count] = string; } /* * array_join() * * łączy elementy tablicy w jeden string oddzielając elementy odpowiednim * separatorem. * * - array - wskaźnik do tablicy, * - sep - seperator. * * zwrócony ciąg znaków należy zwolnić. */ char *array_join(char **array, const char *sep) { string_t s = string_init(NULL); int i; if (!array) return _strdup(""); for (i = 0; array[i]; i++) { if (i) string_append(s, sep); string_append(s, array[i]); } return string_free(s, 0); } /* * array_contains() * * stwierdza, czy tablica zawiera podany element. * * - array - tablica, * - string - szukany ciąg znaków, * - casesensitive - czy mamy zwracać uwagę na wielkość znaków? * * 0/1 */ int array_contains(char **array, const char *string, int casesensitive) { int i; if (!array || !string) return 0; for (i = 0; array[i]; i++) { if (casesensitive && !strcmp(array[i], string)) return 1; if (!casesensitive && !strcasecmp(array[i], string)) return 1; } return 0; } /* * array_free() * * zwalnia pamieć zajmowaną przez tablicę. */ void array_free(char **array) { char **tmp; if (!array) return; for (tmp = array; *tmp; tmp++) free(*tmp); free(array); }