commit 682cab4976ad367d532c5d47e73bab73ade40024
Author: Quentin Rameau <quinq@fifth.space>
Date: Mon, 9 Nov 2015 09:46:55 +0100
Initial commit
Diffstat:
Makefile | | | 38 | ++++++++++++++++++++++++++++++++++++++ |
addrom.c | | | 205 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
arg.h | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
config.mk | | | 14 | ++++++++++++++ |
4 files changed, 320 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,38 @@
+include config.mk
+
+SRC = addrom.c
+OBJ = ${SRC:.c=.o}
+
+all: options addrom
+
+options:
+ @echo addrom build options:
+ @echo "CFLAGS = ${CFLAGS}"
+ @echo "LDFLAGS = ${LDFLAGS}"
+ @echo "CC = ${CC}"
+
+.c.o:
+ @echo CC $<
+ @${CC} -c ${CFLAGS} $<
+
+${OBJ}: config.mk
+
+addrom: ${OBJ}
+ @echo CC -o $@
+ @${CC} -o $@ ${OBJ} ${LDFLAGS}
+
+clean:
+ @echo cleaning
+ @rm -f addrom ${OBJ}
+
+install: all
+ @echo installing executable file to ${DESTDIR}${PREFIX}/bin
+ @mkdir -p ${DESTDIR}${PREFIX}/bin
+ @cp -f addrom ${DESTDIR}${PREFIX}/bin
+ @chmod 755 ${DESTDIR}${PREFIX}/bin/addrom
+
+uninstall:
+ @echo removing executable file from ${DESTDIR}${PREFIX}/bin
+ @rm -f ${DESTDIR}${PREFIX}/bin/addrom
+
+.PHONY: all options clean install uninstall
diff --git a/addrom.c b/addrom.c
@@ -0,0 +1,205 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "arg.h"
+
+#define HEADERSZSZ 4
+#define GAMECNTSZ 4
+#define HEADERSZ 16
+#define CHTITLESZ 64
+#define ENTITLESZ 32
+#define ROMNAMESZ 16
+#define MAGICSZ 8
+#define ENTRYSZ (CHTITLESZ + ENTITLESZ + ROMNAMESZ + MAGICSZ)
+
+#define MAGIC 0x0000000000000000
+
+typedef struct {
+ char *chtitle;
+ char *entitle;
+ char *romname;
+} Rom;
+
+char *argv0;
+static char *in, *out;
+static intmax_t place;
+
+static void
+die(const char *errstr, ...)
+{
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
+static void
+addrom(char *datfile, const Rom *rom)
+{
+ ssize_t pos = 0;
+
+ if (rom->chtitle)
+ strncpy(datfile + pos, rom->chtitle, CHTITLESZ);
+ pos += CHTITLESZ;
+ if (rom->entitle)
+ strncpy(datfile + pos, rom->entitle, ENTITLESZ);
+ pos += ENTITLESZ;
+ if (rom->romname)
+ strncpy(datfile + pos, rom->romname, ROMNAMESZ);
+ pos += ROMNAMESZ;
+ *(uint64_t *)(datfile + pos) = MAGIC;
+}
+
+/* not used
+static uint64_t
+getgamecount(int n)
+{
+ return (n * 0x88888889) >> 32 >> 6;
+}
+*/
+
+static uint32_t
+setgamecount(uint64_t n)
+{
+ return (n << 32 << 6) / 0x88888888;
+}
+
+static void
+ereadinfile(char *datbuf, const ssize_t size, FILE *infile)
+{
+ if (fread(datbuf, 1, size, infile) != size)
+ die("Couldn't read %zu bytes of input file %s\n", size, in);
+}
+
+static void
+usage(void)
+{
+ die("usage: %s [-c chinesetitle] [-e englishtitle] -i inputlist "
+ "[-n placeinlist] -o outputlist -r romname\n", basename(argv0));
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stat st;
+ Rom rom = { 0 };
+ off_t infilesize;
+ size_t outbufsize;
+ ssize_t offset;
+ FILE *infile, *outfile;
+ char *outbuf;
+ int infd;
+
+ ARGBEGIN {
+ case 'c':
+ rom.chtitle = EARGF(usage());
+ if (strlen(rom.chtitle) > CHTITLESZ)
+ die("Chinese title must be less then than %zu bytes\n",
+ CHTITLESZ);
+ break;
+ case 'e':
+ rom.entitle = EARGF(usage());
+ if (strlen(rom.entitle) > ENTITLESZ)
+ die("English title must be less then than %zu bytes\n",
+ ENTITLESZ);
+ break;
+ case 'i':
+ in = EARGF(usage());
+ break;
+ case 'n':
+ place = strtoimax(EARGF(usage()), NULL, 10);
+ if (place < 1)
+ die("Place must be superior to 0\n");
+ break;
+ case 'o':
+ out = EARGF(usage());
+ break;
+ case 'r':
+ rom.romname = EARGF(usage());
+ if (strlen(rom.romname) > ROMNAMESZ)
+ die("Rom name must be less then than %zu bytes\n",
+ ROMNAMESZ);
+ break;
+ default:
+ usage();
+ break;
+ } ARGEND
+
+ if (!in || !out || !rom.romname)
+ usage();
+
+ if (access(out, F_OK) != -1)
+ die("Output file %s exists and will not be overwritten\n",
+ out);
+
+ if ((infd = open(in, O_RDONLY)) == -1)
+ die("Can't open input file %s\n", in);
+
+ if (fstat(infd, &st) == -1 || !S_ISREG(st.st_mode))
+ die("File %s is not a regular file\n", in);
+
+ if ((infilesize = st.st_size) < HEADERSZ)
+ die("Corrupted input file %s\n", in);
+
+ if (!(infile = fdopen(infd, "r")))
+ die("Can't open input file %s\n", in);
+
+ outbufsize = infilesize + ENTRYSZ;
+
+ if (!(outbuf = calloc(outbufsize, 1)))
+ die("Can't allocate enough memory for reading input file\n");
+/*
+ if (place * ENTRYSZ + HEADERSZ > infilesize)
+ place = 0;
+
+ offset = place ? HEADERSZ + (place - 1) * ENTRYSZ : infilesize;
+*/
+ if (place == 0 || place * ENTRYSZ + HEADERSZ > infilesize)
+ offset = infilesize;
+ else
+ offset = HEADERSZ + (place - 1) * ENTRYSZ;
+
+ ereadinfile(outbuf, offset, infile);
+
+ *(uint32_t *)(outbuf + HEADERSZSZ) = setgamecount(
+ (infilesize - HEADERSZ) / ENTRYSZ + 1);
+
+ addrom(outbuf + offset, &rom);
+
+ ereadinfile(outbuf + offset + ENTRYSZ, infilesize - offset, infile);
+
+ if (!(outfile = fopen(out, "w")))
+ die("Can't open output file %s\n", out);
+
+ if (fwrite(outbuf, 1, outbufsize, outfile) !=
+ outbufsize)
+ die("Couldn't write all data to output file %s\n", out);
+
+ free(outbuf);
+
+ if (fclose(infile) == EOF)
+ die("There was an error while closing input file %s\n", in);
+
+ /* already closed by fclose()
+ if (close(infd) == -1)
+ die("There was an error while closing input file %s\n", in);
+ */
+
+ if (fclose(outfile) == EOF)
+ die("There was an error while closing output file %s\n", out);
+
+ return(0);
+}
diff --git a/arg.h b/arg.h
@@ -0,0 +1,63 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef ARG_H__
+#define ARG_H__
+
+extern char *argv0;
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][1]\
+ && argv[0][0] == '-';\
+ argc--, argv++) {\
+ char argc_;\
+ char **argv_;\
+ int brk_;\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk_ = 0, argv[0]++, argv_ = argv;\
+ argv[0][0] && !brk_;\
+ argv[0]++) {\
+ if (argv_ != argv)\
+ break;\
+ argc_ = argv[0][0];\
+ switch (argc_)
+
+/* Handles obsolete -NUM syntax */
+#define ARGNUM case '0':\
+ case '1':\
+ case '2':\
+ case '3':\
+ case '4':\
+ case '5':\
+ case '6':\
+ case '7':\
+ case '8':\
+ case '9'
+
+#define ARGEND }\
+ }
+
+#define ARGC() argc_
+
+#define ARGNUMF(base) (brk_ = 1, strtol(argv[0], NULL, (base)))
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ (char *)0 :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#endif
diff --git a/config.mk b/config.mk
@@ -0,0 +1,14 @@
+# paths
+PREFIX = /usr/local
+
+# includes and libs
+INCS = -I. -I/usr/include
+LIBS = -L/usr/lib
+
+# flags
+CPPFLAGS += -D_POSIX_SOURCE
+CFLAGS += -std=c99 -pedantic -Wall -Os -s ${INCS} ${CPPFLAGS}
+LDFLAGS += -s ${LIBS}
+
+# compiler and linker
+# CC = cc