aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--badroff.c84
1 files changed, 70 insertions, 14 deletions
diff --git a/badroff.c b/badroff.c
index a1255d9..6a630ed 100644
--- a/badroff.c
+++ b/badroff.c
@@ -67,6 +67,7 @@ size_t chrnfill(char chr, size_t sz){//fills to first of chr or sz
// typesetting config and commands to change.
int width = 80;
+char nbsp = 0;
char* center(char* txt){
size_t len = strlen(txt);
@@ -103,7 +104,7 @@ char* leader(char* txt){
fin[i] = repeat[i % rptln];
return fin;
}
-bool endlineset = false;
+bool endgroup = false;
llnode* freenext(llnode* node){
llnode* tmp = node->next;
node->next = tmp->next;
@@ -125,7 +126,6 @@ void multbreak(sb* buffer, size_t start,
} 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
@@ -138,14 +138,14 @@ llnode* accumlines(size_t* ct){ // returns tail of linked list
(*ct) = 0;
while (true){
tail->next = appendll(tail, line());
- if (endlineset) break;
+ if (endgroup) break;
(*ct)++;
tail = tail->next;
}
free(tail->next->str); free(tail->next); //.ELS cmd
tail->next = head->next; // loop linked list
free(head);
- endlineset = false; // prevents false positive on next run
+ endgroup = false; // prevents false positive on next run
return tail;
}
char* lineset(char* txt){
@@ -173,7 +173,6 @@ char* lineset(char* txt){
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
@@ -185,20 +184,61 @@ char* lineset(char* txt){
char* lines = decompose(buf);
return lines;
}
-char* finlineset(char* txt){
+char* emptalloc(void){ // need a null string so it can be freed later
char* str = malloc(sizeof(char)); str[0] = 0;
- endlineset = true;
return str;
}
+char* fingroup(char* txt){
+ endgroup = true;
+ return emptalloc();
+}
char* vert(char* txt){
int ln; sscanf(txt, "%d", &ln);
return chrmult('\n', ln);
}
+char* nbrkspc(char* txt){
+ if (txt[0] == '\n') txt[0] = 0;
+ if (txt[1] == '\n') txt[1] = 0;
+ if (txt[0] != 0 && txt[1] != 0)
+ nbsp = txt[1];
+ else if (txt[0] != 0)
+ nbsp = txt[0];
+ else
+ nbsp = 0;
+ return NULL;
+}
+char* merge(char* txt){ // merges until an endgroup
+ // gather lines
+ size_t ct;
+ llnode* head = accumlines(&ct)->next;
+ // count total length (for malloc)
+ size_t len = 0;
+ for (size_t i = 0; i < ct; i++, head = head->next){
+ size_t slen = strlen(head->str)-1;
+ head->str[slen] = 0; // remove the nl character at the end
+ len += slen; // add the (new) length of string
+ }
+ char *str, *pos;
+ pos = str = malloc(sizeof(char)*(len+2));
+ str[len] = '\n'; str[len+1] = 0; // str = "***********\n"
+ for (size_t i = 0; i < ct; i++){
+ wsclean(head->str);
+ size_t slen = strlen(head->str);
+ memcpy(pos, head->str, slen);
+ pos += slen;
+ llnode* tmp = head;
+ head = head->next;
+ free(tmp->str);
+ free(tmp);
+ }
+ return str;
+}
char* cmds[] = // MUST be sorted alphabetically
- {"CT ", "ELS", "FIL ", "LD ", "LS", "V ", "W "};
+ {"CT ", "EG", "FIL ", "LD ", "LS", "MRG", "NBSP", "V ", "W "};
char* (*call[])(char* txt) =
- {center, finlineset, fillline, leader, lineset, vert, setwidth};
+ {center, fingroup, fillline, leader, lineset, merge, nbrkspc,
+ vert, setwidth};
char* cmd(void){
char* dat = popstrbuf(inbuf, chrfill('\n'));
@@ -237,22 +277,29 @@ void wsclean(char* txt){
txt[i-disp] = txt[i];
}
}
+#define nbspchr (char) 255
+void nbspclean(char* txt){
+ for (; *txt != 0; txt++){
+ if (*txt == nbspchr) *txt = ' ';
+ }
+}
char* wordset(char* txt){
char* orig = txt; // txt will be manipulated
- size_t ws = width;
+ size_t ws = 0; // zero means do not cut
for (size_t i=0; txt[i] != 0; i++){ // turn into a nested loop
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) ){
+ if (txt[i] == '\n' || (ws && i >= width && ws != i) ){
txt += ws;
txt[0] = '\n';
- ws = width;
+ ws = 0;
i = 0;
}
}
wsclean(orig); // remove trailing whitespace
+ nbspclean(orig);
return orig;
}
@@ -264,6 +311,12 @@ char* norm(void){
// a parser to choose when to typeset and when to run a command
+void nbspsub(char* txt){
+ for (; (*txt) != 0; txt++){
+ if (*txt == nbsp) *txt = nbspchr;
+ }
+}
+
char* line(void){
size_t sz;
if ( (sz = fillbuf(2)) == 0)
@@ -271,13 +324,16 @@ char* line(void){
char* twobytes = peekstrbuf(inbuf, 0, 2); // .., .\n, or ^.?
if (sz == 1 || twobytes[1] == '\n') return norm();
if (twobytes[0] == '.') popchrbuf(inbuf);
+ char* out;
if (twobytes[0] == '.' && twobytes[1] != '.'){
char* data = cmd();
if (data) return data;
- return line();
+ out = line();
} else {
- return norm();
+ out = norm();
}
+ nbspsub(out);
+ return out;
}
// orchestration