aboutsummaryrefslogtreecommitdiff
path: root/badroff.c
diff options
context:
space:
mode:
Diffstat (limited to 'badroff.c')
-rw-r--r--badroff.c110
1 files changed, 77 insertions, 33 deletions
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){