Remove no longer needed catman periodic via 'make upgrade'.
[dragonfly.git] / contrib / groff / src / preproc / soelim / soelim.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989-1992, 2000, 2001, 2003, 2004, 2005, 2009
3    Free Software Foundation, Inc.
4      Written by James Clark (jjc@jclark.com)
5
6 This file is part of groff.
7
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 3 of the License, or
11 (at your option) any later version.
12
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.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21 #include "lib.h"
22
23 #include <ctype.h>
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include "errarg.h"
28 #include "error.h"
29 #include "stringclass.h"
30 #include "nonposix.h"
31 #include "searchpath.h"
32
33 // The include search path initially contains only the current directory.
34 static search_path include_search_path(0, 0, 0, 1);
35
36 int compatible_flag = 0;
37 int raw_flag = 0;
38 int tex_flag = 0;
39
40 extern "C" const char *Version_string;
41
42 int do_file(const char *);
43
44
45 void usage(FILE *stream)
46 {
47   fprintf(stream, "usage: %s [ -Crtv ] [ -I dir ] [ files ]\n", program_name);
48 }
49
50 int main(int argc, char **argv)
51 {
52   program_name = argv[0];
53   int opt;
54   static const struct option long_options[] = {
55     { "help", no_argument, 0, CHAR_MAX + 1 },
56     { "version", no_argument, 0, 'v' },
57     { NULL, 0, 0, 0 }
58   };
59   while ((opt = getopt_long(argc, argv, "CI:rtv", long_options, NULL)) != EOF)
60     switch (opt) {
61     case 'v':
62       printf("GNU soelim (groff) version %s\n", Version_string);
63       exit(0);
64       break;
65     case 'C':
66       compatible_flag = 1;
67       break;
68     case 'I':
69       include_search_path.command_line_dir(optarg);
70       break;
71     case 'r':
72       raw_flag = 1;
73       break;
74     case 't':
75       tex_flag = 1;
76       break;
77     case CHAR_MAX + 1: // --help
78       usage(stdout);
79       exit(0);
80       break;
81     case '?':
82       usage(stderr);
83       exit(1);
84       break;
85     default:
86       assert(0);
87     }
88   int nbad = 0;
89   if (optind >= argc)
90     nbad += !do_file("-");
91   else
92     for (int i = optind; i < argc; i++)
93       nbad += !do_file(argv[i]);
94   if (ferror(stdout) || fflush(stdout) < 0)
95     fatal("output error");
96   return nbad != 0;
97 }
98
99 void set_location()
100 {
101   if (!raw_flag) {
102     if (!tex_flag)
103       printf(".lf %d %s\n", current_lineno, current_filename);
104     else
105       printf("%% file %s, line %d\n", current_filename, current_lineno);
106   }
107 }
108
109 void do_so(const char *line)
110 {
111   const char *p = line;
112   while (*p == ' ')
113     p++;
114   string filename;
115   int success = 1;
116   for (const char *q = p;
117        success && *q != '\0' && *q != '\n' && *q != ' ';
118        q++)
119     if (*q == '\\') {
120       switch (*++q) {
121       case 'e':
122       case '\\':
123         filename += '\\';
124         break;
125       case ' ':
126         filename += ' ';
127         break;
128       default:
129         success = 0;
130         break;
131       }
132     }
133     else
134       filename += char(*q);
135   if (success && filename.length() > 0) {
136     filename += '\0';
137     const char *fn = current_filename;
138     int ln = current_lineno;
139     current_lineno--;
140     if (do_file(filename.contents())) {
141       current_filename = fn;
142       current_lineno = ln;
143       set_location();
144       return;
145     }
146     current_lineno++;
147   }
148   fputs(".so", stdout);
149   fputs(line, stdout);
150 }
151
152 int do_file(const char *filename)
153 {
154   char *file_name_in_path = 0;
155   FILE *fp = include_search_path.open_file_cautious(filename,
156                                                     &file_name_in_path);
157   int err = errno;
158   string whole_filename(file_name_in_path ? file_name_in_path : filename);
159   whole_filename += '\0';
160   a_delete file_name_in_path;
161   if (fp == 0) {
162     error("can't open `%1': %2", whole_filename.contents(), strerror(err));
163     return 0;
164   }
165   current_filename = whole_filename.contents();
166   current_lineno = 1;
167   set_location();
168   enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
169   for (;;) {
170     int c = getc(fp);
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;
182         }
183         else
184           state = MIDDLE;
185       }
186       break;
187     case MIDDLE:
188       putchar(c);
189       if (c == '\n') {
190         current_lineno++;
191         state = START;
192       }
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;
205         }
206         else
207           state = MIDDLE;
208       }
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;
220         }
221         else
222           state = MIDDLE;
223       }
224       break;
225     case HAD_so:
226       if (c == ' ' || c == '\n' || compatible_flag) {
227         string line;
228         for (; c != EOF && c != '\n'; c = getc(fp))
229           line += c;
230         current_lineno++;
231         line += '\n';
232         line += '\0';
233         do_so(line.contents());
234         state = START;
235       }
236       else {
237         fputs(".so", stdout);
238         putchar(c);
239         state = MIDDLE;
240       }
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;
252         }
253         else
254           state = MIDDLE;
255       }
256       break;
257     case HAD_lf:
258       if (c == ' ' || c == '\n' || compatible_flag) {
259         string line;
260         for (; c != EOF && c != '\n'; c = getc(fp))
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;
268       }
269       else {
270         fputs(".lf", stdout);
271         putchar(c);
272         state = MIDDLE;
273       }
274       break;
275     default:
276       assert(0);
277     }
278   }
279   switch (state) {
280   case HAD_DOT:
281     fputs(".\n", stdout);
282     break;
283   case HAD_l:
284     fputs(".l\n", stdout);
285     break;
286   case HAD_s:
287     fputs(".s\n", stdout);
288     break;
289   case HAD_lf:
290     fputs(".lf\n", stdout);
291     break;
292   case HAD_so:
293     fputs(".so\n", stdout);
294     break;
295   case MIDDLE:
296     putc('\n', stdout);
297     break;
298   case START:
299     break;
300   }
301   if (fp != stdin)
302     fclose(fp);
303   current_filename = 0;
304   return 1;
305 }