Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / preproc / soelim / soelim.cpp
blob235dfe664430b2eadb074f6ab6201f6effd50943
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 "stringclass.h"
31 #include "nonposix.h"
32 #include "searchpath.h"
34 // The include search path initially contains only the current directory.
35 static search_path include_search_path(0, 0, 0, 1);
37 int compatible_flag = 0;
38 int raw_flag = 0;
39 int tex_flag = 0;
41 extern "C" const char *Version_string;
43 int do_file(const char *filename);
46 void usage(FILE *stream)
48 fprintf(stream, "usage: %s [ -Crtv ] [ -I file ] [ files ]\n", program_name);
51 int main(int argc, char **argv)
53 program_name = argv[0];
54 int opt;
55 static const struct option long_options[] = {
56 { "help", no_argument, 0, CHAR_MAX + 1 },
57 { "version", no_argument, 0, 'v' },
58 { NULL, 0, 0, 0 }
60 while ((opt = getopt_long(argc, argv, "CI:rtv", long_options, NULL)) != EOF)
61 switch (opt) {
62 case 'v':
64 printf("GNU soelim (groff) version %s\n", Version_string);
65 exit(0);
66 break;
68 case 'C':
69 compatible_flag = 1;
70 break;
71 case 'I':
72 include_search_path.command_line_dir(optarg);
73 break;
74 case 'r':
75 raw_flag = 1;
76 break;
77 case 't':
78 tex_flag = 1;
79 break;
80 case CHAR_MAX + 1: // --help
81 usage(stdout);
82 exit(0);
83 break;
84 case '?':
85 usage(stderr);
86 exit(1);
87 break;
88 default:
89 assert(0);
91 int nbad = 0;
92 if (optind >= argc)
93 nbad += !do_file("-");
94 else
95 for (int i = optind; i < argc; i++)
96 nbad += !do_file(argv[i]);
97 if (ferror(stdout) || fflush(stdout) < 0)
98 fatal("output error");
99 return nbad != 0;
102 void set_location()
104 if(!raw_flag) {
105 if(!tex_flag)
106 printf(".lf %d %s\n", current_lineno, current_filename);
107 else
108 printf("%% file %s, line %d\n", current_filename, current_lineno);
112 void do_so(const char *line)
114 const char *p = line;
115 while (*p == ' ')
116 p++;
117 string filename;
118 int success = 1;
119 for (const char *q = p;
120 success && *q != '\0' && *q != '\n' && *q != ' ';
121 q++)
122 if (*q == '\\') {
123 switch (*++q) {
124 case 'e':
125 case '\\':
126 filename += '\\';
127 break;
128 case ' ':
129 filename += ' ';
130 break;
131 default:
132 success = 0;
133 break;
136 else
137 filename += char(*q);
138 if (success && filename.length() > 0) {
139 filename += '\0';
140 const char *fn = current_filename;
141 int ln = current_lineno;
142 current_lineno--;
143 if (do_file(filename.contents())) {
144 current_filename = fn;
145 current_lineno = ln;
146 set_location();
147 return;
149 current_lineno++;
151 fputs(".so", stdout);
152 fputs(line, stdout);
155 int do_file(const char *filename)
157 char *file_name_in_path = 0;
158 FILE *fp = include_search_path.open_file_cautious(filename,
159 &file_name_in_path);
160 int err = errno;
161 string whole_filename(file_name_in_path ? file_name_in_path : filename);
162 whole_filename += '\0';
163 a_delete file_name_in_path;
164 if (fp == 0) {
165 error("can't open `%1': %2", whole_filename.contents(), strerror(err));
166 return 0;
168 current_filename = whole_filename.contents();
169 current_lineno = 1;
170 set_location();
171 enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
172 for (;;) {
173 int c = getc(fp);
174 if (c == EOF)
175 break;
176 switch (state) {
177 case START:
178 if (c == '.')
179 state = HAD_DOT;
180 else {
181 putchar(c);
182 if (c == '\n') {
183 current_lineno++;
184 state = START;
186 else
187 state = MIDDLE;
189 break;
190 case MIDDLE:
191 putchar(c);
192 if (c == '\n') {
193 current_lineno++;
194 state = START;
196 break;
197 case HAD_DOT:
198 if (c == 's')
199 state = HAD_s;
200 else if (c == 'l')
201 state = HAD_l;
202 else {
203 putchar('.');
204 putchar(c);
205 if (c == '\n') {
206 current_lineno++;
207 state = START;
209 else
210 state = MIDDLE;
212 break;
213 case HAD_s:
214 if (c == 'o')
215 state = HAD_so;
216 else {
217 putchar('.');
218 putchar('s');
219 putchar(c);
220 if (c == '\n') {
221 current_lineno++;
222 state = START;
224 else
225 state = MIDDLE;
227 break;
228 case HAD_so:
229 if (c == ' ' || c == '\n' || compatible_flag) {
230 string line;
231 for (; c != EOF && c != '\n'; c = getc(fp))
232 line += c;
233 current_lineno++;
234 line += '\n';
235 line += '\0';
236 do_so(line.contents());
237 state = START;
239 else {
240 fputs(".so", stdout);
241 putchar(c);
242 state = MIDDLE;
244 break;
245 case HAD_l:
246 if (c == 'f')
247 state = HAD_lf;
248 else {
249 putchar('.');
250 putchar('l');
251 putchar(c);
252 if (c == '\n') {
253 current_lineno++;
254 state = START;
256 else
257 state = MIDDLE;
259 break;
260 case HAD_lf:
261 if (c == ' ' || c == '\n' || compatible_flag) {
262 string line;
263 for (; c != EOF && c != '\n'; c = getc(fp))
264 line += c;
265 current_lineno++;
266 line += '\n';
267 line += '\0';
268 interpret_lf_args(line.contents());
269 printf(".lf%s", line.contents());
270 state = START;
272 else {
273 fputs(".lf", stdout);
274 putchar(c);
275 state = MIDDLE;
277 break;
278 default:
279 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;
304 if (fp != stdin)
305 fclose(fp);
306 current_filename = 0;
307 return 1;