eqn: shorten the box_puttext() call
[neateqn.git] / in.c
blob6aff862c3a0d8563da52f15c2dc6f06cb2627eff
1 /* reading input */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "eqn.h"
7 #define NARGS 10
8 #define NMACROS 512
10 /* eqn input stream */
11 struct ein {
12 struct ein *prev; /* previous buffer */
13 char *buf; /* input buffer; NULL for stdin */
14 int pos; /* current position in buf */
15 int unbuf[LNLEN]; /* push-back buffer */
16 int uncnt;
17 char *args[NARGS]; /* macro arguments */
18 int call; /* is a macro call */
21 static struct ein ein_stdin; /* the default input stream */
22 static struct ein *ein = &ein_stdin;
24 static char *in_strdup(char *s)
26 char *d = malloc(strlen(s) + 1);
27 strcpy(d, s);
28 return d;
31 /* push buf in the input stream; this is a macro call if args is not NULL */
32 static void in_push(char *buf, char **args)
34 struct ein *next = malloc(sizeof(*next));
35 int i;
36 memset(next, 0, sizeof(*next));
37 next->prev = ein;
38 next->buf = in_strdup(buf);
39 next->call = args != NULL;
40 if (args)
41 for (i = 0; i < NARGS; i++)
42 next->args[i] = args[i] ? in_strdup(args[i]) : NULL;
43 ein = next;
46 /* back to the previous ein buffer */
47 static void in_pop(void)
49 struct ein *prev = ein->prev;
50 int i;
51 if (prev) {
52 for (i = 0; i < NARGS; i++)
53 free(ein->args[i]);
54 free(ein->buf);
55 free(ein);
56 ein = prev;
60 /* read the next character */
61 int in_next(void)
63 while (1) {
64 if (ein->uncnt)
65 return ein->unbuf[--ein->uncnt];
66 if (!ein->prev)
67 return fgetc(stdin);
68 if (ein->buf[ein->pos])
69 return ein->buf[ein->pos++];
70 in_pop();
72 return 0;
75 /* push back c */
76 void in_back(int c)
78 if (c > 0)
79 ein->unbuf[ein->uncnt++] = c;
82 /* eqn macros */
83 struct macro {
84 char name[NMLEN];
85 char *def;
87 static struct macro macros[NMACROS];
88 static int nmacros;
90 static int in_findmacro(char *name)
92 int i;
93 for (i = 0; i < nmacros; i++)
94 if (!strcmp(macros[i].name, name))
95 return i;
96 return -1;
99 /* define a macro */
100 void in_define(char *name, char *def)
102 int idx = in_findmacro(name);
103 if (idx < 0 && nmacros < NMACROS)
104 idx = nmacros++;
105 if (idx >= 0) {
106 strcpy(macros[idx].name, name);
107 free(macros[idx].def);
108 macros[idx].def = in_strdup(def);
112 /* see if name starts with a macro name followed by a '(' */
113 int in_macrocall(char *name)
115 int mlen, i;
116 for (i = 0; i < nmacros; i++) {
117 mlen = strlen(macros[i].name);
118 if (!strncmp(macros[i].name, name, mlen) && name[mlen] == '(')
119 return mlen;
121 return 0;
124 /* expand macro */
125 int in_expand(char *name, char **args)
127 int i = in_findmacro(name);
128 if (i >= 0)
129 in_push(macros[i].def, args);
130 return i < 0;
133 /* expand argument */
134 int in_arg(int i)
136 int call = ein->call;
137 if (call && ein->args[i - 1])
138 in_push(ein->args[i - 1], NULL);
139 return call ? 0 : 1;