}
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);
}
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)) {
fail:
- array_free_all(lines);
+ array_loop(lines, line, void)
+ free(line);
+
return song;
}
* 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;
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)
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 {
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);
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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;
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;
* 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)
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);
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);
--- /dev/null
+/*
+ * CUtils: some small C utilities
+ *
+ * Copyright (C) 2022 Niki Roo
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "utils/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;
+}
#define TEST_FILE_READLINE "utils/test_readline.txt"
-cstring *s;
+cstring_t *s;
static void setup() {
s = new_cstring();
END
START(clone)
- cstring *clone;
+ cstring_t *clone;
clone = cstring_clone(NULL);
if (clone)
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");
}
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;
}
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_ */
#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);
}
}
if (mot->count) {
- array_add(mot, &zero);
- doline(me, mot->data);
+ array_push(mot, &zero);
+ doline(me, mot_priv->data);
count++;
}
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);
}
/* 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;
}
/**
* @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);
* ```
*/
#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.
*
* @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.
*
* @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()`.
* * `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 *`.
*
* @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`.
*
* @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`.
*
* @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`.
*
* @see array_qsort
*/
-void array_qsortf(array *me, int rev);
+void array_qsortf(array_t *me, int rev);
/**
* Add an element to the array.
* @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.
* @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.
* @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.
* @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.
*
* @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.
*
* @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).
* * `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 */
* 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
#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
} 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
// 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;
return string;
}
-void free_cstring(cstring *string) {
+void free_cstring(cstring_t *string) {
if (!string)
return;
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;
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;
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) {
return 1;
}
-void cstring_compact(cstring *self) {
+void cstring_compact(cstring_t *self) {
if (self != NULL) {
priv_t *priv = ((priv_t *) self->priv);
}
}
-int cstring_add_car(cstring *self, char source) {
+int cstring_add_car(cstring_t *self, char source) {
if (!cstring_grow(self, 1))
return 0;
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);
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';
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);
}
}
-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;
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)
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;
}
}
-void cstring_trim(cstring *self, char car) {
+void cstring_trim(cstring_t *self, char car) {
if (car == '\0')
return;
i++;
if (i) {
- cstring *tmp = new_cstring();
+ cstring_t *tmp = new_cstring();
cstring_add(tmp, self->string + i);
cstring_swap(self, tmp);
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) {
}
}
- cstring *rep;
+ cstring_t *rep;
mbstate_t state_from, state_to;
wchar_t wide;
char tmp[10];
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;
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);
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';
while (i && path[i] != CSTRING_SEP)
i--;
- cstring *rep;
+ cstring_t *rep;
if (path[i] != CSTRING_SEP) {
rep = cstring_clone(path);
} else {
}
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);
* 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
#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.
* 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.
*
* @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
* @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.
* @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.
* @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
* @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
* @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
* @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
* @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.
* @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.
* @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.
*
* @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.
*
* @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.
*
* @param self the string to work on
*/
-void cstring_clear(cstring *self);
+void cstring_clear(cstring_t *self);
/**
* Convert this cstring into a string
*
* @param self the cstring to work on
*/
-char *cstring_convert(cstring *self);
+char *cstring_convert(cstring_t *self);
/**
* Clone this string.
*
* @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.
*
* @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
*
* @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.
*
* @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
*
* @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.
*
* @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
* @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
* @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,
*
* @return TRUE if it is UTF-8
*/
-int cstring_is_utf8(cstring *self);
+int cstring_is_utf8(cstring_t *self);
#endif
char *icon;
char *icon_file;
char *exec;
- array *children;
+ array_t *children;
int id;
}typedef desktop_p;
desktop_p *child = (desktop_p*) new_desktop(childname, best_size);
free(childname);
if (child) {
- array_add(me->children, &child);
+ array_push(me->children, &child);
}
}
}
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)) {
}
}
- array_free_all(tab);
+ array_loop(tab, item, void)
+ free(item);
// Find icon file linked to icon
if (me->icon && !me->icon_file) {
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;
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] == '"') {
free(tmp);
}
- array_free_all(tab);
+ array_loop(tab,item, void)
+ free(item);
}
// Allow NULL
* 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>)
* 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)}).
*
* @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.
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;
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;
*/
/**
- * @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
// 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();
* 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);
* @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
*/
* @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);
#endif
#ifdef __cplusplus
-extern }
+extern}
#endif
* @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.
* 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
*
* This file is in the public domain.
* Feel free to copy, modify or redistribute it!
- *
*/
#ifndef __PRINT_H__
/**
* @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.
*/
#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; \
/**
* @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
/* 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