169497Sbostic // -*- C++ -*-
269497Sbostic /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
369497Sbostic Written by James Clark (jjc@jclark.com)
469497Sbostic
569497Sbostic This file is part of groff.
669497Sbostic
769497Sbostic groff is free software; you can redistribute it and/or modify it under
869497Sbostic the terms of the GNU General Public License as published by the Free
969497Sbostic Software Foundation; either version 2, or (at your option) any later
1069497Sbostic version.
1169497Sbostic
1269497Sbostic groff is distributed in the hope that it will be useful, but WITHOUT ANY
1369497Sbostic WARRANTY; without even the implied warranty of MERCHANTABILITY or
1469497Sbostic FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1569497Sbostic for more details.
1669497Sbostic
1769497Sbostic You should have received a copy of the GNU General Public License along
1869497Sbostic with groff; see the file COPYING. If not, write to the Free Software
1969497Sbostic Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
2069497Sbostic
2169497Sbostic #include <stdio.h>
22*69503Sbostic #include <unistd.h>
2369497Sbostic #include <ctype.h>
2469497Sbostic #include <string.h>
2569497Sbostic #include <assert.h>
2669497Sbostic #include <stdlib.h>
2769497Sbostic #include <errno.h>
2869497Sbostic #include "lib.h"
2969497Sbostic #include "errarg.h"
3069497Sbostic #include "error.h"
3169497Sbostic #include "stringclass.h"
3269497Sbostic
3369497Sbostic int compatible_flag = 0;
3469497Sbostic
3569497Sbostic extern int interpret_lf_args(const char *);
3669497Sbostic
3769497Sbostic int do_file(const char *filename);
3869497Sbostic
usage()3969497Sbostic void usage()
4069497Sbostic {
4169497Sbostic fprintf(stderr, "usage: %s [ -vC ] [ files ]\n", program_name);
4269497Sbostic exit(1);
4369497Sbostic }
4469497Sbostic
main(int argc,char ** argv)4569497Sbostic int main(int argc, char **argv)
4669497Sbostic {
4769497Sbostic program_name = argv[0];
4869497Sbostic int opt;
4969497Sbostic while ((opt = getopt(argc, argv, "vC")) != EOF)
5069497Sbostic switch (opt) {
5169497Sbostic case 'v':
5269497Sbostic {
5369497Sbostic extern const char *version_string;
5469497Sbostic fprintf(stderr, "GNU soelim version %s\n", version_string);
5569497Sbostic fflush(stderr);
5669497Sbostic break;
5769497Sbostic }
5869497Sbostic case 'C':
5969497Sbostic compatible_flag = 1;
6069497Sbostic break;
6169497Sbostic case '?':
6269497Sbostic usage();
6369497Sbostic break;
6469497Sbostic default:
6569497Sbostic assert(0);
6669497Sbostic }
6769497Sbostic int nbad = 0;
6869497Sbostic if (optind >= argc)
6969497Sbostic nbad += !do_file("-");
7069497Sbostic else
7169497Sbostic for (int i = optind; i < argc; i++)
7269497Sbostic nbad += !do_file(argv[i]);
7369497Sbostic if (ferror(stdout) || fflush(stdout) < 0)
7469497Sbostic fatal("output error");
7569497Sbostic exit(nbad != 0);
7669497Sbostic }
7769497Sbostic
set_location()7869497Sbostic void set_location()
7969497Sbostic {
8069497Sbostic printf(".lf %d %s\n", current_lineno, current_filename);
8169497Sbostic }
8269497Sbostic
do_so(const char * line)8369497Sbostic void do_so(const char *line)
8469497Sbostic {
8569497Sbostic const char *p = line;
8669497Sbostic while (*p == ' ')
8769497Sbostic p++;
8869497Sbostic string filename;
8969497Sbostic int success = 1;
9069497Sbostic for (const char *q = p;
9169497Sbostic success && *q != '\0' && *q != '\n' && *q != ' ';
9269497Sbostic q++)
9369497Sbostic if (*q == '\\') {
9469497Sbostic switch (*++q) {
9569497Sbostic case 'e':
9669497Sbostic case '\\':
9769497Sbostic filename += '\\';
9869497Sbostic break;
9969497Sbostic case ' ':
10069497Sbostic filename += ' ';
10169497Sbostic break;
10269497Sbostic default:
10369497Sbostic success = 0;
10469497Sbostic break;
10569497Sbostic }
10669497Sbostic }
10769497Sbostic else
10869497Sbostic filename += char(*q);
10969497Sbostic if (success && filename.length() > 0) {
11069497Sbostic filename += '\0';
11169497Sbostic const char *fn = current_filename;
11269497Sbostic int ln = current_lineno;
11369497Sbostic current_lineno--;
11469497Sbostic if (do_file(filename.contents())) {
11569497Sbostic current_filename = fn;
11669497Sbostic current_lineno = ln;
11769497Sbostic set_location();
11869497Sbostic return;
11969497Sbostic }
12069497Sbostic current_lineno++;
12169497Sbostic }
12269497Sbostic fputs(".so", stdout);
12369497Sbostic fputs(line, stdout);
12469497Sbostic }
12569497Sbostic
do_file(const char * filename)12669497Sbostic int do_file(const char *filename)
12769497Sbostic {
12869497Sbostic FILE *fp;
12969497Sbostic if (strcmp(filename, "-") == 0)
13069497Sbostic fp = stdin;
13169497Sbostic else {
13269497Sbostic errno = 0;
13369497Sbostic fp = fopen(filename, "r");
13469497Sbostic if (fp == 0) {
13569497Sbostic error("can't open `%1': %2", filename, strerror(errno));
13669497Sbostic return 0;
13769497Sbostic }
13869497Sbostic }
13969497Sbostic current_filename = filename;
14069497Sbostic current_lineno = 1;
14169497Sbostic set_location();
14269497Sbostic enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START;
14369497Sbostic for (;;) {
14469497Sbostic int c = getc(fp);
14569497Sbostic if (c == EOF)
14669497Sbostic break;
14769497Sbostic switch (state) {
14869497Sbostic case START:
14969497Sbostic if (c == '.')
15069497Sbostic state = HAD_DOT;
15169497Sbostic else {
15269497Sbostic putchar(c);
15369497Sbostic if (c == '\n') {
15469497Sbostic current_lineno++;
15569497Sbostic state = START;
15669497Sbostic }
15769497Sbostic else
15869497Sbostic state = MIDDLE;
15969497Sbostic }
16069497Sbostic break;
16169497Sbostic case MIDDLE:
16269497Sbostic putchar(c);
16369497Sbostic if (c == '\n') {
16469497Sbostic current_lineno++;
16569497Sbostic state = START;
16669497Sbostic }
16769497Sbostic break;
16869497Sbostic case HAD_DOT:
16969497Sbostic if (c == 's')
17069497Sbostic state = HAD_s;
17169497Sbostic else if (c == 'l')
17269497Sbostic state = HAD_l;
17369497Sbostic else {
17469497Sbostic putchar('.');
17569497Sbostic putchar(c);
17669497Sbostic if (c == '\n') {
17769497Sbostic current_lineno++;
17869497Sbostic state = START;
17969497Sbostic }
18069497Sbostic else
18169497Sbostic state = MIDDLE;
18269497Sbostic }
18369497Sbostic break;
18469497Sbostic case HAD_s:
18569497Sbostic if (c == 'o')
18669497Sbostic state = HAD_so;
18769497Sbostic else {
18869497Sbostic putchar('.');
18969497Sbostic putchar('s');
19069497Sbostic putchar(c);
19169497Sbostic if (c == '\n') {
19269497Sbostic current_lineno++;
19369497Sbostic state = START;
19469497Sbostic }
19569497Sbostic else
19669497Sbostic state = MIDDLE;
19769497Sbostic }
19869497Sbostic break;
19969497Sbostic case HAD_so:
20069497Sbostic if (c == ' ' || c == '\n' || compatible_flag) {
20169497Sbostic string line;
20269497Sbostic for (; c != EOF && c != '\n'; c = getc(fp))
20369497Sbostic line += c;
20469497Sbostic current_lineno++;
20569497Sbostic line += '\n';
20669497Sbostic line += '\0';
20769497Sbostic do_so(line.contents());
20869497Sbostic state = START;
20969497Sbostic }
21069497Sbostic else {
21169497Sbostic fputs(".so", stdout);
21269497Sbostic putchar(c);
21369497Sbostic state = MIDDLE;
21469497Sbostic }
21569497Sbostic break;
21669497Sbostic case HAD_l:
21769497Sbostic if (c == 'f')
21869497Sbostic state = HAD_lf;
21969497Sbostic else {
22069497Sbostic putchar('.');
22169497Sbostic putchar('l');
22269497Sbostic putchar(c);
22369497Sbostic if (c == '\n') {
22469497Sbostic current_lineno++;
22569497Sbostic state = START;
22669497Sbostic }
22769497Sbostic else
22869497Sbostic state = MIDDLE;
22969497Sbostic }
23069497Sbostic break;
23169497Sbostic case HAD_lf:
23269497Sbostic if (c == ' ' || c == '\n' || compatible_flag) {
23369497Sbostic string line;
23469497Sbostic for (; c != EOF && c != '\n'; c = getc(fp))
23569497Sbostic line += c;
23669497Sbostic current_lineno++;
23769497Sbostic line += '\n';
23869497Sbostic line += '\0';
23969497Sbostic interpret_lf_args(line.contents());
24069497Sbostic printf(".lf%s", line.contents());
24169497Sbostic state = START;
24269497Sbostic }
24369497Sbostic else {
24469497Sbostic fputs(".lf", stdout);
24569497Sbostic putchar(c);
24669497Sbostic state = MIDDLE;
24769497Sbostic }
24869497Sbostic break;
24969497Sbostic default:
25069497Sbostic assert(0);
25169497Sbostic }
25269497Sbostic }
25369497Sbostic switch (state) {
25469497Sbostic case HAD_DOT:
25569497Sbostic fputs(".\n", stdout);
25669497Sbostic break;
25769497Sbostic case HAD_l:
25869497Sbostic fputs(".l\n", stdout);
25969497Sbostic break;
26069497Sbostic case HAD_s:
26169497Sbostic fputs(".s\n", stdout);
26269497Sbostic break;
26369497Sbostic case HAD_lf:
26469497Sbostic fputs(".lf\n", stdout);
26569497Sbostic break;
26669497Sbostic case HAD_so:
26769497Sbostic fputs(".so\n", stdout);
26869497Sbostic break;
26969497Sbostic case MIDDLE:
27069497Sbostic putc('\n', stdout);
27169497Sbostic break;
27269497Sbostic case START:
27369497Sbostic break;
27469497Sbostic }
27569497Sbostic if (fp != stdin)
27669497Sbostic fclose(fp);
27769497Sbostic current_filename = 0;
27869497Sbostic return 1;
27969497Sbostic }
280