Merge branch 'topic/sync-to-go-2'
[s-roff.git] / src / pre-soelim / soelim.cpp
blob21bb0759a4a29c9bb5a22a32e3cd27f3551ea969
1 /*
2 * Copyright (c) 2014 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4 * Copyright (C) 1989 - 1992, 2000, 2001, 2003 - 2005
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This 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 * This 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.
23 #include "config.h"
24 #include "soelim-config.h"
26 #include <assert.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <stdlib.h>
31 #include "errarg.h"
32 #include "error.h"
33 #include "file_case.h"
34 #include "lib.h"
35 #include "nonposix.h"
36 #include "searchpath.h"
37 #include "stringclass.h"
39 // The include search path initially contains only the current directory.
40 static search_path include_search_path(0, 0, 0, 1); // FIXME
42 int compatible_flag = 0;
43 int raw_flag = 0;
44 int tex_flag = 0;
46 int do_file(const char *);
48 void usage(FILE *stream)
50 fprintf(stream, "Synopsis: %s [ -Crtv ] [ -I dir ] [ files ]\n",
51 program_name);
54 int main(int argc, char **argv)
56 program_name = argv[0];
57 int opt;
58 static const struct option long_options[] = {
59 { "help", no_argument, 0, CHAR_MAX + 1 },
60 { "version", no_argument, 0, 'v' },
61 { NULL, 0, 0, 0 }
63 while ((opt = getopt_long(argc, argv, "CI:rtv", long_options, NULL)) != EOF)
64 switch (opt) {
65 case 'v':
66 puts(L_P_SOELIM " (" T_ROFF ") v" VERSION);
67 exit(0);
68 break;
69 case 'C':
70 compatible_flag = 1;
71 break;
72 case 'I':
73 include_search_path.command_line_dir(optarg);
74 break;
75 case 'r':
76 raw_flag = 1;
77 break;
78 case 't':
79 tex_flag = 1;
80 break;
81 case CHAR_MAX + 1: // --help
82 usage(stdout);
83 exit(0);
84 break;
85 case '?':
86 usage(stderr);
87 exit(1);
88 break;
89 default:
90 assert(0);
92 int nbad = 0;
93 if (optind >= argc)
94 nbad += !do_file("-");
95 else
96 for (int i = optind; i < argc; i++)
97 nbad += !do_file(argv[i]);
98 if (ferror(stdout) || fflush(stdout) < 0)
99 fatal("output error");
100 return nbad != 0;
103 void set_location()
105 if (!raw_flag) {
106 if (!tex_flag)
107 printf(".lf %d %s\n", current_lineno, current_filename);
108 else
109 printf("%% file %s, line %d\n", current_filename, current_lineno);
113 void do_so(const char *line)
115 const char *p = line;
116 while (*p == ' ')
117 p++;
118 string filename;
119 int success = 1;
120 for (const char *q = p;
121 success && *q != '\0' && *q != '\n' && *q != ' ';
122 q++)
123 if (*q == '\\') {
124 switch (*++q) {
125 case 'e':
126 case '\\':
127 filename += '\\';
128 break;
129 case ' ':
130 filename += ' ';
131 break;
132 default:
133 success = 0;
134 break;
137 else
138 filename += char(*q);
139 if (success && filename.length() > 0) {
140 filename += '\0';
141 const char *fn = current_filename;
142 int ln = current_lineno;
143 current_lineno--;
144 if (do_file(filename.contents())) {
145 current_filename = fn;
146 current_lineno = ln;
147 set_location();
148 return;
150 current_lineno++;
152 fputs(".so", stdout);
153 fputs(line, stdout);
156 int do_file(const char *filename)
158 int rv = 0;
159 enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
161 file_case *fcp;
162 if ((fcp = include_search_path.open_file_cautious(filename,
163 fcp->mux_default | fcp->mux_unpack)) == NULL) {
164 error("can't open `%1': %2", filename, strerror(errno));
165 goto jleave;
168 current_filename = fcp->path();
169 current_lineno = 1;
170 set_location();
171 for (;;) {
172 int c = fcp->get_c();
173 if (c == EOF)
174 break;
175 switch (state) {
176 case START:
177 if (c == '.')
178 state = HAD_DOT;
179 else {
180 putchar(c);
181 if (c == '\n') {
182 current_lineno++;
183 state = START;
185 else
186 state = MIDDLE;
188 break;
189 case MIDDLE:
190 putchar(c);
191 if (c == '\n') {
192 current_lineno++;
193 state = START;
195 break;
196 case HAD_DOT:
197 if (c == 's')
198 state = HAD_s;
199 else if (c == 'l')
200 state = HAD_l;
201 else {
202 putchar('.');
203 putchar(c);
204 if (c == '\n') {
205 current_lineno++;
206 state = START;
208 else
209 state = MIDDLE;
211 break;
212 case HAD_s:
213 if (c == 'o')
214 state = HAD_so;
215 else {
216 putchar('.');
217 putchar('s');
218 putchar(c);
219 if (c == '\n') {
220 current_lineno++;
221 state = START;
223 else
224 state = MIDDLE;
226 break;
227 case HAD_so:
228 if (c == ' ' || c == '\n' || compatible_flag) {
229 string line;
230 for (; c != EOF && c != '\n'; c = fcp->get_c())
231 line += c;
232 current_lineno++;
233 line += '\n';
234 line += '\0';
235 do_so(line.contents());
236 state = START;
238 else {
239 fputs(".so", stdout);
240 putchar(c);
241 state = MIDDLE;
243 break;
244 case HAD_l:
245 if (c == 'f')
246 state = HAD_lf;
247 else {
248 putchar('.');
249 putchar('l');
250 putchar(c);
251 if (c == '\n') {
252 current_lineno++;
253 state = START;
255 else
256 state = MIDDLE;
258 break;
259 case HAD_lf:
260 if (c == ' ' || c == '\n' || compatible_flag) {
261 string line;
262 for (; c != EOF && c != '\n'; c = fcp->get_c())
263 line += c;
264 current_lineno++;
265 line += '\n';
266 line += '\0';
267 interpret_lf_args(line.contents());
268 printf(".lf%s", line.contents());
269 state = START;
271 else {
272 fputs(".lf", stdout);
273 putchar(c);
274 state = MIDDLE;
276 break;
277 default:
278 assert(0);
282 switch (state) {
283 case HAD_DOT:
284 fputs(".\n", stdout);
285 break;
286 case HAD_l:
287 fputs(".l\n", stdout);
288 break;
289 case HAD_s:
290 fputs(".s\n", stdout);
291 break;
292 case HAD_lf:
293 fputs(".lf\n", stdout);
294 break;
295 case HAD_so:
296 fputs(".so\n", stdout);
297 break;
298 case MIDDLE:
299 putc('\n', stdout);
300 break;
301 case START:
302 break;
305 delete fcp;
306 current_filename = 0;
307 rv = 1;
308 jleave:
309 return rv;
312 // s-it2-mode