commit 923b3da7ddeb2e2781d721572a8c0c6d5c5b6d7d
Author: finwo <finwo@pm.me>
Date: Fri, 13 Mar 2026 00:36:58 +0100
Project re-init
Diffstat:
6 files changed, 200 insertions(+), 0 deletions(-)
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+# f4d2ed80-57b6-46e6-b245-5049428a931d
+github: finwo
+liberapay: finwo
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+/lib/
+*.o
+/dep
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
@@ -0,0 +1,6 @@
+<!-- 46b43825-f791-485e-9445-415ee7bbbf2d -->
+# Contributor Code of Conduct
+
+This project adheres to No Code of Conduct. We are all adults. We accept anyone's contributions. Nothing else matters.
+
+For more information please visit the [No Code of Conduct](https://github.com/domgetter/NCoC) homepage.
diff --git a/LICENSE.md b/LICENSE.md
@@ -0,0 +1,34 @@
+Copyright (c) 2026 finwo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to use, copy,
+modify, and distribute the Software, subject to the following conditions:
+
+ 1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions, and the following disclaimer.
+
+ 2. Redistributions in binary form, or any public offering of the Software
+ (including hosted or managed services), must reproduce the above copyright
+ notice, this list of conditions, and the following disclaimer in the
+ documentation and/or other materials provided.
+
+ 3. Any redistribution or public offering of the Software must clearly attribute
+ the Software to the original copyright holder, reference this License, and
+ include a link to the official project repository or website.
+
+ 4. The Software may not be renamed, rebranded, or marketed in a manner that
+ implies it is an independent or proprietary product. Derivative works must
+ clearly state that they are based on the Software.
+
+ 5. Modifications to copies of the Software must carry prominent notices stating
+ that changes were made, the nature of the modifications, and the date of the
+ modifications.
+
+Any violation of these conditions terminates the permissions granted herein.
+
+THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,63 @@
+CC?=clang
+
+FIND=$(shell which gfind find | head -1)
+SRC:=
+INCLUDES:=
+CFLAGS:=
+LDFLAGS:=
+
+SRC+=$(shell $(FIND) src/ -type f -name '*.c')
+INCLUDES+=-Isrc
+INCLUDES+=-Ilib/.dep/include
+LIBS:=
+
+LIBS+=lib/cofyc/argparse
+SRC+=lib/cofyc/argparse/argparse.c
+
+LIBS+=lib/erkkah/naett
+SRC+=lib/erkkah/naett/naett.c
+ifeq ($(OS),Windows_NT)
+ LDFLAGS+=-lwinhttp
+else
+ UNAME_S := $(shell uname -s)
+ ifeq ($(UNAME_S),Linux)
+ LDFLAGS+=-lcurl -lpthread
+ endif
+ ifeq ($(UNAME_S),Darwin)
+ LDFLAGS+=-framework Foundation
+ endif
+endif
+
+LIBS+=lib/rxi/microtar
+SRC+=lib/rxi/microtar/src/microtar.c
+
+OBJ:=$(SRC:.c=.o)
+OBJ:=$(OBJ:.cc=.o)
+CFLAGS+=${INCLUDES}
+
+.PHONY: default
+default: dep
+
+lib/cofyc/argparse:
+ mkdir -p lib/cofyc/argparse
+ curl -sL https://github.com/cofyc/argparse/archive/refs/heads/master.tar.gz | tar xzv --strip-components=1 -C lib/cofyc/argparse
+ mkdir -p lib/.dep/include/cofyc
+ ln -s ../../../cofyc/argparse/argparse.h lib/.dep/include/cofyc/argparse.h
+
+lib/erkkah/naett:
+ mkdir -p lib/erkkah/naett
+ curl -sL https://github.com/erkkah/naett/archive/refs/heads/main.tar.gz | tar xzv --strip-components=1 -C lib/erkkah/naett
+ mkdir -p lib/.dep/include/erkkah
+ ln -s ../../../erkkah/naett/naett.h lib/.dep/include/erkkah/naett.h
+
+lib/rxi/microtar:
+ mkdir -p lib/rxi/microtar
+ curl -sL https://github.com/rxi/microtar/archive/refs/heads/master.tar.gz | tar xzv --strip-components=1 -C lib/rxi/microtar
+ mkdir -p lib/.dep/include/rxi
+ ln -s ../../../rxi/microtar/src/microtar.h lib/.dep/include/rxi/microtar.h
+
+.c.o:
+ ${CC} $< ${CFLAGS} -c -o $@
+
+dep: $(LIBS) $(OBJ)
+ ${CC} ${OBJ} ${CFLAGS} ${LDFLAGS} -o $@
diff --git a/src/main.c b/src/main.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cofyc/argparse.h"
+#include "erkkah/naett.h"
+#include "rxi/microtar.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+static const char *const usages[] = {
+ "subcommands [options] [cmd] [args]",
+ NULL,
+};
+
+struct cmd_struct {
+ const char *cmd;
+ int (*fn) (int, const char **);
+};
+
+int
+cmd_foo(int argc, const char **argv)
+{
+ printf("executing subcommand foo\n");
+ printf("argc: %d\n", argc);
+ for (int i = 0; i < argc; i++) {
+ printf("argv[%d]: %s\n", i, *(argv + i));
+ }
+ int force = 0;
+ int test = 0;
+ const char *path = NULL;
+ struct argparse_option options[] = {
+ OPT_HELP(),
+ OPT_BOOLEAN('f', "force", &force, "force to do", NULL, 0, 0),
+ OPT_BOOLEAN('t', "test", &test, "test only", NULL, 0, 0),
+ OPT_STRING('p', "path", &path, "path to read", NULL, 0, 0),
+ OPT_END(),
+ };
+ struct argparse argparse;
+ argparse_init(&argparse, options, usages, 0);
+ argc = argparse_parse(&argparse, argc, argv);
+ printf("after argparse_parse:\n");
+ printf("argc: %d\n", argc);
+ for (int i = 0; i < argc; i++) {
+ printf("argv[%d]: %s\n", i, *(argv + i));
+ }
+ return 0;
+}
+
+int
+cmd_bar(int argc, const char **argv)
+{
+ printf("executing subcommand bar\n");
+ for (int i = 0; i < argc; i++) {
+ printf("argv[%d]: %s\n", i, *(argv + i));
+ }
+ return 0;
+}
+
+static struct cmd_struct commands[] = {
+ {"foo", cmd_foo},
+ {"bar", cmd_bar},
+};
+
+int
+main(int argc, const char **argv)
+{
+ struct argparse argparse;
+ struct argparse_option options[] = {
+ OPT_HELP(),
+ OPT_END(),
+ };
+ argparse_init(&argparse, options, usages, ARGPARSE_STOP_AT_NON_OPTION);
+ argc = argparse_parse(&argparse, argc, argv);
+ if (argc < 1) {
+ argparse_usage(&argparse);
+ return -1;
+ }
+
+ /* Try to run command with args provided. */
+ struct cmd_struct *cmd = NULL;
+ for (int i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (!strcmp(commands[i].cmd, argv[0])) {
+ cmd = &commands[i];
+ }
+ }
+ if (cmd) {
+ return cmd->fn(argc, argv);
+ }
+ return 0;
+}