home *** CD-ROM | disk | FTP | other *** search
- // -*- C++ -*-
- /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
- Written by James Clark (jjc@jclark.com)
-
- 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 2, 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 COPYING. If not, write to the Free Software
- Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "driver.h"
- #include "device.h"
- #include "cset.h"
-
- const char *current_filename;
- int current_lineno;
- const char *device = 0;
- FILE *current_file;
-
- int get_integer(); // don't read the newline
- int possibly_get_integer(int *);
- char *get_string(int is_long = 0);
- void skip_line();
-
- struct environment_list {
- environment env;
- environment_list *next;
-
- environment_list(const environment &, environment_list *);
- };
-
- environment_list::environment_list(const environment &e, environment_list *p)
- : env(e), next(p)
- {
- }
-
- inline int get_char()
- {
- return getc(current_file);
- }
-
- void do_file(const char *filename)
- {
- int npages = 0;
- if (filename[0] == '-' && filename[1] == '\0') {
- current_filename = "<standard input>";
- current_file = stdin;
- }
- else {
- errno = 0;
- current_file = fopen(filename, "r");
- if (current_file == 0) {
- error("can't open `%1'", filename);
- return;
- }
- current_filename = filename;
- }
- environment env;
- env.vpos = -1;
- env.hpos = -1;
- env.fontno = -1;
- env.height = 0;
- env.slant = 0;
- environment_list *env_list = 0;
- current_lineno = 1;
- int command;
- char *s;
- command = get_char();
- if (command == EOF)
- return;
- if (command != 'x')
- fatal("the first command must be `x T'");
- s = get_string();
- if (s[0] != 'T')
- fatal("the first command must be `x T'");
- char *dev = get_string();
- if (pr == 0) {
- device = strsave(dev);
- if (!font::load_desc())
- fatal("sorry, I can't continue");
- }
- else {
- if (device == 0 || strcmp(device, dev) != 0)
- fatal("all files must use the same device");
- }
- skip_line();
- env.size = 10*font::sizescale;
- command = get_char();
- if (command != 'x')
- fatal("the second command must be `x res'");
- s = get_string();
- if (s[0] != 'r')
- fatal("the second command must be `x res'");
- int n = get_integer();
- if (n != font::res)
- fatal("resolution does not match");
- n = get_integer();
- if (n != font::hor)
- fatal("horizontal resolution does not match");
- n = get_integer();
- if (n != font::vert)
- fatal("vertical resolution does not match");
- skip_line();
- command = get_char();
- if (command != 'x')
- fatal("the third command must be `x init'");
- s = get_string();
- if (s[0] != 'i')
- fatal("the third command must be `x init'");
- skip_line();
- if (pr == 0)
- pr = make_printer();
- while ((command = get_char()) != EOF) {
- switch (command) {
- case 's':
- env.size = get_integer();
- if (env.height == env.size)
- env.height = 0;
- break;
- case 'f':
- env.fontno = get_integer();
- break;
- case 'C':
- {
- if (npages == 0)
- fatal("`C' command illegal before first `p' command");
- char *s = get_string();
- pr->set_special_char(s, &env);
- }
- break;
- case 'N':
- {
- if (npages == 0)
- fatal("`N' command illegal before first `p' command");
- pr->set_numbered_char(get_integer(), &env);
- }
- break;
- case 'H':
- env.hpos = get_integer();
- break;
- case 'h':
- env.hpos += get_integer();
- break;
- case 'V':
- env.vpos = get_integer();
- break;
- case 'v':
- env.vpos += get_integer();
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- int c = get_char();
- if (!csdigit(c))
- fatal("digit expected");
- env.hpos += (command - '0')*10 + (c - '0');
- }
- // fall through
- case 'c':
- {
- if (npages == 0)
- fatal("`c' command illegal before first `p' command");
- int c = get_char();
- if (c == EOF)
- fatal("missing argument to `c' command");
- pr->set_ascii_char(c, &env);
- }
- break;
- case 'n':
- if (npages == 0)
- fatal("`n' command illegal before first `p' command");
- pr->end_of_line();
- (void)get_integer();
- (void)get_integer();
- break;
- case 'w':
- case ' ':
- break;
- case '\n':
- current_lineno++;
- break;
- case 'p':
- if (npages)
- pr->end_page(env.vpos);
- npages++;
- pr->begin_page(get_integer());
- env.vpos = 0;
- break;
- case '{':
- env_list = new environment_list(env, env_list);
- break;
- case '}':
- if (!env_list) {
- fatal("can't pop");
- }
- else {
- env = env_list->env;
- environment_list *tem = env_list;
- env_list = env_list->next;
- delete tem;
- }
- break;
- case 'u':
- {
- if (npages == 0)
- fatal("`u' command illegal before first `p' command");
- int kern = get_integer();
- int c = get_char();
- while (c == ' ')
- c = get_char();
- while (c != EOF) {
- if (c == '\n') {
- current_lineno++;
- break;
- }
- int w;
- pr->set_ascii_char(c, &env, &w);
- env.hpos += w + kern;
- c = get_char();
- if (c == ' ')
- break;
- }
- }
- break;
- case 't':
- {
- if (npages == 0)
- fatal("`t' command illegal before first `p' command");
- int c;
- while ((c = get_char()) != EOF && c != ' ') {
- if (c == '\n') {
- current_lineno++;
- break;
- }
- int w;
- pr->set_ascii_char(c, &env, &w);
- env.hpos += w;
- }
- }
- break;
- case '#':
- skip_line();
- break;
- case 'D':
- {
- if (npages == 0)
- fatal("`D' command illegal before first `p' command");
- int c;
- while ((c = get_char()) == ' ')
- ;
- int n;
- int *p = 0;
- int szp = 0;
- for (int np = 0; possibly_get_integer(&n); np++) {
- if (np >= szp) {
- if (szp == 0) {
- szp = 16;
- p = new int[szp];
- }
- else {
- int *oldp = p;
- p = new int[szp*2];
- memcpy(p, oldp, szp*sizeof(int));
- szp *= 2;
- a_delete oldp;
- }
- }
- p[np] = n;
- }
- pr->draw(c, p, np, &env);
- if (c == 'e') {
- if (np > 0)
- env.hpos += p[0];
- }
- else {
- for (int i = 0; i < np/2; i++) {
- env.hpos += p[i*2];
- env.vpos += p[i*2 + 1];
- }
- // there might be an odd number of characters
- if (i*2 < np)
- env.hpos += p[i*2];
- }
- a_delete p;
- skip_line();
- }
- break;
- case 'x':
- {
- char *s = get_string();
- int suppress_skip = 0;
- switch (s[0]) {
- case 'i':
- error("duplicate `x init' command");
- break;
- case 'T':
- error("duplicate `x T' command");
- break;
- case 'r':
- error("duplicate `x res' command");
- break;
- case 'p':
- break;
- case 's':
- break;
- case 't':
- break;
- case 'f':
- {
- int n = get_integer();
- char *name = get_string();
- pr->load_font(n, name);
- }
- break;
- case 'H':
- env.height = get_integer();
- if (env.height == env.size)
- env.height = 0;
- break;
- case 'S':
- env.slant = get_integer();
- break;
- case 'X':
- if (npages == 0)
- fatal("`x X' command illegal before first `p' command");
- pr->special(get_string(1), &env);
- suppress_skip = 1;
- break;
- default:
- error("unrecognised x command `%1'", s);
- }
- if (!suppress_skip)
- skip_line();
- }
- break;
- default:
- error("unrecognised command code %1", int(command));
- skip_line();
- break;
- }
- }
- if (npages)
- pr->end_page(env.vpos);
- }
-
- int get_integer()
- {
- int c = get_char();
- while (c == ' ')
- c = get_char();
- int neg = 0;
- if (c == '-') {
- neg = 1;
- c = get_char();
- }
- if (!csdigit(c))
- fatal("integer expected");
- int total = 0;
- do {
- total = total*10;
- if (neg)
- total -= c - '0';
- else
- total += c - '0';
- c = get_char();
- } while (csdigit(c));
- if (c != EOF)
- ungetc(c, current_file);
- return total;
- }
-
- int possibly_get_integer(int *res)
- {
- int c = get_char();
- while (c == ' ')
- c = get_char();
- int neg = 0;
- if (c == '-') {
- neg = 1;
- c = get_char();
- }
- if (!csdigit(c)) {
- if (c != EOF)
- ungetc(c, current_file);
- return 0;
- }
- int total = 0;
- do {
- total = total*10;
- if (neg)
- total -= c - '0';
- else
- total += c - '0';
- c = get_char();
- } while (csdigit(c));
- if (c != EOF)
- ungetc(c, current_file);
- *res = total;
- return 1;
- }
-
-
- char *get_string(int is_long)
- {
- static char *buf;
- static int buf_size;
- int c = get_char();
- while (c == ' ')
- c = get_char();
- for (int i = 0;; i++) {
- if (i >= buf_size) {
- if (buf_size == 0) {
- buf_size = 16;
- buf = new char[buf_size];
- }
- else {
- char *old_buf = buf;
- int old_size = buf_size;
- buf_size *= 2;
- buf = new char[buf_size];
- memcpy(buf, old_buf, old_size);
- a_delete old_buf;
- }
- }
- if ((!is_long && (c == ' ' || c == '\n')) || c == EOF) {
- buf[i] = '\0';
- break;
- }
- if (is_long && c == '\n') {
- current_lineno++;
- c = get_char();
- if (c == '+')
- c = '\n';
- else {
- buf[i] = '\0';
- break;
- }
- }
- buf[i] = c;
- c = get_char();
- }
- if (c != EOF)
- ungetc(c, current_file);
- return buf;
- }
-
- void skip_line()
- {
- int c;
- while ((c = get_char()) != EOF)
- if (c == '\n') {
- current_lineno++;
- break;
- }
- }
-
-