#include #include #include #include "buf.h" #include "ll.h" char* line(void); char* wordset(char* txt); void wsclean(char* txt); 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; int addchr(void){ int c = fgetc(in); if (c != EOF) inschrbuf(inbuf, c); return c; } size_t fillbuf(size_t len){ // returns real len int c; size_t set; for (set = buflen(inbuf); set < len && (c = addchr()) != EOF;set++); return set; } size_t chrfill(char chr){ size_t len = buflen(inbuf); char* str = peekstrbuf(inbuf, 0, len); char* line = memchr(str,chr,len); free(str); if (line) return line-str+1; for (int c = 0; c != chr && (c = addchr()) != EOF; len++); return len; } #define min(a,b) a < b ? a : b size_t chrnfill(char chr, size_t sz){//fills to first of chr or sz size_t len = buflen(inbuf); size_t lim = min(len,sz); char* str = peekstrbuf(inbuf, 0, lim); char* line = memchr(str, chr, lim); free(str); if (line) return line-str+1; for (int c = 0; c != chr && (c = addchr()) != EOF&& lennext = appendll(tail, line()); if (endlineset) break; tail = tail->next; ct++; len += strlen(tail->str); } free(tail->next->str); free(tail->next); //.ELS cmd tail = tail->next = head->next; // loop linked list free(head); char *lines, *pos; lines = malloc((sizeof(char)*(len+1))); // construct lines int jmp; for (pos = lines; pos-lines < len; pos += jmp, tail = tail->next){ char* str = tail->str + tail->loc; char* loc = memchr(str, '\n', strlen(str)); jmp = (loc == NULL) ? 0 : loc-str+1; memcpy(pos, str, jmp); tail->loc += jmp; } llnode* last = NULL; /*for (size_t i = 0; i<=ct; i++, last = tail, tail = tail->next){ free(tail->str); free(last); }*/ endlineset = false; wsclean(lines); return lines; } char* finlineset(char* txt){ char* str = malloc(sizeof(char)); str[0] = 0; endlineset = true; return str; } char* vert(char* txt){ int ln; sscanf(txt, "%d", &ln); return chrmult('\n', ln); } char* cmds[] = // MUST be sorted alphabetically {"CT ", "ELS", "FIL ", "LD ", "LS", "V ", "W "}; char* (*call[])(char* txt) = {center, finlineset, fillline, leader, lineset, vert, setwidth}; char* cmd(void){ char* dat = popstrbuf(inbuf, chrfill('\n')); size_t low = 0; size_t high = sizeof(cmds)/sizeof(*cmds); //len char* proc = NULL; 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{ proc = call[mid](dat+strlen(mval)); break; } } free(dat); return proc; } // normal typesetting void wsclean(char* txt){ size_t disp = 0; int firstws; for (size_t i = 0; i == 0 || txt[i-1] != 0; i++){ if ( (txt[i] == ' ' || txt[i] == '\n') && txt[i-1] != ' '){ firstws = i; } if (txt[i] == '\n'){ disp += i-firstws; } txt[i-disp] = txt[i]; } } char* wordset(char* txt){ char* orig = txt; size_t ws = width; for (size_t i=0; txt[i] != 0; i++){ // turn into a nested loop if (txt[i] == ' ') ws = i; if (i >= width && ws != i){ txt += ws; txt[0] = '\n'; ws = width; i = 0; } } wsclean(orig); return orig; } char* norm(void){ return popstrbuf(inbuf, chrfill('\n')); } // 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 norm(); if (twobytes[0] == '.') popchrbuf(inbuf); if (twobytes[0] == '.' && twobytes[1] != '.'){ char* data = cmd(); if (data) return data; return line(); } else { return norm(); } } // 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",wordset(out)); free(out); } fclose(in); return 0; }