tr: allow parsing macro arguments as a request
[neatroff.git] / in.c
blob872d3c9d24d2a798f56810687d70fe28b022613c
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[32]; /* unread characters */
13 int un; /* number of unread characters */
14 int pos;
15 int len;
16 int lnum; /* file line number */
17 struct inbuf *prev;
20 static struct inbuf *buf;
21 static char files[NFILES][PATHLEN];
22 static int nfiles;
23 static int cfile;
25 static char **args_init(char **args);
26 static void args_free(char **args);
28 static void in_new(void)
30 struct inbuf *next = xmalloc(sizeof(*next));
31 memset(next, 0, sizeof(*next));
32 next->prev = buf;
33 buf = next;
36 void in_push(char *s, char **args)
38 int len = strlen(s);
39 in_new();
40 buf->buf = xmalloc(len + 1);
41 buf->len = len;
42 strcpy(buf->buf, s);
43 buf->args = args ? args_init(args) : NULL;
46 void in_so(char *path)
48 FILE *fin = path && path[0] ? fopen(path, "r") : stdin;
49 if (!fin) {
50 errmsg("neatroff: failed to open <%s>\n", path);
51 return;
53 in_new();
54 buf->fin = fin;
55 buf->lnum = 1;
56 if (path)
57 snprintf(buf->path, sizeof(buf->path), "%s", path);
60 void in_lf(char *path, int lnum)
62 struct inbuf *cur = buf;
63 while (cur && !cur->fin)
64 cur = cur->prev;
65 if (path)
66 snprintf(cur->path, sizeof(cur->path), "%s", path);
67 cur->lnum = lnum;
70 void in_queue(char *path)
72 if (nfiles < NFILES)
73 snprintf(files[nfiles++], PATHLEN, "%s", path ? path : "");
76 static void in_pop(void)
78 struct inbuf *old = buf;
79 buf = buf->prev;
80 if (old->args)
81 args_free(old->args);
82 if (old->fin && old->fin != stdin)
83 fclose(old->fin);
84 free(old->buf);
85 free(old);
88 void in_nx(char *path)
90 while (buf)
91 in_pop();
92 if (path)
93 in_so(path);
96 void in_ex(void)
98 while (buf)
99 in_pop();
100 cfile = nfiles;
103 static int in_nextfile(void)
105 while (!buf && cfile < nfiles)
106 in_so(files[cfile++]);
107 return !buf;
110 int in_next(void)
112 int c;
113 while (buf || !in_nextfile()) {
114 if (buf->un)
115 return buf->unbuf[--buf->un];
116 if (buf->buf && buf->pos < buf->len)
117 break;
118 if (!buf->buf && (c = getc(buf->fin)) >= 0) {
119 if (c == '\n')
120 buf->lnum++;
121 return c;
123 in_pop();
125 return buf ? (unsigned char) buf->buf[buf->pos++] : -1;
128 void in_back(int c)
130 if (c < 0)
131 return;
132 if (buf && buf->un < sizeof(buf->unbuf))
133 buf->unbuf[buf->un++] = c;
136 int in_top(void)
138 return buf && buf->un ? buf->unbuf[buf->un - 1] : -1;
141 char *in_arg(int i)
143 struct inbuf *cur = buf;
144 while (cur && !cur->args)
145 cur = cur->prev;
146 return cur && cur->args && i < NARGS &&
147 cur->args[i] ? cur->args[i] : "";
150 int in_nargs(void)
152 struct inbuf *cur = buf;
153 int n = 0;
154 while (cur && !cur->args)
155 cur = cur->prev;
156 while (cur && cur->args && cur->args[n])
157 n++;
158 return n;
161 void in_shift(void)
163 struct inbuf *cur = buf;
164 while (cur && !cur->args)
165 cur = cur->prev;
166 if (cur && cur->args) {
167 free(cur->args[1]);
168 memmove(cur->args + 1, cur->args + 2,
169 (NARGS - 2) * sizeof(cur->args[0]));
170 cur->args[NARGS - 1] = NULL;
174 char *in_filename(void)
176 struct inbuf *cur = buf;
177 while (cur && !cur->fin)
178 cur = cur->prev;
179 return cur && cur->path[0] ? cur->path : "-";
182 int in_lnum(void)
184 struct inbuf *cur = buf;
185 while (cur && !cur->fin)
186 cur = cur->prev;
187 return cur ? cur->lnum : 0;
190 static char **args_init(char **args)
192 char **out = xmalloc(NARGS * sizeof(*out));
193 int i;
194 for (i = 0; i < NARGS; i++) {
195 out[i] = NULL;
196 if (args[i]) {
197 int len = strlen(args[i]) + 1;
198 out[i] = xmalloc(len);
199 memcpy(out[i], args[i], len);
202 return out;
205 static void args_free(char **args)
207 int i;
208 for (i = 0; i < NARGS; i++)
209 if (args[i])
210 free(args[i]);
211 free(args);