#include #include "buf.h" #include #include typedef enum { false, true } bool; FILE* getfile(int argc, char** argv){ if (argc >= 2) return fopen(argv[1], "r"); else return stdin; } char* chrmult(char c, size_t ct){ char* str = malloc(sizeof(char)*(ct+1)); str[ct] = 0; memset(str, c, ct); return str; } // file read & buffer fill helpers FILE* in; buf* inbuf; size_t fillbuf(size_t len){ // returns real len int c; size_t set; for (set = buflen(inbuf); set < len && (c = fgetc(in)) != EOF;set++) inschrbuf(inbuf, c); return set; } size_t chrfill(char chr){ size_t line; size_t len = buflen(inbuf); char* str = peekstrbuf(inbuf, 0, len); for (line = 0; line < len; line++) if (str[line] == chr) return line+1; for (int c = 0; c != chr && (c = fgetc(in)) != EOF; line++) inschrbuf(inbuf, c); return line; } // typesetting config and commands to change. int width = 80; bool brk = false; // not implemented char* center(char* txt){ size_t len = strlen(txt); int max = width/2 + len/2; // excluding terminator int min = max-len+1; // first index of *txt char* str = malloc(sizeof(char)*(max + 1)); memset(str, ' ', min); memcpy(str+min, txt, len); str[max] = 0; return str; } char* setwidth(char* txt){ sscanf(txt, "%d", &width); return NULL; } char* cmds[] = {"CT ", "W "}; char* (*call[])(char* txt) = {center, setwidth}; char* cmd(void){ char* dat = popstrbuf(inbuf, chrfill('\n')); size_t low = 0; size_t high = sizeof(cmds)/sizeof(*cmds); //len while (high >= low){ int mid = ((unsigned int)low + (unsigned int)high) >> 1; char* mval = cmds[mid]; int cmp = strncmp(dat, mval, strlen(mval)); if (cmp < 0) // dat < mval high = mid - 1; else if (cmp > 0) low = mid + 1; else return call[mid](dat+strlen(mval)); } return NULL; } // normal typesetting char* cleanup(char* line){ // cleans up trailing whitespace && ^\n$ for (ws = len-1; line[ws] == ' '; ws--, len--); // rethink if (ws < len-1){ line[ws] = '\n' line[ws+1] = '\0'; } else if (line[len-1] != '\n'){ len++; line = realloc(line, len); } if (line[len-1] != '\n'){ line[len-1] = '\n'; line[len] = '\0'; } return line; } char* fold(char* line){ // inserts \n to limit line length } char* typeset(void){ size_t len; size_t nl; for (nl = 0; (len = chrfill('\n')) == 1; nl++) popstrbuf(inbuf, len); if (nl) return chrmult('\n', nl+1); char* line = popstrbuf(inbuf, len); size_t ws; line = cleanup(line); if (brk && line[len-1] == '\n') line[len-1] = ' '; if (brk) for (; *line == ' '; line++); //remove preceding whitespace return fold(line); } // a parser to choose when to typeset and when to run a command char* line(void){ size_t sz; if ( (sz = fillbuf(2)) == 0) return ""; char* twobytes = peekstrbuf(inbuf, 0, 2); // .., .\n, or ^.? if (sz == 1 || twobytes[1] == '\n') return typeset(); if (twobytes[0] == '.') popchrbuf(inbuf); if (twobytes[0] == '.' && twobytes[1] != '.'){ char* data = cmd(); if (data) return data; return line(); } else { return typeset(); } } // orchestration int main(int argc, char** argv){ int c; in = getfile(argc, argv); inbuf = newbuf(256); if (in == NULL){ perror(argv[1]); return 1; } char* out; while ( (out = line())[0] != '\0'){ printf("%s",out); } fclose(in); return 0; }