From 7fdf49473c970aa96ee1bae16928d1db23643228 Mon Sep 17 00:00:00 2001 From: pst Date: Sat, 7 Sep 1996 16:18:32 +0000 Subject: Virgin import of FSF groff v1.10 --- contrib/groff/libdriver/Makefile.dep | 6 + contrib/groff/libdriver/Makefile.sub | 3 + contrib/groff/libdriver/input.cc | 476 +++++++++++++++++++++++++++++++++++ contrib/groff/libdriver/printer.cc | 241 ++++++++++++++++++ 4 files changed, 726 insertions(+) create mode 100644 contrib/groff/libdriver/Makefile.dep create mode 100644 contrib/groff/libdriver/Makefile.sub create mode 100644 contrib/groff/libdriver/input.cc create mode 100644 contrib/groff/libdriver/printer.cc (limited to 'contrib/groff/libdriver') diff --git a/contrib/groff/libdriver/Makefile.dep b/contrib/groff/libdriver/Makefile.dep new file mode 100644 index 0000000..cf2a695 --- /dev/null +++ b/contrib/groff/libdriver/Makefile.dep @@ -0,0 +1,6 @@ +input.o: input.cc ../include/driver.h ../include/errarg.h \ + ../include/error.h ../include/font.h ../include/printer.h \ + ../include/lib.h ../include/device.h ../include/cset.h +printer.o: printer.cc ../include/driver.h ../include/errarg.h \ + ../include/error.h ../include/font.h ../include/printer.h \ + ../include/lib.h diff --git a/contrib/groff/libdriver/Makefile.sub b/contrib/groff/libdriver/Makefile.sub new file mode 100644 index 0000000..1b3c09f --- /dev/null +++ b/contrib/groff/libdriver/Makefile.sub @@ -0,0 +1,3 @@ +LIB=driver +OBJS=input.o printer.o +CCSRCS=input.cc printer.cc diff --git a/contrib/groff/libdriver/input.cc b/contrib/groff/libdriver/input.cc new file mode 100644 index 0000000..6d77b5e --- /dev/null +++ b/contrib/groff/libdriver/input.cc @@ -0,0 +1,476 @@ +// -*- 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 = ""; + 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; + int np; + for (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 { + int i; + for (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; + } +} + diff --git a/contrib/groff/libdriver/printer.cc b/contrib/groff/libdriver/printer.cc new file mode 100644 index 0000000..e7547de --- /dev/null +++ b/contrib/groff/libdriver/printer.cc @@ -0,0 +1,241 @@ +// -*- 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "driver.h" + +printer *pr = 0; + +font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) +: p(f), next(fp) +{ +} + +printer::printer() +: font_table(0), nfonts(0), font_list(0) +{ +} + +printer::~printer() +{ + a_delete font_table; + while (font_list) { + font_pointer_list *tem = font_list; + font_list = font_list->next; + delete tem->p; + delete tem; + } + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); +} + +void printer::load_font(int n, const char *nm) +{ + assert(n >= 0); + if (n >= nfonts) { + if (nfonts == 0) { + nfonts = 10; + if (nfonts <= n) + nfonts = n + 1; + font_table = new font *[nfonts]; + for (int i = 0; i < nfonts; i++) + font_table[i] = 0; + } + else { + font **old_font_table = font_table; + int old_nfonts = nfonts; + nfonts *= 2; + if (n >= nfonts) + nfonts = n + 1; + font_table = new font *[nfonts]; + int i; + for (i = 0; i < old_nfonts; i++) + font_table[i] = old_font_table[i]; + for (i = old_nfonts; i < nfonts; i++) + font_table[i] = 0; + a_delete old_font_table; + } + } + font *f = find_font(nm); + font_table[n] = f; +} + +font *printer::find_font(const char *nm) +{ + for (font_pointer_list *p = font_list; p; p = p->next) + if (strcmp(p->p->get_name(), nm) == 0) + return p->p; + font *f = make_font(nm); + if (!f) + fatal("sorry, I can't continue"); + font_list = new font_pointer_list(f, font_list); + return f; +} + +font *printer::make_font(const char *nm) +{ + return font::load_font(nm); +} + +void printer::end_of_line() +{ +} + +void printer::special(char *, const environment *) +{ +} + +void printer::draw(int, int *, int, const environment *) +{ +} + +void printer::set_ascii_char(unsigned char c, const environment *env, + int *widthp) +{ + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + set_special_char(buf, env, widthp); +} + +void printer::set_special_char(const char *nm, const environment *env, + int *widthp) +{ + int i = font::name_to_index(nm); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at `%1'", fn); + return; + } + if (!f->contains(i)) { + if (nm[0] != '\0' && nm[1] == '\0') + error("font `%1' does not contain ascii character `%2'", + f->get_name(), + nm[0]); + else + error("font `%1' does not contain special character `%2'", + f->get_name(), + nm); + return; + } + int w = f->get_width(i, env->size); + if (widthp) + *widthp = w; + set_char(i, f, env, w); +} + +void printer::set_numbered_char(int num, const environment *env, int *widthp) +{ + int i = font::number_to_index(num); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at `%1'", fn); + return; + } + if (!f->contains(i)) { + error("font `%1' does not contain numbered character %2", + f->get_name(), + num); + return; + } + int w = f->get_width(i, env->size); + if (widthp) + *widthp = w; + set_char(i, f, env, w); +} + +// This utility function adjusts the specified center of the +// arc so that it is equidistant between the specified start +// and end points. (p[0], p[1]) is a vector from the current +// point to the center; (p[2], p[3]) is a vector from the +// center to the end point. If the center can be adjusted, +// a vector from the current point to the adjusted center is +// stored in c[0], c[1] and 1 is returned. Otherwise 0 is +// returned. + +#if 1 +int printer::adjust_arc_center(const int *p, double *c) +{ + // We move the center along a line parallel to the line between + // the specified start point and end point so that the center + // is equidistant between the start and end point. + // It can be proved (using Lagrange multipliers) that this will + // give the point nearest to the specified center that is equidistant + // between the start and end point. + + double x = p[0] + p[2]; // (x, y) is the end point + double y = p[1] + p[3]; + double n = x*x + y*y; + if (n != 0) { + c[0]= double(p[0]); + c[1] = double(p[1]); + double k = .5 - (c[0]*x + c[1]*y)/n; + c[0] += k*x; + c[1] += k*y; + return 1; + } + else + return 0; +} +#else +int printer::adjust_arc_center(const int *p, double *c) +{ + int x = p[0] + p[2]; // (x, y) is the end point + int y = p[1] + p[3]; + // Start at the current point; go in the direction of the specified + // center point until we reach a point that is equidistant between + // the specified starting point and the specified end point. Place + // the center of the arc there. + double n = p[0]*double(x) + p[1]*double(y); + if (n > 0) { + double k = (double(x)*x + double(y)*y)/(2.0*n); + // (cx, cy) is our chosen center + c[0] = k*p[0]; + c[1] = k*p[1]; + return 1; + } + else { + // We would never reach such a point. So instead start at the + // specified end point of the arc. Go towards the specified + // center point until we reach a point that is equidistant between + // the specified start point and specified end point. Place + // the center of the arc there. + n = p[2]*double(x) + p[3]*double(y); + if (n > 0) { + double k = 1 - (double(x)*x + double(y)*y)/(2.0*n); + // (c[0], c[1]) is our chosen center + c[0] = p[0] + k*p[2]; + c[1] = p[1] + k*p[3]; + return 1; + } + else + return 0; + } +} +#endif -- cgit v1.1