#include #include #include #include #include #include int checkonly; char *file, *contents; typedef struct Slide { char *cmd; char *arg; int nlines; char *lines[]; } Slide; char * nextline(char **p) { char *line; while(1){ line = *p; while(**p != '\n' && **p != '\0') (*p)++; if(**p == '\0') return nil; **p = '\0'; (*p)++; return line; } } Slide * nextslide(char **p) { char *cmd, *arg, *line1, *line, *lineN; int nlines, blines, i; Slide *s; while(1){ if((cmd = nextline(p)) == nil) return nil; if(cmd[0] != '%') continue; break; } cmd++; arg = cmd; while(*arg != ' ' && *arg != '\t' && *arg != '\0') arg++; if(*arg == '\0') arg = nil; else *(arg++) = '\0'; line1 = nextline(p); 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->nlines = 0; return s; } lineN = line1; nlines = 1; blines = 0; while((line = nextline(p)) != 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->nlines = nlines; line = line1; for(i = 0; line != lineN; i++){ s->lines[i] = line; line += strlen(line) + 1; } s->lines[i] = lineN; return s; } void checkfile(void) { int i; char *c2, *p; Slide *s; c2 = strdup(contents); p = c2; while((s = nextslide(&p)) != nil){ print("Slide: %s (%d lines)\n", s->cmd, s->nlines); if(s->arg != nil) print("\targ: %s\n", s->arg); for(i = 0; i < s->nlines; i++) print("\tline %d: %s\n", i, s->lines[i]); } } 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); }