From 2719d59866e96a3ae697a417a35540572af6ddfc Mon Sep 17 00:00:00 2001 From: Holden Rohrer Date: Tue, 12 May 2020 17:26:54 -0400 Subject: Added .LS Did a lot of code cleanup on the way because I was trying to find a bug in the new code, but it was actually in the handling of multiline inputs to wordset (now fixed). sb.* added for correct memory allocation in lineset, which, did I mention, now works. Makefile has been updated, and phrase-circuit.src can now handle line widths of about 50. --- Makefile | 11 ++++-- badroff.c | 110 +++++++++++++++++++++++++++++++++++++---------------- ll.c | 2 +- ll.h | 3 +- phrase-circuit.src | 2 +- sb.c | 88 ++++++++++++++++++++++++++++++++++++++++++ sb.h | 13 +++++++ 7 files changed, 190 insertions(+), 39 deletions(-) create mode 100644 sb.c create mode 100644 sb.h diff --git a/Makefile b/Makefile index 4c782b5..06ebd3f 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,13 @@ .POSIX: -OBJS = badroff.o buf.o ll.o +CC = gcc +CFLAGS = -O2 -Wall +OBJS = badroff.o buf.o ll.o sb.o +phrase-circuit.txt: badroff phrase-circuit.src + ./badroff phrase-circuit.src > phrase-circuit.txt badroff: $(OBJS) -badroff.o: badroff.c buf.h ll.h +badroff.o: badroff.c buf.h ll.h sb.h buf.o: buf.c buf.h ll.o: ll.c ll.h +sb.o: sb.c sb.h clean: - rm -f badroff $(OBJS) + rm -f badroff $(OBJS) phrase-circuit.txt diff --git a/badroff.c b/badroff.c index baed5a7..a1255d9 100644 --- a/badroff.c +++ b/badroff.c @@ -1,19 +1,16 @@ #include #include #include +#include #include "buf.h" +#include "sb.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"); @@ -107,38 +104,85 @@ char* leader(char* txt){ return fin; } bool endlineset = false; -char* lineset(char* txt){ +llnode* freenext(llnode* node){ + llnode* tmp = node->next; + node->next = tmp->next; + free(tmp->str); + free(tmp); + if (tmp == node) return NULL; + return node->next; +} +void multbreak(sb* buffer, size_t start, + size_t len, llnode** tail, size_t* ct){ + for (size_t i = *ct; i > 0; i--){ + char* str = (*tail)->next->str + start; + // tail->next is used so it can be gracefully freed + if (strlen(str) < len){ // if node is smaller than len, + insstr(buffer, str); // put the whole thing in the buffer + // and remove the node, switching to next + *tail = freenext(*tail); + (*ct)--; + } else { + char tmp = str[len]; + str[len] = 0; // truncate str at max length + //printf("string %s\n",str); + insstr(buffer, str); // insert that + insstr(buffer, "\n"); + str[len] = tmp; // restore string + *tail = (*tail)->next; // iter + } + } +} +llnode* accumlines(size_t* ct){ // returns tail of linked list llnode *head, *tail; head = tail = appendll(NULL, NULL); - size_t ct, len; ct = len = 0; + (*ct) = 0; while (true){ tail->next = appendll(tail, line()); if (endlineset) break; + (*ct)++; 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 + tail->next = head->next; // loop linked list free(head); + endlineset = false; // prevents false positive on next run + return tail; +} +char* lineset(char* txt){ + size_t ct; + llnode* tail = accumlines(&ct); + sb* buf = newsb(100); - 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; + size_t oldbrk = 0, brk = 0; + for (size_t i = 0; tail; i++){ // check every column until all rows + // are removed. + bool valid = true; // if stays true, this is a space + bool done = true; // if stays true, all strings are complete + llnode* orig = tail; + do { // check every string + if (tail->end) goto iter; + if (tail->str[i] == 0){ + tail->end = true; + goto iter; + } // ignore strings that have already finished + done = false; + if (tail->str[i] != ' ') + valid = false; + // doesn't break because tail needs to return to orig + iter: + tail = tail->next; + } while (tail != orig); + if (valid) brk = i; + //printf("brk %d\n",brk); + if (done || (!valid && i-oldbrk >= width)){ + // either all strings are done + // or it has hit a non-space column and accum enough space + multbreak(buf, oldbrk, brk-oldbrk+1, &tail, &ct); + oldbrk = brk+1; // tells offset from previous cut + } } - 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); + + char* lines = decompose(buf); return lines; } char* finlineset(char* txt){ @@ -182,7 +226,7 @@ char* cmd(void){ void wsclean(char* txt){ size_t disp = 0; - int firstws; + size_t firstws = 0; for (size_t i = 0; i == 0 || txt[i-1] != 0; i++){ if ( (txt[i] == ' ' || txt[i] == '\n') && txt[i-1] != ' '){ firstws = i; @@ -195,11 +239,12 @@ void wsclean(char* txt){ } char* wordset(char* txt){ - char* orig = txt; + char* orig = txt; // txt will be manipulated 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){ + if (txt[i] == ' ' || txt[i] == '\n') ws = i; + // nl's (multiline input) and spaces are proper linebreaks + if (txt[i] == '\n' || (i >= width && ws != i) ){ txt += ws; txt[0] = '\n'; ws = width; @@ -207,7 +252,7 @@ char* wordset(char* txt){ } } - wsclean(orig); + wsclean(orig); // remove trailing whitespace return orig; } @@ -238,7 +283,6 @@ char* line(void){ // orchestration int main(int argc, char** argv){ - int c; in = getfile(argc, argv); inbuf = newbuf(256); if (in == NULL){ diff --git a/ll.c b/ll.c index d929b2f..40c5f99 100644 --- a/ll.c +++ b/ll.c @@ -5,6 +5,6 @@ llnode* appendll(llnode* tail, char* str){ llnode* new = malloc(sizeof(llnode)); if (tail != NULL) tail->next = new; new->str = str; - new->loc = 0; + new->end = 0; return new; } diff --git a/ll.h b/ll.h index be85ccb..2646715 100644 --- a/ll.h +++ b/ll.h @@ -1,9 +1,10 @@ #ifndef _LL_INCLUDE #define _LL_INCLUDE +#include typedef struct llnode { char* str; - int loc; + bool end; struct llnode* next; } llnode; diff --git a/phrase-circuit.src b/phrase-circuit.src index 37e1b60..cf72556 100644 --- a/phrase-circuit.src +++ b/phrase-circuit.src @@ -1,4 +1,4 @@ -.W 72 +.W 60 .V 10 .CT Holden Rohrer .V 2 diff --git a/sb.c b/sb.c new file mode 100644 index 0000000..06ee8d9 --- /dev/null +++ b/sb.c @@ -0,0 +1,88 @@ +#include +#include + +#include "sb.h" + +struct sb { + sbnode* head; + sbnode* tail; + size_t loc; + size_t sz; +}; + +struct sbnode { + char* str; + sbnode* next; +}; + +sbnode* newsbnode(sbnode* prev, size_t sz){ + sbnode* node = malloc(sizeof(sbnode)); // Allocate + node->str = malloc(sizeof(char)*(sz+1)); node->str[sz] = 0; + node->next = NULL; // Init + if (prev) prev->next = node; // Link + return node; +} + +sb* newsb(size_t sz){ + sb* out = malloc(sizeof(sb)); + out->head = out->tail = newsbnode(NULL, sz); + out->sz = sz; + out->loc = 0; + return out; +} + +void extendsb(sb* buf){ + buf->sz *= 2; + buf->loc = 0; + buf->tail = newsbnode(buf->tail, buf->sz); +} + +void insstr(sb* buf, char* str){ + size_t rem = strlen(str); // remaining chars to push + while (rem > (buf->sz - buf->loc)){ // while buffer has less room + // than needed, fill the buffer with str + memcpy(buf->tail->str+buf->loc, str, buf->sz - buf->loc); + // move the string pointer by that amount + str += buf->sz - buf->loc; + // reduce the number of remaining characters by that amount + rem -= buf->sz - buf->loc; + // and add a new node, resetting buf->loc + extendsb(buf); + } + // copy the rest into the buffer + memcpy(buf->tail->str+buf->loc, str, rem); + // and advance buf->loc + buf->loc += rem; +} + +sbnode* freenodenext(sbnode* node){ + sbnode* out = node->next; + free(node->str); + free(node); + return out; +} + +char* decompose(sb* buf){ + // Make the last node a proper string + buf->tail->str[buf->loc] = 0; + // Start with the length of the last node + size_t len = 0; + // For every non-tail node (cur->next == NULL for it), + for (sbnode* cur = buf->head; cur != NULL; cur = cur->next){ + // add the length of its string + len += strlen(cur->str); + } + // make a string to fit it all + char* str = malloc(sizeof(char)*(len+1)); str[len] = 0; + // and its iterator + char* pos = str; + // for every node, + for (sbnode* cur = buf->head; cur != NULL; cur = freenodenext(cur)){ + size_t slen = strlen(cur->str); + memcpy(pos, cur->str, slen); // copy + pos += slen; + } + free(buf); + return str; +} + diff --git a/sb.h b/sb.h new file mode 100644 index 0000000..4ab78b7 --- /dev/null +++ b/sb.h @@ -0,0 +1,13 @@ +#ifndef __SB_H__ +#define __SB_H__ + +typedef struct sb sb; +typedef struct sbnode sbnode; + +sb* newsb(size_t sz); + +void insstr(sb* buf, char* str); + +char* decompose(sb* buf); + +#endif -- cgit