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