tr: .nx with no arguments
[neatroff.git] / in.c
blob393fd5cde45efa257b2c72e0bcb477825f70d583
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 nl; /* read \n, if the previous char was not */
16 struct inbuf *prev;
19 static struct inbuf *buf;
20 static char files[NFILES][PATHLEN];
21 static int nfiles;
22 static int cfile;
23 static int in_last[2] = {'\n'}; /* the last chars returned from in_next() */
25 static char **args_init(char **args);
26 static void args_free(char **args);
28 static void in_new(void)
30 struct inbuf *next = malloc(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 = malloc(len + 1);
41 buf->len = len;
42 strcpy(buf->buf, s);
43 buf->args = args ? args_init(args) : NULL;
46 void in_pushnl(char *s, char **args)
48 in_push(s, args);
49 buf->nl = 1;
52 void in_so(char *path)
54 FILE *fin = path && path[0] ? fopen(path, "r") : stdin;
55 if (fin) {
56 in_new();
57 buf->fin = fin;
58 if (path)
59 snprintf(buf->path, sizeof(buf->path) - 1, "%s", path);
63 void in_queue(char *path)
65 if (nfiles < NFILES)
66 snprintf(files[nfiles++], PATHLEN - 1, "%s", path ? path : "");
69 static void in_pop(void)
71 struct inbuf *old = buf;
72 buf = buf->prev;
73 if (old->args)
74 args_free(old->args);
75 if (old->fin && old->path[0])
76 fclose(old->fin);
77 free(old->buf);
78 free(old);
81 void in_nx(char *path)
83 while (buf)
84 in_pop();
85 if (path)
86 in_so(path);
89 void in_ex(void)
91 while (buf)
92 in_pop();
93 cfile = nfiles;
96 static int in_nextfile(void)
98 while (!buf && cfile < nfiles)
99 in_so(files[cfile++]);
100 return !buf;
103 static int in_read(void)
105 int c;
106 while (buf || !in_nextfile()) {
107 if (buf->un)
108 return buf->unbuf[--buf->un];
109 if (buf->nl-- > 0 && in_last[0] != '\n')
110 return '\n';
111 if (buf->buf && buf->pos < buf->len)
112 break;
113 if (!buf->buf && (c = getc(buf->fin)) >= 0)
114 return c;
115 in_pop();
117 return buf ? (unsigned char) buf->buf[buf->pos++] : -1;
120 int in_next(void)
122 int c = in_read();
123 if (c >= 0) {
124 in_last[1] = in_last[0];
125 in_last[0] = c;
127 return c;
130 void in_back(int c)
132 if (c < 0)
133 return;
134 in_last[0] = in_last[1];
135 if (buf)
136 buf->unbuf[buf->un++] = c;
139 int in_top(void)
141 return buf && buf->un ? buf->unbuf[buf->un - 1] : -1;
144 char *in_arg(int i)
146 struct inbuf *cur = buf;
147 while (cur && !cur->args)
148 cur = cur->prev;
149 return cur && cur->args && cur->args[i - 1] ? cur->args[i - 1] : "";
152 int in_nargs(void)
154 struct inbuf *cur = buf;
155 int n = 0;
156 while (cur && !cur->args)
157 cur = cur->prev;
158 while (cur && cur->args && cur->args[n])
159 n++;
160 return n;
163 char *in_filename(void)
165 struct inbuf *cur = buf;
166 while (cur && !cur->fin)
167 cur = cur->prev;
168 return cur && cur->path[0] ? cur->path : "-";
171 static char **args_init(char **args)
173 char **out = malloc(NARGS * sizeof(*out));
174 int i;
175 for (i = 0; i < NARGS; i++) {
176 out[i] = NULL;
177 if (args[i]) {
178 int len = strlen(args[i]) + 1;
179 out[i] = malloc(len);
180 memcpy(out[i], args[i], len);
183 return out;
186 static void args_free(char **args)
188 int i;
189 for (i = 0; i < NARGS; i++)
190 if (args[i])
191 free(args[i]);
192 free(args);