diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | badroff.c | 119 | ||||
-rw-r--r-- | ll.c | 10 | ||||
-rw-r--r-- | ll.h | 12 |
4 files changed, 97 insertions, 49 deletions
@@ -1,7 +1,8 @@ .POSIX: -OBJS = badroff.o buf.o +OBJS = badroff.o buf.o ll.o badroff: $(OBJS) -badroff.o: badroff.c buf.h +badroff.o: badroff.c buf.h ll.h buf.o: buf.c buf.h +ll.o: ll.c ll.h clean: rm -f badroff $(OBJS) @@ -3,6 +3,11 @@ #include <stdlib.h> #include "buf.h" +#include "ll.h" + +char* line(void); +char* wordset(char* txt); +void wsclean(char* txt); typedef enum { false, @@ -101,11 +106,51 @@ char* leader(char* txt){ fin[i] = repeat[i % rptln]; return fin; } +bool endlineset = false; +char* lineset(char* txt){ + llnode *head, *tail; head = tail = appendll(NULL, NULL); + size_t ct, len; ct = len = 0; + while (true){ + tail->next = 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* cmds[] = - {"CT ", "FIL ", "LD ", "W "}; // MUST be sorted alphabetically +char* cmds[] = // MUST be sorted alphabetically + {"CT ", "ELS", "FIL ", "LD ", "LS", "W "}; char* (*call[])(char* txt) = - {center, fillline, leader, setwidth}; + {center, finlineset, fillline, leader, lineset, setwidth}; char* cmd(void){ char* dat = popstrbuf(inbuf, chrfill('\n')); @@ -131,62 +176,42 @@ char* cmd(void){ // normal typesetting -bool cont_typst = false; // communicates with line() for broken lines. - -size_t nextws(size_t start){//searches for \n or [^ \n]-1 in buffer - //starts at `start` (if not whitespace, returns start-1) - size_t len = buflen(inbuf); - char* str = peekstrbuf(inbuf, start, len-start); - size_t i; - for (i = 0; i<len-start; i++){ - if (str[i] == '\n') return start+i; - else if (str[i] != ' ') return start+i-1; +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]; } - free(str); - for (int c = 0; c != '\n' && ( c = addchr() ) != EOF && c == ' '; - len++); // if this is a newline, exit late (len is last, !(len-1)). - return len; } -char* wordtypeset(char* txt){ // always ends with \n - size_t len = strlen(txt); +char* wordset(char* txt){ + char* orig = txt; size_t ws = width; - for (size_t i=0; i<len; i++){ // turn into a nested loop - if (i == ' ') ws = i; - if (i > width){ - txt[ws] = '\n'; + 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; - len -= ws; + txt[0] = '\n'; ws = width; + i = 0; } } - return txt; + wsclean(orig); + + return orig; } + char* typeset(void){ size_t len = chrfill('\n'); - return wordtypeset(popstrbuf(inbuf, len)); - /*size_t len = chrnfill('\n', width+1); //+1 for \n on 81-char lines - char* next = peekstrbuf(inbuf, 0, len); - size_t wsend = 0; - if (next[--len] == '\n'){ - wsend = len; - } else if (next[len] == ' '){ - wsend = nextws(len); - } - else for (wsend = len; next[wsend] != ' '; wsend--); - // wsend is last index with a piece of whitespace - for (len = min(wsend,len-1); next[len] == ' '; len--); - // check, within the string, behind the whitespace for a letter. - if (next[len] == '\n') len--; // "\n" shouldn't become "\n\n" - // len should be *index of* last letter - if (peekchrbuf(inbuf, wsend) == '\n') cont_typst = false; - else cont_typst = true; - free(next); - char* ln = popstrbuf(inbuf, wsend+1); - ln[len+1] = '\n'; ln[len+2] = 0; - return ln;*/ + return wordset(popstrbuf(inbuf, len)); } // a parser to choose when to typeset and when to run a command @@ -196,7 +221,7 @@ char* line(void){ if ( (sz = fillbuf(2)) == 0) return ""; char* twobytes = peekstrbuf(inbuf, 0, 2); // .., .\n, or ^.? - if (sz == 1 || twobytes[1] == '\n' || cont_typst) return typeset(); + if (sz == 1 || twobytes[1] == '\n') return typeset(); if (twobytes[0] == '.') popchrbuf(inbuf); if (twobytes[0] == '.' && twobytes[1] != '.'){ char* data = cmd(); @@ -0,0 +1,10 @@ +#include <stdlib.h> +#include "ll.h" + +llnode* appendll(llnode* tail, char* str){ + llnode* new = malloc(sizeof(llnode)); + if (tail != NULL) tail->next = new; + new->str = str; + new->loc = 0; + return new; +} @@ -0,0 +1,12 @@ +#ifndef _LL_INCLUDE +#define _LL_INCLUDE + +typedef struct llnode { + char* str; + int loc; + struct llnode* next; +} llnode; + +llnode* appendll(llnode* tail, char* str); + +#endif |