cembed

convert files to C char arrays
git clone git://git.rr3.xyz/cembed
Log | Files | Refs | LICENSE

commit 3052308aaa824356317c61cd4ecc494dc8848dcf
Author: Robert Russell <robert@rr3.xyz>
Date:   Mon, 11 Nov 2024 19:51:30 -0800

Initial commit

Diffstat:
A.gitignore | 1+
ALICENSE | 16++++++++++++++++
AMakefile | 26++++++++++++++++++++++++++
Acembed.c | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.mk | 6++++++
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