map: use starting character lists for keys[]
[neatroff.git] / in.c
blob93ec0128fc9984d1704a92dd1714090e61959b1e
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "roff.h"
6 struct inbuf {
7 char path[64]; /* for file buffers */
8 FILE *fin;
9 char *buf; /* for string buffers */
10 char **args;
11 int unbuf[8]; /* unread characters */
12 int un; /* number of unread characters */
13 int pos;
14 int len;
15 int lnum; /* file line number */
16 int nl; /* read \n, if the previous char was not */
17 struct inbuf *prev;
20 static struct inbuf *buf;
21 static char files[NFILES][PATHLEN];
22 static int nfiles;
23 static int cfile;
24 static int in_last[2] = {'\n'}; /* the last chars returned from in_next() */
26 static char **args_init(char **args);
27 static void args_free(char **args);
29 static void in_new(void)
31 struct inbuf *next = malloc(sizeof(*next));
32 memset(next, 0, sizeof(*next));
33 next->prev = buf;
34 buf = next;
37 void in_push(char *s, char **args)
39 int len = strlen(s);
40 in_new();
41 buf->buf = malloc(len + 1);
42 buf->len = len;
43 strcpy(buf->buf, s);
44 buf->args = args ? args_init(args) : NULL;
47 void in_pushnl(char *s, char **args)
49 in_push(s, args);
50 buf->nl = 1;
53 void in_so(char *path)
55 FILE *fin = path && path[0] ? fopen(path, "r") : stdin;
56 if (fin) {
57 in_new();
58 buf->fin = fin;
59 buf->lnum = 1;
60 if (path)
61 snprintf(buf->path, sizeof(buf->path) - 1, "%s", path);
65 void in_lf(char *path, int lnum)
67 struct inbuf *cur = buf;
68 while (cur && !cur->fin)
69 cur = cur->prev;
70 if (path)
71 strcpy(cur->path, path);
72 cur->lnum = lnum;
75 void in_queue(char *path)
77 if (nfiles < NFILES)
78 snprintf(files[nfiles++], PATHLEN - 1, "%s", path ? path : "");
81 static void in_pop(void)
83 struct inbuf *old = buf;
84 buf = buf->prev;
85 if (old->args)
86 args_free(old->args);
87 if (old->fin && old->path[0])
88 fclose(old->fin);
89 free(old->buf);
90 free(old);
93 void in_nx(char *path)
95 while (buf)
96 in_pop();
97 if (path)
98 in_so(path);
101 void in_ex(void)
103 while (buf)
104 in_pop();
105 cfile = nfiles;
108 static int in_nextfile(void)
110 while (!buf && cfile < nfiles)
111 in_so(files[cfile++]);
112 return !buf;
115 static int in_read(void)
117 int c;
118 while (buf || !in_nextfile()) {
119 if (buf->un)
120 return buf->unbuf[--buf->un];
121 if (buf->nl-- > 0 && in_last[0] != '\n')
122 return '\n';
123 if (buf->buf && buf->pos < buf->len)
124 break;
125 if (!buf->buf && (c = getc(buf->fin)) >= 0) {
126 if (c == '\n')
127 buf->lnum++;
128 return c;
130 in_pop();
132 return buf ? (unsigned char) buf->buf[buf->pos++] : -1;
135 int in_next(void)
137 int c = in_read();
138 if (c >= 0) {
139 in_last[1] = in_last[0];
140 in_last[0] = c;
142 return c;
145 void in_back(int c)
147 if (c < 0)
148 return;
149 in_last[0] = in_last[1];
150 if (buf)
151 buf->unbuf[buf->un++] = c;
154 int in_top(void)
156 return buf && buf->un ? buf->unbuf[buf->un - 1] : -1;
159 char *in_arg(int i)
161 struct inbuf *cur = buf;
162 while (cur && !cur->args)
163 cur = cur->prev;
164 return cur && cur->args && cur->args[i - 1] ? cur->args[i - 1] : "";
167 int in_nargs(void)
169 struct inbuf *cur = buf;
170 int n = 0;
171 while (cur && !cur->args)
172 cur = cur->prev;
173 while (cur && cur->args && cur->args[n])
174 n++;
175 return n;
178 char *in_filename(void)
180 struct inbuf *cur = buf;
181 while (cur && !cur->fin)
182 cur = cur->prev;
183 return cur && cur->path[0] ? cur->path : "-";
186 int in_lnum(void)
188 struct inbuf *cur = buf;
189 while (cur && !cur->fin)
190 cur = cur->prev;
191 return cur->lnum;
194 static char **args_init(char **args)
196 char **out = malloc(NARGS * sizeof(*out));
197 int i;
198 for (i = 0; i < NARGS; i++) {
199 out[i] = NULL;
200 if (args[i]) {
201 int len = strlen(args[i]) + 1;
202 out[i] = malloc(len);
203 memcpy(out[i], args[i], len);
206 return out;
209 static void args_free(char **args)
211 int i;
212 for (i = 0; i < NARGS; i++)
213 if (args[i])
214 free(args[i]);
215 free(args);