/contrib/groff/src/preproc/soelim/soelim.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 308 lines · 275 code · 12 blank · 21 comment · 79 complexity · 2b27ca8336ac9615273dfd994f558c48 MD5 · raw file

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