Net2/usr/src/usr.bin/groff/eqn/main.cc

// -*- 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);
}