Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/util/xshl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/xshl.c')
-rw-r--r--src/util/xshl.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/src/util/xshl.c b/src/util/xshl.c
new file mode 100644
index 0000000..27ab8d5
--- /dev/null
+++ b/src/util/xshl.c
@@ -0,0 +1,470 @@
+#ifndef _plan9_
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#else
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#endif
+#include <config.h>
+#include <misc-f.h>
+#include "xshl.h"
+
+#define XSHL_ENDLINE (65536)
+#define XSHL_ENDPARAGRAPH (65536*2)
+#define XSHL_NEWSTART (65536*4)
+#define XSHL_SMALL (65536*8)
+#define XSHL_SKIPBLANK (65536*16)
+#define XSHL_COMMAND (65536*32)
+#define XSHL_BLANK (65536*64)
+#define XSHL_CLEARATLINE (65536*128)
+
+#define XSHL_AUTOCLEAN (XSHL_ENDLINE|XSHL_ENDPARAGRAPH|XSHL_NEWSTART|XSHL_SKIPBLANK|XSHL_COMMAND|XSHL_BLANK)
+
+
+#define ALL (~0)
+CONST static struct tag {
+ CONST char *name;
+ int andflagenable;
+ int orflagenable;
+ int andflagdisable;
+ int orflagdisable;
+} tags[] = {
+ {
+ "p", ALL, XSHL_SKIPBLANK | XSHL_ENDPARAGRAPH, ALL,
+ XSHL_SKIPBLANK | XSHL_ENDPARAGRAPH}
+ , {
+ "head", ALL,
+ XSHL_SKIPBLANK | XSHL_BIG | XSHL_CENTERALIGN |
+ XSHL_ENDPARAGRAPH, ~(XSHL_BIG | XSHL_CENTERALIGN),
+ XSHL_SKIPBLANK | XSHL_ENDPARAGRAPH | XSHL_ENDLINE}
+ , {
+ "emph", ALL, XSHL_EMPH, ~XSHL_EMPH, 0}
+ , {
+ "br", ALL, XSHL_SKIPBLANK | XSHL_ENDLINE, ALL, 0}
+ , {
+ "white", ~XSHL_COLORMASK, XSHL_WHITE, ~XSHL_WHITE, 0}
+ , {
+ "red", ~XSHL_COLORMASK, XSHL_RED, ~XSHL_RED, 0}
+ , {
+ "black", ~XSHL_COLORMASK, XSHL_BLACK, ~XSHL_BLACK, 0}
+ , {
+ "right", ALL, XSHL_SKIPBLANK | XSHL_RIGHTALIGN | XSHL_ENDLINE,
+ ~XSHL_RIGHTALIGN, XSHL_SKIPBLANK | XSHL_ENDLINE}
+ , {
+ "center", ALL, XSHL_SKIPBLANK | XSHL_CENTERALIGN | XSHL_ENDLINE,
+ ~XSHL_CENTERALIGN, XSHL_SKIPBLANK | XSHL_ENDLINE}
+ , {
+ "tt", ALL, XSHL_MONOSPACE, ~XSHL_MONOSPACE, 0}
+ , {
+ "dl", ALL, XSHL_SKIPBLANK | XSHL_ENDLINE,
+ ~(XSHL_SMALL | XSHL_EMPH), XSHL_SKIPBLANK | XSHL_ENDLINE}
+ , {
+ "dt", ~XSHL_SMALL, XSHL_SKIPBLANK | XSHL_ENDLINE | XSHL_EMPH, ALL,
+ 0}
+ , {
+ "dd", ~XSHL_EMPH, XSHL_SKIPBLANK | XSHL_NEWSTART | XSHL_SMALL, ALL,
+ 0}
+ , {
+ NULL}
+};
+
+#define MAXINPUT 256
+
+#define SMALLSKIP (4*spacewidth)
+
+struct boxitem {
+ char *text;
+ struct xshl_context c;
+ int xpos;
+ int width;
+ int height;
+ struct boxitem *next;
+};
+static void freebox(struct boxitem *box)
+{
+ if (box->c.linktext != NULL)
+ free(box->c.linktext);
+ free(box->text);
+ free(box);
+}
+
+static struct xshl_item *pack(struct boxitem *first, struct boxitem *last,
+ int *collectedflags, int width)
+{
+ struct xshl_item *f = NULL;
+ struct xshl_item *l = NULL;
+ struct xshl_item *item;
+ struct boxitem *curr = first, *ncurr;
+ int end = 0;
+ char text[256];
+ int collected = 0;
+ while (curr != last) {
+ if (curr->text[0] == 0) {
+ ncurr = curr->next;
+ freebox(curr);
+ curr = ncurr;
+ continue;
+ }
+ strcpy(text, curr->text);
+ item = (struct xshl_item *) malloc(sizeof(struct xshl_item));
+ if (item == NULL)
+ return NULL;
+ item->x = curr->xpos;
+ item->width = curr->width;
+ item->c = curr->c;
+ if (curr->c.linktext != NULL)
+ curr->c.linktext = mystrdup(curr->c.linktext);
+ collected |= item->c.flags;
+ ncurr = curr->next;
+ freebox(curr);
+ curr = ncurr;
+ while (curr != last &&
+ curr->xpos == item->x + item->width &&
+ (curr->c.flags & 0xffff) == (item->c.flags & 0xffff)
+ &&
+ ((curr->c.linktext == NULL && item->c.linktext == NULL) ||
+ (curr->c.linktext != NULL && item->c.linktext != NULL &&
+ !strcmp(curr->c.linktext, item->c.linktext))))
+ {
+ strcat(text, curr->text);
+ item->width += curr->width;
+ collected |= item->c.flags;
+ ncurr = curr->next;
+ freebox(curr);
+ curr = ncurr;
+ }
+ item->text = mystrdup(text);
+ item->next = NULL;
+ if (l != NULL)
+ l->next = item;
+ else
+ f = item;
+ l = item;
+ end = item->x + item->width;
+ }
+ *collectedflags = collected;
+ if (collected & (XSHL_CENTERALIGN | XSHL_RIGHTALIGN)) {
+ if (collected & XSHL_RIGHTALIGN)
+ end = width - end;
+ else
+ end = (width - end) / 2;
+ item = f;
+ while (item != NULL) {
+ item->x += end;
+ item = item->next;
+ }
+ }
+ return (f);
+}
+
+#ifndef isspace
+#define isspace(c) ((c)==' '||(c)=='\t'||(c)=='\n')
+#endif
+static char xshllink[32];
+static int flags;
+static struct boxitem *xshl_readbox(void *data, int (*get) (void *))
+{
+ char inputbuf[256];
+ int c;
+ int i;
+ char command[16];
+ char parameter[32];
+ if (flags & XSHL_BLANK) {
+ struct boxitem *box = (struct boxitem *) malloc(sizeof(*box));
+ box->width = 0;
+ box->next = NULL;
+ box->height = flags & XSHL_BIG ? 0 : 1;
+ box->text = mystrdup(" ");
+ box->c.flags = flags | XSHL_CLEARATLINE;
+ box->c.linktext = NULL;
+ if (xshllink[0] != 0)
+ box->c.linktext = mystrdup(xshllink);
+ flags &= ~XSHL_AUTOCLEAN;
+ flags |= XSHL_SKIPBLANK;
+ return (box);
+ }
+ if (flags & XSHL_COMMAND) {
+ int i = 0;
+ flags &= ~XSHL_COMMAND;
+ parameter[0] = 0;
+ do {
+ c = command[i] = get(data);
+ if (i < 15)
+ i++;
+ }
+ while (c && c != '>' && !isspace(c));
+ command[i - 1] = 0;
+ if (c != '>' && c) {
+ do {
+ c = get(data);
+ }
+ while (c && c != '>' && isspace(c));
+ if (c && c != '>') {
+ i = 1;
+ parameter[0] = c;
+ do {
+ c = parameter[i] = get(data);
+ if (i < 31)
+ i++;
+ }
+ while (c && c != '>' && !isspace(c));
+ parameter[i - 1] = 0;
+ if (isspace(c)) {
+ do {
+ c = get(data);
+ }
+ while (c && c != '>' && isspace(c));
+ }
+ }
+ }
+ {
+ int i;
+ int disabled = 0;
+ if (command[0] == '/')
+ disabled = 1;
+ for (i = 0;
+ tags[i].name != NULL
+ && strcmp(tags[i].name, command + disabled); i++);
+ if (tags[i].name != NULL) {
+ if (disabled) {
+ flags &= tags[i].andflagdisable;
+ flags |= tags[i].orflagdisable;
+ } else {
+ flags &= tags[i].andflagenable;
+ flags |= tags[i].orflagenable;
+ }
+ } else {
+ if (!strcmp(command + disabled, "a")
+ || !strcmp(command + disabled, "tutor")) {
+ if (disabled)
+ xshllink[0] = 0;
+ else
+ strcpy(xshllink, parameter);
+ } else
+ while (c != '>')
+ c = get(data);
+ }
+ }
+ if (c == '>')
+ c = get(data);
+ } else
+ c = get(data);
+ if (!c) {
+ return NULL;
+ }
+ if (flags & XSHL_SKIPBLANK) {
+ while (isspace(c)) {
+ c = get(data);
+ if (!c) {
+ return NULL;
+ }
+ }
+ flags &= ~XSHL_SKIPBLANK;
+ }
+ i = 0;
+ inputbuf[i++] = c;
+ while (c && c != '<' && !isspace(c)) {
+ c = get(data);
+ inputbuf[i++] = c;
+ if (i > 255)
+ i = 255;
+ }
+ inputbuf[i - 1] = 0;
+ if (i == 1 && !c) {
+ return NULL;
+ }
+ if (i == 1 && isspace(c)) {
+ flags |= XSHL_BLANK;
+ return xshl_readbox(data, get);
+ }
+ if (i == 1 && c == '<') {
+ flags |= XSHL_COMMAND;
+ return xshl_readbox(data, get);
+ }
+ {
+ struct boxitem *box = (struct boxitem *) malloc(sizeof(*box));
+ box->width = 0;
+ box->next = NULL;
+ box->height = flags & XSHL_BIG ? 0 : 1;
+ box->text = mystrdup(inputbuf);
+ box->c.flags = flags | XSHL_CLEARATLINE;
+ box->c.linktext = NULL;
+ if (xshllink[0] != 0)
+ box->c.linktext = mystrdup(xshllink);
+ flags &= ~XSHL_AUTOCLEAN;
+ if (isspace(c))
+ flags |= XSHL_BLANK;
+ if (c == '<')
+ flags |= XSHL_COMMAND;
+ return (box);
+ }
+ /*We are at the first word */
+}
+
+struct xshl_line *xshl_interpret(void *data, int (*get) (void *),
+ int width, int getwidth(void *, int flags,
+ CONST char *text),
+ int startflags, int smallheight,
+ int bigheight)
+{
+ int spacewidth = getwidth(data, 0, " ");
+ int cflags;
+ struct boxitem *first = NULL;
+ struct boxitem *last = NULL;
+ struct boxitem *item;
+ struct boxitem *lastword = NULL;
+ int maxlines = 200;
+ struct xshl_line *lines =
+ (struct xshl_line *) malloc(maxlines * sizeof(*lines));
+ int nlines = 0;
+ int ypos = 0;
+ flags = startflags | XSHL_SKIPBLANK;
+ xshllink[0] = 0;
+ while ((item = xshl_readbox(data, get)) != NULL) {
+ if (last == NULL) {
+ if (item->text[0] == ' ' && !item->text[1]) {
+ freebox(item);
+ continue;
+ }
+ lastword = NULL;
+ first = item, item->xpos =
+ item->c.flags & XSHL_SMALL ? SMALLSKIP : 0;
+ } else {
+ if (item->text[0] == ' ' && !item->text[1]) {
+ lastword = item;
+ }
+ last->next = item, item->xpos = last->xpos + last->width;
+ }
+ last = item;
+ item->width = getwidth(data, item->c.flags, item->text);
+ if (item->c.flags & (XSHL_ENDLINE | XSHL_ENDPARAGRAPH)
+ || ((item->c.flags & XSHL_NEWSTART)
+ && item->xpos + spacewidth > SMALLSKIP)) {
+ if (nlines > maxlines - 1)
+ maxlines *= 2, lines =
+ (struct xshl_line *) realloc(lines,
+ (maxlines) *
+ sizeof(*lines));
+ if (first != NULL) {
+ lines[nlines].first = pack(first, last, &cflags, width);
+ lines[nlines].y = ypos;
+ nlines++;
+ if (ypos & XSHL_BIG)
+ ypos += bigheight;
+ else
+ ypos += smallheight;
+ }
+ if (item->c.flags & (XSHL_ENDPARAGRAPH))
+ ypos += smallheight;
+ first = last;
+ item->xpos =
+ item->c.flags & item->c.flags & XSHL_SMALL ? SMALLSKIP : 0;
+ lastword = NULL;
+ } else if (item->c.flags & XSHL_NEWSTART)
+ item->xpos = SMALLSKIP;
+ if (item->xpos + item->width > width) {
+ if (lastword == NULL) {
+ item = first;
+ while (item != NULL) {
+ struct boxitem *c = item->next;
+ freebox(item);
+ item = c;
+ }
+ first = last = NULL;
+ } else {
+ int xpos;
+ if (nlines > maxlines - 1)
+ maxlines *= 2, lines =
+ (struct xshl_line *) realloc(lines,
+ (maxlines) *
+ sizeof(*lines));
+ lines[nlines].first =
+ pack(first, lastword, &cflags, width);
+ lines[nlines].y = ypos;
+ nlines++;
+ if (ypos & XSHL_BIG)
+ ypos += bigheight;
+ else
+ ypos += smallheight;
+ if (lastword != NULL)
+ first = lastword->next;
+ else
+ first = NULL;
+ item = first;
+ if (item != NULL) {
+ xpos =
+ item->c.flags & item->c.
+ flags & XSHL_SMALL ? SMALLSKIP : 0;
+ while (item != NULL) {
+ item->xpos = xpos;
+ xpos += item->width;
+ item = item->next;
+ }
+ }
+ freebox(lastword);
+ lastword = NULL;
+ if (first == NULL)
+ last = NULL;
+ }
+ }
+ }
+ if (last != NULL) {
+ lines[nlines].y = ypos;
+ lines[nlines].first = pack(first, last->next, &cflags, width);
+ }
+ nlines++;
+ lines[nlines].y = -1;
+ lines =
+ (struct xshl_line *) realloc(lines, (nlines + 2) * sizeof(*lines));
+ return (lines);
+}
+
+
+int xshl_textlen(void *data, int flags, CONST char *text)
+{
+ return ((int) strlen(text));
+}
+
+void xshl_print(int startskip, struct xshl_line *lines)
+{
+ int i = 0;
+ int y = 0;
+ while (lines[i].y >= 0) {
+ int xpos = -startskip;
+ struct xshl_item *item;
+ while (y < lines[i].y) {
+ putc('\n', stdout), y++;
+ }
+ item = lines[i].first;
+ while (item) {
+ while (xpos < item->x) {
+ putc(' ', stdout), xpos++;
+ }
+ xpos += item->width;
+ item = item->next;
+ }
+ i++;
+ }
+}
+
+void xshl_free(struct xshl_line *lines)
+{
+ int i = 0;
+ while (lines[i].y >= 0) {
+ struct xshl_item *item, *nextitem;
+ item = lines[i].first;
+ while (item) {
+ nextitem = item->next;
+ if (item->c.linktext != NULL)
+ free(item->c.linktext);
+ free(item->text);
+ free(item);
+ item = nextitem;
+ }
+ i++;
+ }
+ free(lines);
+}