ref: 93d2c8708ddb2bf4e3f4c4ffd801d425064910b0
parent: 095506d4fd2f72fefdf5fe4e0a30e940a26feec4
author: Ali Gholami Rudi <ali@rudi.ir>
date: Mon Apr 22 16:52:05 EDT 2013
line: add \l and \L
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
all: xroff
%.o: %.c xroff.h
$(CC) -c $(CFLAGS) $<
-xroff: xroff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o
+xroff: xroff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o line.o
$(CC) -o $@ $^ $(LDFLAGS)
clean:
rm -f *.o xroff
--- /dev/null
+++ b/line.c
@@ -1,0 +1,123 @@
+#include <stdlib.h>
+#include <string.h>
+#include "xroff.h"
+
+/* horizontal and vertical line characters */
+static char *hs[] = {"_", "\\_", "\\-", "\\(ru", "\\(ul", "\\(rn", NULL};
+static char *vs[] = {"\\(bv", "\\(br", "|", NULL};
+
+static int cwid(char *c)
+{
+ struct glyph *g = dev_glyph(c, n_f);
+ return charwid(g ? g->wid : dev_spacewid(), n_s);
+}
+
+static int lchar(char *c, char **cs)
+{
+ while (*cs)
+ if (!strcmp(*cs++, c))
+ return 1;
+ return 0;
+}
+
+static void vmov(struct adj *adj, int w)
+{
+ adj_put(adj, w, "\\v'%du'", w);
+}
+
+static void hmov(struct adj *adj, int w)
+{
+ adj_put(adj, w, "\\h'%du'", w);
+}
+
+void ren_hline(struct adj *adj, char *arg)
+{
+ char *lc = "\\(ru";
+ int w, l, n, i, rem;
+ l = eval_up(&arg, 0, 'm');
+ if (!l)
+ return;
+ if (arg[0] == '\\' && arg[1] == '&') /* \& can be used as a separator */
+ arg += 2;
+ if (*arg)
+ lc = arg;
+ w = cwid(lc);
+ /* negative length; moving backwards */
+ if (l < 0) {
+ hmov(adj, l);
+ l = -l;
+ }
+ n = l / w;
+ rem = l % w;
+ /* length less than character width */
+ if (l < w) {
+ n = 1;
+ rem = 0;
+ hmov(adj, -(w - l) / 2);
+ }
+ /* the initial gap */
+ if (rem) {
+ if (lchar(lc, hs)) {
+ adj_put(adj, w, "%s", lc);
+ hmov(adj, rem - w);
+ } else {
+ hmov(adj, rem);
+ }
+ }
+ for (i = 0; i < n; i++)
+ adj_put(adj, w, lc);
+ /* moving back */
+ if (l < w)
+ hmov(adj, -(w - l + 1) / 2);
+}
+
+void ren_vline(struct adj *adj, char *arg)
+{
+ char *lc = "\\(br";
+ int w, l, n, i, rem, hw, neg;
+ l = eval_up(&arg, 0, 'm');
+ if (!l)
+ return;
+ neg = l < 0;
+ if (arg[0] == '\\' && arg[1] == '&') /* \& can be used as a separator */
+ arg += 2;
+ if (*arg)
+ lc = arg;
+ w = n_s * SC_PT; /* character height */
+ hw = cwid(lc); /* character width */
+ /* negative length; moving backwards */
+ if (l < 0) {
+ vmov(adj, l);
+ l = -l;
+ }
+ n = l / w;
+ rem = l % w;
+ /* length less than character width */
+ if (l < w) {
+ n = 1;
+ rem = 0;
+ vmov(adj, -w + l / 2);
+ }
+ /* the initial gap */
+ if (rem) {
+ if (lchar(lc, vs)) {
+ vmov(adj, w);
+ adj_put(adj, hw, "%s", lc);
+ hmov(adj, -hw);
+ vmov(adj, rem - w);
+ } else {
+ vmov(adj, rem);
+ }
+ }
+ for (i = 0; i < n; i++) {
+ vmov(adj, w);
+ adj_put(adj, hw, lc);
+ hmov(adj, -hw);
+ }
+ /* moving back */
+ if (l < w)
+ vmov(adj, l / 2);
+ if (neg)
+ vmov(adj, -l);
+ hmov(adj, hw);
+}
--- a/ren.c
+++ b/ren.c
@@ -482,6 +482,12 @@
case 'k':
num_set(REG(arg[0], arg[1]), f_hpos() - n_lb);
break;
+ case 'L':
+ ren_vline(adj, arg);
+ break;
+ case 'l':
+ ren_hline(adj, arg);
+ break;
case 'r':
adj_put(adj, 0, "\\v'%du'", eval("-1m", 0, 0));
break;
--- a/xroff.h
+++ b/xroff.h
@@ -115,6 +115,9 @@
void out_line(char *s); /* output the given rendered line */
int out_draw(char *s, char *cc);
void out(char *s, ...); /* output troff cmd */
+/* drawing lines */
+void ren_hline(struct adj *adj, char *arg);
+void ren_vline(struct adj *adj, char *arg);
/* troff commands */
void tr_bp(char **args);