aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHolden Rohrer <hr@hrhr.dev>2020-05-12 17:26:54 -0400
committerHolden Rohrer <hr@hrhr.dev>2020-05-12 17:26:54 -0400
commit2719d59866e96a3ae697a417a35540572af6ddfc (patch)
tree259a69e1cdb4e9de51f89c5301c22b43be2ed8bc
parent60e6394056de9d7d1cd3c93abb1cd4cd2f5cb192 (diff)
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.
-rw-r--r--Makefile11
-rw-r--r--badroff.c110
-rw-r--r--ll.c2
-rw-r--r--ll.h3
-rw-r--r--phrase-circuit.src2
-rw-r--r--sb.c88
-rw-r--r--sb.h13
7 files changed, 190 insertions, 39 deletions
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <stdbool.h>
#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 <stdbool.h>
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 <stdlib.h>
+#include <string.h>
+
+#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