1 // -*- C++ -*- 2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. 3 Written by James Clark (jjc@jclark.com) 4 5 This file is part of groff. 6 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 2, or (at your option) any later 10 version. 11 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. 16 17 You should have received a copy of the GNU General Public License along 18 with groff; see the file COPYING. If not, write to the Free Software 19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 20 21 #include <stdio.h> 22 #include <unistd.h> 23 #include <ctype.h> 24 #include <string.h> 25 #include <assert.h> 26 #include <stdlib.h> 27 #include <errno.h> 28 #include "lib.h" 29 #include "errarg.h" 30 #include "error.h" 31 #include "stringclass.h" 32 33 int compatible_flag = 0; 34 35 extern int interpret_lf_args(const char *); 36 37 int do_file(const char *filename); 38 39 void usage() 40 { 41 fprintf(stderr, "usage: %s [ -vC ] [ files ]\n", program_name); 42 exit(1); 43 } 44 45 int main(int argc, char **argv) 46 { 47 program_name = argv[0]; 48 int opt; 49 while ((opt = getopt(argc, argv, "vC")) != EOF) 50 switch (opt) { 51 case 'v': 52 { 53 extern const char *version_string; 54 fprintf(stderr, "GNU soelim version %s\n", version_string); 55 fflush(stderr); 56 break; 57 } 58 case 'C': 59 compatible_flag = 1; 60 break; 61 case '?': 62 usage(); 63 break; 64 default: 65 assert(0); 66 } 67 int nbad = 0; 68 if (optind >= argc) 69 nbad += !do_file("-"); 70 else 71 for (int i = optind; i < argc; i++) 72 nbad += !do_file(argv[i]); 73 if (ferror(stdout) || fflush(stdout) < 0) 74 fatal("output error"); 75 exit(nbad != 0); 76 } 77 78 void set_location() 79 { 80 printf(".lf %d %s\n", current_lineno, current_filename); 81 } 82 83 void do_so(const char *line) 84 { 85 const char *p = line; 86 while (*p == ' ') 87 p++; 88 string filename; 89 int success = 1; 90 for (const char *q = p; 91 success && *q != '\0' && *q != '\n' && *q != ' '; 92 q++) 93 if (*q == '\\') { 94 switch (*++q) { 95 case 'e': 96 case '\\': 97 filename += '\\'; 98 break; 99 case ' ': 100 filename += ' '; 101 break; 102 default: 103 success = 0; 104 break; 105 } 106 } 107 else 108 filename += char(*q); 109 if (success && filename.length() > 0) { 110 filename += '\0'; 111 const char *fn = current_filename; 112 int ln = current_lineno; 113 current_lineno--; 114 if (do_file(filename.contents())) { 115 current_filename = fn; 116 current_lineno = ln; 117 set_location(); 118 return; 119 } 120 current_lineno++; 121 } 122 fputs(".so", stdout); 123 fputs(line, stdout); 124 } 125 126 int do_file(const char *filename) 127 { 128 FILE *fp; 129 if (strcmp(filename, "-") == 0) 130 fp = stdin; 131 else { 132 errno = 0; 133 fp = fopen(filename, "r"); 134 if (fp == 0) { 135 error("can't open `%1': %2", filename, strerror(errno)); 136 return 0; 137 } 138 } 139 current_filename = filename; 140 current_lineno = 1; 141 set_location(); 142 enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START; 143 for (;;) { 144 int c = getc(fp); 145 if (c == EOF) 146 break; 147 switch (state) { 148 case START: 149 if (c == '.') 150 state = HAD_DOT; 151 else { 152 putchar(c); 153 if (c == '\n') { 154 current_lineno++; 155 state = START; 156 } 157 else 158 state = MIDDLE; 159 } 160 break; 161 case MIDDLE: 162 putchar(c); 163 if (c == '\n') { 164 current_lineno++; 165 state = START; 166 } 167 break; 168 case HAD_DOT: 169 if (c == 's') 170 state = HAD_s; 171 else if (c == 'l') 172 state = HAD_l; 173 else { 174 putchar('.'); 175 putchar(c); 176 if (c == '\n') { 177 current_lineno++; 178 state = START; 179 } 180 else 181 state = MIDDLE; 182 } 183 break; 184 case HAD_s: 185 if (c == 'o') 186 state = HAD_so; 187 else { 188 putchar('.'); 189 putchar('s'); 190 putchar(c); 191 if (c == '\n') { 192 current_lineno++; 193 state = START; 194 } 195 else 196 state = MIDDLE; 197 } 198 break; 199 case HAD_so: 200 if (c == ' ' || c == '\n' || compatible_flag) { 201 string line; 202 for (; c != EOF && c != '\n'; c = getc(fp)) 203 line += c; 204 current_lineno++; 205 line += '\n'; 206 line += '\0'; 207 do_so(line.contents()); 208 state = START; 209 } 210 else { 211 fputs(".so", stdout); 212 putchar(c); 213 state = MIDDLE; 214 } 215 break; 216 case HAD_l: 217 if (c == 'f') 218 state = HAD_lf; 219 else { 220 putchar('.'); 221 putchar('l'); 222 putchar(c); 223 if (c == '\n') { 224 current_lineno++; 225 state = START; 226 } 227 else 228 state = MIDDLE; 229 } 230 break; 231 case HAD_lf: 232 if (c == ' ' || c == '\n' || compatible_flag) { 233 string line; 234 for (; c != EOF && c != '\n'; c = getc(fp)) 235 line += c; 236 current_lineno++; 237 line += '\n'; 238 line += '\0'; 239 interpret_lf_args(line.contents()); 240 printf(".lf%s", line.contents()); 241 state = START; 242 } 243 else { 244 fputs(".lf", stdout); 245 putchar(c); 246 state = MIDDLE; 247 } 248 break; 249 default: 250 assert(0); 251 } 252 } 253 switch (state) { 254 case HAD_DOT: 255 fputs(".\n", stdout); 256 break; 257 case HAD_l: 258 fputs(".l\n", stdout); 259 break; 260 case HAD_s: 261 fputs(".s\n", stdout); 262 break; 263 case HAD_lf: 264 fputs(".lf\n", stdout); 265 break; 266 case HAD_so: 267 fputs(".so\n", stdout); 268 break; 269 case MIDDLE: 270 putc('\n', stdout); 271 break; 272 case START: 273 break; 274 } 275 if (fp != stdin) 276 fclose(fp); 277 current_filename = 0; 278 return 1; 279 } 280