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