#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "db_sql_codegen.h"
extern int getopt(int, char *const [], const char *);
static int usage(char *);
static char * change_extension(char *path, char *extension);
static int read_and_parse(FILE *fp);
char *progname = "db_sql";
int line_number = 0;
int debug = 0;
int txnflag = 0;
int
main(argc,argv)
int argc;
char **argv;
{
extern char *optarg;
extern int optind;
int opt, free_ofilename, free_hfilename;
FILE *ifile, *hfile, *ofile, *tfile, *vfile;
char *ifilename, *hfilename, *ofilename, *tfilename, *vfilename;
ifilename = hfilename = ofilename = tfilename = vfilename = NULL;
free_ofilename = free_hfilename = 0;
progname = argv[0];
while ((opt = getopt(argc, argv, "i:t:o:h:dv:x")) != -1) {
switch (opt) {
case 'i':
ifilename = optarg;
break;
case 'h':
hfilename = optarg;
break;
case 'o':
ofilename = optarg;
break;
case 't':
tfilename = optarg;
break;
case 'd':
debug = 1;
break;
case 'v':
vfilename = optarg;
break;
case 'x':
txnflag = 1;
break;
default:
return (usage(0));
}
}
argc -= optind;
argv += optind;
if (argc != 0) {
fprintf(stderr,
"extra argument %s after switch arguments\n", *argv);
return (usage(0));
}
if (ifilename == NULL)
ifile = stdin;
else
if ((ifile = fopen(ifilename, "r")) == NULL)
return (usage(ifilename));
if (ofilename == NULL && ifilename != NULL) {
ofilename = change_extension(ifilename, "c");
free_ofilename = 1;
}
if (ofilename == NULL)
ofile = stdout;
else
if ((ofile = fopen(ofilename, "w")) == NULL)
return (usage(ofilename));
if (hfilename == NULL && ofilename != NULL) {
hfilename = change_extension(ofilename, "h");
free_hfilename = 1;
}
if (hfilename == NULL)
hfile = stdout;
else
if ((hfile = fopen(hfilename, "w")) == NULL)
return (usage(hfilename));
if (tfilename == NULL)
tfile = 0;
else {
if (hfilename == NULL) {
fprintf(stderr,
"Can't produce test when streaming to stdout\n");
return (usage(0));
}
if ((tfile = fopen(tfilename, "w")) == NULL)
return (usage(tfilename));
}
if (vfilename == NULL)
vfile = 0;
else {
if (hfilename == NULL) {
fprintf(stderr,
"Can't produce verify when streaming to stdout\n");
return (usage(0));
}
if ((vfile = fopen(vfilename, "w")) == NULL)
return (usage(vfilename));
}
if (read_and_parse(ifile))
exit(1);
generate(hfile, ofile, tfile, vfile, hfilename);
if (free_ofilename)
free(ofilename);
if (free_hfilename)
free(hfilename);
return 0;
}
static char *
scan_for_rightmost_semicolon(p)
char *p;
{
static enum scanner_state {
IDLE = 0, GOT_SLASH = 1, IN_SLASHSTAR_COMMENT = 2,
GOT_STAR = 3, GOT_HYPHEN = 4, IN_HYPHHYPH_COMMENT = 5
} state = IDLE;
char *result;
result = NULL;
if (p == NULL || *p == '\0')
return result;
do {
switch (state) {
case IDLE:
switch (*p) {
case '/': state = GOT_SLASH; break;
case '*': state = GOT_STAR; break;
case '-': state = GOT_HYPHEN; break;
}
break;
case GOT_SLASH:
switch (*p) {
case '*': state = IN_SLASHSTAR_COMMENT; break;
default: state = IDLE;
}
break;
case IN_SLASHSTAR_COMMENT:
switch (*p) {
case '*': state = GOT_STAR; break;
}
break;
case GOT_STAR:
switch (*p) {
case '/': state = IDLE; break;
default: state = IN_SLASHSTAR_COMMENT; break;
}
break;
case GOT_HYPHEN:
switch (*p) {
case '-': state = IN_HYPHHYPH_COMMENT; break;
default: state = IDLE; break;
}
case IN_HYPHHYPH_COMMENT:
switch (*p) {
case '\n': state = IDLE; break;
}
break;
}
if (state == IDLE && *p == ';')
result = p;
} while (*p++);
return result;
}
static int
read_and_parse(fp)
FILE *fp;
{
size_t line_len, copy_len, collector_len;
char *q, *collector, buf[256], *err_msg;
collector = 0;
collector_len = 0;
err_msg = 0;
for (line_number = 1; fgets(buf, sizeof(buf), fp) != 0; line_number++) {
line_len = strlen(buf);
if (1 + strlen(buf) == sizeof(buf)) {
fprintf(stderr, "%s: line %d is too long", progname,
line_number);
return 1;
}
if ((q = scan_for_rightmost_semicolon(buf)) != NULL)
copy_len = 1 + q - buf;
else
copy_len = line_len;
collector_len += 1 + copy_len;
if (collector == NULL)
collector = calloc(1, collector_len);
else
collector = realloc(collector, collector_len);
strnconcat(collector, collector_len, buf, copy_len);
if (q != 0) {
if (do_parse(collector, &err_msg) != 0) {
fprintf(stderr,
"parsing error at line %d : %s\n",
line_number, err_msg);
return 1;
}
collector_len = 1 + line_len - copy_len;
collector = realloc(collector, collector_len);
memcpy(collector, buf + copy_len, collector_len);
assert(collector[collector_len-1] == 0);
}
}
if (collector != 0) {
if (strlen(collector) > 0 &&
do_parse(collector, &err_msg) != 0) {
fprintf(stderr, "parsing error at end of file: %s\n",
err_msg);
return 1;
}
free (collector);
}
return 0;
}
static char *
final_component_of(path)
char *path;
{
char *p;
p = strrchr(path, '/');
if (p == NULL)
p = strrchr(path, '\\');
if (p != NULL)
return p + 1;
return path;
}
static char *
change_extension(path, extension)
char *path, *extension;
{
size_t path_len, copy_len;
char *p, *copy;
const char dot = '.';
p = final_component_of(path);
if (*p != 0)
p++;
if (strrchr(p, dot) != 0) {
p = strrchr(path, dot);
path_len = p - path;
} else
path_len = strlen(path);
copy_len = 2 + path_len + strlen(extension);
copy = malloc(copy_len);
memcpy(copy, path, path_len);
copy[path_len] = 0;
strconcat(copy, copy_len, ".");
strconcat(copy, copy_len, extension);
return copy;
}
static int
usage(char *error_tag) {
if (error_tag != 0)
perror(error_tag);
fprintf(stderr, "\
Usage: %s [-i inputFile] [-h outputHeaderFile] [-o outputFile] \
[-t testOutputFile] [-d] [-v verificationOutputFile] [-x]\n",
progname);
return (1);
}