adj: store the words as strings
[neatroff.git] / in.c
blob32db47880ff946bcbc341d8f399c12c6f486bd82
1 /* input stream management */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 struct inbuf {
8 char path[64]; /* for file buffers */
9 FILE *fin;
10 char *buf; /* for string buffers */
11 char **args;
12 int unbuf[8]; /* unread characters */
13 int un; /* number of unread characters */
14 int pos;
15 int len;
16 int lnum; /* file line number */
17 int nl; /* read \n, if the previous char was not */
18 struct inbuf *prev;
21 static struct inbuf *buf;
22 static char files[NFILES][PATHLEN];
23 static int nfiles;
24 static int cfile;
25 static int in_last[2] = {'\n'}; /* the last chars returned from in_next() */
27 static char **args_init(char **args);
28 static void args_free(char **args);
30 static void in_new(void)
32 struct inbuf *next = malloc(sizeof(*next));
33 memset(next, 0, sizeof(*next));
34 next->prev = buf;
35 buf = next;
38 void in_push(char *s, char **args)
40 int len = strlen(s);
41 in_new();
42 buf->buf = malloc(len + 1);
43 buf->len = len;
44 strcpy(buf->buf, s);
45 buf->args = args ? args_init(args) : NULL;
48 void in_pushnl(char *s, char **args)
50 in_push(s, args);
51 buf->nl = 1;
54 void in_so(char *path)
56 FILE *fin = path && path[0] ? fopen(path, "r") : stdin;
57 if (fin) {
58 in_new();
59 buf->fin = fin;
60 buf->lnum = 1;
61 if (path)
62 snprintf(buf->path, sizeof(buf->path), "%s", path);
66 void in_lf(char *path, int lnum)
68 struct inbuf *cur = buf;
69 while (cur && !cur->fin)
70 cur = cur->prev;
71 if (path)
72 snprintf(cur->path, sizeof(cur->path), "%s", path);
73 cur->lnum = lnum;
76 void in_queue(char *path)
78 if (nfiles < NFILES)
79 snprintf(files[nfiles++], PATHLEN - 1, "%s", path ? path : "");
82 static void in_pop(void)
84 struct inbuf *old = buf;
85 buf = buf->prev;
86 if (old->args)
87 args_free(old->args);
88 if (old->fin && old->fin != stdin)
89 fclose(old->fin);
90 free(old->buf);
91 free(old);
94 void in_nx(char *path)
96 while (buf)
97 in_pop();
98 if (path)
99 in_so(path);
102 void in_ex(void)
104 while (buf)
105 in_pop();
106 cfile = nfiles;
109 static int in_nextfile(void)
111 while (!buf && cfile < nfiles)
112 in_so(files[cfile++]);
113 return !buf;
116 static int in_read(void)
118 int c;
119 while (buf || !in_nextfile()) {
120 if (buf->un)
121 return buf->unbuf[--buf->un];
122 if (buf->nl-- > 0 && in_last[0] != '\n')
123 return '\n';
124 if (buf->buf && buf->pos < buf->len)
125 break;
126 if (!buf->buf && (c = getc(buf->fin)) >= 0) {
127 if (c == '\n')
128 buf->lnum++;
129 return c;
131 in_pop();
133 return buf ? (unsigned char) buf->buf[buf->pos++] : -1;
136 int in_next(void)
138 int c = in_read();
139 if (c >= 0) {
140 in_last[1] = in_last[0];
141 in_last[0] = c;
143 return c;
146 void in_back(int c)
148 if (c < 0)
149 return;
150 in_last[0] = in_last[1];
151 if (buf)
152 buf->unbuf[buf->un++] = c;
155 int in_top(void)
157 return buf && buf->un ? buf->unbuf[buf->un - 1] : -1;
160 char *in_arg(int i)
162 struct inbuf *cur = buf;
163 while (cur && !cur->args)
164 cur = cur->prev;
165 return cur && cur->args && cur->args[i - 1] ? cur->args[i - 1] : "";
168 int in_nargs(void)
170 struct inbuf *cur = buf;
171 int n = 0;
172 while (cur && !cur->args)
173 cur = cur->prev;
174 while (cur && cur->args && cur->args[n])
175 n++;
176 return n;
179 char *in_filename(void)
181 struct inbuf *cur = buf;
182 while (cur && !cur->fin)
183 cur = cur->prev;
184 return cur && cur->path[0] ? cur->path : "-";
187 int in_lnum(void)
189 struct inbuf *cur = buf;
190 while (cur && !cur->fin)
191 cur = cur->prev;
192 return cur->lnum;
195 static char **args_init(char **args)
197 char **out = malloc(NARGS * sizeof(*out));
198 int i;
199 for (i = 0; i < NARGS; i++) {
200 out[i] = NULL;
201 if (args[i]) {
202 int len = strlen(args[i]) + 1;
203 out[i] = malloc(len);
204 memcpy(out[i], args[i], len);
207 return out;
210 static void args_free(char **args)
212 int i;
213 for (i = 0; i < NARGS; i++)
214 if (args[i])
215 free(args[i]);
216 free(args);