README: make the instructions for CM fonts more concise
[neateqn.git] / in.c
blobc2af0a0cb7ee0a7aef8e203f87dc6f9e25957240
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;
23 static int lineno = 1; /* current line number */
25 static char *in_strdup(char *s)
27 char *d = malloc(strlen(s) + 1);
28 strcpy(d, s);
29 return d;
32 /* push buf in the input stream; this is a macro call if args is not NULL */
33 static void in_push(char *buf, char **args)
35 struct ein *next = malloc(sizeof(*next));
36 int i;
37 memset(next, 0, sizeof(*next));
38 next->prev = ein;
39 next->buf = in_strdup(buf);
40 next->call = args != NULL;
41 if (args)
42 for (i = 0; i < NARGS; i++)
43 next->args[i] = args[i] ? in_strdup(args[i]) : NULL;
44 ein = next;
47 /* back to the previous ein buffer */
48 static void in_pop(void)
50 struct ein *prev = ein->prev;
51 int i;
52 if (prev) {
53 for (i = 0; i < NARGS; i++)
54 free(ein->args[i]);
55 free(ein->buf);
56 free(ein);
57 ein = prev;
61 static int in_stdin(void)
63 int c = fgetc(stdin);
64 if (c == '\n')
65 lineno++;
66 return c;
69 /* read the next character */
70 int in_next(void)
72 while (1) {
73 if (ein->uncnt)
74 return ein->unbuf[--ein->uncnt];
75 if (!ein->prev)
76 return in_stdin();
77 if (ein->buf[ein->pos])
78 return (unsigned char) ein->buf[ein->pos++];
79 in_pop();
81 return 0;
84 /* push back c */
85 void in_back(int c)
87 if (c > 0)
88 ein->unbuf[ein->uncnt++] = c;
91 int in_lineget(void)
93 return lineno;
96 void in_lineset(int n)
98 lineno = n;
101 /* eqn macros */
102 struct macro {
103 char name[NMLEN];
104 char *def;
106 static struct macro macros[NMACROS];
107 static int nmacros;
109 static int in_findmacro(char *name)
111 int i;
112 for (i = 0; i < nmacros; i++)
113 if (!strcmp(macros[i].name, name))
114 return i;
115 return -1;
118 /* define a macro */
119 void in_define(char *name, char *def)
121 int idx = in_findmacro(name);
122 if (idx < 0 && nmacros < NMACROS)
123 idx = nmacros++;
124 if (idx >= 0) {
125 strcpy(macros[idx].name, name);
126 free(macros[idx].def);
127 macros[idx].def = in_strdup(def);
131 void in_done(void)
133 int i;
134 for (i = 0; i < nmacros; i++)
135 free(macros[i].def);
138 /* see if name starts with a macro name followed by a '(' */
139 int in_macrocall(char *name)
141 int mlen, i;
142 for (i = 0; i < nmacros; i++) {
143 mlen = strlen(macros[i].name);
144 if (!strncmp(macros[i].name, name, mlen) && name[mlen] == '(')
145 return mlen;
147 return 0;
150 /* expand macro */
151 int in_expand(char *name, char **args)
153 int i = in_findmacro(name);
154 if (i >= 0)
155 in_push(macros[i].def, args);
156 return i < 0;
159 /* expand argument */
160 int in_arg(int i)
162 int call = ein->call;
163 if (call && ein->args[i - 1])
164 in_push(ein->args[i - 1], NULL);
165 return call ? 0 : 1;
168 /* return one if not reading macros and their arguments */
169 int in_top(void)
171 return !ein->prev;