groff before CVS: release 1.05
[s-roff.git] / etc / soelim.c
blobadb5e39e36158e2ff9f7210763ab80036a8ef6f7
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.uucp)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 1, or (at your option) any later
10 version.
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file LICENSE. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include "lib.h"
28 #include "errarg.h"
29 #include "error.h"
30 #include "stringclass.h"
32 int compatible_flag = 0;
34 extern int interpret_lf_args(const char *);
36 int do_file(const char *filename);
38 void usage()
40 fprintf(stderr, "usage: %s [ -vC ] [ files ]\n", program_name);
41 exit(1);
44 int main(int argc, char **argv)
46 program_name = argv[0];
47 int opt;
48 while ((opt = getopt(argc, argv, "vC")) != EOF)
49 switch (opt) {
50 case 'v':
52 extern const char *version_string;
53 fprintf(stderr, "GNU soelim version %s\n", version_string);
54 fflush(stderr);
55 break;
57 case 'C':
58 compatible_flag = 1;
59 break;
60 case '?':
61 usage();
62 break;
63 default:
64 assert(0);
66 int nbad = 0;
67 if (optind >= argc)
68 nbad += !do_file("-");
69 else
70 for (int i = optind; i < argc; i++)
71 nbad += !do_file(argv[i]);
72 if (ferror(stdout) || fflush(stdout) < 0)
73 fatal("output error");
74 exit(nbad != 0);
77 void set_location()
79 printf(".lf %d %s\n", current_lineno, current_filename);
82 void do_so(const char *line)
84 const char *p = line;
85 while (*p == ' ')
86 p++;
87 string filename;
88 int success = 1;
89 for (const char *q = p;
90 success && *q != '\0' && *q != '\n' && *q != ' ';
91 q++)
92 if (*q == '\\') {
93 switch (*++q) {
94 case 'e':
95 case '\\':
96 filename += '\\';
97 break;
98 case ' ':
99 filename += ' ';
100 break;
101 default:
102 success = 0;
103 break;
106 else
107 filename += char(*q);
108 if (success && filename.length() > 0) {
109 filename += '\0';
110 const char *fn = current_filename;
111 int ln = current_lineno;
112 current_lineno--;
113 if (do_file(filename.contents())) {
114 current_filename = fn;
115 current_lineno = ln;
116 set_location();
117 return;
119 current_lineno++;
121 fputs(".so", stdout);
122 fputs(line, stdout);
125 int do_file(const char *filename)
127 FILE *fp;
128 if (strcmp(filename, "-") == 0)
129 fp = stdin;
130 else {
131 errno = 0;
132 fp = fopen(filename, "r");
133 if (fp == 0) {
134 error("can't open `%1': %2", filename, strerror(errno));
135 return 0;
138 current_filename = filename;
139 current_lineno = 1;
140 set_location();
141 enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
142 for (;;) {
143 int c = getc(fp);
144 if (c == EOF)
145 break;
146 switch (state) {
147 case START:
148 if (c == '.')
149 state = HAD_DOT;
150 else {
151 putchar(c);
152 if (c == '\n') {
153 current_lineno++;
154 state = START;
156 else
157 state = MIDDLE;
159 break;
160 case MIDDLE:
161 putchar(c);
162 if (c == '\n') {
163 current_lineno++;
164 state = START;
166 break;
167 case HAD_DOT:
168 if (c == 's')
169 state = HAD_s;
170 else if (c == 'l')
171 state = HAD_l;
172 else {
173 putchar('.');
174 putchar(c);
175 if (c == '\n') {
176 current_lineno++;
177 state = START;
179 else
180 state = MIDDLE;
182 break;
183 case HAD_s:
184 if (c == 'o')
185 state = HAD_so;
186 else {
187 putchar('.');
188 putchar('s');
189 putchar(c);
190 if (c == '\n') {
191 current_lineno++;
192 state = START;
194 else
195 state = MIDDLE;
197 break;
198 case HAD_so:
199 if (c == ' ' || c == '\n' || compatible_flag) {
200 string line;
201 for (; c != EOF && c != '\n'; c = getc(fp))
202 line += c;
203 current_lineno++;
204 line += '\n';
205 line += '\0';
206 do_so(line.contents());
207 state = START;
209 else {
210 fputs(".so", stdout);
211 putchar(c);
212 state = MIDDLE;
214 break;
215 case HAD_l:
216 if (c == 'f')
217 state = HAD_lf;
218 else {
219 putchar('.');
220 putchar('l');
221 putchar(c);
222 if (c == '\n') {
223 current_lineno++;
224 state = START;
226 else
227 state = MIDDLE;
229 break;
230 case HAD_lf:
231 if (c == ' ' || c == '\n' || compatible_flag) {
232 string line;
233 for (; c != EOF && c != '\n'; c = getc(fp))
234 line += c;
235 current_lineno++;
236 line += '\n';
237 line += '\0';
238 interpret_lf_args(line.contents());
239 printf(".lf%s", line.contents());
240 state = START;
242 else {
243 fputs(".lf", stdout);
244 putchar(c);
245 state = MIDDLE;
247 break;
248 default:
249 assert(0);
252 switch (state) {
253 case HAD_DOT:
254 fputs(".\n", stdout);
255 break;
256 case HAD_l:
257 fputs(".l\n", stdout);
258 break;
259 case HAD_s:
260 fputs(".s\n", stdout);
261 break;
262 case HAD_lf:
263 fputs(".lf\n", stdout);
264 break;
265 case HAD_so:
266 fputs(".so\n", stdout);
267 break;
268 case MIDDLE:
269 putc('\n', stdout);
270 break;
271 case START:
272 break;
274 if (fp != stdin)
275 fclose(fp);
276 current_filename = 0;
277 return 1;