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 */