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