~sircmpwn/koio

37f3634007ab89625a21f20622390660e676b841 — Drew DeVault 4 years ago 1265208
Add codegen tool
3 files changed, 208 insertions(+), 0 deletions(-)

A koio.1.scd
M meson.build
A tool/main.c
A koio.1.scd => koio.1.scd +67 -0
@@ 0,0 1,67 @@
koio(1)

# NAME

koio - bundles assets for embedding in your program

# SYNOPSIS

*koio* -o _path_ [flags...] [assets...]

# OPTIONS

*-h*
	Show help message and exit.

*-d* _function_
	Specify the symbol name to assign to the deinitialization function. You may
	call this to unload any assets loaded with the function specified by *-i*.
	This defaults to *koio\_unload\_assets*.

*-i* _function_
	Specify the symbol name to assign to the initialization function. You must
	call this function in your program before using any koio-controlled assets.
	This defaults to *koio\_load\_assets*.

*-o* _path_
	Required. Specifies a _path_ at which the bundle will be written as a C
	source file.

# ASSETS

You can specify any number of files to be embedded the bundle. Simply
specifying a path is enough - the file will be available at *//that/path* via
the koio API. You may also optionally add a colon and specify the virtual path
for that file - this needn't begin with *//* if you wish to overlay files on
the genuine filesystem.

# EXAMPLE

The following command produces *asset\_bundle.c*:

```
$ koio -o asset_bundle.c \\
	images/hello.png \\
	images/world.png://hello/world.png \\
	fakepasswd:/etc/passwd
```

If you compile and link *asset\_bundle.c*, you can then use these files:

```
#include <koio.h>

int main(int argc, char **argv) {
	koio_load_assets();
	
	FILE *f = ko_fopen("//images/hello.png", "r");
	// ...
	f = ko_fopen("//hello/world.png", "r");
	// ...
	f = ko_fopen("/etc/passwd", "r");
}
```

# SEE ALSO

koio.h(0)

M meson.build => meson.build +6 -0
@@ 34,3 34,9 @@ lib_koio = library(meson.project_name(),
	install: true,
	#link_args: symbols_flag,
)

koio_tool = executable(meson.project_name(),
	[
		'tool/main.c'
	],
	install: true)

A tool/main.c => tool/main.c +135 -0
@@ 0,0 1,135 @@
#define _POSIX_C_SOURCE 200112L
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <string.h>

static void print_usage(const char *name) {
	fprintf(stdout, "Usage: %s -o output.c [flags...] [assets...]\n", name);
}

int main(int argc, char **argv) {
	const char *deinit = "koio_unload_assets";
	const char *init = "koio_load_assets";
	const char *output = NULL;

	int c;
	while ((c = getopt(argc, argv, "hd:i:o:")) != -1) {
		switch (c) {
		case 'h':
			print_usage(argv[0]);
			return 0;
		case 'd':
			deinit = optarg;
			break;
		case 'i':
			init = optarg;
			break;
		case 'o':
			output = optarg;
			break;
		default:
			print_usage(argv[0]);
			return 1;
		}
	}

	if (!output) {
		fprintf(stderr, "Must specify an output file.\n");
		return 1;
	}

	FILE *out;
	if (strcmp(output, "-") == 0) {
		out = stdout;
	} else {
		out = fopen(output, "w");
		if (!out) {
			fprintf(stderr, "Unable to open '%s' for writing: %s\n",
					output, strerror(errno));
			return 1;
		}
	}

	fprintf(out, "#include <koio.h>\n\n");
	fprintf(out,
			"static struct {\n"
			"	const char *path;\n"
			"	size_t len;\n"
			"	char *data;\n"
			"} files[] = {\n");

	for (int i = optind; i < argc; ++i) {
		char *real_path = argv[i],
			*virt_path = argv[i];
		char *colon = strchr(argv[i], ':');
		if (colon) {
			*colon = '\0';
			virt_path = colon + 1;
		}
		FILE *in = fopen(real_path, "r");
		if (!in) {
			fprintf(stderr, "Unable to open '%s' for reading: %s\n",
					real_path, strerror(errno));
		}
		fseek(in, 0, SEEK_END);
		size_t len = ftell(in);
		fseek(in, 0, SEEK_SET);
		fprintf(out,
				"	{\n"
				"		.path = \"%s\",\n"
				"		.len = %zu,\n"
				"		.data =", virt_path, len);
		int cols = 1;
		int c;
		while ((c = fgetc(in)) != EOF) {
			if (cols == 1) {
				fprintf(out, "\n\"");
			}
			if (isprint(c)) {
				cols += fprintf(out, "%c", c);
			} else {
				switch (c) {
				case '\n':
					cols += fprintf(out, "\\n");
					break;
				case '\t':
					cols += fprintf(out, "\\t");
					break;
				default:
					cols += fprintf(out, "\\x%02X", c);
					break;
				}
			}
			if (cols >= 79) {
				cols = 1;
				fprintf(out, "\"");
			}
		}
		if (cols != 1) {
			fprintf(out, "\"");
		}
		fprintf(out,
				",\n"
				"	},\n");
	}
	fprintf(out, "};\n\n");

	fprintf(out, "void %s() {\n", init);
	for (int i = 0; i < argc - optind; ++i) {
		fprintf(out, "	ko_add_file(files[%d].path, "
				"files[%d].data, files[%d].len);\n", i, i, i);
	}
	fprintf(out, "}\n\n");

	fprintf(out, "void %s() {\n", deinit);
	for (int i = 0; i < argc - optind; ++i) {
		fprintf(out, "	ko_del_file(files[%d].path, "
				"files[%d].data, files[%d].len);\n", i, i, i);
	}
	fprintf(out, "}\n");

	fclose(out);
	return 0;
}