NetBSD/gnu/usr.bin/groff/eqn/main.cc

280 lines
6.5 KiB
C++

// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
version.
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with groff; see the file LICENSE. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "eqn.h"
#include "stringclass.h"
#ifndef DEVICE
#define DEVICE "ps"
#endif
extern int yyparse();
char start_delim = '\0';
char end_delim = '\0';
int non_empty_flag;
int inline_flag;
int draw_flag = 0;
int one_size_reduction_flag = 0;
int compatible_flag = 0;
int no_newline_in_delim_flag = 0;
int read_line(FILE *fp, string *p)
{
p->clear();
int c = -1;
while ((c = getc(fp)) != EOF) {
if (!illegal_input_char(c))
*p += char(c);
else
error("illegal input character code `%1'", c);
if (c == '\n')
break;
}
current_lineno++;
return p->length() > 0;
}
void do_file(const char *filename)
{
string linebuf;
string str;
FILE *fp;
if (strcmp(filename, "-") == 0)
fp = stdin;
else {
fp = fopen(filename, "r");
if (fp == 0)
fatal("can't open `%1': %2", filename, strerror(errno));
}
printf(".lf 1 %s\n", filename);
current_filename = filename;
current_lineno = 0;
while (read_line(fp, &linebuf)) {
int i;
if (linebuf.length() >= 4
&& linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f'
&& (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
put_string(linebuf, stdout);
linebuf += '\0';
if (interpret_lf_args(linebuf.contents() + 3))
current_lineno--;
}
else if (linebuf.length() >= 4
&& linebuf[0] == '.'
&& linebuf[1] == 'E'
&& linebuf[2] == 'Q'
&& (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
put_string(linebuf, stdout);
int start_lineno = current_lineno + 1;
str.clear();
for (;;) {
if (!read_line(fp, &linebuf))
fatal("end of file before .EN");
if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
if (linebuf[2] == 'N'
&& (linebuf.length() == 3 || linebuf[3] == ' '
|| linebuf[3] == '\n' || compatible_flag))
break;
else if (linebuf[2] == 'Q' && linebuf.length() > 3
&& (linebuf[3] == ' ' || linebuf[3] == '\n'
|| compatible_flag))
fatal("nested .EQ");
}
str += linebuf;
}
str += '\0';
start_string();
init_lex(str.contents(), current_filename, start_lineno);
non_empty_flag = 0;
inline_flag = 0;
yyparse();
if (non_empty_flag) {
printf(".lf %d\n", current_lineno - 1);
output_string();
}
restore_compatibility();
printf(".lf %d\n", current_lineno);
put_string(linebuf, stdout);
}
else if (start_delim != '\0' && (i = linebuf.search(start_delim)) >= 0
&& (i == 0 || linebuf[i - 1] != '\\')) {
start_string();
linebuf += '\0';
char *ptr = &linebuf[0];
inline_flag = 1;
for (;;) {
char *start = strchr(ptr, start_delim);
if (start == 0) {
char *nl = strchr(ptr, '\n');
if (nl != 0)
*nl = '\0';
do_text(ptr);
break;
}
if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
error("missing `%1'", end_delim);
char *nl = strchr(start + 1, '\n');
if (nl != 0)
*nl = '\0';
do_text(ptr);
break;
}
int start_lineno = current_lineno;
*start = '\0';
do_text(ptr);
ptr = start + 1;
str.clear();
for (;;) {
char *end = strchr(ptr, end_delim);
if (end != 0) {
*end = '\0';
str += ptr;
ptr = end + 1;
break;
}
str += ptr;
if (!read_line(fp, &linebuf))
fatal("end of file before `%1'", end_delim);
linebuf += '\0';
ptr = &linebuf[0];
}
str += '\0';
init_lex(str.contents(), current_filename, start_lineno);
yyparse();
}
printf(".lf %d\n", current_lineno);
output_string();
restore_compatibility();
printf(".lf %d\n", current_lineno + 1);
}
else {
put_string(linebuf, stdout);
}
}
if (fp != stdin)
fclose(fp);
current_filename = 0;
current_lineno = 0;
}
void usage()
{
fprintf(stderr, "usage: %s [ -vrDCN ] -dxx -fn -sn -pn -mn -Ts [ files ... ]\n",
program_name);
exit(1);
}
int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
int opt;
const char *device = DEVICE;
const char *tem = getenv("GROFF_TYPESETTER");
if (tem)
device = tem;
while ((opt = getopt(argc, argv, "DCvd:f:p:s:m:T:rN")) != EOF)
switch (opt) {
case 'C':
compatible_flag = 1;
break;
case 'v':
{
extern const char *version_string;
fprintf(stderr, "GNU eqn version %s\n", version_string);
fflush(stderr);
break;
}
case 'd':
if (optarg[0] == '\0' || optarg[1] == '\0')
error("-d requires two character argument");
else if (illegal_input_char(optarg[0]))
error("bad delimiter `%1'", optarg[0]);
else if (illegal_input_char(optarg[1]))
error("bad delimiter `%1'", optarg[1]);
else {
start_delim = optarg[0];
end_delim = optarg[1];
}
break;
case 'f':
set_gfont(optarg);
break;
case 'T':
device = optarg;
break;
case 's':
{
int n;
if (sscanf(optarg, "%d", &n) == 1)
set_gsize(n);
else
error("bad size `%1'", optarg);
}
break;
case 'p':
{
int n;
if (sscanf(optarg, "%d", &n) == 1)
set_script_reduction(n);
else
error("bad size `%1'", optarg);
}
break;
case 'm':
{
int n;
if (sscanf(optarg, "%d", &n) == 1)
set_minimum_size(n);
else
error("bad size `%1'", optarg);
}
break;
case 'r':
one_size_reduction_flag = 1;
break;
case 'D':
draw_flag = 1;
break;
case 'N':
no_newline_in_delim_flag = 1;
break;
case '?':
usage();
break;
default:
assert(0);
}
init_table(device);
init_char_table();
if (optind >= argc)
do_file("-");
else
for (int i = optind; i < argc; i++)
do_file(argv[i]);
if (ferror(stdout) || fflush(stdout) < 0)
fatal("output error");
exit(0);
}