shithub: neatroff

Download patch

ref: 688bc8b668b371a8fa5d4b0415900f1607caccd3
parent: 57e2ed362dfe517efe02504426e9220892a159c3
author: Ali Gholami Rudi <ali@rudi.ir>
date: Thu Jun 27 15:47:12 EDT 2013

reg: add .af

--- a/cp.c
+++ b/cp.c
@@ -40,6 +40,11 @@
 		in_push(buf, NULL);
 }
 
+static void cp_numfmt(void)
+{
+	in_push(num_getfmt(regid()), NULL);
+}
+
 static void cp_arg(void)
 {
 	int c;
@@ -116,6 +121,9 @@
 			c = cp_next();
 		} else if (c == '*') {
 			cp_str();
+			c = cp_next();
+		} else if (c == 'g') {
+			cp_numfmt();
 			c = cp_next();
 		} else if (c == '$') {
 			cp_arg();
--- a/reg.c
+++ b/reg.c
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -17,6 +18,7 @@
 
 static int nregs[NREGS];	/* global number registers */
 static int nregs_inc[NREGS];	/* number register auto-increment size */
+static int nregs_fmt[NREGS];	/* number register format */
 static char *sregs[NREGS];	/* global string registers */
 static void *sregs_dat[NREGS];	/* builtin function data */
 static struct env envs[3];	/* environments */
@@ -60,6 +62,8 @@
 	s[3] = '\0';
 }
 
+static int num_fmt(char *s, int n, int fmt);
+
 /* the contents of a number register (returns a static buffer) */
 char *num_str(int id)
 {
@@ -86,7 +90,8 @@
 		sprintf(numbuf, "%02d", nregs[id]);
 		break;
 	default:
-		sprintf(numbuf, "%d", *nreg(id));
+		if (!nregs_fmt[id] || num_fmt(numbuf, *nreg(id), nregs_fmt[id]))
+			sprintf(numbuf, "%d", *nreg(id));
 	}
 	return numbuf;
 }
@@ -105,6 +110,7 @@
 {
 	*nreg(id) = 0;
 	nregs_inc[id] = 0;
+	nregs_fmt[id] = 0;
 }
 
 int num_get(int id, int inc)
@@ -277,4 +283,108 @@
 		if (env->tabs[i] > pos)
 			return env->tabs[i];
 	return pos;
+}
+
+/* number register format (.af) */
+#define NF_LSH		8		/* number format length shifts */
+#define NF_FMT		0x00ff		/* number format mask */
+
+/* the format of a number register (returns a static buffer) */
+char *num_getfmt(int id)
+{
+	static char fmtbuf[128];
+	char *s = fmtbuf;
+	int i;
+	if (!nregs_fmt[id] || (nregs_fmt[id] & NF_FMT) == '0') {
+		*s++ = '0';
+		i = nregs_fmt[id] >> NF_LSH;
+		while (i-- > 1)
+			*s++ = '0';
+	} else {
+		*s++ = nregs_fmt[id] & NF_FMT;
+	}
+	*s = '\0';
+	return fmtbuf;
+}
+
+void num_setfmt(int id, char *s)
+{
+	int i = 0;
+	if (strchr("iIaA", s[0])) {
+		nregs_fmt[id] = s[0];
+	} else {
+		while (isdigit(s[i]))
+			i++;
+		nregs_fmt[id] = '0' | (i << NF_LSH);
+	}
+}
+
+static void nf_reverse(char *s)
+{
+	char r[128];
+	int i, l;
+	strcpy(r, s);
+	l = strlen(r);
+	for (i = 0; i < l; i++)
+		s[i] = r[l - i - 1];
+}
+
+static void nf_roman(char *s, int n, char *I, char *V)
+{
+	int i;
+	if (!n)
+		return;
+	if (n % 5 == 4) {
+		*s++ = n % 10 == 9 ? I[1] : V[0];
+		*s++ = I[0];
+	} else {
+		for (i = 0; i < n % 5; i++)
+			*s++ = I[0];
+		if (n % 10 >= 5)
+			*s++ = V[0];
+	}
+	*s = '\0';
+	nf_roman(s, n / 10, I + 1, V + 1);
+}
+
+static void nf_alpha(char *s, int n, int a)
+{
+	while (n) {
+		*s++ = a + ((n - 1) % 26);
+		n /= 26;
+	}
+	*s = '\0';
+}
+
+/* returns nonzero on failure */
+static int num_fmt(char *s, int n, int fmt)
+{
+	int type = fmt & NF_FMT;
+	int len;
+	if (n < 0) {
+		n = -n;
+		*s++ = '-';
+	}
+	if ((type == 'i' || type == 'I') && n > 0 && n < 40000) {
+		if (type == 'i')
+			nf_roman(s, n, "ixcmz", "vldw");
+		else
+			nf_roman(s, n, "IXCMZ", "VLDW");
+		nf_reverse(s);
+		return 0;
+	}
+	if ((type == 'a' || type == 'A') && n > 0) {
+		nf_alpha(s, n, type);
+		nf_reverse(s);
+		return 0;
+	}
+	if (type == '0') {
+		sprintf(s, "%d", n);
+		len = strlen(s);
+		while (len++ < fmt >> NF_LSH)
+			*s++ = '0';
+		sprintf(s, "%d", n);
+		return 0;
+	}
+	return 1;
 }
--- a/roff.h
+++ b/roff.h
@@ -47,6 +47,8 @@
 void num_inc(int id, int val);
 void num_del(int id);
 char *num_str(int id);
+char *num_getfmt(int id);
+void num_setfmt(int id, char *fmt);
 int *nreg(int id);
 int eval(char *s, int unit);
 int eval_up(char **s, int unit);
--- a/tr.c
+++ b/tr.c
@@ -57,11 +57,16 @@
 			num_del(REG(args[i][0], args[i][1]));
 }
 
+static void tr_af(char **args)
+{
+	if (args[2])
+		num_setfmt(REG(args[1][0], args[1][1]), args[2]);
+}
+
 static void tr_ds(char **args)
 {
-	if (!args[2])
-		return;
-	str_set(REG(args[1][0], args[1][1]), args[2]);
+	if (args[2])
+		str_set(REG(args[1][0], args[1][1]), args[2]);
 }
 
 static void tr_as(char **args)
@@ -594,6 +599,7 @@
 	{TR_DIVEND, tr_divend},
 	{TR_EJECT, tr_eject},
 	{"ad", tr_ad},
+	{"af", tr_af},
 	{"am", tr_de, mkargs_reg1},
 	{"as", tr_as, mkargs_ds},
 	{"bp", tr_bp},