#include <u.h>
#include <libc.h>
#include <stdio.h>
#include <draw.h>
#include <event.h>
#include <cursor.h>
int checkonly;
char *file, *contents;
typedef struct Slide {
char *cmd;
char *arg;
int linum;
int nlines;
char *lines[];
} Slide;
char *
nextline(char **p, int *linum)
{
char *line;
while(1){
(*linum)++;
line = *p;
while(**p != '\n' && **p != '\0') (*p)++;
if(**p == '\0')
return nil;
**p = '\0';
(*p)++;
return line;
}
}
Slide *
nextslide(char **p, int *linum)
{
char *cmd, *arg, *line1, *line, *lineN;
int nlines, blines, i, slinum;
Slide *s;
while(1){
if((cmd = nextline(p, linum)) == nil)
return nil;
if(cmd[0] != '%')
continue;
break;
}
slinum = *linum;
cmd++;
arg = cmd;
while(*arg != ' ' && *arg != '\t' && *arg != '\0') arg++;
if(*arg == '\0')
arg = nil;
else{
*(arg++) = '\0';
while(*arg == ' ' && *arg == '\t' && *arg != '\0') arg++;
if(*arg == '\0')
arg = nil;
}
line1 = nextline(p, linum);
if(line1 != nil && *line1 == '%'){
*p = line1;
line1[strlen(line1)] = '\n';
line1 = nil;
}
if(line1 == nil){
s = malloc(sizeof(Slide));
s->cmd = cmd;
s->arg = arg;
s->linum = slinum;
s->nlines = 0;
return s;
}
lineN = line1;
nlines = 1;
blines = 0;
while((line = nextline(p, linum)) != nil){
if(*line == '\0'){
blines++;
continue;
}
if(*line == '%'){
*p = line;
line[strlen(line)] = '\n';
break;
}
nlines += blines;
blines = 0;
nlines++;
lineN = line;
}
s = malloc(sizeof(Slide) + sizeof(char*) * nlines);
s->cmd = cmd;
s->arg = arg;
s->linum = slinum;
s->nlines = nlines;
line = line1;
for(i = 0; line != lineN; i++){
s->lines[i] = line;
line += strlen(line) + 1;
}
s->lines[i] = lineN;
return s;
}
#pragma varargck argpos checkerr 2
void
checkerr(Slide *s, char *msg, ...)
{
va_list args;
va_start(args, msg);
fprint(2,"%s:%d: %s: ", file, s->linum, s->cmd);
vfprint(2,msg, args);
fprint(2,"\n");
}
void
checkfile(void)
{
int waserr, linum;
char *c2, *p;
Slide *s;
waserr = 0;
linum = 0;
c2 = strdup(contents);
p = c2;
while((s = nextslide(&p, &linum)) != nil){
if(strcmp(s->cmd, "") == 0)
continue;
else if(strcmp(s->cmd, "bullet") == 0)
continue;
else if(strcmp(s->cmd, "blank") == 0)
continue;
else if(strcmp(s->cmd, "text") == 0)
continue;
else if(strcmp(s->cmd, "title") == 0){
if(s->arg == nil){
waserr = 1;
checkerr(s, "missing arg");
}
}else{
waserr = 1;
checkerr(s, "unknown cmd");
}
}
if(waserr)
exits("checkfile");
}
void
usage(void)
{
fprint(2,"usage: %s [ -c ] filename\n", argv0);
exits("usage");
}
void
main(int argc, char *argv[])
{
int fd;
Dir *d;
ARGBEGIN{
case 'c':
checkonly = 1;
break;
default:
usage();
}ARGEND
if(argc != 1)
usage();
file = argv[0];
if((fd = open(file, OREAD)) < 0)
sysfatal("%r");
if((d = dirfstat(fd)) == nil)
sysfatal("%r");
contents = malloc(d->length + 2);
if(readn(fd, contents, d->length) < 0)
sysfatal("%r");
// cursed but makes the handling nicer above
contents[d->length] = '\n';
contents[d->length + 1] = '\0';
free(d);
close(fd);
checkfile();
if(checkonly)
exits(nil);
}