commit 3052308aaa824356317c61cd4ecc494dc8848dcf
Author: Robert Russell <robert@rr3.xyz>
Date: Mon, 11 Nov 2024 19:51:30 -0800
Initial commit
Diffstat:
5 files changed, 189 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1 @@
+cembed
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2024, Robert Russell
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+\ No newline at end of file
diff --git a/Makefile b/Makefile
@@ -0,0 +1,26 @@
+.POSIX:
+
+include config.mk
+
+cembed: cembed.c config.mk
+ $(CC) $(CFLAGS) -o $@ cembed.c -lrcx
+
+README: cembed.1
+ man ./cembed.1 | col -b | sed 's/\t/ /g' > README
+
+install: cembed
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ cp -f cembed $(DESTDIR)$(PREFIX)/bin/
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/cembed
+ mkdir -p $(DESTDIR)$(MANPREFIX)/man1
+ cp -f cembed.1 $(DESTDIR)$(MANPREFIX)/man1/
+ chmod 644 $(DESTDIR)$(MANPREFIX)/man1/cembed.1
+
+uninstall:
+ rm -f $(DESTDIR)$(PREFIX)/bin/cembed
+ rm -f $(DESTDIR)$(MANPREFIX)/man1/cembed.1
+
+clean:
+ rm -f cembed
+
+.PHONY: install uninstall clean
diff --git a/cembed.c b/cembed.c
@@ -0,0 +1,140 @@
+#include <errno.h>
+#include <rcx/all.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct resource Resource;
+
+struct resource {
+ char *decl;
+ char *name;
+ usize size;
+ char *data;
+};
+
+char *argv0;
+
+void
+print_usage(FILE *file) {
+ fprintf(file, "usage: %s [-h|--help] DECL0:NAME0=PATH0 DECL1:NAME1=PATH1 ...\n", argv0);
+}
+
+Resource
+parse_resource(char *arg) {
+ char *p = arg;
+
+ char *colon = strchr(p, ':');
+ if (!colon) goto fail;
+ *colon = '\0';
+ char *decl = p;
+ p = colon + 1;
+
+ char *equals = strchr(p, '=');
+ if (!equals) goto fail;
+ *equals = '\0';
+ char *name = p;
+ p = equals + 1;
+
+ char *path = p;
+
+ usize size;
+ void *data = r_vmem_open(&size, 0, path, 0, "r");
+ if (!data) {
+ fprintf(stderr, "r_vmem_open: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ return (Resource){
+ .decl = decl,
+ .name = name,
+ .size = size,
+ .data = data,
+ };
+
+fail:
+ fprintf(stderr, "invalid resource: \"%s\"\n", arg);
+ print_usage(stderr);
+ exit(1);
+}
+
+usize
+format_char(char *buf, char c) {
+ // Escape specials
+ switch (c) {
+ case '\0': strcpy(buf, "\\0"); return 2;
+ case '\a': strcpy(buf, "\\a"); return 2;
+ case '\b': strcpy(buf, "\\b"); return 2;
+ case '\t': strcpy(buf, "\\t"); return 2;
+ case '\n': strcpy(buf, "\\n"); return 2;
+ case '\v': strcpy(buf, "\\v"); return 2;
+ case '\f': strcpy(buf, "\\f"); return 2;
+ case '\r': strcpy(buf, "\\r"); return 2;
+ case '"': strcpy(buf, "\\\""); return 2;
+ case '?': strcpy(buf, "\\?"); return 2;
+ case '\\': strcpy(buf, "\\\\"); return 2;
+ }
+
+ // Keep non-special printable ASCII as-is
+ if (' ' <= c && c <= '~') {
+ buf[0] = c;
+ buf[1] = '\0';
+ return 1;
+ }
+
+ // Hex-encode rest
+ buf[0] = '\\';
+ buf[1] = 'x';
+ buf[2] = "0123456789abcdef"[((uchar)c >> 0) & 0xf];
+ buf[3] = "0123456789abcdef"[((uchar)c >> 4) & 0xf];
+ buf[4] = '\0';
+ return 4;
+}
+
+void
+print_resource(Resource rsc) {
+ printf("%s%schar %s[] =\n\t\"", rsc.decl, rsc.decl[0] ? " " : "", rsc.name);
+ usize len = 0;
+ for (usize i = 0; i < rsc.size; i++) {
+ if (len >= 72) {
+ printf("\"\n\t\"");
+ len = 0;
+ }
+ char buf[5];
+ len += format_char(buf, rsc.data[i]);
+ fputs(buf, stdout);
+ }
+ printf("\";\n");
+}
+
+// TODO: Accept only one resource. The user must concatenate externally.
+// This also makes adding decl prefixes possible externally, so we can get
+// rid of that functionality.
+
+int
+main(int argc, char **argv) {
+ argv0 = argv[0];
+
+ // TODO: Replace this with a proper option parsing from RCX (does not
+ // exist at the time of writing).
+ for (usize i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ print_usage(stdout);
+ exit(0);
+ }
+ }
+
+ int nrscs = argc - 1;
+ REQUIRE(nrscs >= 0);
+ Resource *rscs = r_eallocn(nrscs, sizeof *rscs);
+
+ for (usize i = 0; i < nrscs; i++)
+ rscs[i] = parse_resource(argv[i + 1]);
+
+ for (usize i = 0; i < nrscs; i++) {
+ if (i > 0) printf("\n");
+ print_resource(rscs[i]);
+ }
+
+ return 0;
+}
diff --git a/config.mk b/config.mk
@@ -0,0 +1,6 @@
+PREFIX = /usr/local
+MANPREFIX = $(PREFIX)/share/man
+
+CFLAGS = -Wall
+
+CC = cc