utils: changes/more tests
authorNiki Roo <niki@nikiroo.be>
Sun, 20 Mar 2022 13:29:32 +0000 (14:29 +0100)
committerNiki Roo <niki@nikiroo.be>
Sun, 20 Mar 2022 13:29:32 +0000 (14:29 +0100)
13 files changed:
src/nsub/nsub.c
src/tests/utils/array.c
src/tests/utils/cstring.c
src/tests/utils/desktop.c [new file with mode: 0644]
src/tests/utils/main.c
src/tests/utils/main.h
src/tests/utils/test.desktop [new file with mode: 0644]
src/utils/array.c
src/utils/array.h
src/utils/cstring.c
src/utils/cstring.h
src/utils/desktop.c
src/utils/desktop.h

index e0629febc8d29404adc63147ad9f01bcec73f4d0..d5d39cbe50e93a07c96ebe0442c05591a80a6899 100644 (file)
@@ -21,7 +21,6 @@
 #include <string.h>
 
 #include "nsub.h"
-#include "utils/array.h"
 #include "utils/utils.h"
 
 /* Public */
@@ -104,16 +103,18 @@ void song_add_meta(song_t *song, char *key, char *value) {
 }
 
 song_t *nsub_read(FILE *in, NSUB_FORMAT fmt) {
-       array_t *lines = new_array(sizeof(char *), 80);
-       array_readfiles(lines, in);
-
        song_t *song = new_song();
-       array_loop_i(lines, line, char, i)
-       {
+
+       cstring_t *line = new_cstring();
+       size_t i = 0;
+       while (cstring_readline(line, in)) {
+               i++;
+
                switch (fmt) {
                case NSUB_FMT_LRC:
-                       if (!nsub_read_lrc(song, line)) {
-                               fprintf(stderr, "Read error on line %zu: <%s>\n", i, line);
+                       if (!nsub_read_lrc(song, line->string)) {
+                               fprintf(stderr, "Read error on line %zu: <%s>\n", i,
+                                               line->string);
                                song = NULL;
                                goto fail;
                        }
@@ -128,9 +129,7 @@ song_t *nsub_read(FILE *in, NSUB_FORMAT fmt) {
 
        fail:
 
-       array_loop(lines, line, void)
-               free(line);
-
+       free_cstring(line);
        return song;
 }
 
index 6d7d9c2fc787e571ebcab8a57fed0f02729085ec..404c6a6fe5b7c6494c302ff5118f41029265ac2a 100644 (file)
@@ -180,7 +180,7 @@ START(pop)
                ASSERT_EQUALS_INT("bad item popped", (int )'T', (int )*rep);
 
                if (a->count)
-                       FAIL("popped 1-sized array still has %d items", a->count);
+                       FAIL("popped 1-sized array still has %zu items", a->count);
 
                rep = array_new(a);
                *rep = 'T';
@@ -247,10 +247,6 @@ START(NO_TEST_YET_set)
                END
 START(NO_TEST_YET_copy)
                END
-START(NO_TEST_YET_readfile)
-               END
-START(NO_TEST_YET_print)
-               END
 
 Suite *test_array(const char title[]) {
        Suite *suite = suite_create(title);
@@ -272,8 +268,6 @@ Suite *test_array(const char title[]) {
        tcase_add_test(core, NO_TEST_YET_push);
        tcase_add_test(core, NO_TEST_YET_set);
        tcase_add_test(core, NO_TEST_YET_copy);
-       tcase_add_test(core, NO_TEST_YET_readfile);
-       tcase_add_test(core, NO_TEST_YET_print);
 
        suite_add_tcase(suite, core);
 
index fb94c8fe9881552568ba43366acac75ed9ec7d79..267d695dacd3587b11e1627326f7baacf4f068e9 100644 (file)
@@ -390,9 +390,12 @@ START(rfind)
                ASSERT_EQUALS_INT("(a) find error", 0, cstring_rfind(str, "Une", 0));
                ASSERT_EQUALS_INT("(b) find error", 0, cstring_rfind(str, "Une", 1));
                ASSERT_EQUALS_INT("(c) find error", 4, cstring_rfind(str, "petite", 0));
-               ASSERT_EQUALS_INT("(d) find error", 4, cstring_rfind(str, "petite", 11));
-               ASSERT_EQUALS_INT("(e) find error", -1, cstring_rfind(str, "petite", 2));
-               ASSERT_EQUALS_INT("(f) find error", 38, cstring_rfind(str, "choses", 0));
+               ASSERT_EQUALS_INT("(d) find error", 4,
+                               cstring_rfind(str, "petite", 11));
+               ASSERT_EQUALS_INT("(e) find error", -1,
+                               cstring_rfind(str, "petite", 2));
+               ASSERT_EQUALS_INT("(f) find error", 38,
+                               cstring_rfind(str, "choses", 0));
                ASSERT_EQUALS_INT("(g) find error", -1, cstring_rfind(str, "Oops", 0));
                ASSERT_EQUALS_INT("(h) find error", 42, cstring_rfind(str, "e", 0));
                ASSERT_EQUALS_INT("(i) find error", 42, cstring_rfind(str, "e", -1));
@@ -774,6 +777,29 @@ START(dirname)
 
                END
 
+START(concat)
+               char *cc;
+
+               cc = cstring_concat(NULL);
+               if (cc)
+                       FAIL("concat of NULL should return NULL, not: <%s>", cc);
+
+               cc = cstring_concat("only", NULL);
+               ASSERT_EQUALS_STR("Single parameter", "only", cc);
+               free(cc);
+
+               cc = cstring_concat("Only", "Fans", NULL);
+               ASSERT_EQUALS_STR("Test 2 params", "OnlyFans", cc);
+               free(cc);
+
+               cc = cstring_concat("Fanfan", " ", "et", " Tulipe",
+                               " entrent dans un bar", NULL);
+               ASSERT_EQUALS_STR("Test multiple params",
+                               "Fanfan et Tulipe entrent dans un bar", cc);
+               free(cc);
+
+               END
+
 START(many_adds)
                size_t count = 10 * 1000 * 1000;
                for (size_t i = 0; i < count; i++) {
@@ -815,6 +841,7 @@ Suite *test_cstring(const char title[]) {
        tcase_add_test(core, pop_path);
        tcase_add_test(core, basename);
        tcase_add_test(core, dirname);
+       tcase_add_test(core, concat);
 
        suite_add_tcase(suite, core);
 
diff --git a/src/tests/utils/desktop.c b/src/tests/utils/desktop.c
new file mode 100644 (file)
index 0000000..c219d8a
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * CUtils: some small C utilities
+ *
+ * Copyright (C) 2022 Niki Roo
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "../../utils/desktop.h"
+
+#include <check.h>
+
+#include "../launcher.h"
+
+desktop_t *d;
+
+static void setup() {
+       d = new_desktop("utils/test.desktop", 24);
+}
+
+static void teardown() {
+       free_desktop(d);
+}
+
+static void reset() {
+       teardown();
+       setup();
+}
+
+START(init)
+               if (!d)
+                       FAIL("new_desktop returned NULL");
+
+               ASSERT_EQUALS_STR("Name", "IRC", d->name);
+               ASSERT_EQUALS_STR("Icon", "irssi", d->icon);
+               ASSERT_EQUALS_STR("Exec", "irssi", d->icon);
+
+               END
+
+               // TODO
+START(NO_TEST_YET_submenu)
+               END
+START(NO_TEST_YET_icons)
+               END
+START(NO_TEST_YET_find_icon)
+               END
+START(NO_TEST_YET_find_id)
+               END
+
+Suite *test_desktop(const char title[]) {
+
+       d = new_desktop("test.desktop", 24);
+       free_desktop(d);
+
+       Suite *suite = suite_create(title);
+
+       TCase *core = tcase_create("core");
+       tcase_add_checked_fixture(core, setup, teardown);
+       tcase_add_test(core, init);
+       tcase_add_test(core, NO_TEST_YET_submenu);
+       tcase_add_test(core, NO_TEST_YET_icons);
+       tcase_add_test(core, NO_TEST_YET_find_icon);
+       tcase_add_test(core, NO_TEST_YET_find_id);
+
+       suite_add_tcase(suite, core);
+
+       return suite;
+}
+
+Suite *test_desktop_more(const char title[]) {
+       Suite *suite = suite_create(title);
+
+       TCase *tmore = tcase_create("more");
+       tcase_add_checked_fixture(tmore, setup, teardown);
+       // TODO
+
+       suite_add_tcase(suite, tmore);
+
+       return suite;
+}
index 474c43112b9a6b1e1139c83017ced2111ed218b8..4f2986a5f5e0e39abb6bbc1ac3db480bbe12f8b0 100644 (file)
@@ -36,6 +36,10 @@ SRunner *get_tests(int more) {
        if (more)
                add_test(test_base64_more("base64 -- more (longer)"));
 
+       add_test(test_desktop("desktop"));
+               if (more)
+                       add_test(test_desktop_more("desktop -- more (longer)"));
+
        return runner;
 }
 
index 5fced56cb5fe4b3c4d19884b884e4ec4c264fb0f..f27dafad92680b8efad366eb685d2fa8a242581a 100644 (file)
@@ -28,5 +28,7 @@ Suite *test_array(const char title[]);
 Suite *test_array_more(const char title[]);
 Suite *test_base64(const char title[]);
 Suite *test_base64_more(const char title[]);
+Suite *test_desktop(const char title[]);
+Suite *test_desktop_more(const char title[]);
 
 #endif /* SRC_TESTS_UTILS_MAIN_H_ */
diff --git a/src/tests/utils/test.desktop b/src/tests/utils/test.desktop
new file mode 100644 (file)
index 0000000..234d390
--- /dev/null
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Version=1.0
+Name=IRC
+Comment=Launch an IRC client
+Exec=irssi
+Icon=irssi
+Terminal=true
+Categories=Internet
+Type=Application
+StartupNotify=true
index 6e192ef379183591696c19ac67ae3eee5d164b8e..c5299f0ebb94df31999c853657c2aa9369b18da9 100644 (file)
@@ -43,46 +43,59 @@ static int array_qsorti_rfunc(const void *a, const void *b);
 static int array_qsortl_rfunc(const void *a, const void *b);
 static int array_qsortf_rfunc(const void *a, const void *b);
 
-/* for reafilei, readfiles */
-static void array_readfile_funci(array_t *me, const char line[]);
-static void array_readfile_funcs(array_t *me, const char line[]);
-
 array_t *new_array(size_t elem_size, size_t initial) {
-       array_t *me = NULL;
-
-       if (initial)
-               me = malloc(sizeof(array_t));
-
-       if (me) {
-               me->priv = malloc(sizeof(priv_t));
-               if (me->priv) {
-                       priv_t *priv = (priv_t *) me->priv;
-                       strcpy(me->CNAME, "[CArray ]");
-                       priv->elem_size = elem_size;
-                       me->count = 0;
-                       priv->buffer = initial;
-                       priv->data = malloc(elem_size * initial);
-                       if (!priv->data) {
-                               free(me->priv);
-                               free(me);
-                               me = NULL;
-                       }
-               }
+       if (!initial)
+               return NULL;
+
+       array_t *me = malloc(sizeof(array_t));
+       if (!init_array(me, elem_size, initial)) {
+               free(me);
+               me = NULL;
        }
 
        return me;
 }
 
+int init_array(array_t *me, size_t elem_size, size_t initial) {
+       if (!initial)
+               return 0;
+
+       strcpy(me->CNAME, "[CArray ]");
+
+       me->priv = malloc(sizeof(priv_t));
+       if (!me->priv)
+               return 0;
+
+       priv_t *priv = (priv_t *) me->priv;
+       strcpy(me->CNAME, "[CArray ]");
+       priv->elem_size = elem_size;
+       me->count = 0;
+       priv->buffer = initial;
+       priv->data = malloc(elem_size * initial);
+       if (!priv->data) {
+               free(me->priv);
+               return 0;
+       }
+
+       return 1;
+}
+
 void free_array(array_t *me) {
-       if (!me)
-               return;
+       if (me)
+               uninit_array(me);
 
+       free(me);
+}
+
+void uninit_array(array_t *me) {
        priv_t *priv = (priv_t *) me->priv;
        me->count = 0;
        priv->buffer = 0;
        free(priv->data);
+       priv->data = NULL;
        free(priv);
-       free(me);
+       me->priv = NULL;
+       me->CNAME[0] = '!';
 }
 
 void array_clear(array_t *me) {
@@ -305,119 +318,6 @@ int array_setn(array_t *me, size_t i, void *data, size_t n) {
        return 1;
 }
 
-size_t array_readfilei(array_t *me, FILE *in) {
-       return array_readfile(me, in, array_readfile_funci);
-}
-
-size_t array_readfiles(array_t *me, FILE *in) {
-       return array_readfile(me, in, array_readfile_funcs);
-}
-
-size_t array_readfile(array_t *me, FILE *in,
-               void (*doline)(array_t *me, const char line[])) {
-       array_t *mot = NULL;
-
-       char zero = '\0';
-       char buffer[4096];
-       size_t i, n, start, count;
-       mot = new_array(sizeof(char), 80);
-       priv_t *mot_priv = (priv_t *) mot->priv;
-
-       count = 0;
-       for (n = fread(buffer, sizeof(char), sizeof(buffer), in)
-       ; n; n = fread(buffer, sizeof(char), sizeof(buffer), in)) {
-               for (i = 0; i < n; i++) {
-                       for (start = i; i < n && buffer[i] != '\n'; i++)
-                               ;
-                       if (i > start) {
-                               array_pushn(mot, buffer + start, (i - start));
-                       }
-
-                       if (i == start || (i < n && buffer[i] == '\n')) {
-                               array_push(mot, &zero);
-                               doline(me, mot_priv->data);
-                               count++;
-                               array_clear(mot);
-                       }
-               }
-       }
-
-       if (mot->count) {
-               array_push(mot, &zero);
-               doline(me, mot_priv->data);
-               count++;
-       }
-
-       free_array(mot);
-       return count;
-}
-
-void array_print(array_t *me) {
-       array_print_fmt(me, NULL, NULL);
-}
-
-void array_prints(array_t *me) {
-       priv_t *priv = (priv_t *) me->priv;
-
-       array_print_fmt(me, NULL, NULL);
-       for (size_t i = 0; i < me->count; i++) {
-               void *d = (void *) (((void **) priv->data)[i]);
-               fprintf(stdout, "> %zu: %s\n", i, (char *) d);
-       }
-}
-
-void array_printi(array_t *me) {
-       priv_t *priv = (priv_t *) me->priv;
-
-       array_print_fmt(me, NULL, NULL);
-       int *ii = malloc(me->count * priv->elem_size);
-       memcpy(ii, priv->data, me->count * priv->elem_size);
-       for (size_t i = 0; i < me->count; i++) {
-               fprintf(stdout, "> %zu: %d\n", i, ii[i]);
-       }
-       free(ii);
-}
-
-void array_printl(array_t *me) {
-       priv_t *priv = (priv_t *) me->priv;
-
-       array_print_fmt(me, NULL, NULL);
-       long *l = malloc(me->count * priv->elem_size);
-       memcpy(l, priv->data, me->count * priv->elem_size);
-       for (size_t i = 0; i < me->count; i++) {
-               fprintf(stdout, "> %zu: %ld\n", i, l[i]);
-       }
-       free(l);
-}
-
-void array_printf(array_t *me) {
-       priv_t *priv = (priv_t *) me->priv;
-
-       array_print_fmt(me, NULL, NULL);
-       float *f = malloc(me->count * priv->elem_size);
-       memcpy(f, priv->data, me->count * priv->elem_size);
-       for (size_t i = 0; i < me->count; i++) {
-               fprintf(stdout, "> %zu: %f\n", i, f[i]);
-       }
-       free(f);
-}
-
-void array_print_fmt(array_t *me, void (*display)(char *buffer, void *),
-               char *buffer) {
-       priv_t *priv = (priv_t *) me->priv;
-
-       fprintf(stdout,
-                       "Array of %zu elements of %zu bytes (buffer of %zu elements)\n",
-                       me->count, priv->elem_size, priv->buffer);
-       if (display) {
-               for (size_t i = 0; i < me->count; i++) {
-                       void *d = (void *) (((void **) priv->data)[i]);
-                       display(d, buffer);
-                       fprintf(stdout, "> %zu: %s\n", i, buffer);
-               }
-       }
-}
-
 /* Privates functions */
 
 static int array_assure(array_t *me, size_t nb_elem) {
@@ -438,15 +338,3 @@ static int array_assure(array_t *me, size_t nb_elem) {
 
        return 1;
 }
-
-static void array_readfile_funci(array_t *me, const char line[]) {
-       int i = atoi(line);
-       array_push(me, &i);
-}
-
-static void array_readfile_funcs(array_t *me, const char line[]) {
-       char *myline = malloc((strlen(line) + 1) * sizeof(char));
-       strcpy(myline, line);
-       char **n = array_new(me);
-       *n = myline;
-}
index caf81286277a1f13801199ca04f931f5c6bb758a..201c2a01623d4f0554d53cbbcd506383ed7f9072 100644 (file)
@@ -130,23 +130,51 @@ typedef struct {
 /**
  * Create a new array.
  *
+ * @note always identical to <tt>malloc</tt> + <tt>init_array</tt>
+ *
  * @param elem_size the size of one element
- * @param initial the initial number of items the buffer can hold
+ * @param initial the initial number of items the buffer can hold (<b>not</b> 0)
+ *
+ * @see malloc()
+ * @see init_array(array_t *self)
  *
  * @return a new array (you must later call `free_array()` or `array_convert()`)
  */
 array_t *new_array(size_t elem_size, size_t initial);
 
+/**
+ * Create a new array.
+ *
+ * @param elem_size the size of one element
+ * @param initial the initial number of items the buffer can hold (<b>not</b> 0)
+ */
+int init_array(array_t *self, size_t elem_size, size_t initial);
+
 /** 
  * Free the resources held for the given array: you must not use it any more.
  * Note that if you use pointers and not direct data, you may want to free
  * those yourself first.
  *
+ * @note always equivalent to <tt>uninit_array</tt> + <tt>free</tt>
+ *
+ * @see uninit_array(array_t *self)
+ * @see free(void *data)
  * @see array_clear
  * @see array_loop
  */
 void free_array(array_t *me);
 
+/**
+ * Free the resources held for the given array: you must not use it any more.
+ * Note that if you use pointers and not direct data, you may want to free
+ * those yourself first.
+ *
+ * @see free_array(array_t *self)
+ * @see array_clear
+ * @see array_loop
+ */
+void uninit_array(array_t *me);
+
 /**
  * Clear the array, that is, resets its current size to 0 (buffer unchanged).
  */
@@ -328,39 +356,6 @@ int array_push(array_t *me, void *data);
  */
 int array_pushn(array_t *me, void *data, size_t n);
 
-/**
- * Set an element of the array to the given value.
- * Can also append a new elements.
- * Memory will be copied from the given data to the array.
- *
- * @param i the element index
- * @param data the data that will replace the current value, or new data
- *     to append after the current elements (you can add items just at
- *     the end of the array (index = count), but it is not allowed to
- *     set items after that index, so not to create holes)
- *
- * @return FALSE if the array is too short and we cannot allocate enough 
- *     contiguous memory for its needs, or if the index is out of bounds
- */
-int array_set(array_t *me, size_t i, void *data);
-
-/**
- * Set elements of the array to the given value.
- * Can also append some of them to the array if no values were present.
- * Memory will be copied from the given data to the array.
- *
- * @param i the element index to start the insertion at
- * @param data the data that will replace the current values, or new data
- *     to append after the current elements (you can add items just at
- *     the end of the array (index = count), but it is not allowed to
- *     set items with `i` after that index, so not to create holes)
- * @param n the number of elements to copy from `data` and to insert at `i`
- *
- * @return FALSE if the array is too short and we cannot allocate enough 
- *     contiguous memory for its needs, or if the index is out of bounds
- */
-int array_setn(array_t *me, size_t i, void *data, size_t n);
-
 /**
  * Retrieve the content of an item.
  * The item will be copied to the given address location if it exists.
@@ -386,88 +381,37 @@ int array_copy(array_t *me, void *target, size_t i);
 int array_copyn(array_t *me, void *target, size_t i, size_t n);
 
 /**
- * Read all the lines from a file.
- *
- * All the lines are supposed to be \n-terminated.
- *
- * @param in the file to read from
- * @param doline a function that will receive the data for each line
- * @param (parameters)
- *     * `me`: the array we work on (the one you passed to 
- *             `array_readfile()` itself)
- *     * `line`: a read-only copy of the current line
- *
- * @return the number of elements in the array
- */
-size_t array_readfile(array_t *me, FILE *in,
-               void (*doline)(array_t *me, const char line[]));
-
-/**
- * Read all the lines from a file, converting them to integer values.
- *
- * Note that the integer conversion will only convert the initial portion of
- * each line if the rest is not considered numerical (also, if it fails to
- * convert, it will simply store the value 0 for this line).
- *
- * @see array_readfile
+ * Set an element of the array to the given value.
+ * Can also append a new elements.
+ * Memory will be copied from the given data to the array.
  *
- * @param in the file to read
+ * @param i the element index
+ * @param data the data that will replace the current value, or new data
+ *     to append after the current elements (you can add items just at
+ *     the end of the array (index = count), but it is not allowed to
+ *     set items after that index, so not to create holes)
  *
- * @return the number of elements in the array
+ * @return FALSE if the array is too short and we cannot allocate enough 
+ *     contiguous memory for its needs, or if the index is out of bounds
  */
-size_t array_readfilei(array_t *me, FILE *in);
+int array_set(array_t *me, size_t i, void *data);
 
 /**
- * Read all the lines from a file, converting them to strings.
- *
- * Note that you will need to free them before freeing the array,
- * for instance with the <tt>array_loop</tt> macro.
- *
- * @see array_loop
- * @see array_readfile
- *
- * @param in the file to read
+ * Set elements of the array to the given value.
+ * Can also append some of them to the array if no values were present.
+ * Memory will be copied from the given data to the array.
  *
- * @return the number of elements in the array
- */
-size_t array_readfiles(array_t *me, FILE *in);
-
-/**
- * Print the array metadata to `stderr` (mostly for DEBUG).
- */
-void array_print(array_t *me);
-
-/**
- * Print the array and strings content to `stderr` (mostly for DEBUG).
- */
-void array_prints(array_t *me);
-
-/**
- * Print the array and integer content to `stderr` (mostly for DEBUG).
- */
-void array_printi(array_t *me);
-
-/**
- * Print the array and long content to `stderr` (mostly for DEBUG).
- */
-void array_printl(array_t *me);
-
-/**
- * Print the array and floats (%d) content to `stderr` (mostly for DEBUG).
- */
-void array_printf(array_t *me);
-
-/** 
- * Print the array and content to `stderr` (mostly for DEBUG).
+ * @param i the element index to start the insertion at
+ * @param data the data that will replace the current values, or new data
+ *     to append after the current elements (you can add items just at
+ *     the end of the array (index = count), but it is not allowed to
+ *     set items with `i` after that index, so not to create holes)
+ * @param n the number of elements to copy from `data` and to insert at `i`
  *
- * @param display a function that gives a textual representation of an item
- * @param (parameters)
- *     * `item`: the item to describe
- *     * `buffer`: the buffer to use for this (which is the one you pass)
- * @param buffer a buffer that will be passed to `display`
+ * @return FALSE if the array is too short and we cannot allocate enough 
+ *     contiguous memory for its needs, or if the index is out of bounds
  */
-void array_print_fmt(array_t *me, void (*display)(char *buffer, void *item),
-               char *buffer);
+int array_setn(array_t *me, size_t i, void *data, size_t n);
 
 #endif /* ARRAY_H */
 
index 5505f272839b9b8929d6f9008112adacd5f8deb9..6dcdeba3314aa000e6d4fdfd6970da78e987a5e5 100644 (file)
@@ -66,27 +66,48 @@ static char *locale = NULL;
 // end of privates
 
 cstring_t *new_cstring() {
-       cstring_t *string;
+       cstring_t *self = malloc(sizeof(cstring_t));
+       if (!init_cstring(self)) {
+               free(self);
+               self = NULL;
+       }
+
+       return self;
+}
 
-       string = malloc(sizeof(cstring_t));
-       strcpy(string->CNAME, "[CString]");
-       string->priv = malloc(sizeof(priv_t));
-       string->length = 0;
-       ((priv_t *) string->priv)->buffer_length = BUFFER_SIZE;
-       string->string = malloc(sizeof(char) * BUFFER_SIZE);
-       string->string[0] = '\0';
+int init_cstring(cstring_t *self) {
+       strcpy(self->CNAME, "[CString]");
 
-       return string;
+       self->priv = malloc(sizeof(priv_t));
+       if (!self->priv)
+               return 0;
+       self->string = malloc(sizeof(char) * BUFFER_SIZE);
+       if (!self->string) {
+               free(self->priv);
+               return 0;
+       }
+
+       self->length = 0;
+       ((priv_t *) self->priv)->buffer_length = BUFFER_SIZE;
+       self->string[0] = '\0';
+
+       return 1;
 }
 
-void free_cstring(cstring_t *string) {
-       if (!string)
-               return;
+void free_cstring(cstring_t *self) {
+       if (self)
+               uninit_cstring(self);
 
-       free(string->priv);
-       free(string->string);
+       free(self);
+}
 
-       free(string);
+void uninit_cstring(cstring_t *self) {
+       free(self->priv);
+       free(self->string);
+       self->priv = NULL;
+       self->string = NULL;
+       self->length = 0;
+       self->CNAME[0] = '!';
 }
 
 void cstring_swap(cstring_t *a, cstring_t *b) {
@@ -717,3 +738,36 @@ int cstring_is_utf8(cstring_t *self) {
        // -2 = invalid, -1 = not whole
        return (rep != (size_t) -2) && (rep != (size_t) -1);
 }
+
+char *cstring_concat(const char str1[], ...) {
+       if (!str1)
+               return NULL;
+
+       va_list args;
+       size_t total;
+       size_t prec;
+       char *arg;
+       char *ptr;
+       char *rep;
+
+       total = strlen(str1);
+       va_start(args, str1);
+       while ((arg = va_arg(args, char *))) {
+               total += strlen(arg);
+       }
+       va_end(args);
+
+       rep = malloc(total * sizeof(char) + 1);
+       ptr = rep;
+       ptr = strcpy(ptr, str1);
+       prec = strlen(str1);
+
+       va_start(args, str1);
+       while ((arg = va_arg(args, char *))) {
+               ptr = strcpy(ptr + prec, arg);
+               prec = strlen(arg);
+       }
+       va_end(args);
+
+       return rep;
+}
index b38c610698ad33b60b218c6aa2faf2be049003b9..98679dce55ea7bc0d89c6bcf9d3b91a2907cb2bf 100644 (file)
@@ -60,20 +60,48 @@ typedef struct {
 /**
  * Instantiate a new cstring.
  *
+ * @note always identical to <tt>malloc</tt> + <tt>init_cstring</tt>
+ *
  * Create (and allocate the memory for) a new cstring.
  * Do not forget to call cstring_free(cstring) when done.
+ *
+ * @see malloc()
+ * @see init_cstring(cstring_t *self)
  */
 cstring_t *new_cstring();
 
+/**
+ * Instantiate a new cstring.
+ *
+ * Create (and allocate the memory for) a new cstring.
+ * Do not forget to call uninit_cstring(cstring_t *self) when done.
+ *
+ * @see new_cstring()
+ * @see uninit_cstring(cstring_t *self)
+ */
+int init_cstring(cstring_t *self);
+
 /**
  * Free the given cstring.
  *
  * Free all the resources allocated for this cstring.
  *
- * @param self the cstring to free, which MUST NOT be used again afterward
+ * @note always equivalent to <tt>uninit_cstring</tt> + <tt>free</tt>
+ *
+ * @see uninit_cstring(cstring_t *self)
+ * @see free(void *data)
  */
 void free_cstring(cstring_t *self);
 
+/**
+ * Free the given cstring.
+ *
+ * Free all the resources allocated for this cstring.
+ *
+ * @param self the cstring to free, which MUST NOT be used again afterward
+ */
+void uninit_cstring(cstring_t *self);
+
 /**
  * Grow the cstring to accommodate that many characters in addition to those
  * already held, if needed.
@@ -457,6 +485,20 @@ char *cstring_dirname(const char path[]);
  */
 int cstring_is_utf8(cstring_t *self);
 
+/**
+ * Concat all the given string and return the concatenation as a newly allocated
+ * string that you now own.
+ *
+ * @note the last parameter <b>must</b> be NULL
+ *
+ * @note if NULL is passed as first parameter, NULL will be returned
+ *
+ * @param str1 the first string
+ *
+ * @return the concatenated string or NULL if str1 is NULL
+ */
+char *cstring_concat(const char str1[], ...);
+
 #endif
 
 #ifdef __cplusplus
index ba353a7b057c85556b250e6db3eac27cc54b607e..d20055562300b4b8105dfb5a6a7a07648ae00ab9 100644 (file)
 
 #define EXT "desktop"
 
-struct {
-       char *name;
-       char *icon;
-       char *icon_file;
-       char *exec;
-       array_t *children;
-       int id;
-}typedef desktop_p;
-
 /* Private functions */
 static int desktop_compare(const void *a, const void* b);
-static char *desktop_concat(const char str1[], ...);
 static int desktop_test_file(const char filename[]);
 /* */
 
-desktop *new_desktop(const char filename[], int best_size) {
-       desktop_p *me = malloc(sizeof(desktop_p));
+desktop_t *new_desktop(const char filename[], int best_size) {
+       desktop_t *me = malloc(sizeof(desktop_t));
+       if (!init_desktop(me, filename, best_size)) {
+               free(me);
+               me = NULL;
+       }
+
+       return me;
+}
+
+int init_desktop(desktop_t *me, const char filename[], int best_size) {
+       strcpy(me->CNAME, "[Desktop]");
+
        me->name = NULL;
        me->exec = NULL;
        me->icon = NULL;
@@ -94,80 +95,74 @@ desktop *new_desktop(const char filename[], int best_size) {
                        me->icon_file = desktop_find_icon("folder", best_size);
                }
 
-               me->children = new_array(sizeof(desktop_p*), 32);
+               me->children = new_array(sizeof(desktop_t*), 32);
                for (struct dirent *ep = readdir(dp); ep; ep = readdir(dp)) {
                        if (!strcmp(ep->d_name, "."))
                                continue;
                        if (!strcmp(ep->d_name, ".."))
                                continue;
-                       char *childname = desktop_concat(filename, "/", ep->d_name, NULL);
-                       desktop_p *child = (desktop_p*) new_desktop(childname, best_size);
+
+                       desktop_t *child = array_new(me->children);
+                       char *childname = cstring_concat(filename, "/", ep->d_name, NULL);
+                       if (!init_desktop(child, childname, best_size))
+                               array_pop(me->children);
                        free(childname);
-                       if (child) {
-                               array_push(me->children, &child);
-                       }
                }
 
                array_qsort(me->children, desktop_compare);
 
                closedir(dp);
                free(ext);
-               return (desktop*) me;
+               return 1;
        }
 
        // Only process ".desktop" files
        if (!ext || strcmp(ext, EXT)) {
-               free_desktop((desktop *) me);
+               free_desktop(me);
                free(ext);
-               return NULL;
+               return 0;
        }
 
        FILE *file;
-       array_t *tab;
-
-       tab = new_array(sizeof(char *), 32);
+       cstring_t *line;
+       char *startsWith;
 
        file = fopen(filename, "r");
-       array_readfiles(tab, file);
-       fclose(file);
-
-       char *startsWith;
-       size_t n;
-       array_loop_i(tab, line, char, i) {
-               startsWith = "Name=";
-               n = strlen(startsWith);
-               if (!strncmp(line, startsWith, n)) {
-                       free(me->name);
-                       me->name = strdup(line + n);
-               }
+       if (file) {
+               line = new_cstring();
+               while (cstring_readline(line, file)) {
+                       startsWith = "Name=";
+                       if (cstring_starts_with(line->string, startsWith, 0)) {
+                               free(me->name);
+                               me->name = strdup(line->string + strlen(startsWith));
+                       }
 
-               startsWith = "Exec=";
-               n = strlen(startsWith);
-               if (!strncmp(line, startsWith, n)) {
-                       free(me->exec);
-                       me->exec = strdup(line + n);
-                       // TODO: %f %F %u %U %i %c %k: inject values instead
-                       char *cars = "ifFuUck";
-                       for (char *ptr = index(me->exec, '%'); ptr; ptr = index(ptr, '%')) {
-                               if (index(cars, ptr[1])) {
-                                       ptr[0] = ' ';
-                                       ptr[1] = ' ';
+                       startsWith = "Exec=";
+                       if (cstring_starts_with(line->string, startsWith, 0)) {
+                               free(me->exec);
+                               me->exec = strdup(line->string + strlen(startsWith));
+                               // TODO: %f %F %u %U %i %c %k: inject values instead
+                               char *cars = "ifFuUck";
+                               for (char *ptr = index(me->exec, '%'); ptr;
+                                               ptr = index(ptr, '%')) {
+                                       if (index(cars, ptr[1])) {
+                                               ptr[0] = ' ';
+                                               ptr[1] = ' ';
+                                       }
+                                       ptr++;
                                }
-                               ptr++;
                        }
-               }
 
-               startsWith = "Icon=";
-               n = strlen(startsWith);
-               if (!strncmp(line, startsWith, n)) {
-                       free(me->icon);
-                       me->icon = strdup(line + n);
+                       startsWith = "Icon=";
+                       if (cstring_starts_with(line->string, startsWith, 0)) {
+                               free(me->icon);
+                               me->icon = strdup(line->string + strlen(startsWith));
+                       }
                }
+               free_cstring(line);
+               fclose(file);
        }
 
-       array_loop(tab, item, void)
-               free(item);
-
        // Find icon file linked to icon
        if (me->icon && !me->icon_file) {
                me->icon_file = desktop_find_icon(me->icon, best_size);
@@ -178,66 +173,37 @@ desktop *new_desktop(const char filename[], int best_size) {
        }
 
        free(ext);
-       return (desktop *) me;
+       return 1;
 }
 
-void free_desktop(desktop *app) {
-       desktop_p *me = (desktop_p*) app;
+void free_desktop(desktop_t *me) {
+       if (me)
+               uninit_desktop(me);
 
-       if (!me)
-               return;
+       free(me);
+}
 
+void uninit_desktop(desktop_t *me) {
        free(me->name);
        free(me->exec);
        free(me->icon);
        free(me->icon_file);
+       me->name = NULL;
+       me->exec = NULL;
+       me->icon = NULL;
+       me->icon_file = NULL;
        free_array(me->children);
-
-       free(me);
-}
-
-const char *desktop_get_name(desktop *app) {
-       desktop_p *me = (desktop_p*) app;
-       return me->name;
-}
-
-const char *desktop_get_exec(desktop *app) {
-       desktop_p *me = (desktop_p*) app;
-       return me->exec;
-}
-
-const char *desktop_get_icon(desktop *app) {
-       desktop_p *me = (desktop_p*) app;
-       return me->icon;
-}
-
-const char *desktop_get_icon_file(desktop *app) {
-       desktop_p *me = (desktop_p*) app;
-       return me->icon_file;
-}
-
-int desktop_get_id(desktop *app) {
-       desktop_p *me = (desktop_p*) app;
-       return me->id;
-}
-
-void desktop_set_id(desktop *app, int id) {
-       desktop_p *me = (desktop_p*) app;
-       me->id = id;
-}
-
-array_t *desktop_get_children(desktop *app) {
-       desktop_p *me = (desktop_p*) app;
-       return me->children;
+       me->children = NULL;
+       me->CNAME[0] = '!';
 }
 
-desktop *desktop_find_id(array_t *children, int id) {
-       desktop *found = NULL;
+desktop_t *desktop_find_id(array_t *children, int id) {
+       desktop_t *found = NULL;
 
-       array_loop(children, child, desktop_p)
+       array_loop(children, child, desktop_t)
        {
                if (child->id == id) {
-                       found = (desktop*) child;
+                       found = child;
                        break;
                }
 
@@ -251,39 +217,9 @@ desktop *desktop_find_id(array_t *children, int id) {
 
 /* Private functions */
 
-static char *desktop_concat(const char str1[], ...) {
-       va_list args;
-       size_t total;
-       size_t prec;
-       char *arg;
-       char *ptr;
-       char *rep;
-
-       total = strlen(str1);
-       va_start(args, str1);
-       while ((arg = va_arg(args, char *))) {
-               total += strlen(arg);
-       }
-       va_end(args);
-
-       rep = malloc(total * sizeof(char) + 1);
-       ptr = rep;
-       ptr = strcpy(ptr, str1);
-       prec = strlen(str1);
-
-       va_start(args, str1);
-       while ((arg = va_arg(args, char *))) {
-               ptr = strcpy(ptr + prec, arg);
-               prec = strlen(arg);
-       }
-       va_end(args);
-
-       return rep;
-}
-
 static int desktop_compare(const void *a, const void* b) {
-       desktop_p *me1 = ((desktop_p**) a)[0];
-       desktop_p *me2 = ((desktop_p**) b)[0];
+       desktop_t *me1 = ((desktop_t**) a)[0];
+       desktop_t *me2 = ((desktop_t**) b)[0];
 
        if (me1->children && !(me2->children))
                return -1;
@@ -313,7 +249,7 @@ static int desktop_test_file(const char filename[]) {
 
 #define TRY_DIR(a,b,c) \
        do { \
-               tmp = desktop_concat(a, b, c, basename, ".png", NULL); \
+               tmp = cstring_concat(a, b, c, basename, ".png", NULL); \
                if(desktop_test_file(tmp)) \
                        return tmp; \
                free(tmp); \
@@ -328,44 +264,39 @@ char *desktop_find_icon(const char basename[], int icon_size) {
        sprintf(icon_size_str, "%dx%d", icon_size, icon_size);
 
        if (!theme) {
-               array_t *tab = new_array(sizeof(char *), 32);
-
-               tmp = desktop_concat(home, "/.gtkrc-2.0", NULL);
+               tmp = cstring_concat(home, "/.gtkrc-2.0", NULL);
                FILE *file = fopen(tmp, "r");
                free(tmp);
                if (file) {
-                       array_readfiles(tab, file);
+                       const char *startsWith = "gtk-icon-theme-name=";
+                       size_t n = strlen(startsWith);
+
+                       cstring_t *line = new_cstring();
+                       while (cstring_readline(line, file)) {
+                               if (cstring_starts_with(line->string, startsWith, 0)) {
+                                       free(theme);
+                                       if (line->string[n] == '"') {
+                                               theme = strdup(line->string + n + 1);
+                                               theme[strlen(theme) - 1] = '\0';
+                                       } else {
+                                               theme = strdup(line->string + n);
+                                       }
+                               }
+                       }
+                       free_cstring(line);
                        fclose(file);
-               }
 
-               const char *startsWith = "gtk-icon-theme-name=";
-               size_t n = strlen(startsWith);
-
-               array_loop(tab, line, char)
-               {
-                       if (!strncmp(line, startsWith, n)) {
-                               free(theme);
-                               if (line[n] == '"') {
-                                       theme = strdup(line + n + 1);
-                                       theme[strlen(theme) - 1] = '\0';
-                               } else {
-                                       theme = strdup(line + n);
-                               }
+                       if (!theme || !theme[0]) {
+                               theme = strdup("");
+                               ltheme = strdup("");
+                       } else {
+                               tmp = theme;
+                               theme = cstring_concat("/usr/share/icons/", tmp, "/", NULL);
+                               ltheme = cstring_concat(home, "/", ".icons/", tmp, "/", NULL);
+                               free(tmp);
                        }
-               }
 
-               if (!theme || !theme[0]) {
-                       theme = strdup("");
-                       ltheme = strdup("");
-               } else {
-                       tmp = theme;
-                       theme = desktop_concat("/usr/share/icons/", tmp, "/", NULL);
-                       ltheme = desktop_concat(home, "/", ".icons/", tmp, "/", NULL);
-                       free(tmp);
                }
-
-               array_loop(tab,item, void)
-                       free(item);
        }
 
        // Allow NULL
index 8e208ae372fd934710011822ce990e3d7f8d8582..bf39398cc25abfaa84bf896340d5cd7de661ce67 100644 (file)
@@ -52,55 +52,69 @@ extern "C" {
 /**
  * The structure used to represent desktop objects.
  */
-typedef struct desktop_p desktop;
+struct {
+       char CNAME[10];
+       /** The user name of the desktop object. */
+       char *name;
+       /** The icon name, if any. */
+       char *icon;
+       /** The icon file that corresponds, if any. */
+       char *icon_file;
+       /** The EXEC command to start. */
+       char *exec;
+       /** The submenu items of this desktop object (for a menu/submenu). */
+       array_t *children;
+       /** A custom external ID for this desktop object, for your own use. */
+       int id;
+}typedef desktop_t;
 
 /**
  * Create a new desktop object from the given <tt>.desktop</tt> file.
  *
+ * @note always identical to <tt>malloc</tt> + <tt>init_desktop</tt>
+ *
  * @param filename the path to the actual <tt>.desktop</tt> file
  * @param best_size the default size for the icon (see icon selection in the
  *             description of the {@see desktop} object
  *
+ * @see malloc()
+ * @see init_desktop(desktop_t *self, const char filename[], int best_size)
+ * @see free_desktop(desktop_t *self)
+ *
  * @return the desktop object
  */
-desktop *new_desktop(const char filename[], int best_size);
-
-/**
- * Free the given desktop object
- */
-void free_desktop(desktop *self);
-
-/** Return the name of the desktop object (you do <b>not</b> own it). */
-const char *desktop_get_name(desktop *self);
-/** Return the exec command of the desktop object (you do <b>not</b> own it). */
-const char *desktop_get_exec(desktop *self);
-/** Return the icon name of the desktop object (you do <b>not</b> own it). */
-const char *desktop_get_icon(desktop *self);
-/** Return the icon file of the desktop object (you do <b>not</b> own it). */
-const char *desktop_get_icon_file(desktop *self);
+desktop_t *new_desktop(const char filename[], int best_size);
 
 /**
- * Return the external ID of this desktop object
- * ({@see desktop_set_id(desktop*, int)}.
+ * Create a new desktop object from the given <tt>.desktop</tt> file.
  *
- * @return the external ID
+ * @param filename the path to the actual <tt>.desktop</tt> file
+ * @param best_size the default size for the icon (see icon selection in the
+ *             description of the {@see desktop} object
+ *
+ * @see new_desktop(const char filename[], int best_size)
+ * @see uninit_desktop(desktop_t *self)
+ *
+ * @return TRUE if success (could fail if the target is not a <tt>.desktop</tt>
+ *             file
  */
-int desktop_get_id(desktop *self);
+int init_desktop(desktop_t *self, const char filename[], int best_size);
 
 /**
- * Set a custom external ID for this desktop object, for your own use.
+ * Free the given desktop object.
  *
- * @param id the ID to set
+ * @note always equivalent to <tt>uninit_desktop</tt> + <tt>free</tt>
+ *
+ * @see uninit_desktop(desktop_t *self)
+ * @see free(void *data)
  */
-void desktop_set_id(desktop *self, int id);
+void free_desktop(desktop_t *self);
 
 /**
- * Return all the submenu items of this desktop objects (for a menu/submenu).
- *
- * TODO: switch to full objects
- * @return an array of pointers to desktop objects
+ * Free the resources used by the given desktop object -- do not use it anymore
+ * after this call.
  */
-array_t *desktop_get_children(desktop *app);
+void uninit_desktop(desktop_t *self);
 
 /**
  * Find a submenu item by the given ID ({@see desktop_set_id(desktop *, int)}).
@@ -111,7 +125,7 @@ array_t *desktop_get_children(desktop *app);
  *
  * @return the given submenu if found, or NULL
  */
-desktop *desktop_find_id(array_t *children, int menu_id);
+desktop_t *desktop_find_id(array_t *children, int menu_id);
 
 /**
  * Look for the icon file related to this basename.
@@ -119,6 +133,8 @@ desktop *desktop_find_id(array_t *children, int menu_id);
  * @param basename the base name of the icon we want to look for
  * @param icon_size the best_size to use for the icon (see the description of
  *             the {@desktop} object)
+ *
+ * @return the path to the best related icon we found (you own it), or NULL
  */
 char *desktop_find_icon(const char basename[], int icon_size);