stacinhtml

Static C in HTML - simple static site generator
git clone git://git.kocotian.pl/stacinhtml.git
Log | Files | Refs | README

generate.c (4865B)


      1 #include <fcntl.h>
      2 #include <string.h>
      3 #include <sys/stat.h>
      4 #include <sys/types.h>
      5 #include <unistd.h>
      6 
      7 #include "arg.h"
      8 #include "str.h"
      9 #include "util.h"
     10 
     11 /* Macros */
     12 #define $(VARNAME) getVariableValue(#VARNAME)
     13 #define DECLVAR(VARNAME, VALUE) \
     14 	(vs[vss].name.len = strlen(vs[vss].name.data = #VARNAME), \
     15 	 vs[vss].value.len = strlen(vs[vss].value.data = VALUE), \
     16 	 ++vss)
     17 #define BUFFER_SIZE 64 * 1024
     18 #define VS_MAX 256
     19 
     20 /* Types */
     21 typedef struct {
     22 	String name;
     23 	String value;
     24 } Variable;
     25 
     26 /* Prototypes */
     27 static void generateCode(int fd, String input, int c_mode);
     28 static void generateC(int fd, String input);
     29 static String getVariableValue(char *varname);
     30 static void usage(void);
     31 
     32 /* Globals */
     33 char *argv0;
     34 
     35 Variable vs[VS_MAX]; /* Variable stack */
     36 size_t vss; /* Variable stack size */
     37 
     38 /* Functions */
     39 static void
     40 generateCode(int fd, String input, int c_mode)
     41 {
     42 	if (c_mode) {
     43 		write(fd, input.data, input.len);
     44 	} else {
     45 		int i = -1;
     46 		write(fd, "write(fd, \"", 11);
     47 		while (++i < input.len) {
     48 			if (*input.data == '\n')
     49 				dprintf(fd, "\"\n\"");
     50 			dprintf(fd, "\\x%02x", *(input.data++));
     51 		}
     52 		dprintf(fd, "\", %d);", input.len);
     53 	}
     54 }
     55 
     56 static void
     57 generateC(int fd, String input)
     58 {
     59 	int c_mode, i, li;
     60 	String ibuf;
     61 	c_mode = 0;
     62 
     63 	ibuf.data = input.data;
     64 	ibuf.len = input.len;
     65 	for (i = 0; i < input.len; ++i) {
     66 		if (input.data[i] == '%') {
     67 			ibuf.len = ++i - li - 1;
     68 			generateCode(fd, ibuf, c_mode);
     69 			ibuf.data = input.data + i;
     70 			ibuf.len = input.len - i;
     71 			c_mode = !c_mode;
     72 			li = i;
     73 		}
     74 	}
     75 	generateCode(fd, ibuf, c_mode);
     76 }
     77 
     78 static String
     79 getVariableValue(char *v)
     80 {
     81 	size_t n;
     82 	String s = { .data = v, .len = strlen(v) };
     83 	n = vss;
     84 	while (--n >= 0) {
     85 		if (!Strcmp(vs[n].name, s))
     86 			return vs[n].value;
     87 	}
     88 }
     89 
     90 static void
     91 usage(void)
     92 {
     93 	die("usage: %s [-v] [-o OUTPUT] INPUT [TEMPLATE]", argv0);
     94 }
     95 
     96 /* Main */
     97 int
     98 main(int argc, char *argv[])
     99 {
    100 	/* Variables: */
    101 	/* File names and file descriptors */
    102 	char *inputfn = NULL, *outputfn = NULL, *templatefn = NULL;
    103 	int inputfd, outputfd, templatefd, viter;
    104 
    105 	/* Read bytes (from nextline()/write()) */
    106 	ssize_t rb;
    107 
    108 	/* Input data */
    109 	char input_buf[BUFFER_SIZE], idata[BUFFER_SIZE];
    110 
    111 	String input = {
    112 		.data = input_buf,
    113 		.len = 0
    114 	}, readinput, parseinput;
    115 
    116 	/* Options parsing */
    117 	ARGBEGIN {
    118 	case 'o':
    119 		outputfn = ARGF(); break;
    120 	case 'v':
    121 		die("generate-"VERSION); break;
    122 	default:
    123 		  usage(); break;
    124 	} ARGEND
    125 
    126 	/* Argument parsing */
    127 	if (argc == 1)
    128 		inputfn = argv[0];
    129 	else if (argc == 2)
    130 		templatefn = argv[1];
    131 	else
    132 		usage();
    133 
    134 	if (outputfn == NULL) /* TODO */
    135 		die("output not specified (needed in current stage)");
    136 
    137 	/* Opening an input */
    138 	if ((inputfd = open(inputfn, O_RDONLY)) < 0)
    139 		die("open (input):");
    140 
    141 	/* Zeroing first byte of input data */
    142 	*(input.data) = '\0';
    143 
    144 	/* Setting variable stack size to 0 */
    145 	vss = 0;
    146 
    147 	/* Initially, readinput points to beginning of all input */
    148 	readinput.data = input.data;
    149 	readinput.len = input.len;
    150 
    151 	/* Declaring a few variables */
    152 	DECLVAR(title, outputfn);
    153 	DECLVAR(template, templatefn == NULL ? "none" : templatefn);
    154 
    155 	/* Parsing ("preprocessing") input for variables */
    156 	if ((rb = read(inputfd, idata, BUFFER_SIZE)) < 0)
    157 		die("read (input):");
    158 
    159 	readinput.data = idata;
    160 	readinput.len  = rb;
    161 
    162 	while (Strtok(readinput, &parseinput, '\n') > 0) {
    163 		if (*(readinput.data) == '@' && *(readinput.data + 1) != '@') {
    164 			++readinput.data;
    165 			if (*(readinput.data) == '#'); /* comment */
    166 			else { /* variable */
    167 				String tok;
    168 				if (Strtok(readinput, &tok, '=') <= 0)
    169 					/* TODO: return syntax error */;
    170 				vs[vss].name.data = (idata + (parseinput.data - idata) + 1);
    171 				vs[vss].name.len = tok.len;
    172 				vs[vss].value.data = (idata + (parseinput.data - idata) + 1) + (tok.len + 1);
    173 				vs[vss].value.len = parseinput.len - (tok.len + 1) - 1;
    174 				vs[vss].name = Strtrim(vs[vss].name);
    175 				vs[vss].value = Strtrim(vs[vss].value);
    176 				++vss;
    177 			}
    178 			--readinput.data;
    179 		} else {
    180 			strncat(input.data, readinput.data, MIN(BUFFER_SIZE - input.len, parseinput.len + 1));
    181 			input.len += parseinput.len;
    182 		}
    183 		readinput.data += parseinput.len + 1;
    184 		readinput.len -= parseinput.len;
    185 	}
    186 
    187 	/* Closing an input */
    188 	close(inputfd);
    189 
    190 	/* Here will be some templates replacing */
    191 
    192 	/* Opening an output */
    193 	if ((outputfd = open(outputfn, O_WRONLY | O_CREAT, 0644)) < 0)
    194 		die("open (output):");
    195 
    196 	/* Writing beginning of main() */
    197 	write(outputfd, "#include <assemble.h>\nint main(void) {", 38);
    198 
    199 	/* Declaring variables */
    200 	for (viter = 0; viter < vss; ++viter)
    201 		dprintf(outputfd, "DECLVAR(%.*s, \"%.*s\"); ",
    202 				vs[viter].name.len,  vs[viter].name.data,
    203 				vs[viter].value.len, vs[viter].value.data);
    204 
    205 	/* And finally, generating C code to output */
    206 	generateC(outputfd, input);
    207 
    208 	/* After this, closing main() */
    209 	write(outputfd, "\n}", 2);
    210 
    211 	/* Closing an output */
    212 	close(outputfd);
    213 
    214 	return 0;
    215 }