soelim(1): explicit request file_case::mux_unpack
[s-roff.git] / src / preproc / soelim / soelim.cpp
blob414c406d75fca1f1d9614f5465d3eba2686eeb24
1 // -*- C++ -*-
2 /* Copyright (C) 1989-1992, 2000, 2001, 2003, 2004, 2005
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
22 #include "lib.h"
24 #include <ctype.h>
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include "errarg.h"
29 #include "error.h"
30 #include "file_case.h"
31 #include "stringclass.h"
32 #include "nonposix.h"
33 #include "searchpath.h"
35 // The include search path initially contains only the current directory.
36 static search_path include_search_path(0, 0, 0, 1);
38 int compatible_flag = 0;
39 int raw_flag = 0;
40 int tex_flag = 0;
42 extern "C" const char *Version_string;
44 int do_file(const char *);
47 void usage(FILE *stream)
49 fprintf(stream, "usage: %s [ -Crtv ] [ -I dir ] [ files ]\n", program_name);
52 int main(int argc, char **argv)
54 program_name = argv[0];
55 int opt;
56 static const struct option long_options[] = {
57 { "help", no_argument, 0, CHAR_MAX + 1 },
58 { "version", no_argument, 0, 'v' },
59 { NULL, 0, 0, 0 }
61 while ((opt = getopt_long(argc, argv, "CI:rtv", long_options, NULL)) != EOF)
62 switch (opt) {
63 case 'v':
64 printf("GNU soelim (groff) version %s\n", Version_string);
65 exit(0);
66 break;
67 case 'C':
68 compatible_flag = 1;
69 break;
70 case 'I':
71 include_search_path.command_line_dir(optarg);
72 break;
73 case 'r':
74 raw_flag = 1;
75 break;
76 case 't':
77 tex_flag = 1;
78 break;
79 case CHAR_MAX + 1: // --help
80 usage(stdout);
81 exit(0);
82 break;
83 case '?':
84 usage(stderr);
85 exit(1);
86 break;
87 default:
88 assert(0);
90 int nbad = 0;
91 if (optind >= argc)
92 nbad += !do_file("-");
93 else
94 for (int i = optind; i < argc; i++)
95 nbad += !do_file(argv[i]);
96 if (ferror(stdout) || fflush(stdout) < 0)
97 fatal("output error");
98 return nbad != 0;
101 void set_location()
103 if (!raw_flag) {
104 if (!tex_flag)
105 printf(".lf %d %s\n", current_lineno, current_filename);
106 else
107 printf("%% file %s, line %d\n", current_filename, current_lineno);
111 void do_so(const char *line)
113 const char *p = line;
114 while (*p == ' ')
115 p++;
116 string filename;
117 int success = 1;
118 for (const char *q = p;
119 success && *q != '\0' && *q != '\n' && *q != ' ';
120 q++)
121 if (*q == '\\') {
122 switch (*++q) {
123 case 'e':
124 case '\\':
125 filename += '\\';
126 break;
127 case ' ':
128 filename += ' ';
129 break;
130 default:
131 success = 0;
132 break;
135 else
136 filename += char(*q);
137 if (success && filename.length() > 0) {
138 filename += '\0';
139 const char *fn = current_filename;
140 int ln = current_lineno;
141 current_lineno--;
142 if (do_file(filename.contents())) {
143 current_filename = fn;
144 current_lineno = ln;
145 set_location();
146 return;
148 current_lineno++;
150 fputs(".so", stdout);
151 fputs(line, stdout);
154 int do_file(const char *filename)
156 int rv = 0;
157 enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
159 file_case *fcp;
160 if ((fcp = include_search_path.open_file_cautious(filename,
161 fcp->mux_default | fcp->mux_unpack)) == NULL) {
162 error("can't open `%1': %2", filename, strerror(errno));
163 goto jleave;
166 current_filename = fcp->path();
167 current_lineno = 1;
168 set_location();
169 for (;;) {
170 int c = fcp->get_c();
171 if (c == EOF)
172 break;
173 switch (state) {
174 case START:
175 if (c == '.')
176 state = HAD_DOT;
177 else {
178 putchar(c);
179 if (c == '\n') {
180 current_lineno++;
181 state = START;
183 else
184 state = MIDDLE;
186 break;
187 case MIDDLE:
188 putchar(c);
189 if (c == '\n') {
190 current_lineno++;
191 state = START;
193 break;
194 case HAD_DOT:
195 if (c == 's')
196 state = HAD_s;
197 else if (c == 'l')
198 state = HAD_l;
199 else {
200 putchar('.');
201 putchar(c);
202 if (c == '\n') {
203 current_lineno++;
204 state = START;
206 else
207 state = MIDDLE;
209 break;
210 case HAD_s:
211 if (c == 'o')
212 state = HAD_so;
213 else {
214 putchar('.');
215 putchar('s');
216 putchar(c);
217 if (c == '\n') {
218 current_lineno++;
219 state = START;
221 else
222 state = MIDDLE;
224 break;
225 case HAD_so:
226 if (c == ' ' || c == '\n' || compatible_flag) {
227 string line;
228 for (; c != EOF && c != '\n'; c = fcp->get_c())
229 line += c;
230 current_lineno++;
231 line += '\n';
232 line += '\0';
233 do_so(line.contents());
234 state = START;
236 else {
237 fputs(".so", stdout);
238 putchar(c);
239 state = MIDDLE;
241 break;
242 case HAD_l:
243 if (c == 'f')
244 state = HAD_lf;
245 else {
246 putchar('.');
247 putchar('l');
248 putchar(c);
249 if (c == '\n') {
250 current_lineno++;
251 state = START;
253 else
254 state = MIDDLE;
256 break;
257 case HAD_lf:
258 if (c == ' ' || c == '\n' || compatible_flag) {
259 string line;
260 for (; c != EOF && c != '\n'; c = fcp->get_c())
261 line += c;
262 current_lineno++;
263 line += '\n';
264 line += '\0';
265 interpret_lf_args(line.contents());
266 printf(".lf%s", line.contents());
267 state = START;
269 else {
270 fputs(".lf", stdout);
271 putchar(c);
272 state = MIDDLE;
274 break;
275 default:
276 assert(0);
280 switch (state) {
281 case HAD_DOT:
282 fputs(".\n", stdout);
283 break;
284 case HAD_l:
285 fputs(".l\n", stdout);
286 break;
287 case HAD_s:
288 fputs(".s\n", stdout);
289 break;
290 case HAD_lf:
291 fputs(".lf\n", stdout);
292 break;
293 case HAD_so:
294 fputs(".so\n", stdout);
295 break;
296 case MIDDLE:
297 putc('\n', stdout);
298 break;
299 case START:
300 break;
303 delete fcp;
304 current_filename = 0;
305 rv = 1;
306 jleave:
307 return rv;