jdoc, more tests, some utils fixes/changes
authorNiki Roo <niki@nikiroo.be>
Thu, 10 Mar 2022 18:52:59 +0000 (19:52 +0100)
committerNiki Roo <niki@nikiroo.be>
Thu, 10 Mar 2022 18:52:59 +0000 (19:52 +0100)
25 files changed:
src/nsub/nsub.c
src/nsub/nsub.h
src/nsub/nsub_read_lrc.c
src/nsub/nsub_write_lrc.c
src/nsub/nsub_write_srt.c
src/nsub/nsub_write_webvtt.c
src/tests/launcher.c
src/tests/launcher.h
src/tests/utils/array.c
src/tests/utils/base64.c [new file with mode: 0644]
src/tests/utils/cstring.c
src/tests/utils/main.c
src/tests/utils/main.h
src/utils/array.c
src/utils/array.h
src/utils/base64.h
src/utils/cstring.c
src/utils/cstring.h
src/utils/desktop.c
src/utils/desktop.h
src/utils/net.c
src/utils/net.h
src/utils/print.h
src/utils/timing.h
src/utils/utils.h

index ce88cf5efc2abe2bdd38adda0a2973e09e64a1b0..e0629febc8d29404adc63147ad9f01bcec73f4d0 100644 (file)
@@ -37,26 +37,18 @@ song_t *new_song() {
 }
 
 void free_song(song_t *song) {
-       size_t count;
-
        if (!song)
                return;
 
-       count = array_count(song->metas);
-       meta_t *meta;
-       for (size_t i = 0; i < count; i++) {
-               meta = array_get_ptr(song->metas, i);
+       array_loop(song->metas, meta, meta_t)
+       {
                free(meta->key);
                free(meta->value);
        }
        free_array(song->metas);
 
-       count = array_count(song->lyrics);
-       lyric_t *lyric;
-       for (size_t i = 0; i < count; i++) {
-               lyric = array_get_ptr(song->lyrics, i);
+       array_loop(song->lyrics, lyric, lyric_t)
                free(lyric->text);
-       }
        free_array(song->lyrics);
 
        free(song->lang);
@@ -64,66 +56,60 @@ void free_song(song_t *song) {
 }
 
 void song_add_unknown(song_t *song, char *text) {
-       lyric_t lyric;
-       lyric.type = NSUB_UNKNOWN;
-       lyric.num = 0;
-       lyric.start = 0;
-       lyric.stop = 0;
-       lyric.name = NULL;
-       lyric.text = text ? strdup(text) : NULL;
-       array_add(song->lyrics, &lyric);
+       lyric_t *lyric = array_new(song->lyrics);
+       lyric->type = NSUB_UNKNOWN;
+       lyric->num = 0;
+       lyric->start = 0;
+       lyric->stop = 0;
+       lyric->name = NULL;
+       lyric->text = text ? strdup(text) : NULL;
 }
 
 void song_add_empty(song_t *song) {
-       lyric_t lyric;
-       lyric.type = NSUB_EMPTY;
-       lyric.num = 0;
-       lyric.start = 0;
-       lyric.stop = 0;
-       lyric.name = NULL;
-       lyric.text = NULL;
-       array_add(song->lyrics, &lyric);
+       lyric_t *lyric = array_new(song->lyrics);
+       lyric->type = NSUB_EMPTY;
+       lyric->num = 0;
+       lyric->start = 0;
+       lyric->stop = 0;
+       lyric->name = NULL;
+       lyric->text = NULL;
 }
 
 void song_add_comment(song_t *song, char *comment) {
-       lyric_t lyric;
-       lyric.type = NSUB_COMMENT;
-       lyric.num = 0;
-       lyric.start = 0;
-       lyric.stop = 0;
-       lyric.name = NULL;
-       lyric.text = comment ? strdup(comment) : NULL;
-       array_add(song->lyrics, &lyric);
+       lyric_t *lyric = array_new(song->lyrics);
+       lyric->type = NSUB_COMMENT;
+       lyric->num = 0;
+       lyric->start = 0;
+       lyric->stop = 0;
+       lyric->name = NULL;
+       lyric->text = comment ? strdup(comment) : NULL;
 }
 
 void song_add_lyric(song_t *song, int start, int stop, char *name, char *text) {
        song->current_num = song->current_num + 1;
 
-       lyric_t lyric;
-       lyric.type = NSUB_LYRIC;
-       lyric.num = song->current_num;
-       lyric.start = start;
-       lyric.stop = stop;
-       lyric.name = name ? strdup(name) : NULL;
-       lyric.text = text ? strdup(text) : NULL;
-       array_add(song->lyrics, &lyric);
+       lyric_t *lyric = array_new(song->lyrics);
+       lyric->type = NSUB_LYRIC;
+       lyric->num = song->current_num;
+       lyric->start = start;
+       lyric->stop = stop;
+       lyric->name = name ? strdup(name) : NULL;
+       lyric->text = text ? strdup(text) : NULL;
 }
 
 void song_add_meta(song_t *song, char *key, char *value) {
-       meta_t meta;
-       meta.key = key ? strdup(key) : NULL;
-       meta.value = value ? strdup(value) : NULL;
-       array_add(song->metas, &meta);
+       meta_t *meta = array_new(song->metas);
+       meta->key = key ? strdup(key) : NULL;
+       meta->value = value ? strdup(value) : NULL;
 }
 
 song_t *nsub_read(FILE *in, NSUB_FORMAT fmt) {
-       array *lines = new_array(sizeof(char *), 80);
-       size_t count = array_readfiles(lines, in);
+       array_t *lines = new_array(sizeof(char *), 80);
+       array_readfiles(lines, in);
 
        song_t *song = new_song();
-       char *line;
-       for (size_t i = 0; i < count; i++) {
-               array_get(lines, &line, i);
+       array_loop_i(lines, line, char, i)
+       {
                switch (fmt) {
                case NSUB_FMT_LRC:
                        if (!nsub_read_lrc(song, line)) {
@@ -142,7 +128,9 @@ song_t *nsub_read(FILE *in, NSUB_FORMAT fmt) {
 
        fail:
 
-       array_free_all(lines);
+       array_loop(lines, line, void)
+               free(line);
+
        return song;
 }
 
index 257135bbf419ec08aafc2a6d85a4bc7d74159ec4..008b1cca2f34178fa7683eb6939e48fbfcc58a0a 100644 (file)
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+/**
+ * @file nsub.h
+ * @author Niki
+ * @date 2022
+ *
+ * @brief Subtitle/Lyrics conversion program (webvtt/srt/lrc)
+ *
+ * A small program to convert between subtitles and lyrics formats.
+ * It supports webvtt, srt and lrc files.
+ *
+ * Use <tt>nsub --help</tt> for more information.
+ */
+
 #ifndef NSUB_H
 #define NSUB_H
 
 /*
  * Description of the lyrics of a song.
- * Note: all timings are in milliseconds.
+ *
+ * @note all timings are in milliseconds.
  */
-
 #include "utils/array.h"
 
+/**
+ * A subtitle or lyric format to import from/export to.
+ */
 typedef int NSUB_FORMAT;
 
+/** The format is not supported. */
 #define NSUB_FMT_ERROR -1
+/** The format is (not yet) known. */
 #define NSUB_FMT_UNKNOWN 0
+/** Lyrcis format (usually for music lyrics). */
 #define NSUB_FMT_LRC 1
+/** The W3C standard format for video subtitles. */
 #define NSUB_FMT_WEBVTT 2
+/** A de-facto standard for video subtitles (from the program SubRip). */
 #define NSUB_FMT_SRT 3
 
+/**
+ * A type of lyric.
+ */
 typedef int NSUB_TYPE;
 
+/** Unknown type. */
 #define NSUB_UNKNOWN 0
+/** Empty line (more or less a comment). */
 #define NSUB_EMPTY 1
+/** A comment (with content). */
 #define NSUB_COMMENT 2
+/** A lyric. */
 #define NSUB_LYRIC 3
 
+/**
+ * A lyric (the text of a line from a dialogue or part of a song).
+ */
 typedef struct {
        NSUB_TYPE type;
+       /**
+        * The sequential number of this lyric (only valid for NSUB_LYRIC).
+        *
+        * @note the numbering start at 1
+        */
        int num;
+       /**
+        * The time in milliseconds (total song/video play time) after which this
+        * lyric start.
+        */
        int start;
+       /**
+        * The time in milliseconds (total song/video play time) after which this
+        * lyric stop.
+        */
        int stop;
+       /**
+        * The name of this lyric (not the text content, but a name for this line).
+        *
+        * @note most format do not understand this, and make it a comment or ignore
+        *              it altogether (example: « Chorus 1 »)
+        */
        char *name;
+       /**
+        * The actual content of this lyric or comment.
+        */
        char *text;
 } lyric_t;
 
+/**
+ * Some piece of meta-data.
+ */
 typedef struct {
        char *key;
        char *value;
 } meta_t;
 
+/**
+ * A song (or video).
+ *
+ * The main goal of this structure is to group the lyrics.
+ */
 typedef struct {
-       array *lyrics;
-       array *metas;
+       /** The actual lyrics. */
+       array_t *lyrics;
+       /** The meta-data if any. */
+       array_t *metas;
+       /** An offset to apply to every lyrics timings. */
        int offset;
+       /**
+        *  The last lyric number (start at 1, 0 means no lyric).
+        *
+        *  @see lyric_t.num
+        */
        int current_num;
+       /** The language of the lyrics. */
        char *lang;
 } song_t;
 
index 24938f8214b0fb6dd44047d1f2a31d36ac1c72e9..35cbb1505b5c75ccc60fb0c9dcfafd75597bf3a2 100644 (file)
@@ -53,9 +53,8 @@ int nsub_read_lrc(song_t *song, char *line) {
                int start = lrc_millisec(line);
                char *name = NULL;
 
-               size_t count = array_count(song->lyrics);
-               if (count) {
-                       lyric_t *lyric = (lyric_t*) array_get_ptr(song->lyrics, count - 1);
+               array_loop(song->lyrics, lyric, lyric_t)
+               {
                        if (lyric->type == NSUB_LYRIC)
                                lyric->stop = start;
                        if (lyric->type == NSUB_COMMENT)
@@ -73,7 +72,8 @@ int nsub_read_lrc(song_t *song, char *line) {
                if (line[text_offset]) {
                        if (name) {
                                song->current_num--;
-                               array_set_size(song->lyrics, count - 1);
+                               // TODO: memory leak?
+                               array_cut_at(song->lyrics, array_count(song->lyrics) - 1);
                        }
                        song_add_lyric(song, start, start + 5000, name, line + text_offset);
                } else {
@@ -88,7 +88,7 @@ int nsub_read_lrc(song_t *song, char *line) {
                line[end] = '\0';
                if (!strcmp("language", line + 1)) {
                        song->lang = strdup(line + text_offset);
-               }else if (!strcmp("created_by", line + 1)) {
+               } else if (!strcmp("created_by", line + 1)) {
                        // skip (we KNOW what program we are)
                } else {
                        song_add_meta(song, line + 1, line + text_offset);
index cb38ddd6db1bff3252be03b810be2884120fa207..b8bf43868f5ed292aefcf3f7f15e79a7eaa196c5 100644 (file)
@@ -38,7 +38,7 @@ int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
                size_t count = array_count(song->metas);
                meta_t *meta;
                for (size_t i = 0; i < count; i++) {
-                       meta = (meta_t *) array_get_ptr(song->metas, i);
+                       meta = (meta_t *) array_get(song->metas, i);
                        fprintf(out, "[%s: %s]\n", meta->key, meta->value);
                }
        }
@@ -69,7 +69,7 @@ int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
                size_t count = array_count(song->lyrics);
                lyric_t *lyric;
                for (size_t i = 0; i < count; i++) {
-                       lyric = (lyric_t*) array_get_ptr(song->lyrics, i);
+                       lyric = (lyric_t*) array_get(song->lyrics, i);
                        nsub_write_lrc_lyric(out, lyric, offset);
                }
        }
index cf16c01415855e0b625f73c8dfec6609ab24eaa2..742d582344d567d224024003b7247e19ec09e64c 100644 (file)
@@ -47,7 +47,7 @@ int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
                size_t count = array_count(song->lyrics);
                lyric_t *lyric;
                for (size_t i = 0; i < count; i++) {
-                       lyric = (lyric_t*) array_get_ptr(song->lyrics, i);
+                       lyric = (lyric_t*) array_get(song->lyrics, i);
                        nsub_write_srt_lyric(out, lyric, offset);
                }
        }
index b856776a636cdf926e2c1bf89538732a846fe2ed..177d6ae99aeda3a9e7da00720f41b9a2d415c39f 100644 (file)
@@ -45,7 +45,7 @@ int nsub_write_webvtt(FILE *out, song_t *song, NSUB_FORMAT fmt,
                size_t count = array_count(song->metas);
                meta_t *meta;
                for (size_t i = 0; i < count; i++) {
-                       meta = (meta_t *) array_get_ptr(song->metas, i);
+                       meta = (meta_t *) array_get(song->metas, i);
                        fprintf(out, "NOTE META %s: %s\n\n", meta->key, meta->value);
                }
        }
@@ -66,7 +66,7 @@ int nsub_write_webvtt(FILE *out, song_t *song, NSUB_FORMAT fmt,
                size_t count = array_count(song->lyrics);
                lyric_t *lyric;
                for (size_t i = 0; i < count; i++) {
-                       lyric = (lyric_t*) array_get_ptr(song->lyrics, i);
+                       lyric = (lyric_t*) array_get(song->lyrics, i);
                        nsub_write_webvtt_lyric(out, lyric, offset);
                }
        }
index ebdfe83536006376f599d9d7647e0d0117bdab0b..79b9d2d5eaaec052ed32c4b17bf1c5aadf5f13ed 100644 (file)
@@ -146,8 +146,6 @@ int main(int argc, char **argv) {
                        test_failure();
                        cont = 0;
                } else if (!strcmp("--more", argv[i])) {
-                       if ((i + 1) >= argc)
-                               return 1;
                        more = 1;
                } else if (!strcmp("--color", argv[i])) {
                        launcher_color = 1;
index 89a6ac41fd76a42f96ad830b1fe0eaf787fd5315..b1e6e637704959624bea7ace5565038ebfb40b87 100644 (file)
@@ -16,19 +16,19 @@ END_TEST\
 ck_abort_msg(__VA_ARGS__)\
 
 #define ASSERT_EQUALS_STR(title, expected, received) \
-       if (strcmp(expected, received)) { \
+       do { if (strcmp(expected, received)) { \
 ck_abort_msg("%s\n\tExpected: <%s>\n\tReceived: <%s>", title, expected, received); \
-}
+}} while(0)
 
 #define ASSERT_EQUALS_INT(title, expected, received) \
-       if (expected != received) { \
+       do { if (expected != received) { \
 ck_abort_msg("%s\n\tExpected: %lld\n\tReceived: %lld", title, (long long)expected, (long long)received); \
-}
+}} while(0)
 
 #define ASSERT_EQUALS_SIZE(title, expected, received) \
-       if (expected != received) { \
+       do { if (expected != received) { \
 ck_abort_msg("%s\n\tExpected: %zu\n\tReceived: %zu", title, expected, received); \
-}
+}} while(0)
 
 extern int launcher_color;
 
index 956d04d2c96db1c39394daebdb4d2d6effd43332..6d7d9c2fc787e571ebcab8a57fed0f02729085ec 100644 (file)
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-#include "launcher.h"
 #include "utils/array.h"
 
-array *a;
+#include <check.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "launcher.h"
 
-void test_array_setup() {
+static array_t *a;
+
+static void setup() {
        a = new_array(sizeof(char), 80);
 }
 
-void test_array_teardown() {
+static void teardown() {
        free_array(a);
        a = NULL;
 }
 
-void array_reset() {
-       test_array_teardown();
-       test_array_setup();
+static void reset() {
+       teardown();
+       setup();
 }
 
 START(init)
@@ -42,14 +47,233 @@ START(init)
 
                if (array_count(a))
                        FAIL("empty array has a size of %zu", array_count(a));
+
+               END
+
+START(clear)
+               char car = 'T';
+
+               array_push(a, &car);
+               array_push(a, &car);
+               array_clear(a);
+               if (array_count(a))
+                       FAIL("empty array has a size of %zu", array_count(a));
+
+               END
+
+START(convert)
+               char car = 'T';
+               char eos = '\0';
+               char *str;
+
+               array_push(a, &car);
+               array_push(a, &car);
+               array_push(a, &eos);
+
+               str = (char*) array_convert(a);
+               ASSERT_EQUALS_STR("array of chars to string conversion", "TT", str);
+
+               free(str);
+               a = NULL;
+
+               END
+
+START(data)
+               char car = 'T';
+               char eos = '\0';
+               char *str;
+
+               array_push(a, &car);
+               array_push(a, &car);
+               array_push(a, &eos);
+
+               str = (char*) array_data(a);
+               ASSERT_EQUALS_STR("array of chars to string conversion", "TT", str);
+
+               END
+
+START(count)
+               char car = 'T';
+               char eos = '\0';
+
+               ASSERT_EQUALS_INT("empty array", 0, array_count(a));
+               reset();
+
+               array_push(a, &car);
+               ASSERT_EQUALS_INT("1-char array", 1, array_count(a));
+               reset();
+
+               array_push(a, &car);
+               array_push(a, &car);
+               array_push(a, &eos);
+               ASSERT_EQUALS_INT("array with a NUL at the end", 3, array_count(a));
+               reset();
+
+               END
+
+START(pointers)
+               char *ptr;
+               char car;
+
+               ptr = array_new(a);
+               *ptr = 'T';
+               ASSERT_EQUALS_INT("add a new element via ptr", 1, array_count(a));
+
+               ptr = array_first(a);
+               car = *ptr;
+               if (car != 'T')
+                       FAIL("first_ptr: 'T' was expected, but we got: '%c'", car);
+
+               reset();
+
+               char *testy = "Testy";
+               ptr = array_newn(a, strlen(testy) + 1);
+               for (size_t i = 0; i <= strlen(testy); i++) {
+                       *ptr = testy[i];
+                       ptr++;
+               }
+
+               ptr = array_first(a);
+               for (size_t i = 0; i < strlen(testy); i++) {
+                       ASSERT_EQUALS_STR("next_ptr", testy + i, (char* )ptr);
+                       ptr = array_next(a, ptr);
+               }
+
+               array_loop_i(a, ptr2, char, i) {
+                       if (i < strlen(testy))
+                               ASSERT_EQUALS_STR("array_loop", testy + i, ptr2);
+                       else if (i == strlen(testy))
+                               ASSERT_EQUALS_STR("array_loop (last)", "", ptr2);
+                       else
+                               FAIL("array_loop went out of bounds");
+               }
+
+               END
+
+START(get)
+               char *str = "Testy";
+               size_t sz = strlen(str);
+
+               array_pushn(a, str, sz + 1);
+
+               for (size_t i = 0; i < sz + 1; i++) {
+                       char expected = str[i];
+                       char *ret = array_get(a, i);
+                       ASSERT_EQUALS_INT("get each element", expected, *ret);
+               }
+
+               END
+
+START(pop)
+               char *rep;
+
+               if (array_pop(a))
+                       FAIL("popping an item from an empty array");
+
+               rep = array_new(a);
+               *rep = 'T';
+
+               rep = array_pop(a);
+               if (!rep)
+                       FAIL("cannot pop item from 1-sized array");
+
+               ASSERT_EQUALS_INT("bad item popped", (int )'T', (int )*rep);
+
+               if (a->count)
+                       FAIL("popped 1-sized array still has %d items", a->count);
+
+               rep = array_new(a);
+               *rep = 'T';
+               rep = array_new(a);
+               *rep = 'T';
+
+               rep = array_pop(a);
+               ASSERT_EQUALS_INT("bad item 1 popped", (int )'T', (int )*rep);
+               ASSERT_EQUALS_INT("popping should remove 1 from count", 1, a->count);
+
+               rep = array_pop(a);
+               ASSERT_EQUALS_INT("bad item 2 popped", (int )'T', (int )*rep);
+               ASSERT_EQUALS_INT("popping should remove 1 from count", 0, a->count);
+
+               END
+
+START(cut_at)
+               char *rep;
+
+               if (array_cut_at(a, 4))
+                       FAIL("cutting an empty array returned something");
+
+               rep = array_new(a);
+               *rep = 'T';
+               rep = array_new(a);
+               *rep = 'T';
+
+               if (array_cut_at(a, 4))
+                       FAIL("cutting an array above its count returned something");
+
+               if (!array_cut_at(a, 1))
+                       FAIL("failed to cut an array");
+               ASSERT_EQUALS_INT("cutting at 1 should get a 1-sized array", 1,
+                               a->count);
+
+               if (!array_cut_at(a, 0))
+                       FAIL("failed to cut an array");
+               ASSERT_EQUALS_INT("cutting at 0 should get a 1-sized array", 0,
+                               a->count);
+
+               END
+
+START(compact)
+               char car = 'T';
+               char eos = '\0';
+
+               array_compact(a);
+
+               array_push(a, &car);
+               array_push(a, &car);
+               array_push(a, &eos);
+
+               ASSERT_EQUALS_STR("compacted array has wrong data", "TT",
+                               (char* )array_data(a));
+
+               END
+
+               // TODO
+START(NO_TEST_YET_qsort)
+               END
+START(NO_TEST_YET_push)
+               END
+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);
 
        TCase *core = tcase_create("core");
-       tcase_add_checked_fixture(core, test_array_setup, test_array_teardown);
+       tcase_add_checked_fixture(core, setup, teardown);
        tcase_add_test(core, init);
+       tcase_add_test(core, clear);
+       tcase_add_test(core, convert);
+       tcase_add_test(core, data);
+       tcase_add_test(core, count);
+       tcase_add_test(core, pointers); // new, newn, first, next
+       tcase_add_test(core, get);
+       tcase_add_test(core, pop);
+       tcase_add_test(core, cut_at);
+       tcase_add_test(core, compact);
+
+       tcase_add_test(core, NO_TEST_YET_qsort);
+       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);
 
@@ -60,7 +284,7 @@ Suite *test_array_more(const char title[]) {
        Suite *suite = suite_create(title);
 
        TCase *tmore = tcase_create("more");
-       tcase_add_checked_fixture(tmore, test_array_setup, test_array_teardown);
+       tcase_add_checked_fixture(tmore, setup, teardown);
        // TODO
 
        suite_add_tcase(suite, tmore);
diff --git a/src/tests/utils/base64.c b/src/tests/utils/base64.c
new file mode 100644 (file)
index 0000000..18e567f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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/base64.h"
+
+#include <check.h>
+
+#include "launcher.h"
+
+static void setup() {
+}
+
+static void teardown() {
+}
+
+static char decoded[] = "This is Le Test, we will UTF-8 the String, too!";
+static char encoded[] =
+               "VGhpcyBpcyBMZSBUZXN0LCB3ZSB3aWxsIFVURi04IHRoZSBTdHJpbmcsIHRvbyE=";
+
+START(decode)
+               ASSERT_EQUALS_STR("decoding", decoded, base64_decode(encoded));
+               END
+
+START(encode)
+               ASSERT_EQUALS_STR("encoding", encoded, base64_encode(decoded));
+               END
+
+START(both_ways)
+               char *enc = base64_encode(decoded);
+               char *dec = base64_decode(enc);
+               ASSERT_EQUALS_STR("both ways", decoded, dec);
+               END
+
+START(big)
+               size_t sz = 10 * 1024 * 1024;
+               char *dec = malloc((sz + 1) * sizeof(char));
+               for (int i = 0; i < sz; i++) {
+                       dec[i] = '0' + (i % 10);
+               }
+               dec[sz] = '\0';
+
+               char *enc = base64_encode(dec);
+               char *dec2 = base64_decode(enc);
+
+               ASSERT_EQUALS_STR("long encode/decode cycle", dec, dec2);
+               free(dec2);
+               free(enc);
+               free(dec);
+
+               END
+
+START(lots)
+               size_t count = 1 * 1000 * 1000;
+               for (size_t i = 0; i < count; i++) {
+                       char *enc = base64_encode(decoded);
+                       char *dec = base64_decode(enc);
+
+                       if (strcmp(decoded, dec)) {
+                               FAIL("Failed short encode/decode cycle at index %zu", i);
+                       }
+
+                       free(enc);
+                       free(dec);
+               }
+
+               END
+
+Suite *test_base64(const char title[]) {
+       Suite *suite = suite_create(title);
+
+       TCase *core = tcase_create("core");
+       tcase_add_checked_fixture(core, setup, teardown);
+       tcase_add_test(core, decode);
+       tcase_add_test(core, encode);
+
+       suite_add_tcase(suite, core);
+
+       return suite;
+}
+
+Suite *test_base64_more(const char title[]) {
+       Suite *suite = suite_create(title);
+
+       TCase *tmore = tcase_create("more");
+       tcase_add_checked_fixture(tmore, setup, teardown);
+       tcase_add_test(tmore, both_ways);
+       tcase_add_test(tmore, big);
+       tcase_add_test(tmore, lots);
+
+       suite_add_tcase(suite, tmore);
+
+       return suite;
+}
index b44aef23c2f250e30db3b71c33eac37fd49375df..fb94c8fe9881552568ba43366acac75ed9ec7d79 100644 (file)
@@ -24,7 +24,7 @@
 
 #define TEST_FILE_READLINE "utils/test_readline.txt"
 
-cstring *s;
+cstring_t *s;
 
 static void setup() {
        s = new_cstring();
@@ -435,7 +435,7 @@ START(convert)
                END
 
 START(clone)
-               cstring *clone;
+               cstring_t *clone;
 
                clone = cstring_clone(NULL);
                if (clone)
@@ -775,7 +775,7 @@ START(dirname)
                END
 
 START(many_adds)
-               size_t count = 50000000;
+               size_t count = 10 * 1000 * 1000;
                for (size_t i = 0; i < count; i++) {
                        cstring_add(s, "1234567890");
                }
index 182401d77342d9cc757e2d1e5b235283f4815fac..474c43112b9a6b1e1139c83017ced2111ed218b8 100644 (file)
@@ -32,6 +32,10 @@ SRunner *get_tests(int more) {
        if (more)
                add_test(test_array_more("array -- more (longer)"));
 
+       add_test(test_base64("base64"));
+       if (more)
+               add_test(test_base64_more("base64 -- more (longer)"));
+
        return runner;
 }
 
index 497bc2f1c0d2bfb3e150eed59410619826267ad2..5fced56cb5fe4b3c4d19884b884e4ec4c264fb0f 100644 (file)
@@ -26,5 +26,7 @@ Suite *test_cstring(const char title[]);
 Suite *test_cstring_more(const char title[]);
 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[]);
 
 #endif /* SRC_TESTS_UTILS_MAIN_H_ */
index 063483974885d4196d310c738516254749b48f41..6e192ef379183591696c19ac67ae3eee5d164b8e 100644 (file)
 
 #include "array.h"
 
-struct array_p {
+typedef struct {
        size_t elem_size;
-       size_t count;
        size_t buffer;
        void *data;
-};
+} priv_t;
 
 /* make sure we have at least n elements in the buffer, grow if needed */
-int array_assure(array *me, size_t nb_elem);
+static int array_assure(array_t *me, size_t nb_elem);
 
 /* for qsort operations */
-int array_qsorts_func(const void *a, const void *b);
-int array_qsorti_func(const void *a, const void *b);
-int array_qsortl_func(const void *a, const void *b);
-int array_qsortf_func(const void *a, const void *b);
-int array_qsorts_rfunc(const void *a, const void *b);
-int array_qsorti_rfunc(const void *a, const void *b);
-int array_qsortl_rfunc(const void *a, const void *b);
-int array_qsortf_rfunc(const void *a, const void *b);
+static int array_qsorts_func(const void *a, const void *b);
+static int array_qsorti_func(const void *a, const void *b);
+static int array_qsortl_func(const void *a, const void *b);
+static int array_qsortf_func(const void *a, const void *b);
+static int array_qsorts_rfunc(const void *a, const void *b);
+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 */
-void array_readfile_funci(array *me, const char line[]);
-void array_readfile_funcs(array *me, const char line[]);
+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;
 
-array *new_array(size_t elem_size, size_t initial) {
-       array *me = NULL;
        if (initial)
-               me = malloc(sizeof(array));
+               me = malloc(sizeof(array_t));
+
        if (me) {
-               me->elem_size = elem_size;
-               me->count = 0;
-               me->buffer = initial;
-               me->data = malloc(elem_size * initial);
-               if (!me->data) {
-                       free(me);
-                       me = NULL;
+               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;
+                       }
                }
        }
-       
+
        return me;
 }
 
-void free_array(array *me) {
+void free_array(array_t *me) {
        if (!me)
                return;
 
+       priv_t *priv = (priv_t *) me->priv;
        me->count = 0;
-       me->buffer = 0;
-       free(me->data);
+       priv->buffer = 0;
+       free(priv->data);
+       free(priv);
        free(me);
 }
 
-void array_clear(array *me) {
+void array_clear(array_t *me) {
        me->count = 0;
 }
 
 // convert to void * data (free the rest)
-void *array_convert(array *me) {
-       void *data = me->data;
+void *array_convert(array_t *me) {
+       priv_t *priv = (priv_t *) me->priv;
+       void *data = priv->data;
+       free(priv);
        free(me);
        return data;
 }
 
-void *array_data(array *me) {
-       return me->data;
+void *array_data(array_t *me) {
+       priv_t *priv = (priv_t *) me->priv;
+       return priv->data;
 }
 
-size_t array_count(array *me) {
+size_t array_count(array_t *me) {
        return me->count;
 }
 
-void array_compact(array *me) {
-       int c = me->count > 0 ? me->count : 1;
-       me->data = realloc(me->data, c * me->elem_size);
-       me->buffer = c;
+void *array_new(array_t *me) {
+       return array_newn(me, 1);
+}
+
+void *array_newn(array_t *me, size_t how_many) {
+       if (!array_assure(me, me->count + how_many))
+               return 0;
+
+       me->count += how_many;
+       return array_get(me, me->count - how_many);
 }
 
-void array_all(array *me, void(*func)()) {
-       for (size_t i = 0 ; i < me->count ; i++) {
-               func(((void **)me->data)[i]);
+void *array_first(array_t *me) {
+       priv_t *priv = (priv_t *) me->priv;
+       return priv->data;
+}
+
+void *array_next(array_t *me, void *ptr) {
+       priv_t *priv = (priv_t *) me->priv;
+
+       // cast to (char *) because we want 'byte' arithmetic
+       char *cptr = (char *) ptr;
+       char *cdata = (char*) priv->data;
+
+       if (cptr) {
+               cptr += priv->elem_size;
+               char *last = cdata + ((me->count - 1) * priv->elem_size);
+               if (cptr <= last) {
+                       return cptr;
+               }
        }
+
+       return NULL;
 }
 
-void array_free_all(array *me) {
-       array_all(me, free);
-       me->count = 0;
+void *array_get(array_t *me, size_t i) {
+       priv_t *priv = (priv_t *) me->priv;
+
+       // cast to (char *) because we want 'byte' arithmetic
+       return (void *) (((char *) priv->data) + (i * priv->elem_size));
+}
+
+void *array_pop(array_t *me) {
+       return array_cut_at(me, me->count - 1);
+}
+
+void *array_cut_at(array_t *me, size_t n) {
+       if (n < me->count) {
+               void *item = array_get(me, n);
+               me->count = n;
+               return item;
+       }
+
+       return NULL;
 }
 
-void array_qsort(array *me, int (*compar)(const void *, const void *)) {
-       qsort(me->data, me->count, me->elem_size, compar);
+void array_compact(array_t *me) {
+       priv_t *priv = (priv_t *) me->priv;
+
+       int c = me->count ? me->count : 1;
+       priv->data = realloc(priv->data, c * priv->elem_size);
+       priv->buffer = c;
 }
 
-void array_qsorts(array *me, int rev) {
+void array_qsort(array_t *me, int (*compar)(const void *, const void *)) {
+       priv_t *priv = (priv_t *) me->priv;
+       qsort(priv->data, me->count, priv->elem_size, compar);
+}
+
+void array_qsorts(array_t *me, int rev) {
        array_qsort(me, rev ? array_qsorts_rfunc : array_qsorts_func);
 }
-int array_qsorts_func(const void *a, const void *b) {
-       char *stra = ((char **)a)[0];
-       char *strb = ((char **)b)[0];
+static int array_qsorts_func(const void *a, const void *b) {
+       char *stra = ((char **) a)[0];
+       char *strb = ((char **) b)[0];
        return strcmp(stra, strb);
 }
-int array_qsorts_rfunc(const void *a, const void *b) {
-       char *stra = ((char **)a)[0];
-       char *strb = ((char **)b)[0];
+static int array_qsorts_rfunc(const void *a, const void *b) {
+       char *stra = ((char **) a)[0];
+       char *strb = ((char **) b)[0];
        return strcmp(strb, stra);
 }
 
-void array_qsorti(array *me, int rev) {
+void array_qsorti(array_t *me, int rev) {
        array_qsort(me, rev ? array_qsorti_rfunc : array_qsorti_func);
 }
-int array_qsorti_func(const void *a, const void *b) {
+static int array_qsorti_func(const void *a, const void *b) {
        long ia, ib;
-       ia = ((int *)a)[0];
-       ib = ((int *)b)[0];
-       if (ia < ib) return -1;
+       ia = ((int *) a)[0];
+       ib = ((int *) b)[0];
+       if (ia < ib)
+               return -1;
        return !(ia == ib);
 }
-int array_qsorti_rfunc(const void *a, const void *b) {
+static int array_qsorti_rfunc(const void *a, const void *b) {
        long ia, ib;
-       ia = ((int *)a)[0];
-       ib = ((int *)b)[0];
-       if (ia > ib) return -1;
+       ia = ((int *) a)[0];
+       ib = ((int *) b)[0];
+       if (ia > ib)
+               return -1;
        return !(ia == ib);
 }
 
-void array_qsortl(array *me, int rev) {
+void array_qsortl(array_t *me, int rev) {
        array_qsort(me, rev ? array_qsortl_rfunc : array_qsortl_func);
 }
-int array_qsortl_func(const void *a, const void *b) {
+static int array_qsortl_func(const void *a, const void *b) {
        long la, lb;
-       la = ((long *)a)[0];
-       lb = ((long *)b)[0];
-       if (la < lb) return -1;
+       la = ((long *) a)[0];
+       lb = ((long *) b)[0];
+       if (la < lb)
+               return -1;
        return !(la == lb);
 }
-int array_qsortl_rfunc(const void *a, const void *b) {
+static int array_qsortl_rfunc(const void *a, const void *b) {
        long la, lb;
-       la = ((long *)a)[0];
-       lb = ((long *)b)[0];
-       if (la > lb) return -1;
+       la = ((long *) a)[0];
+       lb = ((long *) b)[0];
+       if (la > lb)
+               return -1;
        return !(la == lb);
 }
 
-void array_qsortf(array *me, int rev) {
+void array_qsortf(array_t *me, int rev) {
        array_qsort(me, rev ? array_qsortf_rfunc : array_qsortf_func);
 }
-int array_qsortf_func(const void *a, const void *b) {
+static int array_qsortf_func(const void *a, const void *b) {
        float fa, fb;
-       fa = ((float *)a)[0];
-       fb = ((float *)b)[0];
+       fa = ((float *) a)[0];
+       fb = ((float *) b)[0];
        // Also works:
        //memcpy(&fa, a, sizeof(float));
        //memcpy(&fb, b, sizeof(float));
-       if (fa < fb) return -1;
+       if (fa < fb)
+               return -1;
        return !(fa == fb);
 }
-int array_qsortf_rfunc(const void *a, const void *b) {
+static int array_qsortf_rfunc(const void *a, const void *b) {
        float fa, fb;
-       fa = ((float *)a)[0];
-       fb = ((float *)b)[0];
+       fa = ((float *) a)[0];
+       fb = ((float *) b)[0];
        // Also works:
        //memcpy(&fa, a, sizeof(float));
        //memcpy(&fb, b, sizeof(float));
-       if (fa > fb) return -1;
+       if (fa > fb)
+               return -1;
        return !(fa == fb);
 }
 
-int array_add(array *me, void *data) {
+int array_push(array_t *me, void *data) {
        return array_setn(me, me->count, data, 1);
 }
 
-int array_addn(array *me, void *data, size_t n) {
+int array_pushn(array_t *me, void *data, size_t n) {
        return array_setn(me, me->count, data, n);
 }
 
-void *array_get_ptr(array *me, size_t i) {
-       // cast to (char *) because we want 'byte' arithmetic
-       return (void *)(((char *)me->data) + (i * me->elem_size));
+int array_copy(array_t *me, void *target, size_t i) {
+       return array_copyn(me, target, i, 1);
 }
 
-void array_get(array *me, void *target, size_t i) {
-       array_getn(me, target, i, 1);
-}
+int array_copyn(array_t *me, void *target, size_t i, size_t n) {
+       priv_t *priv = (priv_t *) me->priv;
 
-void array_getn(array *me, void *target, size_t i, size_t n) {
-       // cast to (char *) because we want 'byte' arithmetic
-       memcpy(target, ((char *)(me->data)) + (i * me->elem_size), n * me->elem_size);
+       if (i + n < me->count) {
+               // cast to (char *) because we want 'byte' arithmetic
+               memcpy(target, ((char *) (priv->data)) + (i * priv->elem_size),
+                               n * priv->elem_size);
+
+               return 1;
+       }
+
+       return 0;
 }
 
-int array_set(array *me, size_t i, void *data) {
+int array_set(array_t *me, size_t i, void *data) {
        return array_setn(me, i, data, 1);
 }
 
-int array_setn(array *me, size_t i, void *data, size_t n) {
+int array_setn(array_t *me, size_t i, void *data, size_t n) {
        // allow new items BUT NOT holes in the array
        if (i > me->count)
                return 0;
-       
+
        if (!array_assure(me, i + n))
                return 0;
-       
+
+       priv_t *priv = (priv_t *) me->priv;
+
        // cast to (char *) because we want 'byte' arithmetic
-       memcpy(((char *)(me->data)) + (i * me->elem_size), data, n * me->elem_size);
+       memcpy(((char *) (priv->data)) + (i * priv->elem_size), data,
+                       n * priv->elem_size);
        if ((i + n) > me->count)
                me->count = i + n;
-       return 1;
-}
-
-int array_set_size(array *me, size_t n) {
-       if (n < me->count) {
-               me->count = n;
-               return 1;
-       }
 
-       return 0;
+       return 1;
 }
 
-size_t array_readfilei(array *me, FILE *in) {
+size_t array_readfilei(array_t *me, FILE *in) {
        return array_readfile(me, in, array_readfile_funci);
 }
 
-size_t array_readfiles(array *me, FILE *in) {
+size_t array_readfiles(array_t *me, FILE *in) {
        return array_readfile(me, in, array_readfile_funcs);
 }
 
-size_t array_readfile(array *me, FILE *in, void(*doline)(array *me, const char line[])) {
-       array *mot = NULL;
+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++);
+       ; 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_addn(mot, buffer + start, (i - start));
+                               array_pushn(mot, buffer + start, (i - start));
                        }
 
                        if (i == start || (i < n && buffer[i] == '\n')) {
-                               array_add(mot, &zero);
-                               doline(me, mot->data);
+                               array_push(mot, &zero);
+                               doline(me, mot_priv->data);
                                count++;
                                array_clear(mot);
                        }
@@ -275,8 +343,8 @@ size_t array_readfile(array *me, FILE *in, void(*doline)(array *me, const char l
        }
 
        if (mot->count) {
-               array_add(mot, &zero);
-               doline(me, mot->data);
+               array_push(mot, &zero);
+               doline(me, mot_priv->data);
                count++;
        }
 
@@ -284,57 +352,66 @@ size_t array_readfile(array *me, FILE *in, void(*doline)(array *me, const char l
        return count;
 }
 
-void array_print(array *me) {
+void array_print(array_t *me) {
        array_print_fmt(me, NULL, NULL);
 }
 
-void array_prints(array *me) {
+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 **)me->data)[i]);
-               fprintf(stdout, "> %zu: %s\n", i, (char *)d);
+       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 *me) {
+void array_printi(array_t *me) {
+       priv_t *priv = (priv_t *) me->priv;
+
        array_print_fmt(me, NULL, NULL);
-       int *ii = malloc(me->count * me->elem_size);
-       memcpy(ii, me->data, me->count * me->elem_size);
-       for (size_t i = 0 ; i < me->count ; i++) {
+       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 *me) {
+void array_printl(array_t *me) {
+       priv_t *priv = (priv_t *) me->priv;
+
        array_print_fmt(me, NULL, NULL);
-       long *l = malloc(me->count * me->elem_size);
-       memcpy(l, me->data, me->count * me->elem_size);
-       for (size_t i = 0 ; i < me->count ; i++) {
+       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 *me) {
+void array_printf(array_t *me) {
+       priv_t *priv = (priv_t *) me->priv;
+
        array_print_fmt(me, NULL, NULL);
-       float *f = malloc(me->count * me->elem_size);
-       memcpy(f, me->data, me->count * me->elem_size);
-       for (size_t i = 0 ; i < me->count ; i++) {
+       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 *me, 
-       void(*display)(char *buffer, void *), char *buffer) {
+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, me->elem_size, me->buffer);
+                       "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 **)me->data)[i]);
+               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);
                }
@@ -343,29 +420,33 @@ void array_print_fmt(array *me,
 
 /* Privates functions */
 
-int array_assure(array *me, size_t nb_elem) {
-       if (me->buffer < nb_elem) {
-               me->buffer *= 2;
-               if (me->buffer < nb_elem) {
-                       me->buffer = nb_elem;
+static int array_assure(array_t *me, size_t nb_elem) {
+       priv_t *priv = (priv_t *) me->priv;
+
+       if (priv->buffer < nb_elem) {
+               priv->buffer *= 2;
+               if (priv->buffer < nb_elem) {
+                       priv->buffer = nb_elem;
                }
-               
-               me->data = realloc(me->data, me->elem_size * me->buffer);
-               if (!me->data) {
+
+               void *tmp = realloc(priv->data, priv->elem_size * priv->buffer);
+               if (!tmp)
                        return 0;
-               }
+
+               priv->data = tmp;
        }
-       
+
        return 1;
 }
 
-void array_readfile_funci(array *me, const char line[]) {
+static void array_readfile_funci(array_t *me, const char line[]) {
        int i = atoi(line);
-       array_add(me, &i);
+       array_push(me, &i);
 }
 
-void array_readfile_funcs(array *me, const char line[]) {
+static void array_readfile_funcs(array_t *me, const char line[]) {
        char *myline = malloc((strlen(line) + 1) * sizeof(char));
        strcpy(myline, line);
-       array_add(me, &myline);
+       char **n = array_new(me);
+       *n = myline;
 }
index a8a9d1fda0cd4c10abe0af9c5dba0c40cc219714..caf81286277a1f13801199ca04f931f5c6bb758a 100644 (file)
@@ -20,7 +20,7 @@
 /** 
  * @file array.h
  * @author Niki
- * @date 2020
+ * @date 2020 - 2022
  *
  * @brief A simple auto-growing array-list
  * 
  *     const char *l2 = "3. En réserve";
  *     const char *l3 = "1. Première ligne";
  *
- *     array_add(lines, &l1);
- *     array_add(lines, &l2);
- *     array_add(lines, &l3);
+ *  // push mode (usually used for int, char, long...)
+ *     array_push(lines, &l1);
+ *     array_push(lines, &l2);
  *
- *     array_qsorts(lines);
+ *  // new mode (usually used for structures)
+ *     char **tmp = array_new(lines);
+ *     *tmp = l3;
  *
- *     char *last_line;
- *     array_get(lines, &last_line, array_count(lines) - 1);
- *     printf("Last line is now: %s\n", last_line);
+ *  // sort as Strings (also possible with int, long and custom functions)
+ *     array_qsorts(lines, 0);
+ *
+ *     char **last_line = array_get(lines, array_count(lines) - 1);
+ *     printf("Last line is now: %s\n", *last_line);
  *     // -> last_line is now: 3. En réserve
  *
+ *     array_loop(lines, line, char) {
+ *         printf("Line: %s\n", line);
+ *     }
+ *     // -> Line: 1. Première ligne
+ *     // -> Line: 2. En réserve
+ *     // -> Line: 3. À l'arrière
+ *
  *     free_array(lines);
  * ```
  */
@@ -68,8 +79,53 @@ extern "C" {
 #include <stdlib.h>
 #include <stdio.h>
 
-/** The structure type to use for arrays. */
-typedef struct array_p array;
+/**
+ * Declare a new <tt>TYPE *</tt> pointer and loop through the array with it.
+ *
+ * How to use:
+ * ```C
+ * array_loop(me, line, char) {
+ *     printf("Item: %s\n", line);
+ * }
+ * ```
+ */
+#define array_loop(me, ptr, TYPE) \
+       for (TYPE *ptr = array_first(me); ptr; ptr = array_next(me, ptr))
+
+/**
+ * Similar to <tt>array_loop</tt>, but add a counter <tt>i</tt> starting at 0.
+ *
+ * @see array_loop
+ *
+ * How to use:
+ * ```C
+ * array_loop_i(me, line, char, i) {
+ *     printf("Item n°%d: %s\n", i, line);
+ * }
+ * ```
+ *
+ * @note this macro does expand as 2 separate lines, surround with { } if needed
+ */
+#define array_loop_i(me, ptr, TYPE, i) \
+       size_t i = 0; \
+       for (TYPE *ptr = array_first(me); ptr; ptr = array_next(me, ptr), i++)
+
+/**
+ * @brief A simple auto-growing array-list
+ *
+ * The structure contains a private field (which you should not use) and the
+ * current count of how many items were added. You should probably not modify
+ * the count either (setting it higher is a bad idea and while it should be
+ * possible to set it lower, you are strongly advised to use
+ * <tt>array_cut_at</tt> instead).
+ *
+ * @see array_cut_at
+ */
+typedef struct {
+       char CNAME[10];
+       size_t count;
+       void *priv;
+} array_t;
 
 /**
  * Create a new array.
@@ -79,28 +135,29 @@ typedef struct array_p array;
  *
  * @return a new array (you must later call `free_array()` or `array_convert()`)
  */
-array *new_array(size_t elem_size, size_t initial);
+array_t *new_array(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, or use `array_free_all()` if applicable.
+ * those yourself first.
+ *
  * @see array_clear
- * @see array_free_all
+ * @see array_loop
  */
-void free_array(array *me);
+void free_array(array_t *me);
 
 /**
  * Clear the array, that is, resets its current size to 0 (buffer unchanged).
  */
-void array_clear(array *me);
+void array_clear(array_t *me);
 
 /** 
  * Convert the array to a block of memory where all values are adjacent.
  *
  * @return the data (you must later call `free()` on it)
  */
-void *array_convert(array *me);
+void *array_convert(array_t *me);
 
 /**
  * Return a pointer to the internal storage used by this array.
@@ -111,40 +168,90 @@ void *array_convert(array *me);
  *
  * @return the internal storage area
  */
-void *array_data(array *me);
+void *array_data(array_t *me);
 
 /** 
  * Return the current number of elements in the array.
  *
  * @return the number of elements in the array
  */
-size_t array_count(array *me);
+size_t array_count(array_t *me);
 
-/** 
- * Compact the array (resize the buffer so it is equals to the current number 
- * of items in the array or size 1 if there are no items in the array).
+/**
+ * Create a new element in the array and return a pointer to it.
+ *
+ * @return a pointer to the (newly allocated) last element of the array
  */
-void array_compact(array *me);
+void *array_new(array_t *me);
 
 /**
- * Walk through the array and call `func` on all the valid elements.
- * 
- * @param func: a function that will be called on each element
- * @param (parameters)
- *     * `data`: the element in question
+ * Create <tt>n</tt> elements in the array and return a pointer to the
+ * first one ({see array_next(void *)} to get the next ones).
+ *
+ * @param n how many elements to add
+ *
+ * @return a pointer to the (newly allocated) first new element of the array
+ */
+void *array_newn(array_t *me, size_t n);
+
+/**
+ * Return a pointer to the first element of the array (for instance, if you
+ * store integers, it will be <tt>(int *)</tt>; if you store strings, it will
+ * be <tt>char **</tt>).
+ *
+ * @return a <i>pointer</i> to the first element
+ */
+void *array_first(array_t *me);
+
+/**
+ * Return the pointer to the next element, or NULL if it was the last.
+ *
+ * @param ptr a pointer from an array (the array must be valid)
+ *
+ * @return the next element, or NULL
+ */
+void *array_next(array_t *me, void *ptr);
+
+/**
+ * Retrieve the the pointer of an item.
+ * The address of the item will be returned.
+ *
+ * @param i the index of the element to retrieve
+ *
+ * @return the pointer to the i'th element
+ */
+void *array_get(array_t *me, size_t i);
+
+/**
+ * Return a pointer to the last element of this array and remove it from the
+ * array, if the array is not empty.
+ *
+ * @note be careful, the memory pointed to by the element will be reused the
+ *             next time we add an element -- you should not use it after this; in
+ *             short, the return value is mainly so you can call <tt>free</tt> on
+ *             value pointed to by this pointer (<b>not</b> the pointer itself) if it
+ *             is a pointer to memory you own, or use it locally before continuing to
+ *             use the array
+ * @note in case this was not clear, do <b>not</b> call <tt>free</tt> on the
+ *             returned value
+ *
+ * @return a pointer to the last (now removed) item, or NULL if no element
  */
-void array_all(array *me, void(*func)());
+void *array_pop(array_t *me);
 
 /**
- * Walk through the array and call `free` on all the valid elements.
- * This will not take any precautions, so only use it when you know that all 
- * the elements are indeed pointers you need to `free`.
- * Note that the number of elements will be helfully set to 0 when done, but
- * the array itself will **not** be `free`d.
- * @see `free_array()`
- * @see `array_clear()`
+ * Cut the array at the given size and return a pointer to the first element
+ * that was removed if any.
+ *
+ * @return a pointer to the first removed element, or NULL
  */
-void array_free_all(array *me);
+void *array_cut_at(array_t *me, size_t n);
+
+/** 
+ * Compact the array (resize the buffer so it is equals to the current number 
+ * of items in the array or size 1 if there are no items in the array).
+ */
+void array_compact(array_t *me);
 
 /**
  * Sort the array with a call to `qsort()`.
@@ -161,7 +268,7 @@ void array_free_all(array *me);
  *     *  `0`: if both elements are equals
  *     *  `1`: if element A is more than element B
  */
-void array_qsort(array *me, int (*compar)(const void *itm1, const void *itm2));
+void array_qsort(array_t *me, int (*compar)(const void *itm1, const void *itm2));
 
 /**
  * Sort the array with `qsort()`, data is `char *`.
@@ -170,7 +277,7 @@ void array_qsort(array *me, int (*compar)(const void *itm1, const void *itm2));
  *
  * @see array_qsort
  */
-void array_qsorts(array *me, int rev);
+void array_qsorts(array_t *me, int rev);
 
 /**
  * Sort the array with `qsort()`, data is `int`.
@@ -179,7 +286,7 @@ void array_qsorts(array *me, int rev);
  *
  * @see array_qsort
  */
-void array_qsorti(array *me, int rev);
+void array_qsorti(array_t *me, int rev);
 
 /** 
  * Sort the array with `qsort()`, data is `long`.
@@ -188,7 +295,7 @@ void array_qsorti(array *me, int rev);
  *
  * @see array_qsort
  */
-void array_qsortl(array *me, int rev);
+void array_qsortl(array_t *me, int rev);
 
 /**
  * Sort the array with `qsort()`, data is `float`.
@@ -197,7 +304,7 @@ void array_qsortl(array *me, int rev);
  *
  * @see array_qsort
  */
-void array_qsortf(array *me, int rev);
+void array_qsortf(array_t *me, int rev);
 
 /**
  * Add an element to the array.
@@ -207,7 +314,7 @@ void array_qsortf(array *me, int rev);
  * @return FALSE if the array is too short and we cannot allocate enough 
  *     contiguous memory for its needs
  */
-int array_add(array *me, void *data);
+int array_push(array_t *me, void *data);
 
 /**
  * Add multiple elements to the array.
@@ -219,7 +326,7 @@ int array_add(array *me, void *data);
  * @return FALSE if the array is too short and we cannot allocate enough 
  *     contiguous memory for its needs
  */
-int array_addn(array *me, void *data, size_t n);
+int array_pushn(array_t *me, void *data, size_t n);
 
 /**
  * Set an element of the array to the given value.
@@ -235,7 +342,7 @@ int array_addn(array *me, void *data, size_t n);
  * @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 *me, size_t i, void *data);
+int array_set(array_t *me, size_t i, void *data);
 
 /**
  * Set elements of the array to the given value.
@@ -252,39 +359,31 @@ int array_set(array *me, size_t i, void *data);
  * @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 *me, size_t i, void *data, size_t n);
-
-// only work if new size < current size
-int array_set_size(array *me, size_t n);
-
-/**
- * Retrieve the the pointer of an item.
- * The address of the item will be returned.
- *
- * @param i the index of the element to retrieve
- *
- * @return the pointer to the i'th element
- */
-void *array_get_ptr(array *me, size_t i);
+int array_setn(array_t *me, size_t i, void *data, size_t n);
 
 /**
- * Retrieve the content of an item -- no bounds checking.
- * The item will be copied to the given address location.
+ * Retrieve the content of an item.
+ * The item will be copied to the given address location if it exists.
  *
  * @param target an address where to write a copy of the item
  * @param i the index of the element to retrieve
+ *
+ * @return TRUE if the item exists (if <tt>i</tt> is an element of the array)
  */
-void array_get(array *me, void *target, size_t i);
+int array_copy(array_t *me, void *target, size_t i);
 
 /**
- * Retrieve the content of multiple items -- no bounds checking.
+ * Retrieve the content of multiple items if they exist.
  * The items will be copied in a sequence to the given address location.
  *
  * @param target an address where to write a copy of the items
  * @param i the index of the first element to retrieve
  * @param n the number of elements to retrieve
+ *
+ * @return TRUE if the item exists (if <tt>i</tt> to <tt>n</tt> are elements
+ *             of the array)
  */
-void array_getn(array *me, void *target, size_t i, size_t n);
+int array_copyn(array_t *me, void *target, size_t i, size_t n);
 
 /**
  * Read all the lines from a file.
@@ -300,8 +399,8 @@ void array_getn(array *me, void *target, size_t i, size_t n);
  *
  * @return the number of elements in the array
  */
-size_t array_readfile(array *me, FILE *in, void(*doline)(array *me,
-               const char line[]));
+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.
@@ -316,47 +415,47 @@ size_t array_readfile(array *me, FILE *in, void(*doline)(array *me,
  *
  * @return the number of elements in the array
  */
-size_t array_readfilei(array *me, FILE *in);
+size_t array_readfilei(array_t *me, FILE *in);
 
 /**
  * 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 `array_free_all()`.
+ * for instance with the <tt>array_loop</tt> macro.
  *
+ * @see array_loop
  * @see array_readfile
- * @see array_free_all
  *
  * @param in the file to read
  *
  * @return the number of elements in the array
  */
-size_t array_readfiles(array *me, FILE *in);
+size_t array_readfiles(array_t *me, FILE *in);
 
 /**
  * Print the array metadata to `stderr` (mostly for DEBUG).
  */
-void array_print(array *me);
+void array_print(array_t *me);
 
 /**
  * Print the array and strings content to `stderr` (mostly for DEBUG).
  */
-void array_prints(array *me);
+void array_prints(array_t *me);
 
 /**
  * Print the array and integer content to `stderr` (mostly for DEBUG).
  */
-void array_printi(array *me);
+void array_printi(array_t *me);
 
 /**
  * Print the array and long content to `stderr` (mostly for DEBUG).
  */
-void array_printl(array *me);
+void array_printl(array_t *me);
 
 /**
  * Print the array and floats (%d) content to `stderr` (mostly for DEBUG).
  */
-void array_printf(array *me);
+void array_printf(array_t *me);
 
 /** 
  * Print the array and content to `stderr` (mostly for DEBUG).
@@ -367,8 +466,8 @@ void array_printf(array *me);
  *     * `buffer`: the buffer to use for this (which is the one you pass)
  * @param buffer a buffer that will be passed to `display`
  */
-void array_print_fmt(array *me, 
-       void(*display)(char *buffer, void *item), char *buffer);
+void array_print_fmt(array_t *me, void (*display)(char *buffer, void *item),
+               char *buffer);
 
 #endif /* ARRAY_H */
 
index 84226ab35879addbf4b27333b1c01c8b6fcb3345..b6c3f250c514762923b41ec2d71a23a63898fb5c 100644 (file)
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+/**
+ * @file base64.h
+ * @author Niki
+ * @date 2013 - 2022
+ *
+ * @brief Base64 encode and decode
+ *
+ * This file only provides 2 functions, <tt>base64_encode</tt> and
+ * <tt>base64_decode</tt>, which works on NUL-terminated strings and do what
+ * you expect them to.
+ *
+ * @see base64_encode(const char data[])
+ * @see base64_decode(const char data[])
+ */
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -26,12 +42,26 @@ extern "C" {
 
 #include <stdlib.h>
 
-typedef struct {
-       char *table;
-} base64;
-
+/**
+ * Encode the given data to Base64.
+ *
+ * @note can return NULL if there is not enough memory to allocated the answer
+ *
+ * @param data the data to encode
+ *
+ * @return a newly-allocated string for which you are responsible, or NULL
+ */
 char *base64_encode(const char data[]);
 
+/**
+ * Decode the given data to Base64.
+ *
+ * @note can return NULL if there is not enough memory to allocated the answer
+ *
+ * @param data the data to decode
+ *
+ * @return a newly-allocated string for which you are responsible, or NULL
+ */
 char *base64_decode(const char data[]);
 
 #endif
index 7c06927835801e165ecd645d2a4cfe70142c4d2a..5505f272839b9b8929d6f9008112adacd5f8deb9 100644 (file)
@@ -53,11 +53,11 @@ typedef struct {
 } priv_t;
 
 /** Swap the data */
-static void cstring_swap(cstring *a, cstring *b);
+static void cstring_swap(cstring_t *a, cstring_t *b);
 /** Change the case to upper -or- lower case (UTF8-compatible) */
-static void cstring_change_case(cstring *self, int up);
+static void cstring_change_case(cstring_t *self, int up);
 /** For path-related functions */
-static void normalize_path(cstring *self);
+static void normalize_path(cstring_t *self);
 
 // Private variables
 
@@ -65,10 +65,10 @@ static char *locale = NULL;
 
 // end of privates
 
-cstring *new_cstring() {
-       cstring *string;
+cstring_t *new_cstring() {
+       cstring_t *string;
 
-       string = malloc(sizeof(cstring));
+       string = malloc(sizeof(cstring_t));
        strcpy(string->CNAME, "[CString]");
        string->priv = malloc(sizeof(priv_t));
        string->length = 0;
@@ -79,7 +79,7 @@ cstring *new_cstring() {
        return string;
 }
 
-void free_cstring(cstring *string) {
+void free_cstring(cstring_t *string) {
        if (!string)
                return;
 
@@ -89,7 +89,7 @@ void free_cstring(cstring *string) {
        free(string);
 }
 
-void cstring_swap(cstring *a, cstring *b) {
+void cstring_swap(cstring_t *a, cstring_t *b) {
        void *tmp_p;
        char *tmp_s;
        size_t tmp_l;
@@ -107,14 +107,18 @@ void cstring_swap(cstring *a, cstring *b) {
        b->priv = tmp_p;
 }
 
-int cstring_grow(cstring *self, int min_extra) {
+int cstring_grow(cstring_t *self, int min_extra) {
        priv_t *priv = ((priv_t *) self->priv);
 
        size_t sz = priv->buffer_length;
        size_t req = self->length + min_extra;
 
        if (req > sz) {
-               sz += BUFFER_SIZE;
+               if (sz > BUFFER_SIZE)
+                       sz *= 2;
+               else
+                       sz += BUFFER_SIZE;
+
                if (req > sz)
                        sz = req;
 
@@ -124,7 +128,7 @@ int cstring_grow(cstring *self, int min_extra) {
        return 1;
 }
 
-int cstring_grow_to(cstring *self, int min_buffer) {
+int cstring_grow_to(cstring_t *self, int min_buffer) {
        priv_t *priv = ((priv_t *) self->priv);
 
        if (min_buffer > priv->buffer_length) {
@@ -140,7 +144,7 @@ int cstring_grow_to(cstring *self, int min_buffer) {
        return 1;
 }
 
-void cstring_compact(cstring *self) {
+void cstring_compact(cstring_t *self) {
        if (self != NULL) {
                priv_t *priv = ((priv_t *) self->priv);
 
@@ -149,7 +153,7 @@ void cstring_compact(cstring *self) {
        }
 }
 
-int cstring_add_car(cstring *self, char source) {
+int cstring_add_car(cstring_t *self, char source) {
        if (!cstring_grow(self, 1))
                return 0;
 
@@ -160,19 +164,19 @@ int cstring_add_car(cstring *self, char source) {
        return 1;
 }
 
-int cstring_add(cstring *self, const char source[]) {
+int cstring_add(cstring_t *self, const char source[]) {
        return cstring_addf(self, source, 0);
 }
 
-int cstring_addf(cstring *self, const char source[], size_t idx) {
+int cstring_addf(cstring_t *self, const char source[], size_t idx) {
        return cstring_addfn(self, source, idx, 0);
 }
 
-int cstring_addn(cstring *self, const char source[], size_t n) {
+int cstring_addn(cstring_t *self, const char source[], size_t n) {
        return cstring_addfn(self, source, 0, n);
 }
 
-int cstring_addfn(cstring *self, const char source[], size_t idx, size_t n) {
+int cstring_addfn(cstring_t *self, const char source[], size_t idx, size_t n) {
        size_t ss;
 
        ss = strlen(source);
@@ -196,7 +200,7 @@ int cstring_addfn(cstring *self, const char source[], size_t idx, size_t n) {
        return 1;
 }
 
-int cstring_addp(cstring *self, const char *fmt, ...) {
+int cstring_addp(cstring_t *self, const char *fmt, ...) {
        va_list ap;
        char empty = '\0';
 
@@ -218,16 +222,16 @@ int cstring_addp(cstring *self, const char *fmt, ...) {
        return ok;
 }
 
-void cstring_cut_at(cstring *self, size_t size) {
+void cstring_cut_at(cstring_t *self, size_t size) {
        if (self->length > size) {
                self->string[size] = '\0';
                self->length = size;
        }
 }
 
-cstring *cstring_substring(const char self[], size_t start, size_t length) {
+cstring_t *cstring_substring(const char self[], size_t start, size_t length) {
        size_t sz = strlen(self);
-       cstring * sub = new_cstring();
+       cstring_t * sub = new_cstring();
 
        if (start <= sz) {
                const char *source = (self + start);
@@ -339,8 +343,8 @@ void cstring_reverse(char *self) {
        }
 }
 
-int cstring_replace(cstring *self, const char from[], const char to[]) {
-       cstring *buffer;
+int cstring_replace(cstring_t *self, const char from[], const char to[]) {
+       cstring_t *buffer;
        size_t i;
        size_t step;
        int occur;
@@ -440,12 +444,12 @@ long cstring_rfind(char self[], const char find[], long rstart_index) {
        return -1;
 }
 
-void cstring_clear(cstring *self) {
+void cstring_clear(cstring_t *self) {
        self->length = 0;
        self->string[0] = '\0';
 }
 
-char *cstring_convert(cstring *self) {
+char *cstring_convert(cstring_t *self) {
        char *string;
 
        if (!self)
@@ -462,17 +466,17 @@ char *cstring_convert(cstring *self) {
        return string;
 }
 
-cstring *cstring_clone(const char self[]) {
+cstring_t *cstring_clone(const char self[]) {
        if (self == NULL)
                return NULL;
 
-       cstring *clone = new_cstring();
+       cstring_t *clone = new_cstring();
        cstring_add(clone, self);
 
        return clone;
 }
 
-void cstring_rtrim(cstring *self, char car) {
+void cstring_rtrim(cstring_t *self, char car) {
        for (size_t i = self->length - 1; i >= 0; i--) {
                if (self->string[i] != car)
                        break;
@@ -481,7 +485,7 @@ void cstring_rtrim(cstring *self, char car) {
        }
 }
 
-void cstring_trim(cstring *self, char car) {
+void cstring_trim(cstring_t *self, char car) {
        if (car == '\0')
                return;
 
@@ -492,7 +496,7 @@ void cstring_trim(cstring *self, char car) {
                i++;
 
        if (i) {
-               cstring *tmp = new_cstring();
+               cstring_t *tmp = new_cstring();
                cstring_add(tmp, self->string + i);
 
                cstring_swap(self, tmp);
@@ -512,15 +516,15 @@ size_t cstring_remove_crlf(char *self) {
        return sz;
 }
 
-void cstring_toupper(cstring *self) {
+void cstring_toupper(cstring_t *self) {
        cstring_change_case(self, 1);
 }
 
-void cstring_tolower(cstring *self) {
+void cstring_tolower(cstring_t *self) {
        cstring_change_case(self, 0);
 }
 
-void cstring_change_case(cstring *self, int up) {
+void cstring_change_case(cstring_t *self, int up) {
        // Change LC_ALL to LANG if not found
        // TODO: only take part we need (also, this is still bad practise)
        if (!locale) {
@@ -535,7 +539,7 @@ void cstring_change_case(cstring *self, int up) {
                }
        }
 
-       cstring *rep;
+       cstring_t *rep;
        mbstate_t state_from, state_to;
        wchar_t wide;
        char tmp[10];
@@ -592,7 +596,7 @@ void cstring_change_case(cstring *self, int up) {
        free_cstring(rep);
 }
 
-int cstring_readline(cstring *self, FILE *file) {
+int cstring_readline(cstring_t *self, FILE *file) {
        char buffer[BUFFER_SIZE];
        size_t size = 0;
        int full_line;
@@ -635,13 +639,13 @@ int cstring_readline(cstring *self, FILE *file) {
        return 0;
 }
 
-static void normalize_path(cstring *self) {
+static void normalize_path(cstring_t *self) {
        while (self->length && self->string[self->length - 1] == CSTRING_SEP)
                self->length--;
        self->string[self->length] = '\0';
 }
 
-void cstring_add_path(cstring *self, const char subpath[]) {
+void cstring_add_path(cstring_t *self, const char subpath[]) {
        while (self->length && self->string[self->length - 1] == CSTRING_SEP)
                self->length--;
        cstring_add_car(self, CSTRING_SEP);
@@ -652,7 +656,7 @@ void cstring_add_path(cstring *self, const char subpath[]) {
        normalize_path(self);
 }
 
-int cstring_pop_path(cstring *self, int how_many) {
+int cstring_pop_path(cstring_t *self, int how_many) {
        int count = 0;
        size_t tmp;
        char first = '\0';
@@ -687,7 +691,7 @@ char *cstring_basename(const char path[], const char ext[]) {
        while (i && path[i] != CSTRING_SEP)
                i--;
 
-       cstring *rep;
+       cstring_t *rep;
        if (path[i] != CSTRING_SEP) {
                rep = cstring_clone(path);
        } else {
@@ -703,12 +707,12 @@ char *cstring_basename(const char path[], const char ext[]) {
 }
 
 char *cstring_dirname(const char path[]) {
-       cstring *rep = cstring_clone(path);
+       cstring_t *rep = cstring_clone(path);
        cstring_pop_path(rep, 1);
        return cstring_convert(rep);
 }
 
-int cstring_is_utf8(cstring *self) {
+int cstring_is_utf8(cstring_t *self) {
        size_t rep = mbstowcs(NULL, self->string, 0);
        // -2 = invalid, -1 = not whole
        return (rep != (size_t) -2) && (rep != (size_t) -1);
index ecd34d6a005b84cebaab35277a814309d35b49fa..b38c610698ad33b60b218c6aa2faf2be049003b9 100644 (file)
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+/**
+ * @file cstring.h
+ * @author Niki
+ * @date 2013 - 2022
+ *
+ * @brief Some string utility functions
+ *
+ * This file implements some basic functions of a string, most often by working
+ * directly with <tt>char *</tt> (but when needed with the provided
+ * <tt>cstring</tt> object).
+ */
+
 #ifndef CSTRING_H
 #define CSTRING_H
 
@@ -27,20 +39,23 @@ extern "C" {
 #include <stdio.h>
 
 /**
- * This is a cstring. It contains a suite of characters terminated by a NUL byte
+ * @brief A NUL-byte terminated string, with a known length
+ *
+ * The structure contains a suite of characters terminated by a NUL byte
  * (or just a NUL byte), and a length.
  * It is advised NOT to modify either of those directly.
- * You can use cstring_convert to get a char*, though (in this case, the cstring
- * MUST NOT be used again, and you are responsible for freeing the said char*).
+ * You can use <tt>cstring_convert</tt> to get a <tt>char *</tt>, though
+ * (in this case, the cstring <b>MUST NOT</b> be used again, and you are
+ * responsible for freeing said <tt>char *</tt>).
+ *
+ * @see cstring_convert
  */
-typedef struct cstring_struct cstring;
-
-struct cstring_struct {
-       char CNAME[32];
+typedef struct {
+       char CNAME[10];
        char *string;
        size_t length;
        void *priv;
-};
+} cstring_t;
 
 /**
  * Instantiate a new cstring.
@@ -48,7 +63,7 @@ struct cstring_struct {
  * Create (and allocate the memory for) a new cstring.
  * Do not forget to call cstring_free(cstring) when done.
  */
-cstring *new_cstring();
+cstring_t *new_cstring();
 
 /**
  * Free the given cstring.
@@ -57,7 +72,7 @@ cstring *new_cstring();
  *
  * @param self the cstring to free, which MUST NOT be used again afterward
  */
-void free_cstring(cstring *self);
+void free_cstring(cstring_t *self);
 
 /**
  * Grow the cstring to accommodate that many characters in addition to those
@@ -69,7 +84,7 @@ void free_cstring(cstring *self);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_grow(cstring *self, int min_extra);
+int cstring_grow(cstring_t *self, int min_extra);
 
 /**
  * Grow the cstring to accommodate that many characters in total, if needed.
@@ -80,14 +95,14 @@ int cstring_grow(cstring *self, int min_extra);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_grow_to(cstring *self, int min_buffer);
+int cstring_grow_to(cstring_t *self, int min_buffer);
 
 /**
  * Compact the memory used by this string.
  *
  * @param self the string to work on
  */
-void cstring_compact(cstring *self);
+void cstring_compact(cstring_t *self);
 
 /**
  * Add a char at the end of the given cstring.
@@ -98,7 +113,7 @@ void cstring_compact(cstring *self);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_add_car(cstring *self, char source);
+int cstring_add_car(cstring_t *self, char source);
 
 /**
  * Add a string (a sequence of char that MUST end with '\0') at the end of the
@@ -110,7 +125,7 @@ int cstring_add_car(cstring *self, char source);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_add(cstring *self, const char source[]);
+int cstring_add(cstring_t *self, const char source[]);
 
 /**
  * Add a string (a sequence of char that MUST end with '\0') at the end of the
@@ -123,7 +138,7 @@ int cstring_add(cstring *self, const char source[]);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_addf(cstring *self, const char source[], size_t idx);
+int cstring_addf(cstring_t *self, const char source[], size_t idx);
 
 /**
  * Add a string (a sequence of char that MAY end with '\0') at the end of the
@@ -137,7 +152,7 @@ int cstring_addf(cstring *self, const char source[], size_t idx);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_addn(cstring *self, const char source[], size_t n);
+int cstring_addn(cstring_t *self, const char source[], size_t n);
 
 /**
  * Add a string (a sequence of char that MAY end with '\0') at the end of the
@@ -152,7 +167,7 @@ int cstring_addn(cstring *self, const char source[], size_t n);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_addfn(cstring *self, const char source[], size_t idx, size_t n);
+int cstring_addfn(cstring_t *self, const char source[], size_t idx, size_t n);
 
 /**
  * Add a string via the usual <tt>printf</tt> formatters.
@@ -164,7 +179,7 @@ int cstring_addfn(cstring *self, const char source[], size_t idx, size_t n);
  * @return TRUE if success (FALSE means it was unable to grow due to memory
  *             pressure)
  */
-int cstring_addp(cstring *self, const char *fmt, ...);
+int cstring_addp(cstring_t *self, const char *fmt, ...);
 
 /**
  * Cut the string at the given size if it is greater.
@@ -176,7 +191,7 @@ int cstring_addp(cstring *self, const char *fmt, ...);
  * @param size the size to cut at (the maximum size of the cstring after this
  *             operation, NUL excepted)
  */
-void cstring_cut_at(cstring *self, size_t size);
+void cstring_cut_at(cstring_t *self, size_t size);
 
 /**
  * Create a substring of this one.
@@ -187,7 +202,7 @@ void cstring_cut_at(cstring *self, size_t size);
  *
  * @return a newly allocated cstring
  */
-cstring *cstring_substring(const char self[], size_t start, size_t length);
+cstring_t *cstring_substring(const char self[], size_t start, size_t length);
 
 /**
  * Split a cstring into "smaller" cstrings every time the given separator is found.
@@ -238,7 +253,7 @@ void cstring_reverse(char *self);
  *
  * @return the number of occurrences changed
  */
-int cstring_replace(cstring *self, const char from[], const char to[]);
+int cstring_replace(cstring_t *self, const char from[], const char to[]);
 
 /**
  * Replace all occurrences of a char inside the given string by another.
@@ -306,7 +321,7 @@ long cstring_rfind(char self[], const char find[], long rstart_index);
  *
  * @param self the string to work on
  */
-void cstring_clear(cstring *self);
+void cstring_clear(cstring_t *self);
 
 /**
  * Convert this cstring into a string
@@ -315,7 +330,7 @@ void cstring_clear(cstring *self);
  *
  * @param self the cstring to work on
  */
-char *cstring_convert(cstring *self);
+char *cstring_convert(cstring_t *self);
 
 /**
  * Clone this string.
@@ -323,7 +338,7 @@ char *cstring_convert(cstring *self);
  *
  * @param self the string to clone
  */
-cstring *cstring_clone(const char self[]);
+cstring_t *cstring_clone(const char self[]);
 
 /**
  * Trim this cstring of all trailing 'car' instances.
@@ -333,7 +348,7 @@ cstring *cstring_clone(const char self[]);
  *
  * @return a right trimmed cstring
  */
-void cstring_rtrim(cstring *self, char car);
+void cstring_rtrim(cstring_t *self, char car);
 
 /**
  * Trim this cstring of all 'car' instances from the start and/or the
@@ -344,7 +359,7 @@ void cstring_rtrim(cstring *self, char car);
  * 
  * @return a trimmed cstring
  */
-void cstring_trim(cstring *self, char car);
+void cstring_trim(cstring_t *self, char car);
 
 /**
  * Remove the \r and \n sequence (or one OR the other) at the end of the string.
@@ -364,7 +379,7 @@ size_t cstring_remove_crlf(char *self);
  *
  * @param self the cstring to work on
  */
-void cstring_toupper(cstring *self);
+void cstring_toupper(cstring_t *self);
 
 /**
  * Change the case to lower-case (UTF-8 compatible, but the string MUST be
@@ -375,7 +390,7 @@ void cstring_toupper(cstring *self);
  *
  * @param self the cstring to work on
  */
-void cstring_tolower(cstring *self);
+void cstring_tolower(cstring_t *self);
 
 /**
  * Read a whole line (CR, LN or CR+LN terminated) from the given file stream.
@@ -385,7 +400,7 @@ void cstring_tolower(cstring *self);
  *
  * @return 1 if a line was read, 0 if not
  */
-int cstring_readline(cstring *self, FILE *file);
+int cstring_readline(cstring_t *self, FILE *file);
 
 /**
  * Add a path to the given cstring (if it is currently empty, it
@@ -397,7 +412,7 @@ int cstring_readline(cstring *self, FILE *file);
  * @param self the base cstring (empty for a root path)
  * @param subpath the path component to add
  */
-void cstring_add_path(cstring *self, const char subpath[]);
+void cstring_add_path(cstring_t *self, const char subpath[]);
 
 /**
  * Remove the <tt>how_many</tt> components of the path described by this
@@ -409,7 +424,7 @@ void cstring_add_path(cstring *self, const char subpath[]);
  * @param how_many how many path components to remove (for instance, to go from
  *             <tt>/some/path/to/file</tt> to <tt>/some/path</tt> you would need 2)
  */
-int cstring_pop_path(cstring *self, int how_many);
+int cstring_pop_path(cstring_t *self, int how_many);
 
 /**
  * Return the basename component of this path (for instance,
@@ -440,7 +455,7 @@ char *cstring_dirname(const char path[]);
  * 
  * @return TRUE if it is UTF-8
  */
-int cstring_is_utf8(cstring *self);
+int cstring_is_utf8(cstring_t *self);
 
 #endif
 
index bcdff7d48478376509e5a7ca1ad255c1f7aa579e..ba353a7b057c85556b250e6db3eac27cc54b607e 100644 (file)
@@ -34,7 +34,7 @@ struct {
        char *icon;
        char *icon_file;
        char *exec;
-       array *children;
+       array_t *children;
        int id;
 }typedef desktop_p;
 
@@ -104,7 +104,7 @@ desktop *new_desktop(const char filename[], int best_size) {
                        desktop_p *child = (desktop_p*) new_desktop(childname, best_size);
                        free(childname);
                        if (child) {
-                               array_add(me->children, &child);
+                               array_push(me->children, &child);
                        }
                }
 
@@ -123,21 +123,17 @@ desktop *new_desktop(const char filename[], int best_size) {
        }
 
        FILE *file;
-       array *tab;
-       size_t n_lines;
+       array_t *tab;
 
        tab = new_array(sizeof(char *), 32);
 
        file = fopen(filename, "r");
-       n_lines = array_readfiles(tab, file);
+       array_readfiles(tab, file);
        fclose(file);
 
-       char *line;
        char *startsWith;
        size_t n;
-       for (size_t i = 0; i < n_lines; i++) {
-               array_get(tab, &line, i);
-
+       array_loop_i(tab, line, char, i) {
                startsWith = "Name=";
                n = strlen(startsWith);
                if (!strncmp(line, startsWith, n)) {
@@ -169,7 +165,8 @@ desktop *new_desktop(const char filename[], int best_size) {
                }
        }
 
-       array_free_all(tab);
+       array_loop(tab, item, void)
+               free(item);
 
        // Find icon file linked to icon
        if (me->icon && !me->icon_file) {
@@ -229,27 +226,24 @@ void desktop_set_id(desktop *app, int id) {
        me->id = id;
 }
 
-array *desktop_get_children(desktop *app) {
+array_t *desktop_get_children(desktop *app) {
        desktop_p *me = (desktop_p*) app;
        return me->children;
 }
 
-desktop *desktop_find_id(array *children, int id) {
+desktop *desktop_find_id(array_t *children, int id) {
        desktop *found = NULL;
-       size_t n = 0;
-
-       if (children)
-               n = array_count(children);
 
-       desktop_p *child;
-       for (size_t i = 0; !found && i < n; i++) {
-               array_get(children, &child, i);
+       array_loop(children, child, desktop_p)
+       {
                if (child->id == id) {
                        found = (desktop*) child;
                        break;
                }
 
                found = desktop_find_id(child->children, id);
+               if (found)
+                       break;
        }
 
        return found;
@@ -334,23 +328,21 @@ char *desktop_find_icon(const char basename[], int icon_size) {
        sprintf(icon_size_str, "%dx%d", icon_size, icon_size);
 
        if (!theme) {
-               array *tab = new_array(sizeof(char *), 32);
-               size_t n_lines = 0;
+               array_t *tab = new_array(sizeof(char *), 32);
 
                tmp = desktop_concat(home, "/.gtkrc-2.0", NULL);
                FILE *file = fopen(tmp, "r");
                free(tmp);
                if (file) {
-                       n_lines = array_readfiles(tab, file);
+                       array_readfiles(tab, file);
                        fclose(file);
                }
 
-               char *line;
                const char *startsWith = "gtk-icon-theme-name=";
                size_t n = strlen(startsWith);
 
-               for (size_t i = 0; i < n_lines; i++) {
-                       array_get(tab, &line, i);
+               array_loop(tab, line, char)
+               {
                        if (!strncmp(line, startsWith, n)) {
                                free(theme);
                                if (line[n] == '"') {
@@ -372,7 +364,8 @@ char *desktop_find_icon(const char basename[], int icon_size) {
                        free(tmp);
                }
 
-               array_free_all(tab);
+               array_loop(tab,item, void)
+                       free(item);
        }
 
        // Allow NULL
index e6857f35643e08aa701a631fa0485c5dbd9e8082..8e208ae372fd934710011822ce990e3d7f8d8582 100644 (file)
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-/* @file desktop.h
+/**
+ * @file desktop.h
  * @author Niki
- * @date 2021
+ * @date 2021 - 2022
  *
  * @brief Manipulate <tt>.desktop</tt> files (as described by
  * <a href='https://freedesktop.org/'>FreeDesktop.org</a>)
@@ -99,7 +100,7 @@ void desktop_set_id(desktop *self, int id);
  * TODO: switch to full objects
  * @return an array of pointers to desktop objects
  */
-array *desktop_get_children(desktop *app);
+array_t *desktop_get_children(desktop *app);
 
 /**
  * Find a submenu item by the given ID ({@see desktop_set_id(desktop *, int)}).
@@ -110,7 +111,7 @@ array *desktop_get_children(desktop *app);
  *
  * @return the given submenu if found, or NULL
  */
-desktop *desktop_find_id(array *children, int menu_id);
+desktop *desktop_find_id(array_t *children, int menu_id);
 
 /**
  * Look for the icon file related to this basename.
index f9fe50d75661fde1d3be9e189723c51eece1b4a1..10937fb264b78ca13e0b20b899ba3d9406fdaf41 100644 (file)
@@ -105,7 +105,7 @@ int net_connect(const char server[], int port) {
        int sockfd;
        struct addrinfo hints, *servinfo, *p;
        int rv;
-       cstring *str;
+       cstring_t *str;
 
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_UNSPEC;
@@ -167,7 +167,7 @@ int net_listen(int port, int backlog) {
        struct addrinfo hints, *servinfo, *p;
        char yes = 1;
        int rv;
-       cstring *str;
+       cstring_t *str;
 
        memset(&hints, 0, sizeof hints);
        hints.ai_family = AF_UNSPEC;
index 9652a4dc052f91a1b715d541e00eabaf60d23eb3..73140f3fc9ebe56f32f7e36ab0bb37511aca4654 100644 (file)
  */
 
 /**
- * @file
+ * @file net.h
  * @author niki
- * @date November 2011
+ * @date 2011 - 2022
  *
- * Allows you to make connections to/from a server, and to send/receive data.
+ * @brief Send/receive data from the network
+ *
+ * Allows you to make connections to/from a server, and to send/receive data
+ * through those connections.
  */
 
 #ifndef NET_H
@@ -34,54 +37,48 @@ extern "C" {
 
 // WHY ??
 #ifdef _WIN32
-       #ifndef WIN32
-               #define WIN32
-       #endif
+#ifndef WIN32
+#define WIN32
+#endif
 #endif
 
 #ifdef WIN32
-    #ifndef _WIN32_WINNT
-        #define _WIN32_WINNT 0x501
-    #endif
-       #include <winsock2.h>
-       #include <ws2tcpip.h>
-       typedef SSIZE_T ssize_t;
-       #define close(s) closesocket(s)
-       #define ioctl(a,b,c) ioctlsocket(a,b,c)
-       #pragma comment(lib, "wsock32.lib");
-       #pragma comment(lib, "ws2_32.lib");
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x501
+#endif
+#include <winsock2.h>
+#include <ws2tcpip.h>
+typedef SSIZE_T ssize_t;
+#define close(s) closesocket(s)
+#define ioctl(a,b,c) ioctlsocket(a,b,c)
+#pragma comment(lib, "wsock32.lib");
+#pragma comment(lib, "ws2_32.lib");
 #else
-       #include <unistd.h>
-       #include <sys/socket.h>
-       #include <netinet/in.h>
-       #include <netdb.h>
-       #include <arpa/inet.h>
-       #include <sys/wait.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
 #endif
 
 /* for ssize_t */
 #include <sys/types.h>
 
-/**
- * Obsolete, see net_set_blocking(..)
- */
-int net_set_non_blocking(int fd);
-
 /**
  * You must call this function before doing any network related operation,
  * because of some legacy WIN32 rule.
- * (It is a noop on all other platforms).
+ * (It is a noop on all other platforms.)
  *
- * @return 0 when the Windows host does not support WinSock and thus,
+ * @return FALSE when the Windows host does not support WinSock and thus,
  *             no network for you (you still need to call net_cleanup)
- * 
  */
 int net_init();
 
 /**
  * You must call this function after you are done using network related
  * operations within this DLL, because of some legacy WIN32 rule.
- * (It is a noop on all other platforms).
+ * (It is a noop on all other platforms.)
  */
 void net_cleanup();
 
@@ -90,9 +87,9 @@ void net_cleanup();
  * This function can work with file sockets, too.
  *
  * @param fd the file descriptor or socket to change
- * @param block 1 to block, 0 not to block
+ * @param block TRUE to block, FALSE not to block
  * 
- * @return 1 if success
+ * @return TRUE if success
  */
 int net_set_blocking(int fd, int block);
 
@@ -103,17 +100,17 @@ int net_set_blocking(int fd, int block);
  * @param server the server to connect to
  * @param port the port to connect on
  *
- * @return the server socket or -1 if error
+ * @return the server socket or a negative value on error
  */
 int net_connect(const char server[], int port);
 
 /**
  * Open a port and returns a (server) socket descriptor from which you can
- *               accept connection.
+ * accept connections.
  *
  * @param port the port to connect on
  * @param backlog the maximum number of client connections we will queue for
- *     this socket until you handle them
+ *             this socket until you handle them
  *
  * @return the server socket, or a negative value on error
  */
@@ -145,8 +142,7 @@ void net_close_socketd(int socketd);
  * @param buf the buffer to read from
  * @param n the number of bytes to write
  *
- * @return the actual number of bytes written or a
- *                negative number if error
+ * @return the actual number of bytes written or a negative number if error
  */
 ssize_t net_write(int fd, const void *buf, size_t n);
 
@@ -164,5 +160,5 @@ ssize_t net_read(int fd, void *buf, size_t nbytes);
 #endif
 
 #ifdef __cplusplus
-extern }
+extern}
 #endif
index 30d59e629e67c3ed12180ebcb05fcdb0428a4b4c..f0872a6f37908beaf4bbcd210b111f82e5c48e78 100644 (file)
@@ -3,9 +3,7 @@
  * @author Samantaz Fox
  * @date 2019
  *
- * @brief print.h
- *
- * print.h
+ * @brief File name and line numbers
  *
  * Small utility header designed to print file name and line number
  * along with debug/info messages.
@@ -14,7 +12,7 @@
  *   ERROR("program exited with code %d\n", getErrorCode() );
  *
  * Known issues:
- *   - Must take at least one argument in addtion to format string
+ *   - Must take at least one argument in addition to format string
  *
  *
  * Copyright 2019 (C) Samantaz Fox
@@ -22,7 +20,6 @@
  *
  * This file is in the public domain.
  * Feel free to copy, modify or redistribute it!
- *
 */
 
 #ifndef __PRINT_H__
index b1eba25f62d2253859ed9c6dfe5c921d645b859e..1dd0caecefbb72291d4e53da72fab9ed5ca95471 100644 (file)
@@ -20,9 +20,9 @@
 /** 
  * @file timing.h
  * @author Niki
- * @date 2020
+ * @date 2020 - 2022
  *
- * @brief Timing macro START and STOP
+ * @brief Timing macros START and STOP
  *
  * 2 macro are provided to print the elapsed time between the 2 to stdout.
  */
@@ -36,11 +36,17 @@ extern "C" {
 
 #include <sys/time.h>
 
+/**
+ * Start the timer.
+ */
 #define START struct timeval TIMING_start, TIMING_stop; \
        /* 1 usec = 0.000001 s */ \
        char cusec[7]; \
        gettimeofday(&TIMING_start, NULL);
 
+/**
+ * Stop the timer and print the elapsed time to stdout.
+ */
 #define STOP gettimeofday(&TIMING_stop, NULL); \
        TIMING_stop.tv_sec  = TIMING_stop.tv_sec  - TIMING_start.tv_sec; \
        TIMING_stop.tv_usec = TIMING_stop.tv_usec - TIMING_start.tv_usec; \
index 667407c3dbeaa16042a8034d6b36c6ae37a286aa..90d4a6a7687e1fb692448a8718a381276d811870 100644 (file)
 /**
  * @file utils.h
  * @author Niki
- * @date 2020
+ * @date 2020 - 2022
  *
- * @brief Include all the other .h as well as a C99-compatible strdup/strnlen
- *             functions.
+ * @brief Include all the other .h as well as C99-compatible
+ * <tt>strdup</tt>/<tt>strnlen</tt> functions if they are not already defined
  */
 #ifndef UTILS_H
 #define UTILS_H
@@ -40,10 +40,31 @@ extern "C" {
 
 /* Helps with C99 compatibility for code that is not */
 
-#ifndef strnlen
+#if _POSIX_C_SOURCE < 200809L && _XOPEN_SOURCE < 500
+#ifndef _GNU_SOURCE
+/**
+ * The strnlen() function returns the number of bytes in the string pointed to
+ * by s, excluding the terminating null byte ('\0'), but at most maxlen.
+ * In doing this, strnlen() looks only at the first maxlen characters in the
+ * string pointed to by s and never beyond s[maxlen-1].
+ *
+ * @return The strnlen() function returns strlen(s), if that is less than
+ *             maxlen, or maxlen if there is no null terminating ('\0') among the first
+ *             maxlen characters pointed to by s
+ */
 size_t strnlen(const char *s, size_t maxlen);
 #endif
-#ifndef strdup
+#endif
+#if _POSIX_C_SOURCE < 200809L && _XOPEN_SOURCE < 500
+/**
+ * The strndup() function is similar, but copies at most n bytes.
+ * If s is longer than n, only n bytes are copied, and a terminating null byte
+ * ('\0') is added.
+ *
+ * @return On success, the strndup() function returns a pointer to the
+ *             duplicated string.  It returns NULL if insufficient memory was
+ *             available, with errno set to indicate the error
+ */
 char *strdup(const char *source);
 #endif