#include <string.h>
#include "nsub.h"
-#include "utils/array.h"
#include "utils/utils.h"
/* Public */
}
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;
}
fail:
- array_loop(lines, line, void)
- free(line);
-
+ free_cstring(line);
return song;
}
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';
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);
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);
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));
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++) {
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);
--- /dev/null
+/*
+ * 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;
+}
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;
}
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_ */
--- /dev/null
+[Desktop Entry]
+Version=1.0
+Name=IRC
+Comment=Launch an IRC client
+Exec=irssi
+Icon=irssi
+Terminal=true
+Categories=Internet
+Type=Application
+StartupNotify=true
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) {
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) {
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;
-}
/**
* 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).
*/
*/
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.
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 */
// 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) {
// -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;
+}
/**
* 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.
*/
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
#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;
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);
}
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;
}
/* 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;
#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); \
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
/**
* 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)}).
*
* @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.
* @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);