shithub: neatroff

Download patch

ref: fab9c27fa0b1d53979eb6718015928784a097ed8
parent: 7e51746ad98afe340fb62e9ea196d77414401fd7
author: Ali Gholami Rudi <ali@rudi.ir>
date: Sat Jul 6 21:03:12 EDT 2013

clr: set text color with \m[#rgb]

--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
 all: roff
 %.o: %.c roff.h
 	$(CC) -c $(CFLAGS) $<
-roff: roff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o draw.o wb.o hyph.o map.o
+roff: roff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o draw.o wb.o hyph.o map.o clr.o
 	$(CC) -o $@ $^ $(LDFLAGS)
 clean:
 	rm -f *.o roff
--- /dev/null
+++ b/clr.c
@@ -1,0 +1,56 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "roff.h"
+
+/* returns a static buffer */
+char *clr_str(int c)
+{
+	static char clr_buf[32];
+	if (!c)
+		return "0";
+	sprintf(clr_buf, "#%02x%02x%02x", CLR_R(c), CLR_G(c), CLR_B(c));
+	return clr_buf;
+}
+
+static struct color {
+	char *name;
+	int value;
+} colors[] = {
+	{"black", CLR_RGB(0, 0, 0)},
+	{"red", CLR_RGB(0xff, 0, 0)},
+	{"green", CLR_RGB(0, 0xff, 0)},
+	{"yellow", CLR_RGB(0xff, 0xff, 0)},
+	{"blue", CLR_RGB(0, 0, 0xff)},
+	{"magenta", CLR_RGB(0xff, 0, 0xff)},
+	{"cyan", CLR_RGB(0, 0xff, 0xff)},
+	{"white", CLR_RGB(0xff, 0xff, 0xff)},
+};
+
+/* read color component */
+static int clrcomp(char *s, int len)
+{
+	static char *digs = "0123456789abcdef";
+	int n = 0;
+	int i;
+	for (i = 0; i < len; i++)
+		if (strchr(digs, tolower(s[i])))
+			n = n * 16 + (strchr(digs, tolower(s[i])) - digs);
+	return len == 1 ? n << 4 : n;
+}
+
+int clr_get(char *s)
+{
+	int i;
+	if (s[0] == '#' && strlen(s) == 7)
+		return CLR_RGB(clrcomp(s + 1, 2), clrcomp(s + 3, 2), clrcomp(s + 5, 2));
+	if (s[0] == '#' && strlen(s) == 4)
+		return CLR_RGB(clrcomp(s + 1, 1), clrcomp(s + 2, 1), clrcomp(s + 3, 1));
+	if (isdigit(s[0]) && atoi(s) >= 0 && atoi(s) < LEN(colors))
+		return colors[atoi(s)].value;
+	for (i = 0; i < LEN(colors); i++)
+		if (!strcmp(colors[i].name, s))
+			return colors[i].value;
+	return 0;
+}
--- a/out.c
+++ b/out.c
@@ -190,7 +190,7 @@
 				*r++ = *(*s)++;
 			if (**s == ']')
 				(*s)++;
-		} else if (strchr("CDfhsvXx", d[1])) {
+		} else if (strchr("CDfhmsvXx", d[1])) {
 			int c = d[1];
 			escarg(s, d, d[1]);
 			return c == 'C' ? 0 : c;
@@ -231,6 +231,10 @@
 			break;
 		case 'h':
 			outnn("h%d", eval(c, 'm'));
+			break;
+		case 'm':
+			if (!n_cp)
+				out("m%s\n", clr_str(clr_get(c)));
 			break;
 		case 's':
 			out_ps(eval_re(c, o_s, '\0'));
--- a/reg.c
+++ b/reg.c
@@ -31,6 +31,7 @@
 	REG('.', 'j'),
 	REG('.', 'l'),
 	REG('.', 'L'),
+	REG('.', 'm'),
 	REG('.', 's'),
 	REG('.', 'u'),
 	REG('.', 'v'),
@@ -41,6 +42,7 @@
 	REG(0, 'l'),
 	REG(0, 'L'),
 	REG(0, 'n'),
+	REG(0, 'm'),
 	REG(0, 's'),
 	REG(0, 't'),
 	REG(0, 'T'),
--- a/ren.c
+++ b/ren.c
@@ -485,6 +485,13 @@
 	}
 }
 
+static void ren_m(char *s)
+{
+	int m = !s || !*s ? n_m0 : clr_get(s);
+	n_m0 = n_m;
+	n_m = m;
+}
+
 static void escarg_ren(char *d, int cmd, int (*next)(void), void (*back)(int))
 {
 	char delim[GNLEN];
@@ -574,6 +581,9 @@
 	case 'l':
 		ren_hline(wb, arg);
 		break;
+	case 'm':
+		ren_m(arg);
+		break;
 	case 'o':
 		ren_over(wb, arg);
 		break;
@@ -672,7 +682,7 @@
 				ren_transparent(arg);
 			}
 			return;
-		} else if (strchr(" bCcDdfhkLloprsuvXxz0^|{}&", c[1])) {
+		} else if (strchr(" bCcDdfhkLlmoprsuvXxz0^|{}&", c[1])) {
 			escarg_ren(arg, c[1], next, back);
 			if (c[1] != 'C') {
 				ren_cmd(wb, c[1], arg);
--- a/roff.h
+++ b/roff.h
@@ -29,7 +29,7 @@
 
 /* escape sequences */
 #define ESC_Q	"bCDhHlLNoSvwxX"	/* quoted escape sequences */
-#define ESC_P	"*fgkns"		/* 1 or 2-char escape sequences */
+#define ESC_P	"*fgkmns"		/* 1 or 2-char escape sequences */
 
 #define MIN(a, b)	((a) < (b) ? (a) : (b))
 #define MAX(a, b)	((a) < (b) ? (b) : (a))
@@ -175,8 +175,8 @@
 /* word buffer */
 struct wb {
 	struct sbuf sbuf;
-	int f, s;		/* the last output font and size */
-	int r_f, r_s;		/* current font and size; use n_f and n_s if -1 */
+	int f, s, m;		/* the last output font and size */
+	int r_f, r_s, r_m;	/* current font and size; use n_f and n_s if -1 */
 	int part;		/* partial input (\c) */
 	int els_neg, els_pos;	/* extra line spacing */
 	int h, v;		/* buffer vertical and horizontal positions */
@@ -308,6 +308,15 @@
 #define NREGS2		(NREGS * 2)
 #define REG(c1, c2)	((c1) * 256 + (c2))
 
+/* colors */
+#define CLR_R(c)		(((c) >> 16) & 0xff)
+#define CLR_G(c)		(((c) >> 8) & 0xff)
+#define CLR_B(c)		((c) & 0xff)
+#define CLR_RGB(r, g, b)	(((r) << 16) | ((g) << 8) | (b))
+
+char *clr_str(int c);
+int clr_get(char *s);
+
 /* builtin number registers; n_X for .X register */
 #define n_a		(*nreg(REG('.', 'a')))
 #define n_cp		(*nreg(REG('.', 'C')))
@@ -319,6 +328,7 @@
 #define n_l		(*nreg(REG('.', 'l')))
 #define n_L		(*nreg(REG('.', 'L')))
 #define n_n		(*nreg(REG('.', 'n')))
+#define n_m		(*nreg(REG('.', 'm')))
 #define n_o		(*nreg(REG('.', 'o')))
 #define n_p		(*nreg(REG('.', 'p')))
 #define n_s		(*nreg(REG('.', 's')))
@@ -340,7 +350,8 @@
 #define n_kn		(*nreg(REG(0, 'k')))	/* .kn mode */
 #define n_l0		(*nreg(REG(0, 'l')))	/* last .l */
 #define n_L0		(*nreg(REG(0, 'L')))	/* last .L */
-#define n_mk		(*nreg(REG(0, 'm')))	/* .mk internal register */
+#define n_m0		(*nreg(REG(0, 'm')))	/* last .m */
+#define n_mk		(*nreg(REG(0, 'M')))	/* .mk internal register */
 #define n_na		(*nreg(REG(0, 'n')))	/* .na mode */
 #define n_ns		(*nreg(REG(0, 'N')))	/* .ns mode */
 #define n_o0		(*nreg(REG(0, 'o')))	/* last .o */
--- a/wb.c
+++ b/wb.c
@@ -5,6 +5,7 @@
 
 #define R_F(wb)		((wb)->r_f >= 0 ? (wb)->r_f : n_f)	/* current font */
 #define R_S(wb)		((wb)->r_s >= 0 ? (wb)->r_s : n_s)	/* current size */
+#define R_M(wb)		((wb)->r_m >= 0 ? (wb)->r_m : n_m)	/* current color */
 
 void wb_init(struct wb *wb)
 {
@@ -12,8 +13,10 @@
 	sbuf_init(&wb->sbuf);
 	wb->f = -1;
 	wb->s = -1;
+	wb->m = -1;
 	wb->r_f = -1;
 	wb->r_s = -1;
+	wb->r_m = -1;
 }
 
 void wb_done(struct wb *wb)
@@ -39,6 +42,10 @@
 		sbuf_printf(&wb->sbuf, "%cs(%02d", c_ec, R_S(wb));
 		wb->s = R_S(wb);
 	}
+	if (!n_cp && wb->m != R_M(wb)) {
+		sbuf_printf(&wb->sbuf, "%cm[%s]", c_ec, clr_str(R_M(wb)));
+		wb->m = R_M(wb);
+	}
 	wb_stsb(wb);
 }
 
@@ -217,6 +224,9 @@
 	case 'h':
 		wb_hmov(wb, atoi(s));
 		break;
+	case 'm':
+		wb->r_m = clr_get(s);
+		break;
 	case 's':
 		wb->r_s = atoi(s);
 		break;
@@ -242,6 +252,7 @@
 	part = src->part;
 	wb->r_s = -1;
 	wb->r_f = -1;
+	wb->r_m = -1;
 	wb_reset(src);
 	src->part = part;
 }
@@ -364,6 +375,7 @@
 		wb_putc(w1, 0, "hy");
 	w2->r_s = w1->r_s;
 	w2->r_f = w1->r_f;
+	w2->r_m = w1->r_m;
 	while ((c = out_readc(&s, d)) >= 0)
 		wb_putc(w2, c, d);
 }