ren: add local motion functions
[neatroff.git] / in.c
blobcf0c45bdbff04624369ea09b1ca8701c52935599
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "xroff.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 pos;
12 int len;
13 int backed;
14 int nl; /* read \n, if the previous char was not */
15 struct inbuf *prev;
18 static struct inbuf *buf;
19 static char files[NFILES][PATHLEN];
20 static int nfiles;
21 static int cfile;
22 static int in_last;
24 static char **args_init(char **args);
25 static void args_free(char **args);
27 static void in_new(void)
29 struct inbuf *next = malloc(sizeof(*next));
30 memset(next, 0, sizeof(*next));
31 next->backed = -1;
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_source(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 static int in_nextfile(void)
83 while (!buf && cfile < nfiles)
84 in_source(files[cfile++]);
85 return !buf;
88 static int in_read(void)
90 int c;
91 while (buf || !in_nextfile()) {
92 if (buf->nl-- > 0 && in_last != '\n')
93 return '\n';
94 if (buf->buf && buf->pos < buf->len)
95 break;
96 if (!buf->buf && (c = getc(buf->fin)) >= 0)
97 return c;
98 in_pop();
100 if (!buf)
101 return -1;
102 /* replacing \\ with \ only for buffers inserted via in_push() */
103 if (buf->buf[buf->pos] == '\\' && buf->buf[buf->pos + 1] == '\\')
104 buf->pos++;
105 return buf->buf[buf->pos++];
108 int in_next(void)
110 int c;
111 if (!buf && in_nextfile())
112 return -1;
113 c = buf->backed;
114 if (c >= 0)
115 buf->backed = -1;
116 else
117 c = in_read();
118 in_last = c;
119 return c;
122 void in_back(int c)
124 if (buf)
125 buf->backed = c;
128 char *in_arg(int i)
130 struct inbuf *cur = buf;
131 while (cur && !cur->args)
132 cur = cur->prev;
133 return cur && cur->args && cur->args[i - 1] ? cur->args[i - 1] : "";
136 char *in_filename(void)
138 struct inbuf *cur = buf;
139 while (cur && !cur->fin)
140 cur = cur->prev;
141 return cur && cur->path[0] ? cur->path : "-";
144 static char **args_init(char **args)
146 char **out = malloc(NARGS * sizeof(*out));
147 int i;
148 for (i = 0; i < NARGS; i++) {
149 out[i] = NULL;
150 if (args[i]) {
151 int len = strlen(args[i]) + 1;
152 out[i] = malloc(len);
153 memcpy(out[i], args[i], len);
156 return out;
159 static void args_free(char **args)
161 int i;
162 for (i = 0; i < NARGS; i++)
163 if (args[i])
164 free(args[i]);
165 free(args);