summaryrefslogtreecommitdiff
path: root/Build/source/texk/ps2pk/strexpr.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/ps2pk/strexpr.c')
-rw-r--r--Build/source/texk/ps2pk/strexpr.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/Build/source/texk/ps2pk/strexpr.c b/Build/source/texk/ps2pk/strexpr.c
new file mode 100644
index 00000000000..ebfcc8fcdf5
--- /dev/null
+++ b/Build/source/texk/ps2pk/strexpr.c
@@ -0,0 +1,292 @@
+/*
+ * File: strexpr.c
+ * Purpose: calculate value from algebraic string expression
+ * (Stripped down from expr.c from J.T. Conklin <jtc@netbsd.org>.)
+ * Version: 1.0 (Nov 1995)
+ * Author: Piet Tutelaers
+ */
+
+#include <stdio.h> /* sprintf() */
+#include <stdlib.h> /* free(), malloc() */
+#include <string.h> /* strchr(), strcpy() */
+#include <ctype.h> /* isdigit(), isspace() */
+#include "basics.h" /* fatal() */
+
+const char *OPERATORS = "+-*/%()";
+
+enum token {
+ ADD, SUB, MUL, DIV, MOD, LP, RP, OPERAND, EOI
+};
+
+struct val {
+ enum {
+ integer,
+ string
+ } type;
+
+ union {
+ char *s;
+ int i;
+ } u;
+};
+
+enum token token;
+struct val *tokval;
+char *pexpr;
+
+struct val *
+make_int(int i)
+{
+ struct val *vp;
+
+ vp = (struct val *) malloc(sizeof(*vp));
+ if (vp == NULL) fatal("expression error\n");
+ vp->type = integer;
+ vp->u.i = i;
+ return vp;
+}
+
+
+struct val *
+make_str(char *s)
+{
+ char operand[32]; int i;
+
+ struct val *vp;
+
+ vp = (struct val *) malloc(sizeof(*vp));
+ if (vp == NULL) fatal("expression error\n");
+
+ pexpr = s; i = 0;
+ while (1) {
+ if (isspace(*pexpr) || *pexpr == '\0') break;
+ if (strchr(OPERATORS, *pexpr) != NULL) break;
+ if (i == 30) fatal("operand too large\n");
+ operand[i++] = *pexpr++;
+ }
+ if (i == 0) fatal("invalid operand\n");
+ operand[i] = '\0';
+ vp->u.s = malloc(i+1);
+ if (vp->u.s == NULL) fatal("Out of memory\n");
+ strcpy(vp->u.s, operand);
+ vp->type = string;
+ return vp;
+}
+
+
+void
+free_value(struct val *vp)
+{
+ if (vp->type == string)
+ free(vp->u.s);
+ free(vp);
+}
+
+
+/* determine if vp is an integer; if so, return it's value in *r */
+int
+is_integer(struct val *vp, int *r)
+{
+ char *s;
+ int neg;
+ int i;
+
+ if (vp->type == integer) {
+ *r = vp->u.i;
+ return 1;
+ }
+
+ /*
+ * POSIX.2 defines an "integer" as an optional unary minus
+ * followed by digits.
+ */
+ s = vp->u.s;
+ i = 0;
+
+ neg = (*s == '-');
+ if (neg)
+ s++;
+
+ while (*s) {
+ if (!isdigit(*s))
+ return 0;
+
+ i *= 10;
+ i += *s - '0';
+
+ s++;
+ }
+
+ if (neg)
+ i *= -1;
+
+ *r = i;
+ return 1;
+}
+
+
+/* coerce to vp to an integer */
+int
+to_integer(struct val *vp)
+{
+ int r;
+
+ if (vp->type == integer)
+ return 1;
+
+ if (is_integer(vp, &r)) {
+ free(vp->u.s);
+ vp->u.i = r;
+ vp->type = integer;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* coerce to vp to an string */
+void
+to_string(struct val *vp)
+{
+ char *tmp;
+
+ if (vp->type == string)
+ return;
+
+ tmp = malloc(25);
+ if (tmp == NULL) fatal("Out of memory\n");
+ sprintf(tmp, "%d", vp->u.i);
+ vp->type = string;
+ vp->u.s = tmp;
+}
+
+void
+nexttoken()
+{
+ char *i; /* index */
+
+ while (isspace(*pexpr)) pexpr++;
+
+ if (*pexpr == '\0') {
+ token = EOI;
+ return;
+ }
+
+ if ((i = strchr(OPERATORS, *pexpr)) != NULL) {
+ pexpr++;
+ token = i - OPERATORS;
+ return;
+ }
+ tokval = make_str(pexpr);
+ token = OPERAND;
+ return;
+}
+
+struct val *
+eval6()
+{
+ struct val *eval3(void);
+ struct val *v;
+
+ if (token == OPERAND) {
+ nexttoken();
+ return tokval;
+
+ } else if (token == LP) {
+ nexttoken();
+ v = eval3();
+
+ if (token != RP)
+ fatal("missing parenthesis in expression\n");
+ nexttoken();
+ return v;
+ } else fatal("expression error\n");
+ /* NOTREACHED */
+}
+
+/* Parse and evaluate multiplication and division expressions */
+struct val *
+eval4()
+{
+ struct val *l, *r;
+ enum token op;
+
+ l = eval6();
+ while ((op = token) == MUL || op == DIV || op == MOD) {
+ nexttoken();
+ r = eval6();
+
+ if (!to_integer(l) || !to_integer(r)) {
+ fatal("non-numeric argument\n");
+ }
+
+ if (op == MUL) {
+ l->u.i *= r->u.i;
+ } else {
+ if (r->u.i == 0) {
+ fatal("division by zero\n");
+ }
+ if (op == DIV) {
+ l->u.i /= r->u.i;
+ } else {
+ l->u.i %= r->u.i;
+ }
+ }
+
+ free_value(r);
+ }
+
+ return l;
+}
+
+/* Parse and evaluate addition and subtraction expressions */
+struct val *
+eval3()
+{
+ struct val *l, *r;
+ enum token op;
+
+ l = eval4();
+ while ((op = token) == ADD || op == SUB) {
+ nexttoken();
+ r = eval4();
+
+ if (!to_integer(l) || !to_integer(r)) {
+ fatal("non-numeric argument\n");
+ }
+
+ if (op == ADD) {
+ l->u.i += r->u.i;
+ } else {
+ l->u.i -= r->u.i;
+ }
+
+ free_value(r);
+ }
+
+ return l;
+}
+
+/*
+ * Evaluate the algebraic expression contained in <expression>. The
+ * value will be assigned to <result>. When errors are encountered
+ * non-zero is returned (if program is not aborted) otherwise zero.
+ */
+int strexpr(int *result, char *expression) {
+ struct val *vp;
+
+ pexpr = expression;
+
+ nexttoken();
+ vp = eval3();
+
+ if (token != EOI) return 1;
+
+ if (vp->type == integer || to_integer(vp)) {
+ *result = vp->u.i;
+ return 0;
+ }
+
+ return 1;
+}