shithub: neatroff

Download patch

ref: 9449dc43d41f2539965d9f46e50f5794196a635f
parent: 88b3d68dce91f41a988bf90e1eec7b10bd25dd61
author: Ali Gholami Rudi <ali@rudi.ir>
date: Fri Apr 19 13:23:29 EDT 2013

eval: handle \w in integer expressions

--- a/eval.c
+++ b/eval.c
@@ -1,55 +1,41 @@
 #include <ctype.h>
 #include <stdio.h>
+#include <string.h>
 #include "xroff.h"
 
+#define SCHAR	"icpPvmnu"	/* scale indicators */
+
 static int defunit = 0;		/* default scale indicator */
 static int abspos = 0;		/* absolute position like |1i */
 
-static int readunit(int c, int *mul, int *div)
+static int readunit(int c, int n)
 {
-	*mul = 1;
-	*div = 1;
 	switch (c) {
 	case 'i':
-		*mul = SC_IN;
-		return 0;
+		return n * SC_IN;
 	case 'c':
-		*mul = SC_IN * 50;
-		*div = 127;
-		return 0;
+		return n * SC_IN * 50 / 127;
 	case 'p':
-		*mul = SC_IN;
-		*div = 72;
-		return 0;
+		return n * SC_IN / 72;
 	case 'P':
-		*mul = SC_IN;
-		*div = 6;
-		return 0;
+		return n * SC_IN / 6;
 	case 'v':
-		*mul = n_v;
-		return 0;
+		return n * n_v;
 	case 'm':
-		*mul = n_s * SC_IN;
-		*div = 72;
-		return 0;
+		return n * n_s * SC_IN / 72;
 	case 'n':
-		*mul = n_s * SC_IN;
-		*div = 144;
-		return 0;
+		return n * n_s * SC_IN / 144;
 	case 'u':
-		return 0;
+		return n;
 	}
-	return 1;
+	return n;
 }
 
-static int evalexpr(char **s);
-
 static int evalnum(char **_s)
 {
 	char *s = *_s;
 	int n = 0;		/* the result */
 	int mag = 0;		/* n should be divided by mag */
-	int mul, div;
 	while (isdigit(*s) || *s == '.') {
 		if (*s == '.') {
 			mag = 1;
@@ -59,13 +45,9 @@
 		mag *= 10;
 		n = n * 10 + *s++ - '0';
 	}
-	if (!readunit(*s, &mul, &div))
-		s++;
-	else
-		readunit(defunit, &mul, &div);
+	n = readunit(*s && strchr(SCHAR, *s) ? *s++ : defunit, n);
 	*_s = s;
-	/* this may overflow */
-	return n * mul / div / (mag > 0 ? mag : 1);
+	return n / (mag > 0 ? mag : 1);		/* this may overflow */
 }
 
 static int evaljmp(char **s, int c)
@@ -82,8 +64,26 @@
 	return **s == '.' || isdigit(**s);
 }
 
+static char **wid_s;
+
+static int wid_next(void)
+{
+	return (unsigned char) *(*wid_s)++;
+}
+
+static void wid_back(int c)
+{
+	(*wid_s)--;
+}
+
+static int evalexpr(char **s);
+static int evalatom(char **s);
+
 static int evalatom(char **s)
 {
+	int ret;
+	if (evalisnum(s))
+		return evalnum(s);
 	if (!evaljmp(s, '-'))
 		return -evalatom(s);
 	if (!evaljmp(s, '+'))
@@ -90,11 +90,15 @@
 		return evalatom(s);
 	if (!evaljmp(s, '|'))
 		return abspos + evalatom(s);
-	if (evalisnum(s))
-		return evalnum(s);
 	if (!evaljmp(s, '(')) {
-		int ret = evalexpr(s);
+		ret = evalexpr(s);
 		evaljmp(s, ')');
+		return ret;
+	}
+	if (!evaljmp(s, '\\') && !evaljmp(s, 'w')) {
+		wid_s = s;
+		ret = ren_wid(wid_next, wid_back);
+		readunit(**s && strchr(SCHAR, **s) ? *(*s)++ : defunit, ret);
 		return ret;
 	}
 	return 0;
--- a/ren.c
+++ b/ren.c
@@ -42,20 +42,6 @@
 	ren_backed = c;
 }
 
-static int nextchar(char *s)
-{
-	int c = ren_next();
-	int l = utf8len(c);
-	int i;
-	if (c < 0)
-		return 0;
-	s[0] = c;
-	for (i = 1; i < l; i++)
-		s[i] = ren_next();
-	s[l] = '\0';
-	return l;
-}
-
 void tr_di(char **args)
 {
 	if (args[1]) {
@@ -451,17 +437,30 @@
 	*d = '\0';
 }
 
-static void render_wid(void);
+static int nextchar(char *s, int (*next)(void))
+{
+	int c = next();
+	int l = utf8len(c);
+	int i;
+	if (c < 0)
+		return 0;
+	s[0] = c;
+	for (i = 1; i < l; i++)
+		s[i] = next();
+	s[l] = '\0';
+	return l;
+}
 
 /* read one character and place it inside adj buffer */
-static int render_char(struct adj *adj)
+static int ren_char(struct adj *adj, int (*next)(void), void (*back)(int))
 {
 	char c[GNLEN * 2];
 	char arg[ILNLEN];
+	char widbuf[16];
 	char draw_arg[ILNLEN];
 	struct glyph *g;
 	int esc = 0, n, w;
-	nextchar(c);
+	nextchar(c, next);
 	if (c[0] == ' ' || c[0] == '\n') {
 		adj_put(adj, charwid(dev_spacewid(), n_s), c);
 		return 0;
@@ -468,14 +467,16 @@
 	}
 	if (c[0] == '\\') {
 		esc = 1;
-		nextchar(c);
+		nextchar(c, next);
 		if (c[0] == '(') {
-			int l = nextchar(c);
-			l += nextchar(c + l);
+			int l = nextchar(c, next);
+			l += nextchar(c + l, next);
 			c[l] = '\0';
 		} else if (strchr("DfhksvwXx{}", c[0])) {
 			if (c[0] == 'w') {
-				render_wid();
+				n = ren_wid(next, back);
+				sprintf(widbuf, "%d", n);
+				in_push(widbuf, NULL);
 				return 0;
 			}
 			escarg_ren(arg, c[0]);
@@ -523,26 +524,27 @@
 }
 
 /* read the argument of \w and push its width */
-static void render_wid(void)
+int ren_wid(int (*next)(void), void (*back)(int))
 {
-	char widbuf[16];
 	struct adj *adj = adj_alloc();
-	int c, wid_c;
+	int c, wid_c, n;
 	int type = 0;
-	wid_c = ren_next();
-	c = ren_next();
+	wid_c = next();
+	c = next();
 	adj_ll(adj, n_l);
 	odiv_beg();
 	while (c >= 0 && c != wid_c) {
-		ren_back(c);
-		type |= render_char(adj);
-		c = ren_next();
+		back(c);
+		type |= ren_char(adj, next, back);
+		c = next();
 	}
 	odiv_end();
-	sprintf(widbuf, "%d", adj_wid(adj));
-	in_push(widbuf, NULL);
+	ren_f = 0;
+	ren_s = 0;
+	n = adj_wid(adj);
 	n_ct = type;
 	adj_free(adj);
+	return n;
 }
 
 /* read characters from in.c and pass rendered lines to out.c */
@@ -554,7 +556,7 @@
 	while (c >= 0) {
 		if (c == ' ' || c == '\n') {
 			ren_back(c);
-			render_char(cadj);
+			ren_char(cadj, ren_next, ren_back);
 		}
 		while (adj_full(cadj, n_u))
 			ren_br(0);
@@ -562,7 +564,7 @@
 			n_lb = adj_wid(cadj);
 		if (c != ' ' && c != '\n') {
 			ren_back(c);
-			render_char(cadj);
+			ren_char(cadj, ren_next, ren_back);
 		}
 		c = ren_next();
 	}
--- a/xroff.h
+++ b/xroff.h
@@ -110,6 +110,7 @@
 
 /* rendering */
 void render(void);	/* read from in.c and print the output */
+int ren_wid(int (*next)(void), void (*back)(int));
 void out_line(char *s);	/* output the given rendered line */
 int out_draw(char *s, char *cc);
 void out(char *s, ...);	/* output troff cmd */