#include #include #include #include #include #include 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); }