--- /dev/null
+[submodule "src/cutils"]
+ path = src/cutils
+ url = git@git.nikiroo.be:workspace/cutils.git
-NAME=nsub
-
-.PHONY: all build rebuild install uninstall clean mrpropre mrpropre love debug \
- doc man run tests test run-test run-test-more
+#
+# Simple makefile that will forward all commands to src/xxx
+# > NAME: main program (for 'man' and 'run')
+# > NAMES: list of all the programs to compile
+# > TESTS: list of all test programs to compile and run
+#
+NAME = nsub
+NAMES = $(NAME) cutils
+TESTS =
+
+PREFIX = /usr/local
+dstdir = bin
+
+.PHONY: all build run clean mrpropre mrpropre love debug doc man \
+ test run-test run-test-more \
+ mess-build mess-run mess-clean mess-propre mess-doc mess-man \
+ mess-test mess-run-test mess-run-test-more \
+ $(NAMES) $(TESTS)
all: build
-build: bin/nsub
- @echo Build successful.
-
-run: bin/nsub
- bin/nsub
-
-tests: test
+build: mess-build $(NAMES)
-test:
- $(MAKE) -C src -f tests.d
-
-run-test:
- $(MAKE) -C src -f tests.d run
+test: mess-test $(TESTS)
-run-test-more:
- $(MAKE) -C src -f tests.d run-more
+# Main buildables
+M_OPTS=$(MAKECMDGOALS) --no-print-directory PREFIX=$(PREFIX) DEBUG=$(DEBUG)
+$(NAMES) $(TESTS):
+ $(MAKE) -C src/$@ $(M_OPTS)
-rebuild: clean build
+# Manual
+man: mess-man
+ @$(MAKE) -f man.d $(MAKECMDGOALS) NAME=$(NAME)
-doc:
- doxygen
+# Run
+run: mess-run $(NAME)
-man: VERSION README*.md
- $(MAKE) -f man.d NAME=$(NAME)
+# Run main test
+run-test: mess-run-test $(TESTS)
+run-test-more: mess-run-test-more $(TESTS)
+# Doc/man/misc
+doc: mess-doc
+ doxygen
love:
@echo " ...not war."
-
debug:
- $(MAKE) DEBUG=1
+ $(MAKE) $(MAKECMDGOALS) PREFIX=$(PREFIX) NAME=$(NAME) DEBUG=1
+# Clean
+clean: mess-clean $(TESTS) $(NAMES)
mrproper: mrpropre
-
-mrpropre: clean
- $(MAKE) -C src -f tests.d mrpropre
- $(MAKE) -C src -f utils.d mrpropre
- $(MAKE) -C src -f nsub.d mrpropre
- rm -f man/man1/*.1 man/*/man1/*.1
- rmdir man/*/man1 man/* man || true
+mrpropre: mess-propre $(TESTS) $(NAMES) man
rm -rf doc/html doc/latex doc/man
- rmdir doc || true
-
-clean:
- $(MAKE) -C src -f tests.d clean
- $(MAKE) -C src -f utils.d clean
- $(MAKE) -C src -f nsub.d clean
-
-install:
- $(MAKE) -C src -f nsub.d install
- @if [ -e "man/man1/$(NAME).1" ]; then \
- cp -r man/ "$(PREFIX)"/share/; \
- else \
- echo "No manual has been built (see \`make man')"; \
- fi
-
-uninstall:
- $(MAKE) -C src -f nsub.d uninstall
-
-bin/nsub: bin/utils.o
- $(MAKE) -C src -f nsub.d DEBUG=$(DEBUG)
-
-bin/utils.o:
- $(MAKE) -C src -f utils.d DEBUG=$(DEBUG)
+ rmdir doc 2>/dev/null || true
+
+# Install/uninstall
+install: mess-install $(NAMES) man
+uninstall: mess-uninstall $(NAMES) man
+
+# Messages
+mess-build:
+ @echo
+ @echo ">>>>>>>>>> Building $(NAMES)..."
+mess-run:
+ @echo
+ @echo ">>>>>>>>>> Running $(NAME)..."
+mess-clean:
+ @echo
+ @echo ">>>>>>>>>> Cleaning $(NAMES) $(TESTS)..."
+mess-propre:
+ @echo
+ @echo ">>>>>>>>>> Calling Mr Propre..."
+mess-doc:
+ @echo
+ @echo ">>>>>>>>>> Generating documentation for $(NAME)..."
+mess-man:
+ @echo
+ @echo ">>>>>>>>>> Manual of $(NAME): $(MAKECMDGOALS)..."
+mess-test:
+ @echo
+ @echo ">>>>>>>>>> Building all tests: $(TESTS)..."
+mess-run-test:
+ @echo
+ @echo ">>>>>>>>>> Running tests: $(TESTS)..."
+mess-run-test-more:
+ @echo
+ @echo ">>>>>>>>>> Running more tests: $(TESTS)..."
+mess-install:
+ @echo
+ @echo ">>>>>>>>>> Installing $(NAME) into $(PREFIX)..."
+mess-uninstall:
+ @echo
+ @echo ">>>>>>>>>> Uninstalling $(NAME) from $(PREFIX)..."
-# Requires variable: NAME
+# Requires variables: NAME, PREFIX (for install and uninstall only)
-.PHONY: man
+.PHONY: man mrpropre mrproper install uninstall
-man: README*.md
- @echo Checking for possible manual pages...
- @if [ -e README.md ]; then \
- echo Sources found for man pages; \
- if pandoc -v >/dev/null 2>&1; then \
- ls README*.md 2>/dev/null \
- | grep 'README\(-..\|\)\.md' \
- | while read man; do \
- echo " Processing page $$lang..."; \
- lang="`echo "$$man" \
- | sed 's:README\.md:en:' \
- | sed 's:README-\(.*\)\.md:\1:'`"; \
- mkdir -p man/"$$lang"/man1; \
+man: VERSION README.md README*.md
+ @if pandoc -v >/dev/null 2>&1; then \
+ ls README*.md 2>/dev/null \
+ | grep 'README\(-..\|\)\.md' \
+ | while read man; do \
+ lang="`echo "$$man" \
+ | sed 's:README\.md:en:' \
+ | sed 's:README-\(.*\)\.md:\1:'`"; \
+ echo "Processing language: $$lang..."; \
+ echo mkdir -p man/"$$lang"/man1; \
+ mkdir -p man/"$$lang"/man1; \
+ echo "pandoc [...] > man/$$lang"/man1/"${NAME}.1"; \
+ ( \
+ echo ".TH \"${NAME}\" 1 `\
+ date +%Y-%m-%d\
+ ` \"version `cat VERSION`\""; \
+ echo; \
+ UNAME="`echo "${NAME}" \
+ | sed 's:\(.*\):\U\1:g'`"; \
( \
- echo ".TH \"${NAME}\" 1 `\
- date +%Y-%m-%d\
- ` \"version `cat VERSION`\""; \
- echo; \
- UNAME="`echo "${NAME}" \
- | sed 's:\(.*\):\U\1:g'`"; \
- ( \
- cat "$$man" | head -n1 \
- | sed 's:.*(README\(-fr\|\)\.md).*::g'; \
- cat "$$man" | tail -n+2; \
- ) | sed 's:^#\(#.*\):\1:g' \
+ cat "$$man" | head -n1 \
+ | sed 's:.*(README\(-..\|\)\.md).*::g'; \
+ cat "$$man" | tail -n+2; \
+ ) | sed 's:^#\(#.*\):\1:g' \
| sed 's:^\(#.*\):\U\1:g;s:# *'"$$UNAME"':# NAME\n'"${NAME}"' \\- :g' \
| sed 's:--:——:g' \
| pandoc -f markdown -t man | sed 's:——:--:g' ; \
- ) > man/"$$lang"/man1/"${NAME}.1"; \
- done; \
- mkdir -p "man/man1"; \
- cp man/en/man1/"${NAME}".1 man/man1/; \
- else \
- echo "man pages generation: pandoc required" >&2; \
- false; \
- fi; \
- fi;
+ ) > man/"$$lang"/man1/"${NAME}.1"; \
+ done; \
+ echo mkdir -p "man/man1"; \
+ mkdir -p "man/man1"; \
+ echo cp man/en/man1/"${NAME}".1 man/man1/; \
+ cp man/en/man1/"${NAME}".1 man/man1/; \
+ else \
+ echo "man pages generation: pandoc required" >&2; \
+ false; \
+ fi; \
+mrproper: mrpropre
+mrpropre:
+ rm -f man/man1/*.1 man/*/man1/*.1
+ rmdir man/*/man1 man/* man 2>/dev/null || true
+
+install:
+ @if [ -e "man/man1/$(NAME).1" ]; then \
+ echo mkdir -p "$(PREFIX)"/share/man; \
+ mkdir -p "$(PREFIX)"/share/man; \
+ echo cp -r man "$(PREFIX)"/share/; \
+ cp -r man "$(PREFIX)"/share/; \
+ else \
+ echo "No manual has been built (see \`make man')"; \
+ fi
+
+uninstall:
+ @if [ -e "man/man1/$(NAME).1" ]; then \
+ find man/ -type f | while read -r page; do \
+ echo rm "$(PREFIX)/share/$$page";\
+ rm "$(PREFIX)/share/$$page";\
+ done; \
+ echo rmdir "$(PREFIX)/share/man" 2>/dev/null \|\| true; \
+ rmdir "$(PREFIX)/share/man" 2>/dev/null || true; \
+ rmdir "$(PREFIX)/share" 2>/dev/null || true; \
+ else \
+ echo "No manual has been built (see \`make man')"; \
+ fi
--- /dev/null
+Subproject commit 9e29e2f55d36a2e05a3420825b8ecc33006a45eb
+++ /dev/null
-# Note: 99+ required for for-loop initial declaration (CentOS 6)
-
-CFLAGS += -Wall -pedantic -I./ -std=c99
-CXXFLAGS += -Wall -pedantic -I./
-PREFIX = /usr/local
-
-ifdef DEBUG
-CFLAGS += -ggdb -O0
-CXXFLAGS += -ggdb -O0
-endif
-
-.PHONY: all install uninstall clean mrpropre mrpropre
-
-all: ../bin/nsub
-
-SOURCES=$(wildcard nsub/*.c)
-HEADERS=$(wildcard nsub/*.h)
-
-## Correct, but longer:
-
-## OBJECTS=$(SOURCES:%.c=%.o)
-##
-## nsub/nsub.o: nsub/nsub.c
-##
-## $(OBJECTS): nsub/nsub.h
-##
-## # easier, but more recompiles:
-## $(OBJECTS): $(HEADERS)
-##
-##../bin/nsub: $(OBJECTS) ../bin/libutils.o
-## $(CC) $(CFLAGS) $^ -o $@
-
-## Quicker:
-../bin/nsub: $(SOURCES) $(HEADERS)
- # In two steps, so it works with clang, too
- $(CC) $(CFLAGS) $^ -c && mv *.o nsub/
- $(CC) nsub/*.o ../bin/libutils.o -o $@ && rm -f nsub/*.o nsub/*.h.gch
-
-clean:
- rm -f nsub/*.o
-
-mrproper: mrpropre
-
-mrpropre: clean
- rm -f ../bin/nsub
- rmdir ../bin || true
-
-install:
- @echo "installing nsub to $(PREFIX)..."
- mkdir -p "$(PREFIX)/bin" \
- && cp ../bin/nsub "$(PREFIX)/bin/"
-
-uninstall:
- @echo "uninstalling nsub from $(PREFIX)..."
- rm -f "$(PREFIX)/bin/nsub" \
- && rmdir "$(PREFIX)/bin" 2>/dev/null || true \
- && rmdir "$(PREFIX)" 2>/dev/null || true
-
--- /dev/null
+# Simply pass everything to makefile.d, but calling from "../"
+
+.PHONY: all build install uninstall clean mrpropre mrpropre \
+ run test run-test run-test-more default \
+ nsub
+
+default $(MAKECMDGOALS):
+ @$(MAKE) --no-print-directory -C ../ -f $(CURDIR)/makefile.d \
+ $(MAKECMDGOALS)
+
--- /dev/null
+# Note: 99+ required for for-loop initial declaration (CentOS 6)
+# Note: gnu99 (instead of c99) required for libcutils-net
+
+NAME = nsub
+NAMES = $(NAME)
+srcdir = $(NAME)
+dstdir = ../bin
+
+CFLAGS += -Wall -pedantic -I./ -std=gnu99
+CXXFLAGS += -Wall -pedantic -I./
+# LDFLAGS += -lcheck
+PREFIX = /usr/local
+
+ifdef DEBUG
+CFLAGS += -ggdb -O0
+CXXFLAGS += -ggdb -O0
+endif
+
+.PHONY: all build install uninstall clean mrpropre mrpropre \
+ $(NAMES)
+
+SOURCES=$(wildcard $(srcdir)/*.c)
+HEADERS=$(wildcard $(srcdir)/*.h)
+OBJECTS=$(SOURCES:%.c=%.o)
+
+# Main targets
+
+all: build
+
+build: $(NAMES)
+
+nsub: $(dstdir)/nsub
+
+run:
+ $(dstdir)/nsub --help
+
+################
+# Dependencies #
+################
+OBJECTS+=$(dstdir)/libcutils.o
+$(dstdir)/libcutils.o:
+ $(MAKE) --no-print-directory -C cutils/ cutils
+################
+
+$(dstdir)/nsub: $(OBJECTS)
+ mkdir -p $(dstdir)
+ $(CC) $(OBJECTS) -o $@
+
+debug:
+ $(MAKE) -f $(srcdir)/makefile.d DEBUG=1
+
+clean:
+ rm -f $(srcdir)/*.o
+
+mrproper: mrpropre
+
+mrpropre: clean
+ rm -f $(dstdir)/nsub
+ rmdir $(dstdir) 2>/dev/null || true
+
+install:
+ mkdir -p "$(PREFIX)/bin"
+ cp $(dstdir)/nsub "$(PREFIX)/bin/"
+
+uninstall:
+ rm "$(PREFIX)/bin/nsub"
+ rmdir "$(PREFIX)/bin" 2>/dev/null
+
#include <string.h>
#include "nsub.h"
-#include "utils/utils.h"
+#include "cutils/cutils.h"
/* Public */
/**
* @file nsub.h
* @author Niki
- * @date 2022
+ * @date 2024
*
* @brief Subtitle/Lyrics conversion program (webvtt/srt/lrc)
*
*
* @note all timings are in milliseconds.
*/
-#include "utils/array.h"
+#include "cutils/array.h"
/**
* A subtitle or lyric format to import from/export to.
#include <string.h>
#include "nsub.h"
-#include "utils/utils.h"
+#include "cutils/cutils.h"
/* Declarations */
#include <string.h>
#include "nsub.h"
-#include "utils/utils.h"
+#include "cutils/cutils.h"
/* Declarations */
#include <string.h>
#include "nsub.h"
-#include "utils/utils.h"
+#include "cutils/cutils.h"
/* Declarations */
#include <stdio.h>
#include "nsub.h"
-#include "utils/utils.h"
+#include "cutils/cutils.h"
/* Declarations */
#include <stdio.h>
#include "nsub.h"
-#include "utils/utils.h"
+#include "cutils/cutils.h"
/* Declarations */
+++ /dev/null
-# Note: 99+ required for for-loop initial declaration (CentOS 6)
-
-CFLAGS += -Wall -pedantic -I./ -I ../ -std=c99
-CXXFLAGS += -Wall -pedantic -I./ -I ../
-
-ifdef DEBUG
-CFLAGS += -ggdb -O0
-CXXFLAGS += -ggdb -O0
-endif
-
-.PHONY: all clean mrpropre mrpropre test tests run run-more
-
-all: test
-
-tests: test
-
-test: tests/launcher.o
- $(MAKE) -C tests/ -f utils.d
-
-clean:
- $(MAKE) -C tests/ -f utils.d clean
- rm -f tests/launcher.o
-
-mrproper: mrpropre
-
-mrpropre: clean
- $(MAKE) -C tests/ -f utils.d mrpropre
-
-run:
- $(MAKE) -C tests/ -f utils.d run
-
-run-more:
- $(MAKE) -C tests/ -f utils.d run-more
+++ /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 "launcher.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-
-// Shared globals
-int launcher_color = -1;
-
-// Private functions
-static int has_colour();
-static char *waiting_color();
-static char *passed_color();
-static char *failed_color();
-static char *stop_color();
-
-// Private vars
-// static char BLEU[] = { (char) 27, '[', '3', '4', 'm', '\0' };
-// static char TEAL[] = { (char) 27, '[', '3', '6', 'm', '\0' };
-// static char GRIS[] = { (char) 27, '[', '3', '7', 'm', '\0' };
-static char VERT[] = { (char) 27, '[', '3', '2', 'm', '\0' };
-static char ROUGE[] = { (char) 27, '[', '3', '1', 'm', '\0' };
-static char ORANGE[] = { (char) 27, '[', '3', '3', 'm', '\0' };
-static char STOP[] = { (char) 27, '[', '0', 'm', '\0' };
-static char bs9[] = { 8, 8, 8, 8, 8, 8, 8, 8, 8, '\0' };
-
-// COLORTERM : if it exists and is not empty, the system will default to
-// colour mode (--color) as opposed to --no-color
-
-// CK_ENV : Gets the print mode from the environment variable CK_VERBOSITY,
-// which can have the values "silent", "minimal", "normal", "verbose". If the
-// variable is not found or the value is not recognised, the print mode is set
-// to CK_NORMAL.
-
-// How to start the program:
-// ========================
-//
-// $0
-// test the code (normal tests only)
-// $0 --more
-// run extra tests (if available; usually, they are specified as extra if they
-// take long to process)
-//
-//
-// $0 --name NAME
-// do not test, just format the name as if it was tested
-// $0 --passed
-// format the line as if it was passes
-// $0 --failed
-// format the line as if it was failed
-
-char *tests_name = NULL;
-
-void test_init(const char name[]) {
- int i;
- int cols;
- struct winsize ws;
-
- ioctl(1, TIOCGWINSZ, &ws);
- cols = ws.ws_col;
-
- if (!tests_name) {
- tests_name = malloc(sizeof(char) * (cols + 1));
- }
-
- for (i = 0; i < (cols + 1); i++) {
- if (i < 4)
- tests_name[i] = ' ';
- else
- tests_name[i] = '.';
- }
-
- strcpy(tests_name + 4, name);
- tests_name[strlen(name) + 4] = ' ';
- tests_name[cols - 6 - 1 - 4] = '\0';
-
- fprintf(stderr, "%s", tests_name);
- fprintf(stderr, "%s[%s%s%s] ", " ", waiting_color(), " ?? ",
- stop_color());
-}
-
-void test_success() {
- fprintf(stderr, "%s[%s%s%s] ", bs9, passed_color(), " OK ",
- stop_color());
-}
-
-void test_failure() {
- fprintf(stderr, "%s[%s%s%s] ", bs9, failed_color(), "FAIL",
- stop_color());
-}
-
-int test_start(int more) {
- int failed;
- SRunner *runner;
-
- runner = get_tests(more);
-
- failed = 0;
- if (runner) {
- srunner_run_all(runner, CK_ENV);
-
- failed = srunner_ntests_failed(runner);
- srunner_free(runner);
- } else {
- printf(">>> No tests have been found <<<\n");
- }
-
- return failed;
-}
-
-int main(int argc, char **argv) {
- int more = 0;
- int cont = 1;
-
- for (int i = 1; i < argc; i++) {
- if (!strcmp("--name", argv[i])) {
- if ((i + 1) >= argc)
- return 1;
- test_init(argv[++i]);
- cont = 0;
- } else if (!strcmp("--passed", argv[i])) {
- test_success();
- cont = 0;
- } else if (!strcmp("--failed", argv[i])) {
- test_failure();
- cont = 0;
- } else if (!strcmp("--more", argv[i])) {
- more = 1;
- } else if (!strcmp("--color", argv[i])) {
- launcher_color = 1;
- } else if (!strcmp("--no-color", argv[i])) {
- launcher_color = 0;
- }
- }
-
- if (!cont)
- return 0;
-
- return test_start(more);
-}
-
-static int has_colour() {
- if (launcher_color == -1) {
- // TODO: could we do better?
- const char *cterm = getenv("COLORTERM");
- if (cterm && cterm[0])
- launcher_color = 1;
- else
- launcher_color = 0;
- }
-
- return launcher_color;
-}
-
-static char *waiting_color() {
- if (has_colour())
- return ORANGE;
- return "";
-}
-
-static char *passed_color() {
- if (has_colour())
- return VERT;
- return "";
-}
-
-static char *failed_color() {
- if (has_colour())
- return ROUGE;
- return "";
-}
-
-static char *stop_color() {
- if (has_colour())
- return STOP;
- return "";
-}
+++ /dev/null
-#ifndef _LAUNCHER_H
-#define _LAUNCHER_H
-
-#include <check.h>
-
-#define START(name) \
-START_TEST(name) {\
- test_init(#name);\
-
-#define END \
- test_success();\
-}\
-END_TEST\
-
-#define FAIL(...) \
-ck_abort_msg(__VA_ARGS__)\
-
-#define ASSERT_EQUALS_STR(title, 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) \
- 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) \
- do { if (expected != received) { \
-ck_abort_msg("%s\n\tExpected: %zu\n\tReceived: %zu", title, expected, received); \
-}} while(0)
-
-extern int launcher_color;
-
-SRunner *get_tests(int more);
-
-void test_init(const char name[]);
-
-int test_start(int more);
-
-void test_success();
-
-void test_failure();
-
-#endif
-
+++ /dev/null
-# Note: 99+ required for for-loop initial declaration (CentOS 6)
-
-CFLAGS += -Wall -pedantic -I./ -I ../ -std=c99
-CXXFLAGS += -Wall -pedantic -I./ -I ../
-LDFLAGS += -lcheck
-ifdef DEBIAN
-LDFLAGS += -lsubunit -lm -lpthread -lrt
-endif
-
-ifdef DEBUG
-CFLAGS += -ggdb -O0
-CXXFLAGS += -ggdb -O0
-endif
-
-.PHONY: all clean mrpropre mrpropre test tests run run-more
-
-SOURCES=$(wildcard utils/*.c)
-OBJECTS=$(SOURCES:%.c=%.o)
-
-all: test
-
-tests: test
-
-test: launcher.o ../../bin/libutils.o $(OBJECTS)
- mkdir -p bin
- $(CC) $(CFLAGS) $^ -o bin/utils $(LDFLAGS)
-
-run:
- bin/utils
-
-run-more:
- bin/utils --more
-
-clean:
- rm -f utils/*.o
-
-mrproper: mrpropre
-
-mrpropre: clean
- rm -f bin/utils
- rmdir bin || true
+++ /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/array.h"
-
-#include <check.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "launcher.h"
-
-static array_t *a;
-
-static void setup() {
- a = new_array(sizeof(char), 80);
-}
-
-static void teardown() {
- free_array(a);
- a = NULL;
-}
-
-static void reset() {
- teardown();
- setup();
-}
-
-START(init)
- if (!a)
- FAIL("new_array returned NULL");
-
- 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 %zu 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
-
-Suite *test_array(const char title[]) {
- Suite *suite = suite_create(title);
-
- TCase *core = tcase_create("core");
- tcase_add_checked_fixture(core, setup, teardown);
- tcase_add_test(core, init);
- tcase_add_test(core, 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);
-
- suite_add_tcase(suite, core);
-
- return suite;
-}
-
-Suite *test_array_more(const char title[]) {
- Suite *suite = suite_create(title);
-
- TCase *tmore = tcase_create("more");
- tcase_add_checked_fixture(tmore, setup, teardown);
- // TODO
-
- suite_add_tcase(suite, tmore);
-
- return suite;
-}
+++ /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=";
-
-static char decoded_utf8[] = "Le café d'Abigaëlle";
-static char encoded_utf8[] = "TGUgY2Fmw6kgZCdBYmlnYcOrbGxl";
-
-START(decode)
- char *tmp = base64_decode(encoded);
- ASSERT_EQUALS_STR("decoding", decoded, tmp);
- free(tmp);
- END
-
-START(encode)
- char *tmp = base64_encode(decoded);
- ASSERT_EQUALS_STR("encoding", encoded, tmp);
- free(tmp);
- END
-
-START(utf8)
- char *tmp;
-
- tmp = base64_decode(encoded_utf8);
- ASSERT_EQUALS_STR("UTF-8 decoding", decoded_utf8, tmp);
- free(tmp);
-
- tmp = base64_encode(decoded_utf8);
- ASSERT_EQUALS_STR("UTF-8 encoding", encoded_utf8, tmp);
- free(tmp);
-
- END
-
-START(both_ways)
- char *enc = base64_encode(decoded);
- char *dec = base64_decode(enc);
- ASSERT_EQUALS_STR("both ways DEC", decoded, dec);
- ASSERT_EQUALS_STR("both ways ENC", encoded, enc);
- free(dec);
- free(enc);
- 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);
- tcase_add_test(core, utf8);
-
- 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;
-}
+++ /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 <stdlib.h>
-
-#include "launcher.h"
-#include "utils/cstring.h"
-
-#define TEST_FILE_READLINE "utils/test_readline.txt"
-
-cstring_t *s;
-
-static void setup() {
- s = new_cstring();
-}
-
-static void teardown() {
- free_cstring(s);
- s = NULL;
-}
-
-static void reset() {
- teardown();
- setup();
-}
-
-START(init)
- if (!s)
- FAIL("new_cstring returned NULL");
-
- if (s->length)
- FAIL("empty cstring has a size of %zu", s->length);
-
- END
-
-START(add_car)
- cstring_add_car(s, 'T');
- ASSERT_EQUALS_STR("Cannot add a single char", "T", s->string);
-
- cstring_add_car(s, 'e');
- cstring_add_car(s, 's');
- cstring_add_car(s, 't');
- cstring_add_car(s, 'y');
- ASSERT_EQUALS_STR("Cannot add multiple chars", "Testy", s->string);
-
- END
-
-START(add_all_but_p)
- char *str;
-
- str = "testy";
- cstring_add(s, str);
- ASSERT_EQUALS_STR("Short string", str, s->string);
- reset();
-
- str = "Fanfan entre dans un bar";
- cstring_add(s, str);
- ASSERT_EQUALS_STR("Medium string", str, s->string);
- reset();
-
- str = "Ligne 1\nLigne 2\nLigne 3, attention 4 = vide\n";
- cstring_add(s, str);
- ASSERT_EQUALS_STR("Multi-line", str, s->string);
- reset();
-
- str = "Les accents en français sont bien là et se "
- "retrouvent avec une fréquence élevée";
- cstring_add(s, str);
- ASSERT_EQUALS_STR("accents", str, s->string);
- reset();
-
- str = "cents: ¢, copyright: ©, arrows: →↓↑←";
- cstring_add(s, str);
- ASSERT_EQUALS_STR("UTF-8", str, s->string);
- reset();
-
- str = "Os iusti meditabitur sapientiam,\n"
- "Et lingua\n"
- "eius loquetur\n"
- "indicium.\n"
- "\n"
- "Beatus\n"
- "vir qui\n"
- "suffert tentationem, Quoniqm\n"
- "cum probates\n"
- "fuerit accipient\n"
- "coronam vitae\n"
- "\n"
- "Kyrie, fons bonitatis.\n"
- "Kyrie, ignis divine, eleison.\n"
- "\n"
- "O quam sancta, quam serena,\n"
- "Quam benigma, quam amoena esse Virgo creditur.\n"
- "O quam sancta, quam serena,\n"
- "Quam benigma, quam amoena,\n"
- "O castitatis lilium.\n"
- "\n"
- "Kyrie, fons bonitatis.\n"
- "Kyrie, ignis divine, eleison.\n"
- "\n"
- "O quam sancta, quam serena,\n"
- "Quam benigma, quam amoena,\n"
- "O castitatis lilium.\n";
- cstring_add(s, str);
- ASSERT_EQUALS_STR("Long, multi-line string", str, s->string);
- reset();
-
- str = "String 1, String 2";
- cstring_add(s, "String 1, ");
- cstring_add(s, "String 2");
- ASSERT_EQUALS_STR("Concat with add", str, s->string);
- reset();
-
- str = "0123456789";
- cstring_addf(s, str, 4);
- ASSERT_EQUALS_STR("addf error (start at 4)", "456789", s->string);
- reset();
-
- str = "0123456789";
- cstring_addf(s, str, 4);
- cstring_addf(s, str, 8);
- str = "45678989";
- ASSERT_EQUALS_STR("Concat with addf", str, s->string);
- reset();
-
- str = "0123456789";
- cstring_addn(s, str, 4);
- ASSERT_EQUALS_STR("addn error (4)", "0123", s->string);
- reset();
-
- str = "0123456789";
- cstring_addn(s, str, 4);
- cstring_addn(s, str, 2);
- str = "012301";
- ASSERT_EQUALS_STR("Concat with addn", str, s->string);
- reset();
-
- str = "0123456789";
- cstring_addfn(s, str, 4, 3);
- ASSERT_EQUALS_STR("addf error (4, 3)", "456", s->string);
- reset();
-
- str = "0123456789";
- cstring_addfn(s, str, 4, 3);
- cstring_addfn(s, str, 2, 2);
- str = "45623";
- ASSERT_EQUALS_STR("Concat with addfn", str, s->string);
- reset();
-
- END
-
-START(addp)
- char *str;
-
- cstring_addp(s, "%d", 42);
- ASSERT_EQUALS_STR("Simple int", "42", s->string);
- reset();
-
- cstring_addp(s, "%02d", 1);
- ASSERT_EQUALS_STR("Leading zero int", "01", s->string);
- reset();
-
- cstring_addp(s, "%d", 352646);
- ASSERT_EQUALS_STR("Large int", "352646", s->string);
- reset();
-
- str = "Simple test string";
- cstring_addp(s, "%s", str);
- ASSERT_EQUALS_STR("Simple string", str, s->string);
- reset();
-
- str = "String 1, String 2";
- cstring_addp(s, "%s", "String 1, ");
- cstring_addp(s, "%s", "String 2");
- ASSERT_EQUALS_STR("Cumulative strings", str, s->string);
- reset();
-
- END
-
-START(cut_at)
- cstring_add(s, "0123456789");
- cstring_cut_at(s, 4);
- ASSERT_EQUALS_STR("cut at failed", "0123", s->string);
-
- END
-
-START(substring)
- free_cstring(s);
- s = cstring_substring("0123456789", 4, 2);
- ASSERT_EQUALS_STR("substring failed 4,2", "45", s->string);
-
- free_cstring(s);
- s = cstring_substring("0123456789", 0, 4);
- ASSERT_EQUALS_STR("substring failed 0,4", "0123", s->string);
-
- free_cstring(s);
- s = cstring_substring("0123456789", 3, 0);
- ASSERT_EQUALS_STR("substring failed 3,0", "3456789", s->string);
-
- free_cstring(s);
- s = cstring_substring("0123456789", 0, 0);
- ASSERT_EQUALS_STR("substring failed 0,0", "0123456789", s->string);
-
- END
-
-START(reverse)
- cstring_add(s, "kayak");
- cstring_reverse(s->string);
- ASSERT_EQUALS_STR("reversing a palyndrome failed", "kayak", s->string);
- reset();
-
- cstring_add(s, "plantigrade");
- cstring_reverse(s->string);
- ASSERT_EQUALS_STR("reverse failed", "edargitnalp", s->string);
- reset();
-
- cstring_add(s, "123");
- cstring_reverse(s->string);
- ASSERT_EQUALS_STR("reverse failed", "321", s->string);
- reset();
-
- cstring_add(s, "1234");
- cstring_reverse(s->string);
- ASSERT_EQUALS_STR("reverse failed", "4321", s->string);
- reset();
-
- END
-
-START(replace)
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(a) Bad number of replacements returned", 0,
- cstring_replace(s, "", ""));
- ASSERT_EQUALS_STR("Replacement failed", "test string AC/DC", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(b) Bad number of replacements returned", 1,
- cstring_replace(s, "AC/DC", "AC/DC"));
- ASSERT_EQUALS_STR("Replacement failed", "test string AC/DC", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(c) Bad number of replacements returned", 1,
- cstring_replace(s, "AC/DC", "woof"));
- ASSERT_EQUALS_STR("Replacement failed", "test string woof", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(d) Bad number of replacements returned", 2,
- cstring_replace(s, "C", "*"));
- ASSERT_EQUALS_STR("Replacement failed", "test string A*/D*", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(e) Bad number of replacements returned", 1,
- cstring_replace(s, "test ", ""));
- ASSERT_EQUALS_STR("Replacement failed", "string AC/DC", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(f) Bad number of replacements returned", 1,
- cstring_replace(s, "test ", "longer test "));
- ASSERT_EQUALS_STR("Replacement failed", "longer test string AC/DC",
- s->string);
-
- END
-
-START(replace_car)
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(a) Bad number of replacements returned", 0,
- cstring_replace_car(s->string, '?', '!'));
- ASSERT_EQUALS_STR("Replacement failed", "test string AC/DC", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(b) Bad number of replacements returned", 1,
- cstring_replace_car(s->string, '/', '/'));
- ASSERT_EQUALS_STR("Replacement failed", "test string AC/DC", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(c) Bad number of replacements returned", 1,
- cstring_replace_car(s->string, 'A', 'a'));
- ASSERT_EQUALS_STR("Replacement failed", "test string aC/DC", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(d) Bad number of replacements returned", 2,
- cstring_replace_car(s->string, 'C', '*'));
- ASSERT_EQUALS_STR("Replacement failed", "test string A*/D*", s->string);
-
- reset();
- cstring_add(s, "test string AC/DC");
- ASSERT_EQUALS_INT("(e) Bad number of replacements returned", 1,
- cstring_replace_car(s->string, '/', '\0'));
- ASSERT_EQUALS_STR("Replacement failed", "test string AC", s->string);
-
- END
-
-START(starts_with)
- char *start;
-
- cstring_add(s, "fichier.ext");
-
- start = "fichier";
- if (!cstring_starts_with(s->string, start, 0))
- FAIL("fichier.ext does not start with %s", start);
-
- start = "ichier";
- if (cstring_starts_with(s->string, start, 0))
- FAIL("fichier.ext starts with %s", start);
-
- start = "afichier";
- if (cstring_starts_with(s->string, start, 0))
- FAIL("fichier.ext starts with %s", start);
-
- start = "";
- if (!cstring_starts_with(s->string, start, 0))
- FAIL("fichier.ext does not start with nothing");
-
- start = "chier";
- if (!cstring_starts_with(s->string, start, 2))
- FAIL("fichier.ext +2 does not start with %s", start);
-
- END
-
-START(ends_with)
- char *end;
-
- cstring_add(s, "fichier.ext");
-
- end = ".ext";
- if (!cstring_ends_with(s->string, end))
- FAIL("fichier.ext does not end in %s", end);
-
- end = ".ex";
- if (cstring_ends_with(s->string, end))
- FAIL("fichier.ext ends in %s", end);
-
- end = "aext";
- if (cstring_ends_with(s->string, end))
- FAIL("fichier.ext does not end in %s", end);
-
- end = "";
- if (!cstring_ends_with(s->string, end))
- FAIL("fichier.ext does not end with nothing");
-
- END
-
-START(find)
- char *str = "Une petite string pour y chercher des choses";
-
- ASSERT_EQUALS_INT("(a) find error", 0, cstring_find(str, "Une", 0));
- ASSERT_EQUALS_INT("(b) find error", -1, cstring_find(str, "Une", 1));
- ASSERT_EQUALS_INT("(c) find error", 4, cstring_find(str, "petite", 0));
- ASSERT_EQUALS_INT("(d) find error", 4, cstring_find(str, "petite", 1));
- ASSERT_EQUALS_INT("(e) find error", 4, cstring_find(str, "petite", 2));
- ASSERT_EQUALS_INT("(f) find error", 4, cstring_find(str, "petite", 3));
- ASSERT_EQUALS_INT("(g) find error", 4, cstring_find(str, "petite", 4));
- ASSERT_EQUALS_INT("(h) find error", -1, cstring_find(str, "petite", 5));
- ASSERT_EQUALS_INT("(i) find error", 38, cstring_find(str, "choses", 0));
- ASSERT_EQUALS_INT("(j) find error", -1, cstring_find(str, "Oops", 0));
- ASSERT_EQUALS_INT("(k) find error", 2, cstring_find(str, "e", 0));
- ASSERT_EQUALS_INT("(l) find error", 2, cstring_find(str, "e", 1));
- ASSERT_EQUALS_INT("(m) find error", 2, cstring_find(str, "e", 2));
- ASSERT_EQUALS_INT("(n) find error", 5, cstring_find(str, "e", 3));
- ASSERT_EQUALS_INT("(o) find error", 9, cstring_find(str, "e", 6));
-
- END
-
-START(rfind)
- char *str = "Une petite string pour y chercher des choses";
-
- ASSERT_EQUALS_INT("(a) find error", 0, cstring_rfind(str, "Une", 0));
- ASSERT_EQUALS_INT("(b) find error", 0, cstring_rfind(str, "Une", 1));
- ASSERT_EQUALS_INT("(c) find error", 4, cstring_rfind(str, "petite", 0));
- ASSERT_EQUALS_INT("(d) find error", 4,
- cstring_rfind(str, "petite", 11));
- ASSERT_EQUALS_INT("(e) find error", -1,
- cstring_rfind(str, "petite", 2));
- ASSERT_EQUALS_INT("(f) find error", 38,
- cstring_rfind(str, "choses", 0));
- ASSERT_EQUALS_INT("(g) find error", -1, cstring_rfind(str, "Oops", 0));
- ASSERT_EQUALS_INT("(h) find error", 42, cstring_rfind(str, "e", 0));
- ASSERT_EQUALS_INT("(i) find error", 42, cstring_rfind(str, "e", -1));
- ASSERT_EQUALS_INT("(j) find error", 35, cstring_rfind(str, "e", -2));
- ASSERT_EQUALS_INT("(k) find error", 35, cstring_rfind(str, "e", -3));
- ASSERT_EQUALS_INT("(l) find error", 35, cstring_rfind(str, "e", 38));
-
- END
-
-START(clear)
- if (!s)
- FAIL("new_cstring returned NULL");
-
- if (s->length)
- FAIL("empty cstring has a size of %zu", s->length);
-
- cstring_add(s, "testy");
- cstring_clear(s);
- if (s->length)
- FAIL("cleared cstring has a size of %zu", s->length);
-
- END
-
-START(convert)
- char *str;
-
- str = cstring_convert(s);
- s = NULL;
-
- ASSERT_EQUALS_STR("Convert failed with an empty string", "", str);
-
- reset();
-
- cstring_add(s, "testy");
- str = cstring_convert(s);
- s = NULL;
- ASSERT_EQUALS_STR("Convert did not return the same string", "testy",
- str);
-
- END
-
-START(clone)
- cstring_t *clone;
-
- clone = cstring_clone(NULL);
- if (clone)
- FAIL("Cloning NULL must return NULL");
-
- clone = cstring_clone("");
- ASSERT_EQUALS_STR("Cannot clone the empty string", "", clone->string);
- free_cstring(clone);
-
- cstring_add(s, "Testy viva la vida");
- clone = cstring_clone(s->string);
- ASSERT_EQUALS_STR("Failed to clone the string", s->string,
- clone->string);
- free_cstring(clone);
-
- END
-
-START(rtrim)
- char *expected;
-
- expected = "testy";
- cstring_add(s, expected);
- cstring_add(s, " ");
-
- cstring_rtrim(s, ' ');
- ASSERT_EQUALS_STR("(a) Failed to rtrim", expected, s->string);
-
- reset();
-
- expected = " testy";
- cstring_add(s, expected);
- cstring_add(s, " ");
-
- cstring_rtrim(s, ' ');
- ASSERT_EQUALS_STR("(b) Failed to rtrim", expected, s->string);
-
- reset();
-
- expected = " testy ";
- cstring_add(s, expected);
- cstring_add(s, "...");
-
- cstring_rtrim(s, '.');
- ASSERT_EQUALS_STR("(c) Failed to rtrim", expected, s->string);
-
- reset();
-
- expected = "...testy ";
- cstring_add(s, expected);
- cstring_add(s, "...");
-
- cstring_rtrim(s, '.');
- ASSERT_EQUALS_STR("(d) Failed to rtrim", expected, s->string);
-
- END
-
-START(trim)
- char *expected;
-
- expected = "testy";
- cstring_add(s, expected);
- cstring_add(s, " ");
-
- cstring_trim(s, ' ');
- ASSERT_EQUALS_STR("(a) Failed to trim", expected, s->string);
-
- reset();
-
- expected = "testy";
- cstring_add(s, " ");
- cstring_add(s, expected);
- cstring_add(s, " ");
-
- cstring_trim(s, ' ');
- ASSERT_EQUALS_STR("(b) Failed to trim", expected, s->string);
-
- reset();
-
- expected = " testy ";
- cstring_add(s, expected);
- cstring_add(s, "...");
-
- cstring_trim(s, '.');
- ASSERT_EQUALS_STR("(c) Failed to trim", expected, s->string);
-
- reset();
-
- expected = " testy ";
- cstring_add(s, "...");
- cstring_add(s, expected);
- cstring_add(s, "...");
-
- cstring_trim(s, '.');
- ASSERT_EQUALS_STR("(d) Failed to trim", expected, s->string);
-
- END
-
-START(remove_crlf)
- char *str = "testy";
-
- cstring_add(s, str);
- s->length = cstring_remove_crlf(s->string);
- ASSERT_EQUALS_STR("no-op failed", str, s->string);
-
- reset();
- cstring_add(s, str);
- cstring_add(s, "\n");
- s->length = cstring_remove_crlf(s->string);
- ASSERT_EQUALS_STR("\\n failed", str, s->string);
-
- reset();
- cstring_add(s, str);
- cstring_add(s, "\r\n");
- s->length = cstring_remove_crlf(s->string);
- ASSERT_EQUALS_STR("\\r\\n failed", str, s->string);
-
- reset();
- cstring_add(s, str);
- cstring_add(s, "\n\n");
- s->length = cstring_remove_crlf(s->string);
- ASSERT_EQUALS_STR("\\n\\n failed", "testy\n", s->string);
-
- reset();
- cstring_add(s, str);
- cstring_add(s, "\r\n\r\n");
- s->length = cstring_remove_crlf(s->string);
- ASSERT_EQUALS_STR("\\r\\n\\r\\n failed", "testy\r\n", s->string);
-
- reset();
- cstring_add(s, "\n");
- s->length = cstring_remove_crlf(s->string);
- ASSERT_EQUALS_STR("\\n uniq failed", "", s->string);
-
- END
-
-START(toupper)
- cstring_add(s, "");
- cstring_toupper(s);
- ASSERT_EQUALS_STR("Failed to uppercase empty", "", s->string);
-
- reset();
-
- cstring_add(s, "Simple Testy");
- cstring_toupper(s);
- ASSERT_EQUALS_STR("Failed to uppercase", "SIMPLE TESTY", s->string);
-
- reset();
-
- cstring_add(s, "C'est l'été");
- cstring_toupper(s);
- ASSERT_EQUALS_STR("Failed to uppercase", "C'EST L'ÉTÉ", s->string);
-
- reset();
-
- cstring_add(s, "Test en français");
- cstring_toupper(s);
- ASSERT_EQUALS_STR("Failed to uppercase", "TEST EN FRANÇAIS", s->string);
-
- END
-
-START(tolower)
- cstring_add(s, "");
- cstring_tolower(s);
- ASSERT_EQUALS_STR("Failed to lowercase empty", "", s->string);
-
- reset();
-
- cstring_add(s, "Simple Testy");
- cstring_tolower(s);
- ASSERT_EQUALS_STR("Failed to lowercase", "simple testy", s->string);
-
- reset();
-
- cstring_add(s, "Été ! C'est l'été !");
- cstring_tolower(s);
- ASSERT_EQUALS_STR("Failed to lowercase", "été ! c'est l'été !",
- s->string);
-
- reset();
-
- cstring_add(s, "Test en français");
- cstring_tolower(s);
- ASSERT_EQUALS_STR("Failed to lowercase", "test en français", s->string);
-
- reset();
-
- cstring_add(s, "À la claire fontaine");
- cstring_tolower(s);
- ASSERT_EQUALS_STR("Failed to lowercase", "à la claire fontaine",
- s->string);
-
- END
-
-START(readline)
- int read;
- FILE *testin = fopen(TEST_FILE_READLINE, "r");
- if (!testin)
- FAIL("Test file not found: test_readln.txt");
-
- read = cstring_readline(s, testin);
- if (!read)
- FAIL("first line should not be last");
- ASSERT_EQUALS_STR("first line incorrect", "ligne 1", s->string);
- reset();
-
- read = cstring_readline(s, testin);
- if (!read)
- FAIL("second line should not be last");
- ASSERT_EQUALS_STR("second line incorrect", "", s->string);
- reset();
-
- read = cstring_readline(s, testin);
- if (!read)
- FAIL("third line should not be last");
- ASSERT_EQUALS_STR("third line incorrect", "ligne 3", s->string);
- reset();
-
- if (cstring_readline(s, testin)) {
- FAIL("fourth line should not exist");
- }
-
- END
-
-START(add_path)
- cstring_add_path(s, "root");
- ASSERT_EQUALS_STR("failed to create root path", "/root", s->string);
-
- cstring_add_path(s, "dir");
- ASSERT_EQUALS_STR("failed to add a dir", "/root/dir", s->string);
-
- cstring_add_path(s, "sub/");
- ASSERT_EQUALS_STR("extra / failed", "/root/dir/sub", s->string);
-
- END
-
-START(pop_path)
- cstring_add(s, "");
- ASSERT_EQUALS_INT("empty test failed", 0, cstring_pop_path(s, 1));
-
- reset();
- cstring_add(s, "root");
- ASSERT_EQUALS_INT("0 nbr test failed", 0, cstring_pop_path(s, 0));
- ASSERT_EQUALS_STR("0 test failed", "root", s->string);
-
- reset();
- cstring_add(s, "root/");
- ASSERT_EQUALS_INT("0² nbr test failed", 0, cstring_pop_path(s, 0));
- ASSERT_EQUALS_STR("0² test failed", "root", s->string);
-
- reset();
- cstring_add(s, "/");
- ASSERT_EQUALS_INT("root test nbr failed", 0, cstring_pop_path(s, 1));
- ASSERT_EQUALS_STR("root test failed", "/", s->string);
-
- reset();
- cstring_add(s, "/");
- ASSERT_EQUALS_INT("root² test nbr failed", 0, cstring_pop_path(s, 2));
- ASSERT_EQUALS_STR("root² test failed", "/", s->string);
-
- reset();
- cstring_add(s, "/root");
- ASSERT_EQUALS_INT("/root test nbr failed", 1, cstring_pop_path(s, 1));
- ASSERT_EQUALS_STR("/root test failed", "/", s->string);
-
- reset();
- cstring_add(s, "/root");
- ASSERT_EQUALS_INT("/root³ test nbr failed", 1, cstring_pop_path(s, 2));
- ASSERT_EQUALS_STR("/root³ test failed", "/", s->string);
-
- reset();
- cstring_add(s, "/root/dir/file");
- ASSERT_EQUALS_INT("2 test nbr failed", 2, cstring_pop_path(s, 2));
- ASSERT_EQUALS_STR("2 test failed", "/root", s->string);
-
- reset();
- cstring_add(s, "/root/dir/file/");
- ASSERT_EQUALS_INT("trailing / test nbr failed", 1,
- cstring_pop_path(s, 1));
- ASSERT_EQUALS_STR("trailing / test failed", "/root/dir", s->string);
-
- END
-
-START(basename)
- char *str;
-
- cstring_add(s, "");
- str = cstring_basename(s->string, NULL);
- ASSERT_EQUALS_STR("empty test", "", str);
- free(str);
-
- reset();
- cstring_add(s, "/root/path/dir/file");
- str = cstring_basename(s->string, NULL);
- ASSERT_EQUALS_STR("simple test", "file", str);
- free(str);
-
- reset();
- cstring_add(s, "/root/path/dir/file");
- str = cstring_basename(s->string, ".ext");
- ASSERT_EQUALS_STR("no ext test", "file", str);
- free(str);
-
- reset();
- cstring_add(s, "/root/path/dir/file.test");
- str = cstring_basename(s->string, ".ext");
- ASSERT_EQUALS_STR("wrong ext test", "file.test", str);
- free(str);
-
- reset();
- cstring_add(s, "/root/path/dir/file.ext");
- str = cstring_basename(s->string, ".ext");
- ASSERT_EQUALS_STR("good ext test", "file", str);
- free(str);
-
- END
-
-START(dirname)
- char *str;
-
- cstring_add(s, "/root/path");
- str = cstring_dirname(s->string);
- ASSERT_EQUALS_STR("simple test", "/root", str);
- free(str);
-
- reset();
- cstring_add(s, "/root/path/");
- str = cstring_dirname(s->string);
- ASSERT_EQUALS_STR("trailing / test", "/root", str);
- free(str);
-
- reset();
- cstring_add(s, "/");
- str = cstring_dirname(s->string);
- ASSERT_EQUALS_STR("root is root of root test", "/", str);
- free(str);
-
- END
-
-START(concat)
- char *cc;
-
- cc = cstring_concat(NULL);
- if (cc)
- FAIL("concat of NULL should return NULL, not: <%s>", cc);
-
- cc = cstring_concat("only", NULL);
- ASSERT_EQUALS_STR("Single parameter", "only", cc);
- free(cc);
-
- cc = cstring_concat("Only", "Fans", NULL);
- ASSERT_EQUALS_STR("Test 2 params", "OnlyFans", cc);
- free(cc);
-
- cc = cstring_concat("Fanfan", " ", "et", " Tulipe",
- " entrent dans un bar", NULL);
- ASSERT_EQUALS_STR("Test multiple params",
- "Fanfan et Tulipe entrent dans un bar", cc);
- free(cc);
-
- END
-
-START(many_adds)
- size_t count = 10 * 1000 * 1000;
- for (size_t i = 0; i < count; i++) {
- cstring_add(s, "1234567890");
- }
-
- ASSERT_EQUALS_SIZE("Lot of adds", count * 10, s->length);
-
- END
-
-Suite *test_cstring(const char title[]) {
- Suite *suite = suite_create(title);
-
- TCase *core = tcase_create("core");
- tcase_add_checked_fixture(core, setup, teardown);
- tcase_add_test(core, init);
- tcase_add_test(core, add_car);
- tcase_add_test(core, add_all_but_p);
- tcase_add_test(core, addp);
- tcase_add_test(core, cut_at);
- tcase_add_test(core, substring);
- tcase_add_test(core, reverse);
- tcase_add_test(core, replace);
- tcase_add_test(core, replace_car);
- tcase_add_test(core, starts_with);
- tcase_add_test(core, ends_with);
- tcase_add_test(core, find);
- tcase_add_test(core, rfind);
- tcase_add_test(core, clear);
- tcase_add_test(core, convert);
- tcase_add_test(core, clone);
- tcase_add_test(core, rtrim);
- tcase_add_test(core, trim);
- tcase_add_test(core, remove_crlf);
- tcase_add_test(core, toupper);
- tcase_add_test(core, tolower);
- tcase_add_test(core, readline);
- tcase_add_test(core, add_path);
- tcase_add_test(core, pop_path);
- tcase_add_test(core, basename);
- tcase_add_test(core, dirname);
- tcase_add_test(core, concat);
-
- suite_add_tcase(suite, core);
-
- return suite;
-}
-
-Suite *test_cstring_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, many_adds);
-
- suite_add_tcase(suite, tmore);
-
- return suite;
-}
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2022 Niki Roo
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "../../utils/desktop.h"
-
-#include <check.h>
-
-#include "../launcher.h"
-
-desktop_t *d;
-
-static void setup() {
- d = new_desktop("utils/test.desktop", 24);
-}
-
-static void teardown() {
- free_desktop(d);
-}
-
-START(init)
- if (!d)
- FAIL("new_desktop returned NULL");
-
- ASSERT_EQUALS_STR("Name", "IRC", d->name);
- ASSERT_EQUALS_STR("Icon", "irssi", d->icon);
- ASSERT_EQUALS_STR("Exec", "irssi", d->icon);
-
- END
-
- // TODO
-START(NO_TEST_YET_submenu)
- END
-START(NO_TEST_YET_icons)
- END
-START(NO_TEST_YET_find_icon)
- END
-START(NO_TEST_YET_find_id)
- END
-
-Suite *test_desktop(const char title[]) {
-
- d = new_desktop("test.desktop", 24);
- free_desktop(d);
-
- Suite *suite = suite_create(title);
-
- TCase *core = tcase_create("core");
- tcase_add_checked_fixture(core, setup, teardown);
- tcase_add_test(core, init);
- tcase_add_test(core, NO_TEST_YET_submenu);
- tcase_add_test(core, NO_TEST_YET_icons);
- tcase_add_test(core, NO_TEST_YET_find_icon);
- tcase_add_test(core, NO_TEST_YET_find_id);
-
- suite_add_tcase(suite, core);
-
- return suite;
-}
-
-Suite *test_desktop_more(const char title[]) {
- Suite *suite = suite_create(title);
-
- TCase *tmore = tcase_create("more");
- tcase_add_checked_fixture(tmore, setup, teardown);
- // TODO
-
- suite_add_tcase(suite, tmore);
-
- return suite;
-}
+++ /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 "main.h"
-#include "launcher.h"
-
-SRunner *runner = NULL;
-void add_test(Suite *test);
-
-SRunner *get_tests(int more) {
- add_test(test_cstring("cstring"));
- if (more)
- add_test(test_cstring_more("cstring -- more (longer)"));
-
- add_test(test_array("array"));
- 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)"));
-
- add_test(test_desktop("desktop"));
- if (more)
- add_test(test_desktop_more("desktop -- more (longer)"));
-
- return runner;
-}
-
-void add_test(Suite *test) {
- if (!runner) {
- runner = srunner_create(test);
- } else {
- srunner_add_suite(runner, test);
- }
-}
+++ /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/>.
- */
-
-#ifndef SRC_TESTS_UTILS_MAIN_H_
-#define SRC_TESTS_UTILS_MAIN_H_
-
-#include <check.h>
-
-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[]);
-Suite *test_desktop(const char title[]);
-Suite *test_desktop_more(const char title[]);
-
-#endif /* SRC_TESTS_UTILS_MAIN_H_ */
+++ /dev/null
-[Desktop Entry]
-Version=1.0
-Name=IRC
-Comment=Launch an IRC client
-Exec=irssi
-Icon=irssi
-Terminal=true
-Categories=Internet
-Type=Application
-StartupNotify=true
+++ /dev/null
-ligne 1
-
-ligne 3
+++ /dev/null
-# Note: 99+ required for for-loop initial declaration (CentOS 6)
-# Note: gnu required for net.c/net.h
-
-CFLAGS += -Wall -pedantic -I./ -std=gnu99
-CXXFLAGS += -Wall -pedantic -I./
-PREFIX = /usr/local
-
-ifdef DEBUG
-CFLAGS += -ggdb -O0
-CXXFLAGS += -ggdb -O0
-endif
-
-.PHONY: all install uninstall clean mrpropre mrpropre
-
-all: ../bin/libutils.o
-
-SOURCES=$(wildcard utils/*.c)
-HEADERS=$(wildcard utils/*.h)
-OBJECTS=$(SOURCES:%.c=%.o)
-
-utils/array.o: utils/array.[ch]
-utils/desktop.o: utils/desktop.[ch] utils/array.h
-
-# easier, but more recompiles:
-# $(OBJECTS): $(HEADERS)
-
-../bin/libutils.o: $(OBJECTS)
- mkdir -p ../bin
- # note: -r = --relocatable, but former also works with Clang
- $(LD) -r $(OBJECTS) -o $@
-
-clean:
- rm -f utils/*.o
-
-mrproper: mrpropre
-
-mrpropre: clean
- rm -f ../bin/libutils.o
- rmdir ../bin || true
-
-install:
- @echo "installing utils to $(PREFIX)..."
- mkdir -p "$(PREFIX)/lib/cutils/" \
- && cp ../bin/libutils.o "$(PREFIX)/lib/cutils/" \
- && mkdir -p "$(PREFIX)/include/cutils/utils/" \
- && cp utils/*.h "$(PREFIX)/include/cutils/utils/" \
-
-uninstall:
- @echo "uninstalling utils from $(PREFIX)..."
- rm -f "$(PREFIX)/lib/cutils/utils.o" \
- && rmdir "$(PREFIX)/lib/cutils/utils" 2>/dev/null || true \
- && rm -f "$(PREFIX)/include/cutils/utils/"*.h \
- && rmdir "$(PREFIX)/include/cutils/utils" 2>/dev/null || true \
- && rmdir "$(PREFIX)/lib/cutils" 2>/dev/null || true \
- && rmdir "$(PREFIX)/include/cutils" 2>/dev/null || true
-
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2020 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 <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "array.h"
-
-typedef struct {
- size_t elem_size;
- size_t buffer;
- void *data;
-} priv_t;
-
-/* make sure we have at least n+1 elements in the buffer, grow if needed */
-/* +1 is so we can always end with a NULL value for array_data/convert() */
-static int array_assure(array_t *me, size_t nb_elem);
-
-/* for qsort operations */
-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);
-
-array_t *new_array(size_t elem_size, size_t initial) {
- if (!initial)
- return NULL;
-
- array_t *me = malloc(sizeof(array_t));
- if (!init_array(me, elem_size, initial)) {
- free(me);
- me = NULL;
- }
-
- return me;
-}
-
-int init_array(array_t *me, size_t elem_size, size_t initial) {
- if (!initial)
- return 0;
-
- strcpy(me->CNAME, "[CArray ]");
-
- me->priv = malloc(sizeof(priv_t));
- if (!me->priv)
- return 0;
-
- priv_t *priv = (priv_t *) me->priv;
- strcpy(me->CNAME, "[CArray ]");
- priv->elem_size = elem_size;
- me->count = 0;
- priv->buffer = initial;
- priv->data = malloc(elem_size * initial);
- if (!priv->data) {
- free(me->priv);
- return 0;
- }
-
- return 1;
-}
-
-void free_array(array_t *me) {
- if (me)
- uninit_array(me);
-
- free(me);
-}
-
-void uninit_array(array_t *me) {
- priv_t *priv = (priv_t *) me->priv;
- me->count = 0;
- priv->buffer = 0;
- free(priv->data);
- priv->data = NULL;
- free(priv);
- me->priv = NULL;
- me->CNAME[0] = '!';
-}
-
-void array_clear(array_t *me) {
- me->count = 0;
-}
-
-// convert to void * data (free the rest)
-void *array_convert(array_t *me) {
- priv_t *priv = (priv_t *) me->priv;
- void *data = array_data(me);
- free(priv);
- free(me);
- return data;
-}
-
-void *array_data(array_t *me) {
- priv_t *priv = (priv_t *) me->priv;
-
- // Note: this should be impossible
- if (me->count >= priv->buffer)
- array_assure(me, me->count + 1);
-
- // cast to (char *) because we want 'byte' arithmetic
- void *after_end = (void *) (((char *) priv->data)
- + (me->count * priv->elem_size));
-
- // last item is always NULL
- memset(after_end, '\0', priv->elem_size);
-
- return priv->data;
-}
-
-size_t array_count(array_t *me) {
- return me->count;
-}
-
-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_first(array_t *me) {
- if (!me->count)
- return NULL;
-
- priv_t *priv = (priv_t *) me->priv;
- return priv->data;
-}
-
-void *array_last(array_t *me) {
- if (!me->count)
- return NULL;
-
- priv_t *priv = (priv_t *) me->priv;
- // cast to (char *) because we want 'byte' arithmetic
- return (void *) (((char *) priv->data) + ((me->count - 1) * priv->elem_size));
-}
-
-void *array_prev(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;
- if (cptr >= cdata) {
- return cptr;
- }
- }
-
- return NULL;
-}
-
-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_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_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_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);
-}
-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);
-}
-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_t *me, int rev) {
- array_qsort(me, rev ? array_qsorti_rfunc : array_qsorti_func);
-}
-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;
- return !(ia == ib);
-}
-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;
- return !(ia == ib);
-}
-
-void array_qsortl(array_t *me, int rev) {
- array_qsort(me, rev ? array_qsortl_rfunc : array_qsortl_func);
-}
-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;
- return !(la == lb);
-}
-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;
- return !(la == lb);
-}
-
-void array_qsortf(array_t *me, int rev) {
- array_qsort(me, rev ? array_qsortf_rfunc : array_qsortf_func);
-}
-static int array_qsortf_func(const void *a, const void *b) {
- float fa, fb;
- 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;
- return !(fa == fb);
-}
-static int array_qsortf_rfunc(const void *a, const void *b) {
- float fa, fb;
- 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;
- return !(fa == fb);
-}
-
-int array_push(array_t *me, void *data) {
- return array_setn(me, me->count, data, 1);
-}
-
-int array_pushn(array_t *me, void *data, size_t n) {
- return array_setn(me, me->count, data, n);
-}
-
-int array_copy(array_t *me, void *target, size_t i) {
- return array_copyn(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;
-
- 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_t *me, size_t i, void *data) {
- return array_setn(me, i, data, 1);
-}
-
-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 *) (priv->data)) + (i * priv->elem_size), data,
- n * priv->elem_size);
- if ((i + n) > me->count)
- me->count = i + n;
-
- return 1;
-}
-
-/* Privates functions */
-
-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;
- }
-
- void *tmp = realloc(priv->data, priv->elem_size * priv->buffer);
- if (!tmp)
- return 0;
-
- priv->data = tmp;
- }
-
- return 1;
-}
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2020 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/>.
- */
-
-/**
- * @file array.h
- * @author Niki
- * @date 2020 - 2022
- *
- * @brief A simple auto-growing array-list
- *
- * A simple auto-growing array-list, with a minimum buffer of 1.
- *
- * It has a link to `qsort`, too, so you don't need to retype all
- * the parameters you already passed to the array.
- *
- * It is created with `new_array()` and must be freed with :
- * - `free_array()` for normal operations
- * - `array_convert()` if you want to free the array but keep the data
- * (the data is now your responsibility to free or not, it was allocated
- * with `malloc`/`realloc`)
- *
- * Example usage:
- * ```C
- * array lines = new_array(sizeof(char *), 100);
- *
- * const char *l1 = "2. À l'arrière";
- * const char *l2 = "3. En réserve";
- * const char *l3 = "1. Première ligne";
- *
- * // push mode (usually used for int, char, long...)
- * array_push(lines, &l1);
- * array_push(lines, &l2);
- *
- * // new mode (usually used for structures)
- * char **tmp = array_new(lines);
- * *tmp = l3;
- *
- * // 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);
- * ```
- */
-
-#ifndef ARRAY_H
-#define ARRAY_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-
-/**
- * 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.
- *
- * @note always identical to <tt>malloc</tt> + <tt>init_array</tt>
- *
- * @param elem_size the size of one element
- * @param initial the initial number of items the buffer can hold (<b>not</b> 0)
- *
- * @see malloc()
- * @see init_array(array_t *self)
- *
- * @return a new array (you must later call `free_array()` or `array_convert()`)
- */
-array_t *new_array(size_t elem_size, size_t initial);
-
-/**
- * Initialise a new array.
- *
- * @param elem_size the size of one element
- * @param initial the initial number of items the buffer can hold (<b>not</b> 0)
- */
-int init_array(array_t *self, size_t elem_size, size_t initial);
-
-/**
- * Free the resources held for the given array: you must not use it any more.
- * Note that if you use pointers and not direct data, you may want to free
- * those yourself first.
- *
- * @note always equivalent to <tt>uninit_array</tt> + <tt>free</tt>
- *
- * @see uninit_array(array_t *self)
- * @see free(void *data)
- * @see array_clear
- * @see array_loop
- */
-void free_array(array_t *me);
-
-/**
- * Free the resources held for the given array: you must not use it any more.
- * Note that if you use pointers and not direct data, you may want to free
- * those yourself first.
- *
- * @see free_array(array_t *self)
- * @see array_clear
- * @see array_loop
- */
-void uninit_array(array_t *me);
-
-/**
- * Clear the array, that is, resets its current size to 0 (buffer unchanged).
- *
- * @note if you hold custom structures with owned resources in the array, you
- * should deallocate them properly before
- */
-void array_clear(array_t *me);
-
-/**
- * Convert the array to a block of memory where all values are adjacent.
- *
- * @note an extra NULL value is assured to be present as last element
- *
- * @return the data (you must later call `free()` on it)
- */
-void *array_convert(array_t *me);
-
-/**
- * Return a pointer to the internal storage used by this array.
- * This is the same value as would return `array_convert()`,
- * but the array is still valid.
- *
- * Be careful if you change the content (you should not).
- *
- * @note an extra NULL value is assured to be present as last element
- *
- * @return the internal storage area
- */
-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_t *me);
-
-/**
- * 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_new(array_t *me);
-
-/**
- * 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, or NULL if no elements are
- * present
- */
-void *array_first(array_t *me);
-
-/**
- * Return a pointer to the last 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 last element, or NULL if no elements are
- * present
- */
-void *array_last(array_t *me);
-
-/**
- * Return the pointer to the previous element, or NULL if it was the first.
- *
- * @param ptr a pointer from an array (the array must be valid)
- *
- * @return the previous element, or NULL
- */
-void *array_prev(array_t *me, void *ptr);
-
-/**
- * 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
- *
- * @note if the index is out of bounds, you will get invalid data
- *
- * @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_pop(array_t *me);
-
-/**
- * Cut the array at the given size and return a pointer to the first element
- * that was removed if any.
- *
- * @note be careful, the memory pointed to by the element(s) 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(s) 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(s)
- *
- * @return a pointer to the first removed element, or NULL
- */
-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()`.
- * All the appropriate parameters are passed, except the sorting function.
- *
- * @param compar a custom comparison function
- * @param (parameters)
- * * `itm1`: a **pointer** to one of your data element (for instance,
- * if you store floats, it will be a `(float *)`,
- * so you would need to cast it via `((float *)itm1)[0]`
- * * `itm2`: another **pointer** to compare with the first one
- * @param (returns)
- * * `-1`: if element A is less than element B
- * * `0`: if both elements are equals
- * * `1`: if element A is more than element B
- */
-void array_qsort(array_t *me, int (*compar)(const void *itm1, const void *itm2));
-
-/**
- * Sort the array with `qsort()`, data is `char *`.
- *
- * @param rev FALSE for normal order, TRUE for reverse order
- *
- * @see array_qsort
- */
-void array_qsorts(array_t *me, int rev);
-
-/**
- * Sort the array with `qsort()`, data is `int`.
- *
- * @param rev FALSE for normal order, TRUE for reverse order
- *
- * @see array_qsort
- */
-void array_qsorti(array_t *me, int rev);
-
-/**
- * Sort the array with `qsort()`, data is `long`.
- *
- * @param rev FALSE for normal order, TRUE for reverse order
- *
- * @see array_qsort
- */
-void array_qsortl(array_t *me, int rev);
-
-/**
- * Sort the array with `qsort()`, data is `float`.
- *
- * @param rev FALSE for normal order, TRUE for reverse order
- *
- * @see array_qsort
- */
-void array_qsortf(array_t *me, int rev);
-
-/**
- * Add an element to the array (will create a new item in the array and copy the
- * data from the given element in it).
- *
- * @param data the memory position of the element to add
- *
- * @return FALSE if the array is too short and we cannot allocate enough
- * contiguous memory for its needs
- */
-int array_push(array_t *me, void *data);
-
-/**
- * Add multiple elements to the array (will create new items in the array and
- * copy the data from the given elements in them).
- *
- * @param data the memory position of the elements to add, adjacent to each
- * other
- * @param n the number of elements to copy from `data`
- *
- * @return FALSE if the array is too short and we cannot allocate enough
- * contiguous memory for its needs
- */
-int array_pushn(array_t *me, void *data, size_t n);
-
-/**
- * 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)
- */
-int array_copy(array_t *me, void *target, size_t i);
-
-/**
- * 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)
- */
-int array_copyn(array_t *me, void *target, size_t i, size_t n);
-
-/**
- * Set an element of the array to the given value.
- * Can also append an element at the end of the array (i.e., <tt>i</tt> can be
- * the size of the array and this will result in an array with one more
- * element).
- * Memory will be copied from the given data to the array.
- *
- * @param i the element index
- * @param data the data that will replace the current value, or new data
- * to append after the current elements (you can add items just at
- * the end of the array (index = count), but it is not allowed to
- * set items after that index, so not to create holes)
- *
- * @return FALSE if the array is too short and we cannot allocate enough
- * contiguous memory for its needs, or if the index is out of bounds
- */
-int array_set(array_t *me, size_t i, void *data);
-
-/**
- * Set elements of the array to the given value.
- * Can also append elements at the end of the array (i.e., <tt>i</tt> can be
- * the size of the array and this will result in an array with <tt>n</tt> more
- * elements).
- * Memory will be copied from the given data to the array.
- *
- * @param i the element index to start the insertion at
- * @param data the data that will replace the current values, or new data
- * to append after the current elements (you can add items just at
- * the end of the array (index = count), but it is not allowed to
- * set items with `i` after that index, so not to create holes)
- * @param n the number of elements to copy from `data` and to insert at `i`
- *
- * @return FALSE if the array is too short and we cannot allocate enough
- * contiguous memory for its needs, or if the index is out of bounds
- */
-int array_setn(array_t *me, size_t i, void *data, size_t n);
-
-#endif /* ARRAY_H */
-
-#ifdef __cplusplus
-}
-#endif
-
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2013 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 "base64.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-static char encoding_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
- 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
- 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
- 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
- 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
-
-static int decoding_table_flg = 0;
-static char decoding_table[256];
-
-static void init_dtable() {
- if (!decoding_table_flg) {
- for (int i = 0; i < 64; i++)
- decoding_table[(unsigned char) encoding_table[i]] = i;
- decoding_table_flg = 1;
- }
-}
-
-char *base64_encode(const char *data) {
- size_t input_length = strlen(data);
- size_t output_length = 4 * ((input_length + 2) / 3);
-
- char *encoded_data = malloc(output_length + 1);
- if (!encoded_data)
- return NULL;
-
- for (unsigned int i = 0, j = 0; i < input_length;) {
- unsigned int octet_a = i < input_length ? (unsigned char) data[i++] : 0;
- unsigned int octet_b = i < input_length ? (unsigned char) data[i++] : 0;
- unsigned int octet_c = i < input_length ? (unsigned char) data[i++] : 0;
-
- unsigned int triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
-
- encoded_data[j++] = (char) encoding_table[(triple >> 3 * 6) & 0x3F];
- encoded_data[j++] = (char) encoding_table[(triple >> 2 * 6) & 0x3F];
- encoded_data[j++] = (char) encoding_table[(triple >> 1 * 6) & 0x3F];
- encoded_data[j++] = (char) encoding_table[(triple >> 0 * 6) & 0x3F];
- }
-
- if ((input_length % 3) > 0)
- encoded_data[output_length - 1] = '=';
- if ((input_length % 3) == 1)
- encoded_data[output_length - 2] = '=';
-
- encoded_data[output_length] = '\0';
-
- return encoded_data;
-}
-
-char *base64_decode(const char *data) {
- init_dtable();
-
- size_t input_length = strlen(data);
- if (input_length % 4 != 0)
- return NULL;
-
- size_t output_length = ((input_length / 4) * 3);
- if (data[input_length - 1] == '=')
- output_length--;
- if (data[input_length - 2] == '=')
- output_length--;
-
- char *decoded_data = malloc(output_length + 1);
- if (!decoded_data)
- return NULL;
-
- for (unsigned int i = 0, j = 0; i < input_length; i += 4) {
- unsigned int sextet_a = 0;
- unsigned int sextet_b = 0;
- unsigned int sextet_c = 0;
- unsigned int sextet_d = 0;
-
- if (data[i] != '=') {
- sextet_a = decoding_table[(unsigned char) data[i + 0]];
- sextet_b = decoding_table[(unsigned char) data[i + 1]];
- sextet_c = decoding_table[(unsigned char) data[i + 2]];
- sextet_d = decoding_table[(unsigned char) data[i + 3]];
- }
-
- unsigned int triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6)
- + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
-
- if (j < output_length)
- decoded_data[j++] = (char) ((triple >> 2 * 8) & 0xFF);
- if (j < output_length)
- decoded_data[j++] = (char) ((triple >> 1 * 8) & 0xFF);
- if (j < output_length)
- decoded_data[j++] = (char) ((triple >> 0 * 8) & 0xFF);
- }
-
- decoded_data[output_length] = '\0';
- return decoded_data;
-}
-
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2013 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/>.
- */
-
-/**
- * @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
-
-#ifndef BASE64_H
-#define BASE64_H
-
-#include <stdlib.h>
-
-/**
- * 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
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2011 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/>.
- */
-
-/*
- Name: cstring.c
- Copyright: niki (gpl3 or later) 2011
- Author: niki
- Date: 2011-06-16
- Description: cstring is a collection of helper functions to manipulate text
- */
-
-#include "cstring.h"
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
-#include <wctype.h>
-
-// For upper/lowercase
-#include <locale.h>
-
-#ifndef BUFFER_SIZE
-#define BUFFER_SIZE 81
-#endif
-
-#ifdef WIN32
-#define CSTRING_SEP '\\'
-#else
-#define CSTRING_SEP '/'
-#endif
-
-// Private functions
-
-typedef struct {
- size_t buffer_length;
-} priv_t;
-
-/** Swap the data */
-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_t *self, int up);
-/** For path-related functions */
-static void normalize_path(cstring_t *self);
-
-// Private variables
-
-static char *locale = NULL;
-
-// end of privates
-
-cstring_t *new_cstring() {
- cstring_t *self = malloc(sizeof(cstring_t));
- if (!init_cstring(self)) {
- free(self);
- self = NULL;
- }
-
- return self;
-}
-
-int init_cstring(cstring_t *self) {
- strcpy(self->CNAME, "[CString]");
-
- self->priv = malloc(sizeof(priv_t));
- if (!self->priv)
- return 0;
- self->string = malloc(sizeof(char) * BUFFER_SIZE);
- if (!self->string) {
- free(self->priv);
- return 0;
- }
-
- self->length = 0;
- ((priv_t *) self->priv)->buffer_length = BUFFER_SIZE;
- self->string[0] = '\0';
-
- return 1;
-}
-
-void free_cstring(cstring_t *self) {
- if (self)
- uninit_cstring(self);
-
- free(self);
-}
-
-void uninit_cstring(cstring_t *self) {
- free(self->priv);
- free(self->string);
- self->priv = NULL;
- self->string = NULL;
- self->length = 0;
- self->CNAME[0] = '!';
-}
-
-void cstring_swap(cstring_t *a, cstring_t *b) {
- void *tmp_p;
- char *tmp_s;
- size_t tmp_l;
-
- tmp_s = a->string;
- tmp_l = a->length;
- tmp_p = a->priv;
-
- a->string = b->string;
- a->length = b->length;
- a->priv = b->priv;
-
- b->string = tmp_s;
- b->length = tmp_l;
- b->priv = tmp_p;
-}
-
-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) {
- if (sz > BUFFER_SIZE)
- sz *= 2;
- else
- sz += BUFFER_SIZE;
-
- if (req > sz)
- sz = req;
-
- return cstring_grow_to(self, sz);
- }
-
- return 1;
-}
-
-int cstring_grow_to(cstring_t *self, int min_buffer) {
- priv_t *priv = ((priv_t *) self->priv);
-
- if (min_buffer > priv->buffer_length) {
- priv->buffer_length = min_buffer;
- void *mem = realloc(self->string, sizeof(char) * priv->buffer_length);
-
- if (mem)
- self->string = (char *) mem;
- else
- return 0;
- }
-
- return 1;
-}
-
-void cstring_compact(cstring_t *self) {
- if (self != NULL) {
- priv_t *priv = ((priv_t *) self->priv);
-
- priv->buffer_length = self->length + 1;
- self->string = (char *) realloc(self->string, self->length + 1);
- }
-}
-
-int cstring_add_car(cstring_t *self, char source) {
- if (!cstring_grow(self, 1))
- return 0;
-
- self->string[self->length] = source;
- self->length++;
- self->string[self->length] = '\0';
-
- return 1;
-}
-
-int cstring_add(cstring_t *self, const char source[]) {
- return cstring_addf(self, source, 0);
-}
-
-int cstring_addf(cstring_t *self, const char source[], size_t idx) {
- return cstring_addfn(self, source, idx, 0);
-}
-
-int cstring_addn(cstring_t *self, const char source[], size_t n) {
- return cstring_addfn(self, source, 0, n);
-}
-
-int cstring_addfn(cstring_t *self, const char source[], size_t idx, size_t n) {
- size_t ss;
-
- ss = strlen(source);
- if (source && ss > idx && idx >= 0) {
- ss -= idx;
-
- if (n && n < ss)
- ss = n;
-
- if (ss) {
- // "+1" for the added '\0'
- if (!cstring_grow(self, ss + 1))
- return 0;
-
- memcpy(self->string + self->length, source + idx, ss);
- self->length += ss;
- self->string[self->length] = '\0';
- }
- }
-
- return 1;
-}
-
-int cstring_addp(cstring_t *self, const char *fmt, ...) {
- va_list ap;
- char empty = '\0';
-
- va_start(ap, fmt);
- int sz = vsnprintf(&empty, 0, fmt, ap);
- va_end(ap);
-
- char *tmp = malloc((sz + 1) * sizeof(char));
- if (!tmp)
- return 0;
-
- va_start(ap, fmt);
- sz = vsnprintf(tmp, sz + 1, fmt, ap);
- va_end(ap);
-
- int ok = cstring_add(self, tmp);
- free(tmp);
-
- return ok;
-}
-
-void cstring_cut_at(cstring_t *self, size_t size) {
- if (self->length > size) {
- self->string[size] = '\0';
- self->length = size;
- }
-}
-
-cstring_t *cstring_substring(const char self[], size_t start, size_t length) {
- size_t sz = strlen(self);
- cstring_t * sub = new_cstring();
-
- if (start <= sz) {
- const char *source = (self + start);
-
- if (!length)
- cstring_add(sub, source);
- else
- cstring_addn(sub, source, length);
- }
-
- return sub;
-}
-
-/*
- clist *cstring_splitc(cstring *self, char delim, char quote) {
- clist *list;
- cstring *d, *q;
-
- d = new_cstring();
- q = new_cstring();
-
- if (delim)
- cstring_add_car(d, delim);
- if (quote)
- cstring_add_car(q, quote);
-
- list = cstring_split(self, d, q);
-
- free_cstring(d);
- free_cstring(q);
-
- return list;
- }
-
- clist *cstring_splits(cstring *self, const char delim[], const char quote[]) {
- clist *list;
- cstring *d, *q;
-
- d = new_cstring();
- q = new_cstring();
-
- if (delim)
- cstring_add(d, delim);
- if (quote)
- cstring_add(q, quote);
-
- list = cstring_split(self, d, q);
-
- free_cstring(d);
- free_cstring(q);
-
- return list;
- }
- clist *cstring_split(cstring *self, cstring *delim, cstring *quote) {
- clist *list;
- cstring *elem;
- clist_node *node;
- size_t i;
- int in_quote;
- int hasdelim;
-
- hasdelim = delim && delim->length > 0;
-
- list = clist_new();
- in_quote = 0;
- elem = NULL;
- for (i = 0; i < self->length; i++) {
- if (quote->length > 0 && cstring_starts_with(self, quote, i)) {
- in_quote = !in_quote;
- i += quote->length - 1;
- } else {
- if (elem == NULL) {
- elem = new_cstring();
- node = clist_node_new();
- node->data = elem;
- node->free_data = free_cstring;
- clist_add(list, node);
- }
- if (!in_quote && hasdelim && cstring_starts_with(self, delim, i)) {
- elem = new_cstring();
- node = clist_node_new();
- node->data = elem;
- node->free_data = free_cstring;
- clist_add(list, node);
- i += delim->length - 1;
- } else {
- cstring_add_car(elem, self->string[i]);
- }
- }
- }
-
- return list;
- }
- */
-
-void cstring_reverse(char *self) {
- size_t i;
- size_t last;
- char tmp;
-
- size_t sz = strlen(self);
- if (sz) {
- last = sz - 1;
- for (i = 0; i <= (last / 2); i++) {
- tmp = self[i];
- self[i] = self[last - i];
- self[last - i] = tmp;
- }
- }
-}
-
-int cstring_replace(cstring_t *self, const char from[], const char to[]) {
- cstring_t *buffer;
- size_t i;
- size_t step;
- int occur;
-
- // easy optimisation:
- if (!from || !from[0])
- return 0;
- if (from && to && from[0] && to[0] && !from[1] && !to[1])
- return cstring_replace_car(self->string, from[0], to[0]);
-
- // optimise for same-size strings?
-
- step = strlen(from) - 1;
- buffer = new_cstring();
- occur = 0;
- for (i = 0; i < self->length; i++) {
- if (cstring_starts_with(self->string, from, i)) {
- cstring_add(buffer, to);
- i += step;
- occur++;
- } else {
- cstring_add_car(buffer, self->string[i]);
- }
- }
-
- cstring_swap(self, buffer);
- free_cstring(buffer);
- return occur;
-}
-
-int cstring_replace_car(char *self, char from, char to) {
- size_t i;
- int occur = 0;
-
- for (i = 0; self[i]; i++) {
- if (self[i] == from) {
- self[i] = to;
- occur++;
- }
- }
-
- return occur;
-}
-
-int cstring_starts_with(const char string[], const char find[],
- size_t start_idx) {
- size_t i;
-
- for (i = 0;
- string[start_idx + i] == find[i] && string[start_idx + i] != '\0'
- && find[i] != '\0'; i++)
- ;
-
- return find[i] == '\0';
-}
-
-int cstring_ends_with(const char self[], const char find[]) {
- size_t sz = strlen(self);
- size_t sz_needle = strlen(find);
- if (sz_needle <= sz) {
- if (!strcmp(self + (sz - sz_needle), find))
- return 1;
- }
-
- return 0;
-}
-
-long cstring_find(const char self[], const char find[], size_t start_index) {
- size_t sz = strlen(self);
- if (sz > start_index) {
- char *found = strstr(self + start_index, find);
- if (found) {
- return (long) (found - self);
- }
- }
-
- return -1;
-}
-
-long cstring_rfind(char self[], const char find[], long rstart_index) {
- size_t sz = strlen(self);
- size_t sz_needle = strlen(find);
-
- if (rstart_index <= 0)
- rstart_index += (sz - 1);
-
- if (sz > rstart_index && sz_needle <= sz) {
- for (size_t i = rstart_index;; i--) {
- if (cstring_starts_with(self, find, i))
- return i;
-
- if (!i)
- break;
- }
- }
-
- return -1;
-}
-
-void cstring_clear(cstring_t *self) {
- self->length = 0;
- self->string[0] = '\0';
-}
-
-char *cstring_convert(cstring_t *self) {
- char *string;
-
- if (!self)
- return NULL;
-
- // Note: this could be skipped.
- cstring_compact(self);
-
- string = (self->string);
- self->string = NULL;
-
- free_cstring(self);
-
- return string;
-}
-
-cstring_t *cstring_clone(const char self[]) {
- if (self == NULL)
- return NULL;
-
- cstring_t *clone = new_cstring();
- cstring_add(clone, self);
-
- return clone;
-}
-
-void cstring_rtrim(cstring_t *self, char car) {
- for (size_t i = self->length - 1; i >= 0; i--) {
- if (self->string[i] != car)
- break;
- self->string[i] = '\0';
- self->length--;
- }
-}
-
-void cstring_trim(cstring_t *self, char car) {
- if (car == '\0')
- return;
-
- cstring_rtrim(self, car);
-
- int i = 0;
- while (self->string[i] == car)
- i++;
-
- if (i) {
- cstring_t *tmp = new_cstring();
- cstring_add(tmp, self->string + i);
-
- cstring_swap(self, tmp);
- free_cstring(tmp);
- }
-}
-
-size_t cstring_remove_crlf(char *self) {
- size_t sz = strlen(self);
- if (sz && self[sz - 1] == '\n')
- sz--;
- if (sz && self[sz - 1] == '\r')
- sz--;
-
- self[sz] = '\0';
-
- return sz;
-}
-
-void cstring_toupper(cstring_t *self) {
- cstring_change_case(self, 1);
-}
-
-void cstring_tolower(cstring_t *self) {
- cstring_change_case(self, 0);
-}
-
-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) {
- locale = setlocale(LC_ALL, NULL);
- if (!locale || !locale[0] || !strcmp("C", locale)) {
- char *lang = getenv("LANG");
- if (lang && lang[0]) {
- locale = setlocale(LC_ALL, lang);
- if (!locale)
- locale = "";
- }
- }
- }
-
- cstring_t *rep;
- mbstate_t state_from, state_to;
- wchar_t wide;
- char tmp[10];
- size_t count;
-
- // init the state (NULL = internal hidden state, not thread-safe)
- memset(&state_from, '\0', sizeof(mbstate_t));
- memset(&state_to, '\0', sizeof(mbstate_t));
-
- rep = new_cstring();
-
- size_t i = 0;
- while (i < self->length) {
- count = mbrtowc(&wide, self->string + i, self->length - i, &state_from);
-
- //incomplete (should not happen)
- if (count == (size_t) -2) {
- // return;
- cstring_add_car(rep, '_');
- i++;
- continue;
- }
- // invalid multibyte sequence
- if (count == (size_t) -1) {
- // return;
- cstring_add_car(rep, '_');
- i++;
- continue;
- }
-
- // End of String (should not happen, see WHILE condition)
- if (!count)
- break;
-
- // char is ok
- i += count;
-
- if (up)
- wide = (wchar_t) towupper((wint_t) wide);
- else
- wide = (wchar_t) towlower((wint_t) wide);
-
- count = wcrtomb(tmp, wide, &state_to);
- if (count == (size_t) -1) {
- // failed to convert :(
- cstring_add_car(rep, '_');
- } else {
- tmp[count] = '\0';
- cstring_add(rep, tmp);
- }
- }
-
- cstring_swap(self, rep);
- free_cstring(rep);
-}
-
-static char buffer[BUFFER_SIZE];
-int cstring_readline(cstring_t *self, FILE *file) {
- size_t size = 0;
- int full_line;
-
- // sanity check:
- if (!file)
- return 0;
-
- buffer[BUFFER_SIZE - 1] = '\0'; // just in case
-
- if (!feof(file)) {
- cstring_clear(self);
- buffer[0] = '\0';
-
- // Note: fgets() could return NULL if EOF is reached
- if (!fgets(buffer, (int) BUFFER_SIZE - 1, file))
- return 0;
-
- size = strlen(buffer);
- full_line = ((file && feof(file)) || size == 0
- || buffer[size - 1] == '\n');
- size = cstring_remove_crlf(buffer);
- cstring_add(self, buffer);
-
- // No luck, we need to continue getting data
- while (!full_line) {
- if (!fgets(buffer, (int) BUFFER_SIZE - 1, file))
- break;
-
- size = strlen(buffer);
- full_line = ((file && feof(file)) || size == 0
- || buffer[size - 1] == '\n');
- size = cstring_remove_crlf(buffer);
- cstring_add(self, buffer);
- }
-
- return 1;
- }
-
- return 0;
-}
-
-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_t *self, const char subpath[]) {
- while (self->length && self->string[self->length - 1] == CSTRING_SEP)
- self->length--;
- cstring_add_car(self, CSTRING_SEP);
- if (subpath && subpath[0]) {
- cstring_add(self, subpath);
- }
-
- normalize_path(self);
-}
-
-int cstring_pop_path(cstring_t *self, int how_many) {
- int count = 0;
- size_t tmp;
- char first = '\0';
-
- if (self->length)
- first = self->string[0];
-
- normalize_path(self);
- for (int i = 0; i < how_many; i++) {
- tmp = self->length;
- while (self->length && self->string[self->length - 1] != CSTRING_SEP)
- self->length--;
- while (self->length && self->string[self->length - 1] == CSTRING_SEP)
- self->length--;
- if (self->length != tmp)
- count++;
- }
- normalize_path(self);
-
- // Root is root of root
- if (first == CSTRING_SEP && !self->length)
- cstring_add_car(self, CSTRING_SEP);
-
- return count;
-}
-
-char *cstring_basename(const char path[], const char ext[]) {
- size_t i;
- size_t sz = strlen(path);
-
- i = sz;
- while (i && path[i] != CSTRING_SEP)
- i--;
-
- cstring_t *rep;
- if (path[i] != CSTRING_SEP) {
- rep = cstring_clone(path);
- } else {
- rep = new_cstring();
- cstring_addf(rep, path, i + 1);
- }
-
- if (ext && ext[0] && cstring_ends_with(rep->string, ext)) {
- cstring_cut_at(rep, rep->length - strlen(ext));
- }
-
- return cstring_convert(rep);
-}
-
-char *cstring_dirname(const char path[]) {
- cstring_t *rep = cstring_clone(path);
- cstring_pop_path(rep, 1);
- return cstring_convert(rep);
-}
-
-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);
-}
-
-char *cstring_concat(const char str1[], ...) {
- if (!str1)
- return NULL;
-
- va_list args;
- size_t total;
- size_t prec;
- char *arg;
- char *ptr;
- char *rep;
-
- total = strlen(str1);
- va_start(args, str1);
- while ((arg = va_arg(args, char *))) {
- total += strlen(arg);
- }
- va_end(args);
-
- rep = malloc(total * sizeof(char) + 1);
- ptr = rep;
- ptr = strcpy(ptr, str1);
- prec = strlen(str1);
-
- va_start(args, str1);
- while ((arg = va_arg(args, char *))) {
- ptr = strcpy(ptr + prec, arg);
- prec = strlen(arg);
- }
- va_end(args);
-
- return rep;
-}
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2013 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/>.
- */
-
-/**
- * @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
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-
-/**
- * @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 <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 {
- char CNAME[10];
- char *string;
- size_t length;
- void *priv;
-} cstring_t;
-
-/**
- * Instantiate a new cstring.
- *
- * @note always identical to <tt>malloc</tt> + <tt>init_cstring</tt>
- *
- * Create (and allocate the memory for) a new cstring.
- * Do not forget to call cstring_free(cstring) when done.
- *
- * @see malloc()
- * @see init_cstring(cstring_t *self)
- */
-cstring_t *new_cstring();
-
-/**
- * Instantiate a new cstring.
- *
- * Create (and allocate the memory for) a new cstring.
- * Do not forget to call uninit_cstring(cstring_t *self) when done.
- *
- * @see new_cstring()
- * @see uninit_cstring(cstring_t *self)
- */
-int init_cstring(cstring_t *self);
-
-/**
- * Free the given cstring.
- *
- * Free all the resources allocated for this cstring.
- *
- * @note always equivalent to <tt>uninit_cstring</tt> + <tt>free</tt>
- *
- * @see uninit_cstring(cstring_t *self)
- * @see free(void *data)
- */
-void free_cstring(cstring_t *self);
-
-/**
- * Free the given cstring.
- *
- * Free all the resources allocated for this cstring.
- *
- * @param self the cstring to free, which MUST NOT be used again afterward
- */
-void uninit_cstring(cstring_t *self);
-
-/**
- * Grow the cstring to accommodate that many characters in addition to those
- * already held, if needed.
- *
- * @param self the string to grow
- * @param min the minimum number of extra characters it should be able to hold
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-int cstring_grow(cstring_t *self, int min_extra);
-
-/**
- * Grow the cstring to accommodate that many characters in total, if needed.
- *
- * @param self the string to grow
- * @param min the minimum number of characters it should be able to hold
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-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_t *self);
-
-/**
- * Add a char at the end of the given cstring.
- *
- * @param self the cstring to work on
- * @param source the character to add
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-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
- * given cstring.
- *
- * @param self the string to work on
- * @param source the string to add
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-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
- * given cstring, starting from index.
- *
- * @param self the cstring to work on
- * @param source the string to add
- * @param idx the starting index at which to copy from the source
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-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
- * given string, up to N chars long.
- *
- * @param self the string to work on
- * @param source the string to add
- * @param n the maximum number of chars to add (excluding the NUL byte), or 0
- * to add the whole source (which MUST then end with a '\0')
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-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
- * given cstring, starting from index, up to N chars long.
- *
- * @param self the string to work on
- * @param source the string to add
- * @param idx the starting index at which to copy from the source
- * @param n the maximum number of chars to add (excluding the NUL byte) or 0
- * to add the whole source (which MUST then end with a '\0')
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-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.
- *
- * @param self the string to add to
- * @param fmt the required format specifiers (@{see printf})
- * @param ... the printf-format parameters
- *
- * @return TRUE if success (FALSE means it was unable to grow due to memory
- * pressure)
- */
-int cstring_addp(cstring_t *self, const char *fmt, ...);
-
-/**
- * Cut the string at the given size if it is greater.
- *
- * E.g.: it will have (at most) this many characters (without counting NULL) in
- * it after.
- *
- * @param self the string to work on
- * @param size the size to cut at (the maximum size of the cstring after this
- * operation, NUL excepted)
- */
-void cstring_cut_at(cstring_t *self, size_t size);
-
-/**
- * Create a substring of this one.
- *
- * @param self the string to work on
- * @param start the index to start at
- * @param length the number of characters to copy, 0 for 'up to the end'
- *
- * @return a newly allocated cstring
- */
-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.
- * Will also allow empty fields, ie: "a,b,,c" will return 4 cstrings, the third being empty).
- *
- * @param self the cstring to work on
- * @param delim the separator, which can be longer than one character
- *
- * @return a list of cstring
- */
-//TODO: use a []
-//clist *cstring_split(cstring *self, cstring *delim, cstring *quote);
-/**
- * Split a cstring into "smaller" cstrings every time the given separator (which MUST end in \0) is found.
- * Will also allow empty fields, ie: "a,b,,c" will return 4 cstrings, the third being empty).
- *
- * @param self the cstring to work on
- * @param delim the separator, which can be longer than one character and MUST end with \0
- *
- * @return a list of cstring
- */
-//TODO: use a []
-//clist *cstring_splits(cstring *self, const char delim[], const char quote[]);
-/**
- * Split a cstring into "smaller" cstrings every time the given separator is found.
- * Will also allow empty fields, ie: "a,b,,c" will return 4 cstrings, the third being empty).
- *
- * @param self the cstring to work on
- * @param delim the separator
- *
- * @return a list of cstring
- */
-//TODO: use a []
-//clist *cstring_splitc(cstring *self, char delim, char quote);
-/**
- * Reverse the given string.
- *
- * @param self the string to work on
- */
-void cstring_reverse(char *self);
-
-/**
- * Replace all occurrences of a string inside the given cstring by another.
- *
- * @param self the string to work on
- * @param from the string to replace
- * @param to the replacement string
- *
- * @return the number of occurrences changed
- */
-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
- * @param from the char to replace
- * @param to the replacement char
- *
- * @return the number of occurrences changed
- */
-int cstring_replace_car(char *self, char from, char to);
-
-/**
- * Check if the string starts with the given pattern.
- *
- * @param self the string to work on
- * @param find the string to find
- * @param start_idx the index at which to start the comparison
- *
- * @return 1 if it does
- */
-int cstring_starts_with(const char self[], const char find[], size_t start_idx);
-
-/**
- * Check if the string ends with the given pattern.
- *
- * @param self the string to work on
- * @param find the string to find (if empty, will always be found)
- * @param start_index the index at which to start the comparison
- *
- * @return 1 if it does
- */
-int cstring_ends_with(const char self[], const char find[]);
-
-/**
- * Find the given substring in this one.
- *
- * @param self the string to work on
- * @param find the string to find
- * @param start_index the index at which to start the search
- *
- * @return the start index of the found string if found, or a negative value
- * if not
- */
-long cstring_find(const char self[], const char find[], size_t rstart_index);
-
-/**
- * Find the given substring in this one, but search in the reverse direction.
- *
- * @param self the string to work on
- * @param find the string to find
- * @param rstart_index the index at which to start the search, or 0 for
- * "end of string" (remember that it is reverse, you would then never
- * find anything with a real rstart_index of 0), or a negative value
- * to count from the end of the string (-2 means 2 character before the
- * end)
- *
- * @return the start index of the found string if found, or a negative value
- * if not
- */
-long cstring_rfind(char self[], const char find[], long rstart_index);
-
-/**
- * Clear (truncate its size to 0) the given string.
- *
- * @param self the string to work on
- */
-void cstring_clear(cstring_t *self);
-
-/**
- * Convert this cstring into a string
- * This means that you MUST NOT call cstring_free nor use the cstring anymore.
- * NULL will return NULL.
- *
- * @param self the cstring to work on
- */
-char *cstring_convert(cstring_t *self);
-
-/**
- * Clone this string.
- * NULL will return NULL.
- *
- * @param self the string to clone
- */
-cstring_t *cstring_clone(const char self[]);
-
-/**
- * Trim this cstring of all trailing 'car' instances.
- *
- * @param self the cstring to work on
- * @param car the character to trim (right only)
- *
- * @return a right trimmed cstring
- */
-void cstring_rtrim(cstring_t *self, char car);
-
-/**
- * Trim this cstring of all 'car' instances from the start and/or the
- * end of the string.
- *
- * @param self the cstring to work on
- * @param car the character to trim
- *
- * @return a trimmed cstring
- */
-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 string to change
- *
- * @return the new length of the string
- */
-size_t cstring_remove_crlf(char *self);
-
-/**
- * Change the case to upper-case (UTF-8 compatible, but the string MUST be
- * whole).
- *
- * @note: if LC_ALL is not set or is set to C and a viable $LANG exists, it will
- * set LC_ALL to $LANG
- *
- * @param self the cstring to work on
- */
-void cstring_toupper(cstring_t *self);
-
-/**
- * Change the case to lower-case (UTF-8 compatible, but the string MUST be
- * whole).
- *
- * @note: if LC_ALL is not set or is set to C and a viable $LANG exists, it will
- * set LC_ALL to $LANG
- *
- * @param self the cstring to work on
- */
-void cstring_tolower(cstring_t *self);
-
-/**
- * Read a whole line (CR, LN or CR+LN terminated) from the given file stream.
- *
- * @param self the cstring to read into
- * @param file the file to read
- *
- * @return 1 if a line was read, 0 if not
- */
-int cstring_readline(cstring_t *self, FILE *file);
-
-/**
- * Add a path to the given cstring (if it is currently empty, it
- * will result in a root path).
- *
- * Will be separated by a forward '/' except on non-standard systems
- * that uses reverse slash (i.e., Windows).
- *
- * @param self the base cstring (empty for a root path)
- * @param subpath the path component to add
- */
-void cstring_add_path(cstring_t *self, const char subpath[]);
-
-/**
- * Remove the <tt>how_many</tt> components of the path described by this
- * cstring. Will ignore extra path separators and always trim it from the final
- * result (i.e., <tt>some//path/</tt> is identical to <tt>some/path</tt>).
- *
- * @note popping "0" path will simply make sure the string does not end in "/"
- *
- * @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_t *self, int how_many);
-
-/**
- * Return the basename component of this path (for instance,
- * '/home/user/file.ext' becomes 'file.ext').
- *
- * @param path the path to get the dir of (it can be a dir itself)
- * @param ext the extension to remove if any (can be empty or NULL for none)
- *
- * @note the extension should include the "." if any
- *
- * @return a new string representing the parent directory
- */
-char *cstring_basename(const char path[], const char ext[]);
-
-/**
- * Return the dirname of this path (for instance,
- * '/home/user/file.ext' becomes '/home/user').
- *
- * @param path the path to get the dir of (it can be a dir itself)
- *
- * @return a new string representing the parent directory
- */
-char *cstring_dirname(const char path[]);
-
-/**
- * Check if the string is a correct and whole UTF-8 string (i.e., it is indeed
- * an UTF-8 string and doesn't contain incomplete UTF-8 sequences).
- *
- * @return TRUE if it is UTF-8
- */
-int cstring_is_utf8(cstring_t *self);
-
-/**
- * Concat all the given string and return the concatenation as a newly allocated
- * string that you now own.
- *
- * @note the last parameter <b>must</b> be NULL
- *
- * @note if NULL is passed as first parameter, NULL will be returned
- *
- * @param str1 the first string
- *
- * @return the concatenated string or NULL if str1 is NULL
- */
-char *cstring_concat(const char str1[], ...);
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2021 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 <stdio.h>
-#include <dirent.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-
-#include "utils.h"
-
-#define EXT "desktop"
-
-/* Private functions */
-static int desktop_compare(const void *a, const void* b);
-static int desktop_test_file(const char filename[]);
-/* */
-
-desktop_t *new_desktop(const char filename[], int best_size) {
- desktop_t *me = malloc(sizeof(desktop_t));
- if (!init_desktop(me, filename, best_size)) {
- free(me);
- me = NULL;
- }
-
- return me;
-}
-
-int init_desktop(desktop_t *me, const char filename[], int best_size) {
- strcpy(me->CNAME, "[Desktop]");
-
- me->name = NULL;
- me->exec = NULL;
- me->icon = NULL;
- me->icon_file = NULL;
- me->children = NULL;
- me->id = 0;
-
- // Copy name
- me->name = strdup(filename);
-
- // Get extension an remove ".desktop" from name
- char *ext = rindex(me->name, '.');
- if (ext) {
- size_t idot = (ext - me->name);
- ext++;
- if (!strcmp(ext, EXT))
- me->name[idot] = '\0';
- }
- if (ext)
- ext = strdup(ext);
-
- // If PNG of the same name, use as default icon
- me->icon_file = desktop_find_icon(me->name, best_size);
-
- // Pretify default name (remove dir part)
- char *slash = rindex(me->name, '/');
- if (slash && !slash[1]) {
- slash[0] = '\0';
- slash = rindex(me->name, '/');
- }
- if (slash) {
- char *copy = strdup(slash + 1);
- free(me->name);
- me->name = copy;
- }
-
- // Try with the base name, too
- if (!me->icon_file) {
- me->icon_file = desktop_find_icon(me->name, best_size);
- }
-
- DIR *dp = opendir(filename);
- if (dp) {
- // Try to get the default folder icon if no icon yet
- if (!me->icon_file) {
- me->icon_file = desktop_find_icon("folder", best_size);
- }
-
- me->children = new_array(sizeof(desktop_t), 32);
- for (struct dirent *ep = readdir(dp); ep; ep = readdir(dp)) {
- if (!strcmp(ep->d_name, "."))
- continue;
- if (!strcmp(ep->d_name, ".."))
- continue;
-
- desktop_t *child = array_new(me->children);
- char *childname = cstring_concat(filename, "/", ep->d_name, NULL);
- if (!init_desktop(child, childname, best_size))
- array_pop(me->children);
- free(childname);
- }
-
- array_qsort(me->children, desktop_compare);
-
- closedir(dp);
- free(ext);
- return 1;
- }
-
- // Only process ".desktop" files
- if (!ext || strcmp(ext, EXT)) {
- uninit_desktop(me);
- free(ext);
- return 0;
- }
-
- FILE *file;
- cstring_t *line;
- char *startsWith;
-
- file = fopen(filename, "r");
- if (file) {
- line = new_cstring();
- while (cstring_readline(line, file)) {
- startsWith = "Name=";
- if (cstring_starts_with(line->string, startsWith, 0)) {
- free(me->name);
- me->name = strdup(line->string + strlen(startsWith));
- }
-
- startsWith = "Exec=";
- if (cstring_starts_with(line->string, startsWith, 0)) {
- free(me->exec);
- me->exec = strdup(line->string + strlen(startsWith));
- // TODO: %f %F %u %U %i %c %k: inject values instead
- char *cars = "ifFuUck";
- for (char *ptr = index(me->exec, '%'); ptr;
- ptr = index(ptr, '%')) {
- if (index(cars, ptr[1])) {
- ptr[0] = ' ';
- ptr[1] = ' ';
- }
- ptr++;
- }
- }
-
- startsWith = "Icon=";
- if (cstring_starts_with(line->string, startsWith, 0)) {
- free(me->icon);
- me->icon = strdup(line->string + strlen(startsWith));
- }
- }
- free_cstring(line);
- fclose(file);
- }
-
- // Find icon file linked to icon
- if (me->icon && !me->icon_file) {
- me->icon_file = desktop_find_icon(me->icon, best_size);
- }
- // ...or any we can find, actually
- if (!me->icon_file) {
- me->icon_file = desktop_find_icon(me->name, best_size);
- }
-
- free(ext);
- return 1;
-}
-
-void free_desktop(desktop_t *me) {
- if (me)
- uninit_desktop(me);
-
- free(me);
-}
-
-void uninit_desktop(desktop_t *me) {
- free(me->name);
- free(me->exec);
- free(me->icon);
- free(me->icon_file);
- me->name = NULL;
- me->exec = NULL;
- me->icon = NULL;
- me->icon_file = NULL;
- free_array(me->children);
- me->children = NULL;
- me->CNAME[0] = '!';
-}
-
-desktop_t *desktop_find_id(array_t *children, int id) {
- desktop_t *found = NULL;
-
- array_loop(children, child, desktop_t)
- {
- if (child->id == id) {
- found = child;
- break;
- }
-
- if (child->children) {
- found = desktop_find_id(child->children, id);
- break;
- }
- }
-
- return found;
-}
-
-/* Private functions */
-
-static int desktop_compare(const void *a, const void* b) {
- desktop_t *me1 = (desktop_t *)a;
- desktop_t *me2 = (desktop_t *)b;
-
- if (me1->children && !(me2->children))
- return -1;
- if (!(me1->children) && me2->children)
- return 1;
-
- return strcmp(me1->name, me2->name);
-}
-
-static int desktop_test_file(const char filename[]) {
- FILE *test;
- DIR *test_dir;
-
- test = fopen(filename, "r");
- if (test) {
- fclose(test);
- test_dir = opendir(filename);
- if (test_dir) {
- closedir(test_dir);
- } else {
- return 1;
- }
- }
-
- return 0;
-}
-
-#define TRY_DIR(a,b,c) \
- do { \
- tmp = cstring_concat(a, b, c, basename, ".png", NULL); \
- if(desktop_test_file(tmp)) \
- return tmp; \
- free(tmp); \
- } while(0)
-
-static char *theme = NULL;
-static char *ltheme = NULL;
-char *desktop_find_icon(const char basename[], int icon_size) {
- char *tmp = NULL;
- char *home = getenv("HOME");
- char icon_size_str[100];
- sprintf(icon_size_str, "%dx%d", icon_size, icon_size);
-
- if (!theme) {
- tmp = cstring_concat(home, "/.gtkrc-2.0", NULL);
- FILE *file = fopen(tmp, "r");
- free(tmp);
- if (file) {
- const char *startsWith = "gtk-icon-theme-name=";
- size_t n = strlen(startsWith);
-
- cstring_t *line = new_cstring();
- while (cstring_readline(line, file)) {
- if (cstring_starts_with(line->string, startsWith, 0)) {
- free(theme);
- if (line->string[n] == '"') {
- theme = strdup(line->string + n + 1);
- theme[strlen(theme) - 1] = '\0';
- } else {
- theme = strdup(line->string + n);
- }
- }
- }
- free_cstring(line);
- fclose(file);
-
- if (!theme || !theme[0]) {
- theme = strdup("");
- ltheme = strdup("");
- } else {
- tmp = theme;
- theme = cstring_concat("/usr/share/icons/", tmp, "/", NULL);
- ltheme = cstring_concat(home, "/", ".icons/", tmp, "/", NULL);
- free(tmp);
- }
-
- }
- }
-
- // Allow NULL
- if (!basename || !basename[0])
- return NULL;
-
- // exact match
- tmp = strdup(basename);
- if (desktop_test_file(tmp))
- return tmp;
- free(tmp);
-
- // same name, with ".png"
- TRY_DIR("", "", "");
-
- // local icons
- TRY_DIR(home, "/.local/share/icons/", "");
-
- // theme icons
- if (theme && theme[0]) {
- // exact size (apps, places)
- TRY_DIR(theme, icon_size_str, "/apps/");
- TRY_DIR(theme, icon_size_str, "/places/");
-
- // scalable (apps, places)
- TRY_DIR(ltheme, "scalable", "/apps/");
- TRY_DIR(ltheme, "scalable", "/places/");
- }
-
- // shared icons, exact size (apps, places)
- TRY_DIR("/usr/share/icons/hicolors/", icon_size_str, "/apps/");
- TRY_DIR("/usr/share/icons/hicolors/", icon_size_str, "/places/");
-
- // shared icons, scalable (apps, places)
- TRY_DIR("/usr/share/icons/hicolors/scalable/apps/", "", "");
- TRY_DIR("/usr/share/icons/hicolors/scalable/places/", "", "");
-
- return NULL;
-}
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2021 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/>.
- */
-
-/**
- * @file desktop.h
- * @author Niki
- * @date 2021 - 2022
- *
- * @brief Manipulate <tt>.desktop</tt> files (as described by
- * <a href='https://freedesktop.org/'>FreeDesktop.org</a>)
- *
- * This structure helps you manipulate <tt>.desktop</tt> files (as described by
- * <a href='https://freedesktop.org/'>FreeDesktop.org</a>).
- *
- * @note the desktop object can use icons; for the selection of those, an exact
- * match will first be tried (same name as the <tt>desktop</tt> file, with
- * a <tt>.png</tt> extension), then we will look into the local
- * <tt>.local/share/icons</tt> and if we still haven't found an icon, into
- * the theme (first by looking for a <tt>best_size</tt> sized icon and if
- * not in <tt>scalable</tt>)
- *
- * @note we support the use of desktop objects for menu, too, and that includes
- * submenu items support
- */
-#ifndef DESKTOP_H
-#define DESKTOP_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-
-#include "array.h"
-
-/**
- * The structure used to represent desktop objects.
- */
-struct {
- char CNAME[10];
- /** The user name of the desktop object. */
- char *name;
- /** The icon name, if any. */
- char *icon;
- /** The icon file that corresponds, if any. */
- char *icon_file;
- /** The EXEC command to start. */
- char *exec;
- /** The submenu items of this desktop object (for a menu/submenu). */
- array_t *children;
- /** A custom external ID for this desktop object, for your own use. */
- int id;
-}typedef desktop_t;
-
-/**
- * Create a new desktop object from the given <tt>.desktop</tt> file.
- *
- * @note always identical to <tt>malloc</tt> + <tt>init_desktop</tt>
- *
- * @param filename the path to the actual <tt>.desktop</tt> file
- * @param best_size the default size for the icon (see icon selection in the
- * description of the {@see desktop} object
- *
- * @see malloc()
- * @see init_desktop(desktop_t *self, const char filename[], int best_size)
- * @see free_desktop(desktop_t *self)
- *
- * @return the desktop object
- */
-desktop_t *new_desktop(const char filename[], int best_size);
-
-/**
- * Create a new desktop object from the given <tt>.desktop</tt> file.
- *
- * @param filename the path to the actual <tt>.desktop</tt> file
- * @param best_size the default size for the icon (see icon selection in the
- * description of the {@see desktop} object
- *
- * @see new_desktop(const char filename[], int best_size)
- * @see uninit_desktop(desktop_t *self)
- *
- * @return TRUE if success (could fail if the target is not a <tt>.desktop</tt>
- * file
- */
-int init_desktop(desktop_t *self, const char filename[], int best_size);
-
-/**
- * Free the given desktop object.
- *
- * @note always equivalent to <tt>uninit_desktop</tt> + <tt>free</tt>
- *
- * @see uninit_desktop(desktop_t *self)
- * @see free(void *data)
- */
-void free_desktop(desktop_t *self);
-
-/**
- * Free the resources used by the given desktop object -- do not use it anymore
- * after this call.
- */
-void uninit_desktop(desktop_t *self);
-
-/**
- * Find a submenu item by the given ID ({@see desktop_set_id(desktop *, int)}).
- *
- * TODO: use full objects instead
- * @param children the array of pointers to desktop objects to look through
- * @param menu_id the ID of the submenu we want to find
- *
- * @return the given submenu if found, or NULL
- */
-desktop_t *desktop_find_id(array_t *children, int menu_id);
-
-/**
- * Look for the icon file related to this basename.
- *
- * @param basename the base name of the icon we want to look for
- * @param icon_size the best_size to use for the icon (see the description of
- * the {@desktop} object)
- *
- * @return the path to the best related icon we found (you own it), or NULL
- */
-char *desktop_find_icon(const char basename[], int icon_size);
-
-#endif /* DESKTOP_H */
-
-#ifdef __cplusplus
-}
-#endif
-
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2012 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 <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <signal.h>
-
-#ifndef WIN32
- #include <fcntl.h>
- #include <netdb.h>
-#else
- #include <ws2tcpip.h>
-#endif
-
-#include "net.h"
-
-#define bool int
-#define true 1
-#define false 0
-
-/**
- * Get the sockaddr, IPv4 or IPv6.
- * @param sa the socket address is in this structure
- * @return the sockaddr_in or sockaddr_in6 inside this socketaddr,
- * depending if it is IPv4 or IPv6
- */
-void *get_in_addr(struct sockaddr *sa);
-
-#ifndef WIN32
-/**
- * Reap all zombie processes.
- * This function will be called when a child process terminates, and
- * will loop on all zombie processes to properly acknowledge them
- * so they can die.
- *
- * @param s
- */
-void sigchld_handler(int pid);
-
-void sigchld_handler(int pid) {
- if (pid > 0 || pid < 0) pid = 0;
-
- // Reap all zombie processes
- while (waitpid(-1, NULL, WNOHANG) > 0);
-}
-#endif
-
-int net_init(){
-#if defined (WIN32)
- WSADATA WSAData;
- return !WSAStartup(MAKEWORD(2,2), &WSAData);
-#endif
- return 1;
-}
-
-void net_cleanup(){
-#if defined (WIN32)
- WSACleanup();
-#endif
-}
-
-int net_set_non_blocking(int fd) {
- return net_set_blocking(fd, 0);
-}
-
-int net_set_blocking(int fd, int block) {
- int flags;
-
-/* If they have O_NONBLOCK, use the POSIX way to do it */
-#if defined (O_NONBLOCK)
- /* O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
- if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
- flags = 0;
- }
- if (block) {
- return fcntl(fd, F_SETFL, flags ^ O_NONBLOCK);
- }
- else {
- return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
- }
-#else
- flags = block?0:1;
- return ioctl(fd, FIONBIO, (int)(&flags));
-#endif
-}
-
-int net_connect(const char server[], int port) {
- int sockfd;
- struct addrinfo hints, *servinfo, *p;
- int rv;
- char string[10];
-
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-
- // convert the port number to a string
- sprintf(string, "%i\0", port);
- rv = getaddrinfo(server, string, &hints, &servinfo);
- //
-
- if (rv != 0) {
- // DO NOT dirty the stderr
- //fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
- return -1;
- }
-
- // loop through all the results and connect to the first we can
- for (p = servinfo; p != NULL; p = p->ai_next) {
- if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
- == -1) {
- //perror("client: socket");
- continue;
- }
-
- if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
- close(sockfd);
- //perror("client: connect");
- continue;
- }
-
- break;
- }
-
- if (p == NULL) {
- //fprintf(stderr, "client: failed to connect\n");
- return -1;
- }
-
- freeaddrinfo(servinfo);
-
- return sockfd;
-}
-
-int net_accept(int ssocketd) {
- struct sockaddr_storage their_addr;
- socklen_t sin_size;
-
- sin_size = sizeof(their_addr);
- return accept(ssocketd, (struct sockaddr *) &their_addr, &sin_size);
-}
-
-int net_listen(int port, int backlog) {
-#ifndef WIN32
- struct sigaction sa;
-#endif
- int sockfd;
- struct addrinfo hints, *servinfo, *p;
- char yes = 1;
- int rv;
- char string[10];
-
- memset(&hints, 0, sizeof hints);
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE; // use my IP
-
- // convert the port number to a string
- sprintf(string, "%i\0", port);
- rv = getaddrinfo(NULL, string, &hints, &servinfo);
- //
-
- if (rv != 0) {
- // DO NOT dirty the stderr
- //fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
- return -1;
- }
-
- // loop through all the results and bind to the first we can
- for (p = servinfo; p != NULL; p = p->ai_next) {
- if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
- //perror("server: socket");
- continue;
- }
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
- //perror("setsockopt");
- return -1;
- }
-
- if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
- close(sockfd);
- //perror("server: bind");
- continue;
- }
-
- break;
- }
-
- if (p == NULL) {
- //fprintf(stderr, "server: failed to bind\n");
- return -1;
- }
-
- // all done with this structure
- freeaddrinfo(servinfo);
-
- if (listen(sockfd, backlog) == -1) {
- //perror("listen");
- return -1;
- }
-
-#ifndef WIN32
- sa.sa_handler = sigchld_handler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- if (sigaction(SIGCHLD, &sa, NULL) == -1) {
- //perror("sigaction");
- return -1;
- }
-#endif
-
- return sockfd;
-}
-
-void net_close_socketd(int socketd) {
- close(socketd);
-}
-
-#ifndef MSG_NOSIGNAL
-#define MSG_NOSIGNAL 0
-#endif
-ssize_t net_write(int fd, const void *buf, size_t n) {
- // In UNIX: send() with flag set to '0' == write()
- // In WIN32: cannot write() to a socket
- return send(fd, (char *)buf, n, MSG_NOSIGNAL);
-}
-
-ssize_t net_read(int fd, void *buf, size_t nbytes) {
- // In UNIX: recv() with flag set to '0' == send()
- // In WIN32: cannot read() from a socket
- return recv(fd, (char *)buf, nbytes, 0);
-}
-
-void *get_in_addr(struct sockaddr *sa) {
- if (sa->sa_family == AF_INET) {
- return &(((struct sockaddr_in*) sa)->sin_addr);
- }
- else {
- return &(((struct sockaddr_in6*) sa)->sin6_addr);
- }
-}
-
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2012 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/>.
- */
-
-/**
- * @file net.h
- * @author niki
- * @date 2011 - 2022
- *
- * @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
-#define NET_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// WHY ??
-#ifdef _WIN32
-#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");
-#else
-#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>
-
-/**
- * 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.)
- *
- * @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.)
- */
-void net_cleanup();
-
-/**
- * Set the given socket to (non-)blocking I/O mode.
- * This function can work with file sockets, too.
- *
- * @param fd the file descriptor or socket to change
- * @param block TRUE to block, FALSE not to block
- *
- * @return TRUE if success
- */
-int net_set_blocking(int fd, int block);
-
-/**
- * Connect to this server on this port, and return a socket descriptor
- * to write to or read from it.
- *
- * @param server the server to connect to
- * @param port the port to connect on
- *
- * @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 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
- *
- * @return the server socket, or a negative value on error
- */
-int net_listen(int port, int backlog);
-
-/**
- * Block (or not) and wait for a client to connect on this socket.
- * When this is done, return a socket to this specific client/server
- * connection. It can takes the connections from a queue,
- * as defined in net_listen.
- *
- * @param ssocketd the server socket on which to accept a connection
- *
- * @return the socket, or a negative value on error
- */
-int net_accept(int ssocketd);
-
-/**
- * Close a socket (or a server socket).
- *
- * @param socketd the (server) socket to close
- */
-void net_close_socketd(int socketd);
-
-/**
- * Write to this socket, as you would with a file.
- *
- * @param fd the socket to write to
- * @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
- */
-ssize_t net_write(int fd, const void *buf, size_t n);
-
-/**
- * Read from this socket, as you would with a file.
- *
- * @param fd the socket to read from
- * @param buf the buffer to write to
- * @param nbytes the number of bytes to read
- *
- * @return the actual number of bytes read
- */
-ssize_t net_read(int fd, void *buf, size_t nbytes);
-
-#endif
-
-#ifdef __cplusplus
-extern}
-#endif
+++ /dev/null
-/**
- * @file print.h
- * @author Samantaz Fox
- * @date 2019
- *
- * @brief File name and line numbers
- *
- * Small utility header designed to print file name and line number
- * along with debug/info messages.
- *
- * Usage example:
- * ERROR("program exited with code %d\n", getErrorCode() );
- *
- * Known issues:
- * - Must take at least one argument in addition to format string
- *
- *
- * Copyright 2019 (C) Samantaz Fox
- * https://github.com/SamantazFox/Micro-projects/raw/master/library/print.h
- *
- * This file is in the public domain.
- * Feel free to copy, modify or redistribute it!
-*/
-
-#ifndef __PRINT_H__
-#define __PRINT_H__
-
-
-#ifdef __cplusplus
- #include <cstdio>
-#else
- #include <stdio.h>
-#endif
-
-
-#define TRACE(_format, ...) \
- do { \
- fprintf(stdout, "[Trace] %s:%d\t" _format, __FILE__, __LINE__, __VA_ARGS__); \
- } while (0)
-
-#define DEBUG(_format, ...) \
- do { \
- fprintf(stdout, "[Debug] %s:%d\t" _format, __FILE__, __LINE__, __VA_ARGS__); \
- } while (0)
-
-#define INFO(_format, ...) \
- do { \
- fprintf(stdout, "[Info ] %s:%d\t" _format, __FILE__, __LINE__, __VA_ARGS__); \
- } while (0)
-
-#define WARN(_format, ...) \
- do { \
- fprintf(stderr, "[Warn ] %s:%d\t" _format, __FILE__, __LINE__, __VA_ARGS__); \
- } while (0)
-
-#define ERROR(_format, ...) \
- do { \
- fprintf(stderr, "[Error] %s:%d\t" _format, __FILE__, __LINE__, __VA_ARGS__); \
- } while (0)
-
-
-#endif /* !__PRINT_H__ */
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2020 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/>.
- */
-
-/**
- * @file timing.h
- * @author Niki
- * @date 2020 - 2022
- *
- * @brief Timing macros START and STOP
- *
- * 2 macro are provided to print the elapsed time between the 2 to stdout.
- */
-
-#ifndef TIMING_H
-#define TIMING_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#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; \
- sprintf(cusec, "%0.6d", TIMING_stop.tv_usec); \
- printf("TIME: %d.%s sec\n", TIMING_stop.tv_sec, cusec); \
- gettimeofday(&TIMING_start, NULL);
-
-#endif // TIMING_H
-
-#ifdef __cplusplus
-}
-#endif
-
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2020 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 <string.h>
-
-#include "utils.h"
-#include "cstring.h"
-
-#ifndef strnlen
-size_t strnlen(const char *s, size_t maxlen) {
- size_t i;
- for (i = 0; s[i]; i++) {
- if (i >= maxlen)
- return maxlen;
- }
-
- return i;
-}
-#endif
-
-#ifndef strdup
-char *strdup(const char *source) {
- size_t sz = strlen(source);
- char *new = malloc((sz + 1) * sizeof(char));
- strcpy(new, source);
- return new;
-}
-#endif
+++ /dev/null
-/*
- * CUtils: some small C utilities
- *
- * Copyright (C) 2020 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/>.
- */
-
-/**
- * @file utils.h
- * @author Niki
- * @date 2020 - 2022
- *
- * @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
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "cstring.h"
-#include "array.h"
-#include "desktop.h"
-#include "print.h"
-#include "timing.h"
-
-/* Helps with C99 compatibility for code that is not */
-
-#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
-#endif
-#if _POSIX_C_SOURCE < 200809L && _XOPEN_SOURCE < 500
-/**
- * The strdup() function returns a pointer to a new string which is a
- * duplicate of the string s. Memory for the new string is obtained with
- * malloc(3), and can be freed with free(3).
- *
- *
- * @return On success, the strdup() 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
-
-/* */
-
-#endif // UTILS_H
-
-#ifdef __cplusplus
-}
-#endif
-