From bfbdfe00b3a7278899603d226f338d4bd1c1339a Mon Sep 17 00:00:00 2001 From: ru Date: Thu, 1 May 2003 13:15:22 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r114405, which included commits to RCS files with non-trunk default branches. --- contrib/groff/src/devices/grodvi/dvi.cc | 947 --- contrib/groff/src/devices/grohtml/html-table.cc | 687 -- contrib/groff/src/devices/grohtml/html-text.cc | 964 --- contrib/groff/src/devices/grohtml/output.cc | 356 -- contrib/groff/src/devices/grohtml/post-html.cc | 3745 ----------- contrib/groff/src/devices/grolbp/lbp.cc | 740 --- contrib/groff/src/devices/grolj4/lj4.cc | 708 --- contrib/groff/src/devices/grops/ps.cc | 1642 ----- contrib/groff/src/devices/grops/psrm.cc | 1147 ---- contrib/groff/src/devices/grotty/tty.cc | 776 --- contrib/groff/src/libs/libbib/common.cc | 38 - contrib/groff/src/libs/libbib/index.cc | 640 -- contrib/groff/src/libs/libbib/linear.cc | 503 -- contrib/groff/src/libs/libbib/search.cc | 133 - contrib/groff/src/libs/libdriver/input.cc | 1814 ------ contrib/groff/src/libs/libdriver/printer.cc | 216 - contrib/groff/src/libs/libgroff/assert.cc | 34 - contrib/groff/src/libs/libgroff/change_lf.cc | 37 - contrib/groff/src/libs/libgroff/color.cc | 363 -- contrib/groff/src/libs/libgroff/device.cc | 36 - contrib/groff/src/libs/libgroff/errarg.cc | 128 - contrib/groff/src/libs/libgroff/error.cc | 137 - contrib/groff/src/libs/libgroff/fatal.cc | 27 - contrib/groff/src/libs/libgroff/filename.cc | 1 - contrib/groff/src/libs/libgroff/font.cc | 1035 --- contrib/groff/src/libs/libgroff/fontfile.cc | 67 - contrib/groff/src/libs/libgroff/geometry.cc | 286 - contrib/groff/src/libs/libgroff/htmlhint.cc | 59 - contrib/groff/src/libs/libgroff/lf.cc | 62 - contrib/groff/src/libs/libgroff/lineno.cc | 1 - contrib/groff/src/libs/libgroff/macropath.cc | 30 - contrib/groff/src/libs/libgroff/maxfilename.cc | 69 - contrib/groff/src/libs/libgroff/mksdir.cc | 34 - contrib/groff/src/libs/libgroff/mkstemp.cc | 34 - contrib/groff/src/libs/libgroff/nametoindex.cc | 117 - contrib/groff/src/libs/libgroff/new.cc | 69 - contrib/groff/src/libs/libgroff/paper.cc | 84 - contrib/groff/src/libs/libgroff/prime.cc | 26 - contrib/groff/src/libs/libgroff/progname.cc | 1 - contrib/groff/src/libs/libgroff/ptable.cc | 52 - contrib/groff/src/libs/libgroff/searchpath.cc | 132 - contrib/groff/src/libs/libgroff/string.cc | 341 - contrib/groff/src/libs/libgroff/strsave.cc | 31 - contrib/groff/src/libs/libgroff/tmpfile.cc | 172 - contrib/groff/src/libs/libgroff/tmpname.cc | 116 - contrib/groff/src/preproc/eqn/box.cc | 611 -- contrib/groff/src/preproc/eqn/delim.cc | 381 -- contrib/groff/src/preproc/eqn/lex.cc | 1166 ---- contrib/groff/src/preproc/eqn/limit.cc | 195 - contrib/groff/src/preproc/eqn/list.cc | 237 - contrib/groff/src/preproc/eqn/main.cc | 395 -- contrib/groff/src/preproc/eqn/mark.cc | 121 - contrib/groff/src/preproc/eqn/other.cc | 601 -- contrib/groff/src/preproc/eqn/over.cc | 197 - contrib/groff/src/preproc/eqn/pile.cc | 293 - contrib/groff/src/preproc/eqn/script.cc | 221 - contrib/groff/src/preproc/eqn/special.cc | 115 - contrib/groff/src/preproc/eqn/sqrt.cc | 179 - contrib/groff/src/preproc/eqn/text.cc | 528 -- contrib/groff/src/preproc/grn/hdb.cc | 339 - contrib/groff/src/preproc/grn/hgraph.cc | 1055 ---- contrib/groff/src/preproc/grn/hpoint.cc | 49 - contrib/groff/src/preproc/grn/main.cc | 906 --- contrib/groff/src/preproc/html/pre-html.cc | 1525 ----- contrib/groff/src/preproc/html/pushback.cc | 333 - contrib/groff/src/preproc/pic/common.cc | 496 -- contrib/groff/src/preproc/pic/lex.cc | 1992 ------ contrib/groff/src/preproc/pic/main.cc | 635 -- contrib/groff/src/preproc/pic/object.cc | 1894 ------ contrib/groff/src/preproc/pic/tex.cc | 438 -- contrib/groff/src/preproc/pic/troff.cc | 561 -- contrib/groff/src/preproc/refer/command.cc | 809 --- contrib/groff/src/preproc/refer/ref.cc | 1160 ---- contrib/groff/src/preproc/refer/refer.cc | 1235 ---- contrib/groff/src/preproc/refer/token.cc | 378 -- contrib/groff/src/preproc/soelim/soelim.cc | 346 - contrib/groff/src/preproc/tbl/main.cc | 1529 ----- contrib/groff/src/preproc/tbl/table.cc | 2778 -------- contrib/groff/src/roff/groff/groff.cc | 753 --- contrib/groff/src/roff/troff/column.cc | 732 --- contrib/groff/src/roff/troff/dictionary.cc | 212 - contrib/groff/src/roff/troff/div.cc | 1185 ---- contrib/groff/src/roff/troff/env.cc | 3829 ----------- contrib/groff/src/roff/troff/input.cc | 7665 ----------------------- contrib/groff/src/roff/troff/node.cc | 5888 ----------------- contrib/groff/src/roff/troff/number.cc | 697 --- contrib/groff/src/roff/troff/reg.cc | 474 -- contrib/groff/src/roff/troff/symbol.cc | 154 - contrib/groff/src/utils/addftinfo/addftinfo.cc | 218 - contrib/groff/src/utils/addftinfo/guess.cc | 490 -- contrib/groff/src/utils/hpftodit/hpftodit.cc | 809 --- contrib/groff/src/utils/indxbib/indxbib.cc | 789 --- contrib/groff/src/utils/lkbib/lkbib.cc | 137 - contrib/groff/src/utils/lookbib/lookbib.cc | 141 - contrib/groff/src/utils/tfmtodit/tfmtodit.cc | 874 --- contrib/groff/win32-diffs | 2708 -------- 96 files changed, 70090 deletions(-) delete mode 100644 contrib/groff/src/devices/grodvi/dvi.cc delete mode 100644 contrib/groff/src/devices/grohtml/html-table.cc delete mode 100644 contrib/groff/src/devices/grohtml/html-text.cc delete mode 100644 contrib/groff/src/devices/grohtml/output.cc delete mode 100644 contrib/groff/src/devices/grohtml/post-html.cc delete mode 100644 contrib/groff/src/devices/grolbp/lbp.cc delete mode 100644 contrib/groff/src/devices/grolj4/lj4.cc delete mode 100644 contrib/groff/src/devices/grops/ps.cc delete mode 100644 contrib/groff/src/devices/grops/psrm.cc delete mode 100644 contrib/groff/src/devices/grotty/tty.cc delete mode 100644 contrib/groff/src/libs/libbib/common.cc delete mode 100644 contrib/groff/src/libs/libbib/index.cc delete mode 100644 contrib/groff/src/libs/libbib/linear.cc delete mode 100644 contrib/groff/src/libs/libbib/search.cc delete mode 100644 contrib/groff/src/libs/libdriver/input.cc delete mode 100644 contrib/groff/src/libs/libdriver/printer.cc delete mode 100644 contrib/groff/src/libs/libgroff/assert.cc delete mode 100644 contrib/groff/src/libs/libgroff/change_lf.cc delete mode 100644 contrib/groff/src/libs/libgroff/color.cc delete mode 100644 contrib/groff/src/libs/libgroff/device.cc delete mode 100644 contrib/groff/src/libs/libgroff/errarg.cc delete mode 100644 contrib/groff/src/libs/libgroff/error.cc delete mode 100644 contrib/groff/src/libs/libgroff/fatal.cc delete mode 100644 contrib/groff/src/libs/libgroff/filename.cc delete mode 100644 contrib/groff/src/libs/libgroff/font.cc delete mode 100644 contrib/groff/src/libs/libgroff/fontfile.cc delete mode 100644 contrib/groff/src/libs/libgroff/geometry.cc delete mode 100644 contrib/groff/src/libs/libgroff/htmlhint.cc delete mode 100644 contrib/groff/src/libs/libgroff/lf.cc delete mode 100644 contrib/groff/src/libs/libgroff/lineno.cc delete mode 100644 contrib/groff/src/libs/libgroff/macropath.cc delete mode 100644 contrib/groff/src/libs/libgroff/maxfilename.cc delete mode 100644 contrib/groff/src/libs/libgroff/mksdir.cc delete mode 100644 contrib/groff/src/libs/libgroff/mkstemp.cc delete mode 100644 contrib/groff/src/libs/libgroff/nametoindex.cc delete mode 100644 contrib/groff/src/libs/libgroff/new.cc delete mode 100644 contrib/groff/src/libs/libgroff/paper.cc delete mode 100644 contrib/groff/src/libs/libgroff/prime.cc delete mode 100644 contrib/groff/src/libs/libgroff/progname.cc delete mode 100644 contrib/groff/src/libs/libgroff/ptable.cc delete mode 100644 contrib/groff/src/libs/libgroff/searchpath.cc delete mode 100644 contrib/groff/src/libs/libgroff/string.cc delete mode 100644 contrib/groff/src/libs/libgroff/strsave.cc delete mode 100644 contrib/groff/src/libs/libgroff/tmpfile.cc delete mode 100644 contrib/groff/src/libs/libgroff/tmpname.cc delete mode 100644 contrib/groff/src/preproc/eqn/box.cc delete mode 100644 contrib/groff/src/preproc/eqn/delim.cc delete mode 100644 contrib/groff/src/preproc/eqn/lex.cc delete mode 100644 contrib/groff/src/preproc/eqn/limit.cc delete mode 100644 contrib/groff/src/preproc/eqn/list.cc delete mode 100644 contrib/groff/src/preproc/eqn/main.cc delete mode 100644 contrib/groff/src/preproc/eqn/mark.cc delete mode 100644 contrib/groff/src/preproc/eqn/other.cc delete mode 100644 contrib/groff/src/preproc/eqn/over.cc delete mode 100644 contrib/groff/src/preproc/eqn/pile.cc delete mode 100644 contrib/groff/src/preproc/eqn/script.cc delete mode 100644 contrib/groff/src/preproc/eqn/special.cc delete mode 100644 contrib/groff/src/preproc/eqn/sqrt.cc delete mode 100644 contrib/groff/src/preproc/eqn/text.cc delete mode 100644 contrib/groff/src/preproc/grn/hdb.cc delete mode 100644 contrib/groff/src/preproc/grn/hgraph.cc delete mode 100644 contrib/groff/src/preproc/grn/hpoint.cc delete mode 100644 contrib/groff/src/preproc/grn/main.cc delete mode 100644 contrib/groff/src/preproc/html/pre-html.cc delete mode 100644 contrib/groff/src/preproc/html/pushback.cc delete mode 100644 contrib/groff/src/preproc/pic/common.cc delete mode 100644 contrib/groff/src/preproc/pic/lex.cc delete mode 100644 contrib/groff/src/preproc/pic/main.cc delete mode 100644 contrib/groff/src/preproc/pic/object.cc delete mode 100644 contrib/groff/src/preproc/pic/tex.cc delete mode 100644 contrib/groff/src/preproc/pic/troff.cc delete mode 100644 contrib/groff/src/preproc/refer/command.cc delete mode 100644 contrib/groff/src/preproc/refer/ref.cc delete mode 100644 contrib/groff/src/preproc/refer/refer.cc delete mode 100644 contrib/groff/src/preproc/refer/token.cc delete mode 100644 contrib/groff/src/preproc/soelim/soelim.cc delete mode 100644 contrib/groff/src/preproc/tbl/main.cc delete mode 100644 contrib/groff/src/preproc/tbl/table.cc delete mode 100644 contrib/groff/src/roff/groff/groff.cc delete mode 100644 contrib/groff/src/roff/troff/column.cc delete mode 100644 contrib/groff/src/roff/troff/dictionary.cc delete mode 100644 contrib/groff/src/roff/troff/div.cc delete mode 100644 contrib/groff/src/roff/troff/env.cc delete mode 100644 contrib/groff/src/roff/troff/input.cc delete mode 100644 contrib/groff/src/roff/troff/node.cc delete mode 100644 contrib/groff/src/roff/troff/number.cc delete mode 100644 contrib/groff/src/roff/troff/reg.cc delete mode 100644 contrib/groff/src/roff/troff/symbol.cc delete mode 100644 contrib/groff/src/utils/addftinfo/addftinfo.cc delete mode 100644 contrib/groff/src/utils/addftinfo/guess.cc delete mode 100644 contrib/groff/src/utils/hpftodit/hpftodit.cc delete mode 100644 contrib/groff/src/utils/indxbib/indxbib.cc delete mode 100644 contrib/groff/src/utils/lkbib/lkbib.cc delete mode 100644 contrib/groff/src/utils/lookbib/lookbib.cc delete mode 100644 contrib/groff/src/utils/tfmtodit/tfmtodit.cc delete mode 100644 contrib/groff/win32-diffs diff --git a/contrib/groff/src/devices/grodvi/dvi.cc b/contrib/groff/src/devices/grodvi/dvi.cc deleted file mode 100644 index 8412636..0000000 --- a/contrib/groff/src/devices/grodvi/dvi.cc +++ /dev/null @@ -1,947 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "nonposix.h" - -extern "C" const char *Version_string; - -#define DEFAULT_LINEWIDTH 40 -static int linewidth = DEFAULT_LINEWIDTH; - -static int draw_flag = 1; - -/* These values were chosen because: - -(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27) - -and 57816 is an exact multiple of both 72.27*SIZESCALE and 72. - -The width in the groff font file is the product of MULTIPLIER and the -width in the tfm file. */ - -#define RES 57816 -#define RES_7227 (RES/7227) -#define UNITWIDTH 131072 -#define SIZESCALE 100 -#define MULTIPLIER 1 - -class dvi_font : public font { - dvi_font(const char *); -public: - int checksum; - int design_size; - ~dvi_font(); - void handle_unknown_font_command(const char *command, const char *arg, - const char *filename, int lineno); - static dvi_font *load_dvi_font(const char *); -}; - -dvi_font *dvi_font::load_dvi_font(const char *s) -{ - dvi_font *f = new dvi_font(s); - if (!f->load()) { - delete f; - return 0; - } - return f; -} - -dvi_font::dvi_font(const char *nm) -: font(nm), checksum(0), design_size(0) -{ -} - -dvi_font::~dvi_font() -{ -} - -void dvi_font::handle_unknown_font_command(const char *command, - const char *arg, - const char *filename, int lineno) -{ - char *ptr; - if (strcmp(command, "checksum") == 0) { - if (arg == 0) - fatal_with_file_and_line(filename, lineno, - "`checksum' command requires an argument"); - checksum = int(strtol(arg, &ptr, 10)); - if (checksum == 0 && ptr == arg) { - fatal_with_file_and_line(filename, lineno, "bad checksum"); - } - } - else if (strcmp(command, "designsize") == 0) { - if (arg == 0) - fatal_with_file_and_line(filename, lineno, - "`designsize' command requires an argument"); - design_size = int(strtol(arg, &ptr, 10)); - if (design_size == 0 && ptr == arg) { - fatal_with_file_and_line(filename, lineno, "bad design size"); - } - } -} - -#define FONTS_MAX 256 - -struct output_font { - dvi_font *f; - int point_size; - output_font() : f(0) { } -}; - -class dvi_printer : public printer { - FILE *fp; - int max_drift; - int byte_count; - int last_bop; - int page_count; - int cur_h; - int cur_v; - int end_h; - int max_h; - int max_v; - output_font output_font_table[FONTS_MAX]; - font *cur_font; - int cur_point_size; - color cur_color; - int pushed; - int pushed_h; - int pushed_v; - int have_pushed; - void preamble(); - void postamble(); - void define_font(int); - void set_font(int); - void possibly_begin_line(); - void set_color(color *); -protected: - enum { - id_byte = 2, - set1 = 128, - put1 = 133, - put_rule = 137, - bop = 139, - eop = 140, - push = 141, - pop = 142, - right1 = 143, - down1 = 157, - fnt_num_0 = 171, - fnt1 = 235, - xxx1 = 239, - fnt_def1 = 243, - pre = 247, - post = 248, - post_post = 249, - filler = 223 - }; - int line_thickness; - - void out1(int); - void out2(int); - void out3(int); - void out4(int); - void moveto(int, int); - void out_string(const char *); - void out_signed(unsigned char, int); - void out_unsigned(unsigned char, int); - void do_special(const char *); -public: - dvi_printer(); - ~dvi_printer(); - font *make_font(const char *); - void begin_page(int); - void end_page(int); - void set_char(int, font *, const environment *, int w, const char *name); - void special(char *arg, const environment *env, char type); - void end_of_line(); - void draw(int code, int *p, int np, const environment *env); -}; - - -class draw_dvi_printer : public dvi_printer { - int output_pen_size; - void set_line_thickness(const environment *); - void fill_next(const environment *); -public: - draw_dvi_printer(); - ~draw_dvi_printer(); - void draw(int code, int *p, int np, const environment *env); - void end_page(int); -}; - -dvi_printer::dvi_printer() -: fp(stdout), byte_count(0), last_bop(-1), page_count(0), max_h(0), max_v(0), - cur_font(0), cur_point_size(-1), pushed(0), line_thickness(-1) -{ - if (font::res != RES) - fatal("resolution must be %1", RES); - if (font::unitwidth != UNITWIDTH) - fatal("unitwidth must be %1", UNITWIDTH); - if (font::hor != 1) - fatal("hor must be equal to 1"); - if (font::vert != 1) - fatal("vert must be equal to 1"); - if (font::sizescale != SIZESCALE) - fatal("sizescale must be equal to %1", SIZESCALE); - max_drift = font::res/1000; // this is fairly arbitrary - preamble(); -} - -dvi_printer::~dvi_printer() -{ - postamble(); -} - - -draw_dvi_printer::draw_dvi_printer() -: output_pen_size(-1) -{ -} - -draw_dvi_printer::~draw_dvi_printer() -{ -} - - -void dvi_printer::out1(int n) -{ - byte_count += 1; - putc(n & 0xff, fp); -} - -void dvi_printer::out2(int n) -{ - byte_count += 2; - putc((n >> 8) & 0xff, fp); - putc(n & 0xff, fp); -} - -void dvi_printer::out3(int n) -{ - byte_count += 3; - putc((n >> 16) & 0xff, fp); - putc((n >> 8) & 0xff, fp); - putc(n & 0xff, fp); -} - -void dvi_printer::out4(int n) -{ - byte_count += 4; - putc((n >> 24) & 0xff, fp); - putc((n >> 16) & 0xff, fp); - putc((n >> 8) & 0xff, fp); - putc(n & 0xff, fp); -} - -void dvi_printer::out_string(const char *s) -{ - out1(strlen(s)); - while (*s != 0) - out1(*s++); -} - - -void dvi_printer::end_of_line() -{ - if (pushed) { - out1(pop); - pushed = 0; - cur_h = pushed_h; - cur_v = pushed_v; - } -} - -void dvi_printer::possibly_begin_line() -{ - if (!pushed) { - have_pushed = pushed = 1; - pushed_h = cur_h; - pushed_v = cur_v; - out1(push); - } -} - -int scale(int x, int z) -{ - int sw; - int a, b, c, d; - int alpha, beta; - alpha = 16*z; beta = 16; - while (z >= 040000000L) { - z /= 2; beta /= 2; - } - d = x & 255; - c = (x >> 8) & 255; - b = (x >> 16) & 255; - a = (x >> 24) & 255; - sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; - if (a == 255) - sw -= alpha; - else - assert(a == 0); - return sw; -} - -void dvi_printer::set_color(color *col) -{ - cur_color = *col; - char buf[256]; - unsigned int components[4]; - color_scheme cs = col->get_components(components); - switch (cs) { - case DEFAULT: - sprintf(buf, "color gray 0"); - break; - case RGB: - sprintf(buf, "color rgb %.3g %.3g %.3g", - double(Red) / color::MAX_COLOR_VAL, - double(Green) / color::MAX_COLOR_VAL, - double(Blue) / color::MAX_COLOR_VAL); - break; - case CMY: - col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); - // fall through - case CMYK: - sprintf(buf, "color cmyk %.3g %.3g %.3g %.3g", - double(Cyan) / color::MAX_COLOR_VAL, - double(Magenta) / color::MAX_COLOR_VAL, - double(Yellow) / color::MAX_COLOR_VAL, - double(Black) / color::MAX_COLOR_VAL); - break; - case GRAY: - sprintf(buf, "color gray %.3g", - double(Gray) / color::MAX_COLOR_VAL); - break; - } - do_special(buf); -} - -void dvi_printer::set_char(int index, font *f, const environment *env, - int w, const char *name) -{ - if (*env->col != cur_color) - set_color(env->col); - int code = f->get_code(index); - if (env->size != cur_point_size || f != cur_font) { - cur_font = f; - cur_point_size = env->size; - int i; - for (i = 0;; i++) { - if (i >= FONTS_MAX) { - fatal("too many output fonts required"); - } - if (output_font_table[i].f == 0) { - output_font_table[i].f = (dvi_font *)cur_font; - output_font_table[i].point_size = cur_point_size; - define_font(i); - } - if (output_font_table[i].f == cur_font - && output_font_table[i].point_size == cur_point_size) - break; - } - set_font(i); - } - int distance = env->hpos - cur_h; - if (env->hpos != end_h && distance != 0) { - out_signed(right1, distance); - cur_h = env->hpos; - } - else if (distance > max_drift) { - out_signed(right1, distance - max_drift); - cur_h = env->hpos - max_drift; - } - else if (distance < -max_drift) { - out_signed(right1, distance + max_drift); - cur_h = env->hpos + max_drift; - } - if (env->vpos != cur_v) { - out_signed(down1, env->vpos - cur_v); - cur_v = env->vpos; - } - possibly_begin_line(); - end_h = env->hpos + w; - cur_h += scale(f->get_width(index, UNITWIDTH)/MULTIPLIER, - cur_point_size*RES_7227); - if (cur_h > max_h) - max_h = cur_h; - if (cur_v > max_v) - max_v = cur_v; - if (code >= 0 && code <= 127) - out1(code); - else - out_unsigned(set1, code); -} - -void dvi_printer::define_font(int i) -{ - out_unsigned(fnt_def1, i); - dvi_font *f = output_font_table[i].f; - out4(f->checksum); - out4(output_font_table[i].point_size*RES_7227); - out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5)); - const char *nm = f->get_internal_name(); - out1(0); - out_string(nm); -} - -void dvi_printer::set_font(int i) -{ - if (i >= 0 && i <= 63) - out1(fnt_num_0 + i); - else - out_unsigned(fnt1, i); -} - -void dvi_printer::out_signed(unsigned char base, int param) -{ - if (-128 <= param && param < 128) { - out1(base); - out1(param); - } - else if (-32768 <= param && param < 32768) { - out1(base+1); - out2(param); - } - else if (-(1 << 23) <= param && param < (1 << 23)) { - out1(base+2); - out3(param); - } - else { - out1(base+3); - out4(param); - } -} - -void dvi_printer::out_unsigned(unsigned char base, int param) -{ - if (param >= 0) { - if (param < 256) { - out1(base); - out1(param); - } - else if (param < 65536) { - out1(base+1); - out2(param); - } - else if (param < (1 << 24)) { - out1(base+2); - out3(param); - } - else { - out1(base+3); - out4(param); - } - } - else { - out1(base+3); - out4(param); - } -} - -void dvi_printer::preamble() -{ - out1(pre); - out1(id_byte); - out4(254000); - out4(font::res); - out4(1000); - out1(0); -} - -void dvi_printer::postamble() -{ - int tem = byte_count; - out1(post); - out4(last_bop); - out4(254000); - out4(font::res); - out4(1000); - out4(max_v); - out4(max_h); - out2(have_pushed); // stack depth - out2(page_count); - int i; - for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++) - define_font(i); - out1(post_post); - out4(tem); - out1(id_byte); - for (i = 0; i < 4 || byte_count % 4 != 0; i++) - out1(filler); -} - -void dvi_printer::begin_page(int i) -{ - page_count++; - int tem = byte_count; - out1(bop); - out4(i); - for (int j = 1; j < 10; j++) - out4(0); - out4(last_bop); - last_bop = tem; - if (cur_color != default_color) - set_color(&cur_color); - // By convention position (0,0) in a dvi file is placed at (1in, 1in). - cur_h = font::res; - cur_v = font::res; - end_h = 0; -} - -void dvi_printer::end_page(int) -{ - set_color(&default_color); - if (pushed) - end_of_line(); - out1(eop); - cur_font = 0; -} - -void draw_dvi_printer::end_page(int len) -{ - dvi_printer::end_page(len); - output_pen_size = -1; -} - -void dvi_printer::do_special(const char *s) -{ - int len = strlen(s); - if (len == 0) - return; - possibly_begin_line(); - out_unsigned(xxx1, len); - while (*s) - out1(*s++); -} - -void dvi_printer::special(char *arg, const environment *env, char type) -{ - if (type != 'p') - return; - moveto(env->hpos, env->vpos); - do_special(arg); -} - -void dvi_printer::moveto(int h, int v) -{ - if (h != cur_h) { - out_signed(right1, h - cur_h); - cur_h = h; - if (cur_h > max_h) - max_h = cur_h; - } - if (v != cur_v) { - out_signed(down1, v - cur_v); - cur_v = v; - if (cur_v > max_v) - max_v = cur_v; - } - end_h = 0; -} - -void dvi_printer::draw(int code, int *p, int np, const environment *env) -{ - if (code == 'l') { - int x = 0, y = 0; - int height = 0, width = 0; - int thickness; - if (line_thickness < 0) - thickness = env->size*RES_7227*linewidth/1000; - else if (line_thickness > 0) - thickness = line_thickness; - else - thickness = 1; - if (np != 2) { - error("2 arguments required for line"); - } - else if (p[0] == 0) { - // vertical rule - if (p[1] > 0) { - x = env->hpos - thickness/2; - y = env->vpos + p[1] + thickness/2; - height = p[1] + thickness; - width = thickness; - } - else if (p[1] < 0) { - x = env->hpos - thickness/2; - y = env->vpos + thickness/2; - height = thickness - p[1]; - width = thickness; - } - } - else if (p[1] == 0) { - if (p[0] > 0) { - x = env->hpos - thickness/2; - y = env->vpos + thickness/2; - height = thickness; - width = p[0] + thickness; - } - else if (p[0] < 0) { - x = env->hpos - p[0] - thickness/2; - y = env->vpos + thickness/2; - height = thickness; - width = thickness - p[0]; - } - } - if (height != 0) { - moveto(x, y); - out1(put_rule); - out4(height); - out4(width); - } - } - else if (code == 't') { - if (np == 0) { - line_thickness = -1; - } - else { - // troff gratuitously adds an extra 0 - if (np != 1 && np != 2) - error("0 or 1 argument required for thickness"); - else - line_thickness = p[0]; - } - } - else if (code == 'R') { - if (np != 2) - error("2 arguments required for rule"); - else if (p[0] != 0 || p[1] != 0) { - int dh = p[0]; - int dv = p[1]; - int oh = env->hpos; - int ov = env->vpos; - if (dv > 0) { - ov += dv; - dv = -dv; - } - if (dh < 0) { - oh += dh; - dh = -dh; - } - moveto(oh, ov); - out1(put_rule); - out4(-dv); - out4(dh); - } - } -} - -// XXX Will this overflow? - -inline int milliinches(int n) -{ - return (n*1000 + font::res/2)/font::res; -} - -void draw_dvi_printer::set_line_thickness(const environment *env) -{ - int desired_pen_size - = milliinches(line_thickness < 0 - // Will this overflow? - ? env->size*RES_7227*linewidth/1000 - : line_thickness); - if (desired_pen_size != output_pen_size) { - char buf[256]; - sprintf(buf, "pn %d", desired_pen_size); - do_special(buf); - output_pen_size = desired_pen_size; - } -} - -void draw_dvi_printer::fill_next(const environment *env) -{ - unsigned int g; - if (env->fill->is_default()) - g = 0; - else { - // currently, only BW support - env->fill->get_gray(&g); - } - char buf[256]; - sprintf(buf, "sh %.3g", 1 - double(g)/color::MAX_COLOR_VAL); - do_special(buf); -} - -void draw_dvi_printer::draw(int code, int *p, int np, const environment *env) -{ - char buf[1024]; - int fill_flag = 0; - switch (code) { - case 'C': - fill_flag = 1; - // fall through - case 'c': - // troff adds an extra argument to C - if (np != 1 && !(code == 'C' && np == 2)) { - error("1 argument required for circle"); - break; - } - moveto(env->hpos+p[0]/2, env->vpos); - if (fill_flag) - fill_next(env); - else - set_line_thickness(env); - int rad; - rad = milliinches(p[0]/2); - sprintf(buf, "%s 0 0 %d %d 0 6.28319", - (fill_flag ? "ia" : "ar"), - rad, - rad); - do_special(buf); - break; - case 'l': - if (np != 2) { - error("2 arguments required for line"); - break; - } - moveto(env->hpos, env->vpos); - set_line_thickness(env); - do_special("pa 0 0"); - sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1])); - do_special(buf); - do_special("fp"); - break; - case 'E': - fill_flag = 1; - // fall through - case 'e': - if (np != 2) { - error("2 arguments required for ellipse"); - break; - } - moveto(env->hpos+p[0]/2, env->vpos); - if (fill_flag) - fill_next(env); - sprintf(buf, "%s 0 0 %d %d 0 6.28319", - (fill_flag ? "ia" : "ar"), - milliinches(p[0]/2), - milliinches(p[1]/2)); - do_special(buf); - break; - case 'P': - fill_flag = 1; - // fall through - case 'p': - { - if (np & 1) { - error("even number of arguments required for polygon"); - break; - } - if (np == 0) { - error("no arguments for polygon"); - break; - } - moveto(env->hpos, env->vpos); - if (fill_flag) - fill_next(env); - else - set_line_thickness(env); - do_special("pa 0 0"); - int h = 0, v = 0; - for (int i = 0; i < np; i += 2) { - h += p[i]; - v += p[i+1]; - sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); - do_special(buf); - } - do_special("pa 0 0"); - do_special(fill_flag ? "ip" : "fp"); - break; - } - case '~': - { - if (np & 1) { - error("even number of arguments required for spline"); - break; - } - if (np == 0) { - error("no arguments for spline"); - break; - } - moveto(env->hpos, env->vpos); - set_line_thickness(env); - do_special("pa 0 0"); - int h = 0, v = 0; - for (int i = 0; i < np; i += 2) { - h += p[i]; - v += p[i+1]; - sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); - do_special(buf); - } - do_special("sp"); - break; - } - case 'a': - { - if (np != 4) { - error("4 arguments required for arc"); - break; - } - set_line_thickness(env); - double c[2]; - if (adjust_arc_center(p, c)) { - int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5)); - moveto(env->hpos + int(c[0]), env->vpos + int(c[1])); - sprintf(buf, "ar 0 0 %d %d %f %f", - rad, - rad, - atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]), - atan2(-c[1], -c[0])); - do_special(buf); - } - else { - moveto(env->hpos, env->vpos); - do_special("pa 0 0"); - sprintf(buf, - "pa %d %d", - milliinches(p[0] + p[2]), - milliinches(p[1] + p[3])); - do_special(buf); - do_special("fp"); - } - break; - } - case 't': - { - if (np == 0) { - line_thickness = -1; - } - else { - // troff gratuitously adds an extra 0 - if (np != 1 && np != 2) { - error("0 or 1 argument required for thickness"); - break; - } - line_thickness = p[0]; - } - break; - } - case 'R': - { - if (np != 2) { - error("2 arguments required for rule"); - break; - } - int dh = p[0]; - if (dh == 0) - break; - int dv = p[1]; - if (dv == 0) - break; - int oh = env->hpos; - int ov = env->vpos; - if (dv > 0) { - ov += dv; - dv = -dv; - } - if (dh < 0) { - oh += dh; - dh = -dh; - } - moveto(oh, ov); - out1(put_rule); - out4(-dv); - out4(dh); - break; - } - default: - error("unrecognised drawing command `%1'", char(code)); - break; - } -} - -font *dvi_printer::make_font(const char *nm) -{ - return dvi_font::load_dvi_font(nm); -} - -printer *make_printer() -{ - if (draw_flag) - return new draw_dvi_printer; - else - return new dvi_printer; -} - -static void usage(FILE *stream); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int c; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((c = getopt_long(argc, argv, "F:vw:d", long_options, NULL)) != EOF) - switch(c) { - case 'v': - { - printf("GNU grodvi (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'w': - if (sscanf(optarg, "%d", &linewidth) != 1 - || linewidth < 0 || linewidth > 1000) { - error("bad line width"); - linewidth = DEFAULT_LINEWIDTH; - } - break; - case 'd': - draw_flag = 0; - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } -#ifdef SET_BINARY - SET_BINARY(fileno(stdout)); -#endif - if (optind >= argc) - do_file("-"); - else { - for (int i = optind; i < argc; i++) - do_file(argv[i]); - } - delete pr; - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n", - program_name); -} diff --git a/contrib/groff/src/devices/grohtml/html-table.cc b/contrib/groff/src/devices/grohtml/html-table.cc deleted file mode 100644 index a2bb255..0000000 --- a/contrib/groff/src/devices/grohtml/html-table.cc +++ /dev/null @@ -1,687 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2002 Free Software Foundation, Inc. - * - * Gaius Mulley (gaius@glam.ac.uk) wrote html-table.cc - * - * html-table.h - * - * provides the methods necessary to handle indentation and tab - * positions using html tables. - */ - -/* -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 "stringclass.h" -#include "cset.h" -#include "html-table.h" -#include "ctype.h" -#include "html.h" - -#if !defined(TRUE) -# define TRUE (1==1) -#endif -#if !defined(FALSE) -# define FALSE (1==0) -#endif - -tabs::tabs () - : tab(NULL) -{ -} - -tabs::~tabs () -{ - delete_list(); -} - -/* - * delete_list - frees the tab list and sets tab to NULL. - */ - -void tabs::delete_list (void) -{ - tab_position *p = tab; - tab_position *q; - - while (p != NULL) { - q = p; - p = p->next; - free(q); - } - tab = NULL; -} - -void tabs::clear (void) -{ - delete_list(); -} - -/* - * compatible - returns TRUE if the tab stops in, s, do - * not conflict with the current tab stops. - * The new tab stops are _not_ placed into - * this class. - */ - -int tabs::compatible (const char *s) -{ - char align; - int total=0; - tab_position *last = tab; - - if (last == NULL) - return FALSE; // no tab stops defined - - // move over tag name - while ((*s != (char)0) && !isspace(*s)) - s++; - - while (*s != (char)0 && last != NULL) { - // move over white space - while ((*s != (char)0) && isspace(*s)) - s++; - // collect alignment - align = *s; - // move over alignment - s++; - // move over white space - while ((*s != (char)0) && isspace(*s)) - s++; - // collect tab position - total += atoi(s); - // move over tab position - while ((*s != (char)0) && !isspace(*s)) - s++; - if (last->alignment != align || last->position != total) - return FALSE; - - last = last->next; - } - return TRUE; -} - -/* - * init - scans the string, s, and initializes the tab stops. - */ - -void tabs::init (const char *s) -{ - char align; - int total=0; - tab_position *last = NULL; - - clear(); // remove any tab stops - - // move over tag name - while ((*s != (char)0) && !isspace(*s)) - s++; - - while (*s != (char)0) { - // move over white space - while ((*s != (char)0) && isspace(*s)) - s++; - // collect alignment - align = *s; - // move over alignment - s++; - // move over white space - while ((*s != (char)0) && isspace(*s)) - s++; - // collect tab position - total = atoi(s); - // move over tab position - while ((*s != (char)0) && !isspace(*s)) - s++; - if (last == NULL) { - tab = (tab_position *)malloc(sizeof(tab_position)); - last = tab; - } else { - last->next = (tab_position *)malloc(sizeof(tab_position)); - last = last->next; - } - last->alignment = align; - last->position = total; - last->next = NULL; - } -} - -/* - * find_tab - returns the tab number corresponding to the position, pos. - */ - -int tabs::find_tab (int pos) -{ - tab_position *p; - int i=0; - - for (p = tab; p != NULL; p = p->next) { - i++; - if (p->position == pos) - return i; - } - return 0; -} - -/* - * get_tab_pos - returns the, nth, tab position - */ - -int tabs::get_tab_pos (int n) -{ - tab_position *p; - - n--; - for (p = tab; (p != NULL) && (n>0); p = p->next) { - n--; - if (n == 0) - return p->position; - } - return 0; -} - -char tabs::get_tab_align (int n) -{ - tab_position *p; - - n--; - for (p = tab; (p != NULL) && (n>0); p = p->next) { - n--; - if (n == 0) - return p->alignment; - } - return 'L'; -} - -/* - * dump_tab - display tab positions - */ - -void tabs::dump_tabs (void) -{ - int i=1; - tab_position *p; - - for (p = tab; p != NULL; p = p->next) { - printf("tab %d is %d\n", i, p->position); - i++; - } -} - -/* - * html_table - methods - */ - -html_table::html_table (simple_output *op, int linelen) - : columns(NULL), out(op), linelength(linelen), last_col(NULL), start_space(FALSE) -{ - tab_stops = new tabs(); -} - -html_table::~html_table () -{ - if (tab_stops != NULL) - delete tab_stops; -} - -/* - * remove_cols - remove a list of columns as defined by, c. - */ - -void html_table::remove_cols (cols *c) -{ - cols *p; - - while (c != NULL) { - p = c; - c = c->next; - free(p); - } -} - -/* - * set_linelength - sets the line length value in this table. - * It also adds an extra blank column to the - * table should linelen exceed the last column. - */ - -void html_table::set_linelength (int linelen) -{ - cols *p = NULL; - cols *c; - linelength = linelen; - - for (c = columns; c != NULL; c = c->next) { - if (c->right > linelength) { - c->right = linelength; - remove_cols(c->next); - c->next = NULL; - return; - } - p = c; - } - if (p != NULL && p->right != 0) - add_column(p->no+1, p->right+1, linelen, 'L'); -} - -/* - * get_effective_linelength - - */ - -int html_table::get_effective_linelength (void) -{ - if (columns != NULL) - return linelength - columns->left; - else - return linelength; -} - -/* - * add_indent - adds the indent to a table. - */ - -void html_table::add_indent (int indent) -{ - if (columns != NULL && columns->left > indent) - add_column(0, indent, columns->left-1, 'L'); -} - -/* - * emit_table_header - emits the html header for this table. - */ - -void html_table::emit_table_header (int space) -{ - if (columns == NULL) - return; - - // dump_table(); - - last_col = NULL; - if (linelength > 0) { - int n = no_columns() + no_gaps(); - - out->nl(); - out->nl(); - if (space) - out->put_string("

"); - start_space = space; - out->put_string("").nl(); - out->put_string("").nl(); - } -} - -/* - * get_right - returns the right most position of this column. - */ - -int html_table::get_right (cols *c) -{ - if (c != NULL && c->right > 0) - return c->right; - if (c->next != NULL) - return c->left; - return linelength; -} - -/* - * emit_col - moves onto column, n. - */ - -void html_table::emit_col (int n) -{ - cols *c = columns; - cols *b = columns; - int width = 0; - - // must be a different row - if (last_col != NULL && n <= last_col->no) - emit_new_row(); - - while (c != NULL && c->no < n) - c = c->next; - - // can we find column, n? - if (c != NULL && c->no == n) { - // shutdown previous column - if (last_col != NULL) - out->put_string("").nl(); - - // find previous column - if (last_col == NULL) - b = columns; - else - b = last_col; - - // have we a gap? - if (last_col != NULL) { - if (is_gap(b)) - out->put_string("").nl(); - b = b->next; - } - - // move across to column n - while (b != c) { - width = ((get_right(b) - b->left) * 100)/get_effective_linelength(); - out->put_string("").nl(); - // have we a gap? - if (is_gap(b)) - out->put_string("").nl(); - b = b->next; - } - width = ((get_right(b) - b->left) * 100)/get_effective_linelength(); - switch (b->alignment) { - - case 'C': out->put_string("").nl(); - } -} - -/* - * emit_new_row - move to the next row. - */ - -void html_table::emit_new_row (void) -{ - finish_row(); - out->put_string("").nl(); - last_col = NULL; -} - -void html_table::emit_finish_table (void) -{ - finish_row(); - // out->put_string("linelength = ").put_number(linelength).nl(); - out->put_string("
").nl(); - break; - case 'R': out->put_string("").nl(); - break; - default: - out->put_string("").nl(); - } - // remember column, b - last_col = b; - } -} - -/* - * finish_row - - */ - -void html_table::finish_row (void) -{ - int n = 0; - cols *c; - - if (last_col != NULL) { - for (c = last_col->next; c != NULL; c = c->next) - n = c->no; - - if (n > 0) - emit_col(n); - out->put_string("
"); - if (start_space) - out->put_string("

"); - out->nl(); -} - -/* - * add_column - adds a column. It returns FALSE if hstart..hend - * crosses into a different columns. - */ - -int html_table::add_column (int coln, int hstart, int hend, char align) -{ - cols *c = get_column(coln); - - if (c == NULL) - return insert_column(coln, hstart, hend, align); - else - return modify_column(c, hstart, hend, align); -} - -/* - * get_column - returns the column, coln. - */ - -cols *html_table::get_column (int coln) -{ - cols *c = columns; - - while (c != NULL && coln != c->no) - c = c->next; - - if (c != NULL && coln == c->no) - return c; - else - return NULL; -} - -/* - * insert_column - inserts a column, coln. - * It returns TRUE if it does not bump into - * another column. - */ - -int html_table::insert_column (int coln, int hstart, int hend, char align) -{ - cols *c = columns; - cols *l = NULL; - cols *n = NULL; - - while (c != NULL && c->no < coln) { - l = c; - c = c->next; - } - if ((l != NULL) && (hstart < l->right)) - return FALSE; // new column bumps into previous one - - if ((l != NULL) && (l->next != NULL) && - (l->next->left < hend)) - return FALSE; // new column bumps into next one - - n = (cols *)malloc(sizeof(cols)); - if (l == NULL) { - n->next = columns; - columns = n; - } else { - n->next = l->next; - l->next = n; - } - n->left = hstart; - n->right = hend; - n->no = coln; - n->alignment = align; - return TRUE; -} - -/* - * modify_column - given a column, c, modify the width to - * contain hstart..hend. - * It returns TRUE if it does not clash with - * the next or previous column. - */ - -int html_table::modify_column (cols *c, int hstart, int hend, char align) -{ - cols *l = columns; - - while (l != NULL && l->next != c) - l = l->next; - - if ((l != NULL) && (hstart < l->right)) - return FALSE; // new column bumps into previous one - - if ((c->next != NULL) && (c->next->left < hend)) - return FALSE; // new column bumps into next one - - if (c->left > hstart) - c->left = hstart; - - if (c->right < hend) - c->right = hend; - - c->alignment = align; - - return TRUE; -} - -/* - * find_tab_column - finds the column number for position, pos. - * It searches through the list tab stops. - */ - -int html_table::find_tab_column (int pos) -{ - // remember the first column is reserved for un tabbed glyphs - return tab_stops->find_tab(pos)+1; -} - -/* - * find_column - find the column number for position, pos. - * It searches through the list of columns. - */ - -int html_table::find_column (int pos) -{ - int p=0; - cols *c; - - for (c = columns; c != NULL; c = c->next) { - if (c->left > pos) - return p; - p = c->no; - } - return p; -} - -/* - * no_columns - returns the number of table columns (rather than tabs) - */ - -int html_table::no_columns (void) -{ - int n=0; - cols *c; - - for (c = columns; c != NULL; c = c->next) - n++; - return n; -} - -/* - * is_gap - returns the gap between column, c, and the next column. - */ - -int html_table::is_gap (cols *c) -{ - if (c == NULL || c->right == 0 || c->next == NULL) - return 0; - else - return (c->next->left - c->right)*100/get_effective_linelength(); -} - -/* - * no_gaps - returns the number of table gaps between the columns - */ - -int html_table::no_gaps (void) -{ - int n=0; - cols *c; - - for (c = columns; c != NULL; c = c->next) - if (is_gap(c)) - n++; - return n; -} - -/* - * get_tab_pos - returns the, nth, tab position - */ - -int html_table::get_tab_pos (int n) -{ - return tab_stops->get_tab_pos(n); -} - -char html_table::get_tab_align (int n) -{ - return tab_stops->get_tab_align(n); -} - - -void html_table::dump_table (void) -{ - if (columns != NULL) { - cols *c; - for (c = columns; c != NULL; c = c->next) { - printf("column %d %d..%d %c\n", c->no, c->left, c->right, c->alignment); - } - } else - tab_stops->dump_tabs(); -} - -/* - * html_indent - creates an indent with indentation, ind, given - * a line length of linelength. - */ - -html_indent::html_indent (simple_output *op, int ind, int pageoffset, int linelength) -{ - table = new html_table(op, linelength); - - table->add_column(1, ind+pageoffset, linelength, 'L'); - table->add_indent(pageoffset); - in = ind; - pg = pageoffset; - ll = linelength; - is_used = FALSE; -} - -html_indent::~html_indent (void) -{ - end(); - delete table; -} - -void html_indent::begin (int space) -{ - if (! is_used) { - table->emit_table_header(space); - table->emit_col(1); - is_used = TRUE; - } -} - -void html_indent::end (void) -{ - if (is_used) - table->emit_finish_table(); - is_used = FALSE; -} - -/* - * get_reg - collects the registers as supplied during initialization. - */ - -void html_indent::get_reg (int *ind, int *pageoffset, int *linelength) -{ - *ind = in; - *pageoffset = pg; - *linelength = ll; -} diff --git a/contrib/groff/src/devices/grohtml/html-text.cc b/contrib/groff/src/devices/grohtml/html-text.cc deleted file mode 100644 index 31e4311..0000000 --- a/contrib/groff/src/devices/grohtml/html-text.cc +++ /dev/null @@ -1,964 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. - * - * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc - * - * html-text.cc - * - * provide a troff like state machine interface which - * generates html text. - */ - -/* -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 "stringclass.h" -#include "cset.h" - -#if !defined(TRUE) -# define TRUE (1==1) -#endif -#if !defined(FALSE) -# define FALSE (1==0) -#endif - - -#include "html-text.h" - -// #define DEBUGGING - -html_text::html_text (simple_output *op) : - stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE), - current_indentation(-1), pageoffset(-1), linelength(-1), - blank_para(TRUE), start_space(FALSE) -{ -} - -html_text::~html_text () -{ - flush_text(); -} - - -#if defined(DEBUGGING) -static int debugStack = FALSE; - - -/* - * turnDebug - flip the debugStack boolean and return the new value. - */ - -static int turnDebug (void) -{ - debugStack = 1-debugStack; - return debugStack; -} - -/* - * dump_stack_element - display an element of the html stack, p. - */ - -void html_text::dump_stack_element (tag_definition *p) -{ - fprintf(stderr, " | "); - switch (p->type) { - - case P_TAG: if (p->indent == NULL) { - fprintf(stderr, "

", (char *)p->arg1); break; - } else { - fprintf(stderr, "

", (char *)p->arg1); break; - } - case I_TAG: fprintf(stderr, ""); break; - case B_TAG: fprintf(stderr, ""); break; - case SUB_TAG: fprintf(stderr, ""); break; - case SUP_TAG: fprintf(stderr, ""); break; - case TT_TAG: fprintf(stderr, ""); break; - case PRE_TAG: if (p->indent == NULL) { - fprintf(stderr, "

"); break;
-                   } else {
-                      fprintf(stderr, "
"); break;
-		   }
-  case SMALL_TAG:  fprintf(stderr, ""); break;
-  case BIG_TAG:    fprintf(stderr, ""); break;
-  case BREAK_TAG:  fprintf(stderr, ""); break;
-  case COLOR_TAG:  {
-    if (p->col.is_default())
-      fprintf(stderr, "");
-    else {
-      unsigned int r, g, b;
-      
-      p->col.get_rgb(&r, &g, &b);
-      fprintf(stderr, "", r/0x101, g/0x101, b/0x101);
-    }
-    break;
-  }
-  default: fprintf(stderr, "unknown tag");
-  }
-  if (p->text_emitted)
-    fprintf(stderr, "[t] ");
-}
-
-/*
- *  dump_stack - debugging function only.
- */
-
-void html_text::dump_stack (void)
-{
-  if (debugStack) {
-    tag_definition *p = stackptr;
-
-    while (p != NULL) {
-      dump_stack_element(p);
-      p = p->next;
-    }
-  }
-  fprintf(stderr, "\n");
-  fflush(stderr);
-}
-#else
-void html_text::dump_stack (void) {}
-#endif
-
-
-/*
- *  end_tag - shuts down the tag.
- */
-
-void html_text::end_tag (tag_definition *t)
-{
-  switch (t->type) {
-
-  case I_TAG:      out->put_string(""); break;
-  case B_TAG:      out->put_string(""); break;
-  case P_TAG:      out->put_string("

"); - if (t->indent != NULL) { - delete t->indent; - t->indent = NULL; - } - out->nl(); out->enable_newlines(FALSE); - blank_para = TRUE; break; - case SUB_TAG: out->put_string(""); break; - case SUP_TAG: out->put_string(""); break; - case TT_TAG: out->put_string("
"); break; - case PRE_TAG: out->put_string("
"); out->nl(); out->enable_newlines(TRUE); - blank_para = TRUE; break; - case SMALL_TAG: out->put_string(""); break; - case BIG_TAG: out->put_string(""); break; - case COLOR_TAG: out->put_string(""); break; - - default: - error("unrecognised tag"); - } -} - -/* - * issue_tag - writes out an html tag with argument. - */ - -void html_text::issue_tag (char *tagname, char *arg) -{ - if ((arg == 0) || (strlen(arg) == 0)) { - out->put_string(tagname); - out->put_string(">"); - } else { - out->put_string(tagname); - out->put_string(" "); - out->put_string(arg); - out->put_string(">"); - } -} - -/* - * issue_color_begin - writes out an html color tag. - */ - -void html_text::issue_color_begin (color *c) -{ - unsigned int r, g, b; - char buf[6+1]; - - out->put_string("is_default()) - sprintf(buf, "000000"); - else { - c->get_rgb(&r, &g, &b); - // we have to scale 0..0xFFFF to 0..0xFF - sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101); - } - out->put_string(buf); - out->put_string("\">"); -} - -/* - * start_tag - starts a tag. - */ - -void html_text::start_tag (tag_definition *t) -{ - switch (t->type) { - - case I_TAG: issue_tag("arg1); break; - case B_TAG: issue_tag("arg1); break; - case P_TAG: if (t->indent == NULL) { - out->nl(); - issue_tag("\narg1); - } else { - out->nl(); - out->simple_comment("INDENTATION"); - t->indent->begin(FALSE); - start_space = FALSE; - issue_tag("arg1); - } - - out->enable_newlines(TRUE); break; - case SUB_TAG: issue_tag("arg1); break; - case SUP_TAG: issue_tag("arg1); break; - case TT_TAG: issue_tag("arg1); break; - case PRE_TAG: if (t->indent != NULL) { - out->nl(); - out->simple_comment("INDENTATION"); - t->indent->begin(FALSE); - start_space = FALSE; - } - out->enable_newlines(TRUE); - out->nl(); issue_tag("arg1); - out->enable_newlines(FALSE); break; - case SMALL_TAG: issue_tag("arg1); break; - case BIG_TAG: issue_tag("arg1); break; - case BREAK_TAG: break; - case COLOR_TAG: issue_color_begin(&t->col); break; - - default: - error("unrecognised tag"); - } -} - -/* - * flush_text - flushes html tags which are outstanding on the html stack. - */ - -void html_text::flush_text (void) -{ - int notext=TRUE; - tag_definition *p=stackptr; - - while (stackptr != 0) { - notext = (notext && (! stackptr->text_emitted)); - if (! notext) { - end_tag(stackptr); - } - p = stackptr; - stackptr = stackptr->next; - free(p); - } - lastptr = NULL; -} - -/* - * is_present - returns TRUE if tag is already present on the stack. - */ - -int html_text::is_present (HTML_TAG t) -{ - tag_definition *p=stackptr; - - while (p != NULL) { - if (t == p->type) - return TRUE; - p = p->next; - } - return FALSE; -} - -extern void stop(); - -/* - * do_push - places, tag_definition, p, onto the stack - */ - -void html_text::do_push (tag_definition *p) -{ - HTML_TAG t = p->type; - -#if defined(DEBUGGING) - if (t == PRE_TAG) - stop(); - debugStack = TRUE; - fprintf(stderr, "\nentering do_push ("); - dump_stack_element(p); - fprintf(stderr, ")\n"); - dump_stack(); - fprintf(stderr, ")\n"); - fflush(stderr); -#endif - - /* - * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack. - */ - - if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) { - /* - * store, p, at the end - */ - lastptr->next = p; - lastptr = p; - p->next = NULL; - } else { - p->next = stackptr; - if (stackptr == NULL) - lastptr = p; - stackptr = p; - } - -#if defined(DEBUGGING) - dump_stack(); - fprintf(stderr, "exiting do_push\n"); -#endif -} - -/* - * push_para - adds a new entry onto the html paragraph stack. - */ - -void html_text::push_para (HTML_TAG t, void *arg, html_indent *in) -{ - tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); - - p->type = t; - p->arg1 = arg; - p->text_emitted = FALSE; - p->indent = in; - - if (t == PRE_TAG && is_present(PRE_TAG)) - fatal("cannot have multiple PRE_TAGs"); - - do_push(p); -} - -void html_text::push_para (HTML_TAG t) -{ - push_para(t, (void *)"", NULL); -} - -void html_text::push_para (color *c) -{ - tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); - - p->type = COLOR_TAG; - p->arg1 = NULL; - p->col = *c; - p->text_emitted = FALSE; - p->indent = NULL; - - do_push(p); -} - -/* - * do_italic - changes to italic - */ - -void html_text::do_italic (void) -{ - if (! is_present(I_TAG)) - push_para(I_TAG); -} - -/* - * do_bold - changes to bold. - */ - -void html_text::do_bold (void) -{ - if (! is_present(B_TAG)) - push_para(B_TAG); -} - -/* - * do_tt - changes to teletype. - */ - -void html_text::do_tt (void) -{ - if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) - push_para(TT_TAG); -} - -/* - * do_pre - changes to preformated text. - */ - -void html_text::do_pre (void) -{ - done_tt(); - if (is_present(P_TAG)) { - html_indent *i = remove_indent(P_TAG); - (void)done_para(); - if (! is_present(PRE_TAG)) - push_para(PRE_TAG, NULL, i); - } else if (! is_present(PRE_TAG)) - push_para(PRE_TAG, NULL, NULL); - dump_stack(); -} - -/* - * is_in_pre - returns TRUE if we are currently within a preformatted - *
 block.
- */
-
-int html_text::is_in_pre (void)
-{
-  return is_present(PRE_TAG);
-}
-
-/*
- *  do_color - initiates a new color tag.
- */
-
-void html_text::do_color (color *c)
-{
-  shutdown(COLOR_TAG);   // shutdown a previous color tag, if present
-  push_para(c);
-}
-
-/*
- *  done_color - shutdown an outstanding color tag, if it exists.
- */
-
-void html_text::done_color (void)
-{
-  shutdown(COLOR_TAG);
-}
-
-/*
- *  shutdown - shuts down an html tag.
- */
-
-char *html_text::shutdown (HTML_TAG t)
-{
-  char *arg=NULL;
-
-  if (is_present(t)) {
-    tag_definition *p    =stackptr;
-    tag_definition *temp =NULL;
-    int notext           =TRUE;
-    
-    dump_stack();
-    while ((stackptr != NULL) && (stackptr->type != t)) {
-      notext = (notext && (! stackptr->text_emitted));
-      if (! notext) {
-	end_tag(stackptr);
-      }
-
-      /*
-       *  pop tag
-       */
-      p        = stackptr;
-      stackptr = stackptr->next;
-      if (stackptr == NULL)
-	lastptr = NULL;
-    
-      /*
-       *  push tag onto temp stack
-       */
-      p->next  = temp;
-      temp     = p;
-    }
-
-    /*
-     *  and examine stackptr
-     */
-    if ((stackptr != NULL) && (stackptr->type == t)) {
-      if (stackptr->text_emitted) {
-	end_tag(stackptr);
-      }
-      if (t == P_TAG) {
-	arg = (char *)stackptr->arg1;
-      }
-      p        = stackptr;
-      stackptr = stackptr->next;
-      if (stackptr == NULL)
-	lastptr = NULL;
-      if (p->indent != NULL)
-	delete p->indent;
-      free(p);
-    }
-
-    /*
-     *  and restore unaffected tags
-     */
-    while (temp != NULL) {
-      if (temp->type == COLOR_TAG)
-	push_para(&temp->col);
-      else
-	push_para(temp->type, temp->arg1, temp->indent);
-      p    = temp;
-      temp = temp->next;
-      free(p);
-    }
-  }
-  return arg;
-}
-
-/*
- *  done_bold - shuts downs a bold tag.
- */
-
-void html_text::done_bold (void)
-{
-  shutdown(B_TAG);
-}
-
-/*
- *  done_italic - shuts downs an italic tag.
- */
-
-void html_text::done_italic (void)
-{
-  shutdown(I_TAG);
-}
-
-/*
- *  done_sup - shuts downs a sup tag.
- */
-
-void html_text::done_sup (void)
-{
-  shutdown(SUP_TAG);
-}
-
-/*
- *  done_sub - shuts downs a sub tag.
- */
-
-void html_text::done_sub (void)
-{
-  shutdown(SUB_TAG);
-}
-
-/*
- *  done_tt - shuts downs a tt tag.
- */
-
-void html_text::done_tt (void)
-{
-  shutdown(TT_TAG);
-}
-
-/*
- *  done_pre - shuts downs a pre tag.
- */
-
-void html_text::done_pre (void)
-{
-  shutdown(PRE_TAG);
-}
-
-/*
- *  done_small - shuts downs a small tag.
- */
-
-void html_text::done_small (void)
-{
-  shutdown(SMALL_TAG);
-}
-
-/*
- *  done_big - shuts downs a big tag.
- */
-
-void html_text::done_big (void)
-{
-  shutdown(BIG_TAG);
-}
-
-/*
- *  check_emit_text - ensures that all previous tags have been emitted (in order)
- *                    before the text is written.
- */
-
-void html_text::check_emit_text (tag_definition *t)
-{
-  if ((t != NULL) && (! t->text_emitted)) {
-    check_emit_text(t->next);
-    t->text_emitted = TRUE;
-    start_tag(t);
-  }
-}
-
-/*
- *  do_emittext - tells the class that text was written during the current tag.
- */
-
-void html_text::do_emittext (const char *s, int length)
-{
-  if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
-    do_para("");
-
-  if (is_present(BREAK_TAG)) {
-    int text = remove_break();
-    check_emit_text(stackptr);
-    if (text) {
-      if (is_present(PRE_TAG)) {
-	out->nl();
-      } else {
-	out->put_string("
").nl(); - } - } - } else { - check_emit_text(stackptr); - } - out->put_string(s, length); - space_emitted = FALSE; - blank_para = FALSE; -} - -/* - * do_para - starts a new paragraph - */ - -void html_text::do_para (const char *arg, html_indent *in) -{ - if (! is_present(P_TAG)) { - if (is_present(PRE_TAG)) { - html_indent *i = remove_indent(PRE_TAG); - done_pre(); - if (i == in || in == NULL) - in = i; - else - delete i; - } - remove_sub_sup(); - push_para(P_TAG, (void *)arg, in); - space_emitted = TRUE; - } -} - -void html_text::do_para (const char *arg) -{ - do_para(arg, NULL); -} - -void html_text::do_para (simple_output *op, const char *arg1, - int indentation, int pageoffset, int linelength) -{ - html_indent *indent; - - if (indentation == 0) - indent = NULL; - else - indent = new html_indent(op, indentation, pageoffset, linelength); - do_para(arg1, indent); -} - -/* - * done_para - shuts down a paragraph tag. - */ - -char *html_text::done_para (void) -{ - space_emitted = TRUE; - return shutdown(P_TAG); -} - -/* - * remove_indent - returns the indent associated with, tag. - * The indent associated with tag is set to NULL. - */ - -html_indent *html_text::remove_indent (HTML_TAG tag) -{ - tag_definition *p=stackptr; - - while (p != NULL) { - if (tag == p->type) { - html_indent *i = p->indent; - p->indent = NULL; - return i; - } - p = p->next; - } - return NULL; -} - -/* - * do_space - issues an end of paragraph - */ - -void html_text::do_space (void) -{ - if (is_in_pre()) { - if (blank_para) - start_space = TRUE; - else { - do_emittext("", 0); - out->nl(); - } - } else { - html_indent *i = remove_indent(P_TAG); - - do_para(done_para(), i); - space_emitted = TRUE; - start_space = TRUE; - } -} - -/* - * do_break - issue a break tag. - */ - -void html_text::do_break (void) -{ - if (! is_present(PRE_TAG)) { - if (emitted_text()) { - if (! is_present(BREAK_TAG)) { - push_para(BREAK_TAG); - } - } - } - space_emitted = TRUE; -} - -/* - * do_newline - issue a newline providing that we are inside a
 tag.
- */
-
-void html_text::do_newline (void)
-{
-  if (is_present(PRE_TAG)) {
-    do_emittext("\n", 1);
-    space_emitted = TRUE;
-  }
-}
-
-/*
- *  emitted_text - returns FALSE if white space has just been written.
- */
-
-int html_text::emitted_text (void)
-{
-  return !space_emitted;
-}
-
-/*
- *  ever_emitted_text - returns TRUE if we have ever emitted text in this paragraph.
- */
-
-int html_text::ever_emitted_text (void)
-{
-  return !blank_para;
-}
-
-/*
- *  starts_with_space - returns TRUE if we have start this paragraph with a .sp
- */
-
-int html_text::starts_with_space (void)
-{
-  return start_space;
-}
-
-/*
- *  emit_space - writes a space providing that text was written beforehand.
- */
-
-void html_text::emit_space (void)
-{
-  if (space_emitted) {
-    if (is_present(PRE_TAG)) {
-      do_emittext(" ", 1);
-    }
-  } else {
-    out->space_or_newline();
-    space_emitted = TRUE;
-  }
-}
-
-/*
- *  remove_def - removes a definition, t, from the stack.
- */
-
-void html_text::remove_def (tag_definition *t)
-{
-  tag_definition *p    = stackptr;
-  tag_definition *l    = 0;
-  tag_definition *q    = 0;
-    
-  while ((p != 0) && (p != t)) {
-    l = p;
-    p = p->next;
-  }
-  if ((p != 0) && (p == t)) {
-    if (p == stackptr) {
-      stackptr = stackptr->next;
-      if (stackptr == NULL)
-	lastptr = NULL;
-      q = stackptr;
-    } else if (l == 0) {
-      error("stack list pointers are wrong");
-    } else {
-      l->next = p->next;
-      q = p->next;
-      if (l->next == NULL)
-	lastptr = l;
-    }
-    free(p);
-  }
-}
-
-/*
- *  remove_tag - removes a tag from the stack.
- */
-
-void html_text::remove_tag (HTML_TAG tag)
-{
-  tag_definition *p = stackptr;
-    
-  while ((p != 0) && (p->type != tag)) {
-    p = p->next;
-  }
-  if ((p != 0) && (p->type == tag))
-    remove_def(p);
-}
-
-/*
- *  remove_sub_sup - removes a sub or sup tag, should either exist on the stack.
- */
-
-void html_text::remove_sub_sup (void)
-{
-  if (is_present(SUB_TAG)) {
-    remove_tag(SUB_TAG);
-  }
-  if (is_present(SUP_TAG)) {
-    remove_tag(SUP_TAG);
-  }
-  if (is_present(PRE_TAG)) {
-    remove_tag(PRE_TAG);
-  }
-}
-
-/*
- *  remove_break - break tags are not balanced thus remove it once it has been emitted.
- *                 It returns TRUE if text was emitted before the 
was issued. - */ - -int html_text::remove_break (void) -{ - tag_definition *p = stackptr; - tag_definition *l = 0; - tag_definition *q = 0; - - while ((p != 0) && (p->type != BREAK_TAG)) { - l = p; - p = p->next; - } - if ((p != 0) && (p->type == BREAK_TAG)) { - if (p == stackptr) { - stackptr = stackptr->next; - if (stackptr == NULL) - lastptr = NULL; - q = stackptr; - } else if (l == 0) - error("stack list pointers are wrong"); - else { - l->next = p->next; - q = p->next; - if (l->next == NULL) - lastptr = l; - } - free(p); - } - /* - * now determine whether text was issued before
- */ - while (q != 0) { - if (q->text_emitted) - return TRUE; - else - q = q->next; - } - return FALSE; -} - -/* - * remove_para_align - removes a paragraph which has a text - * argument. If the paragraph has no text - * argument then it is left alone. - */ - -void html_text::remove_para_align (void) -{ - if (is_present(P_TAG)) { - tag_definition *p=stackptr; - - while (p != NULL) { - if (p->type == P_TAG && p->arg1 != NULL) { - html_indent *i = remove_indent(P_TAG); - done_para(); - do_para("", i); - return; - } - p = p->next; - } - } -} - -/* - * do_small - potentially inserts a tag into the html stream. - * However we check for a tag, if present then we terminate it. - * Otherwise a tag is inserted. - */ - -void html_text::do_small (void) -{ - if (is_present(BIG_TAG)) - done_big(); - else - push_para(SMALL_TAG); -} - -/* - * do_big - is the mirror image of do_small. - */ - -void html_text::do_big (void) -{ - if (is_present(SMALL_TAG)) - done_small(); - else - push_para(BIG_TAG); -} - -/* - * do_sup - save a superscript tag on the stack of tags. - */ - -void html_text::do_sup (void) -{ - push_para(SUP_TAG); -} - -/* - * do_sub - save a subscript tag on the stack of tags. - */ - -void html_text::do_sub (void) -{ - push_para(SUB_TAG); -} - diff --git a/contrib/groff/src/devices/grohtml/output.cc b/contrib/groff/src/devices/grohtml/output.cc deleted file mode 100644 index 67d5874..0000000 --- a/contrib/groff/src/devices/grohtml/output.cc +++ /dev/null @@ -1,356 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. - * - * Gaius Mulley (gaius@glam.ac.uk) wrote output.cc - * but it owes a huge amount of ideas and raw code from - * James Clark (jjc@jclark.com) grops/ps.cc. - * - * output.cc - * - * provide the simple low level output routines needed by html.cc - */ - -/* -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 "stringclass.h" -#include "cset.h" - -#include -#include "html.h" - -#ifdef HAVE_UNISTD_H -#include -#endif - -#undef DEBUGGING -// #define DEBUGGING - -#if !defined(TRUE) -# define TRUE (1==1) -#endif -#if !defined(FALSE) -# define FALSE (1==0) -#endif - - -#if defined(DEBUGGING) -# define FPUTC(X,Y) do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0) -# define FPUTS(X,Y) do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0) -# define PUTC(X,Y) do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0) -#else -# define FPUTC(X,Y) do { fputc((X),(Y)); } while (0) -# define FPUTS(X,Y) do { fputs((X),(Y)); } while (0) -# define PUTC(X,Y) do { putc((X),(Y)); } while (0) -#endif - - -/* - * word - initialise a word and set next to NULL - */ - -word::word (const char *w, int n) - : next(0) -{ - s = (char *)malloc(n+1); - strncpy(s, w, n); - s[n] = (char)0; -} - -/* - * destroy word and the string copy. - */ - -word::~word () -{ - free(s); -} - -/* - * word_list - create an empty word list. - */ - -word_list::word_list () - : length(0), head(0), tail(0) -{ -} - -/* - * flush - flush a word list to a FILE, f, and return the - * length of the buffered string. - */ - -int word_list::flush (FILE *f) -{ - word *t; - int len=length; - - while (head != 0) { - t = head; - head = head->next; - FPUTS(t->s, f); - delete t; - } - head = 0; - tail = 0; - length = 0; -#if defined(DEBUGGING) - fflush(f); // just for testing -#endif - return( len ); -} - -/* - * add_word - adds a word to the outstanding word list. - */ - -void word_list::add_word (const char *s, int n) -{ - if (head == 0) { - head = new word(s, n); - tail = head; - } else { - tail->next = new word(s, n); - tail = tail->next; - } - length += n; -} - -/* - * get_length - returns the number of characters buffered - */ - -int word_list::get_length (void) -{ - return( length ); -} - -/* - * the classes and methods for simple_output manipulation - */ - -simple_output::simple_output(FILE *f, int n) -: fp(f), max_line_length(n), col(0), fixed_point(0), newlines(0) -{ -} - -simple_output &simple_output::set_file(FILE *f) -{ - if (fp) - fflush(fp); - fp = f; - return *this; -} - -simple_output &simple_output::copy_file(FILE *infp) -{ - int c; - while ((c = getc(infp)) != EOF) - PUTC(c, fp); - return *this; -} - -simple_output &simple_output::end_line() -{ - flush_last_word(); - if (col != 0) { - PUTC('\n', fp); - col = 0; - } - return *this; -} - -simple_output &simple_output::special(const char *s) -{ - return *this; -} - -simple_output &simple_output::simple_comment(const char *s) -{ - flush_last_word(); - if (col != 0) - PUTC('\n', fp); - FPUTS("\n", fp); - col = 0; - return *this; -} - -simple_output &simple_output::begin_comment(const char *s) -{ - flush_last_word(); - if (col != 0) - PUTC('\n', fp); - col = 0; - put_string("").nl(); - return *this; -} - -/* - * check_newline - checks to see whether we are able to issue - * a newline and that one is needed. - */ - -simple_output &simple_output::check_newline(int n) -{ - if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) { - FPUTC('\n', fp); - col = last_word.flush(fp); - } - return *this; -} - -/* - * space_or_newline - will emit a newline or a space later on - * depending upon the current column. - */ - -simple_output &simple_output::space_or_newline (void) -{ - if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) { - FPUTC('\n', fp); - if (last_word.get_length() > 0) { - col = last_word.flush(fp); - } else { - col = 0; - } - } else { - if (last_word.get_length() != 0) { - if (col > 0) { - FPUTC(' ', fp); - col++; - } - col += last_word.flush(fp); - } - } - return *this; -} - -/* - * nl - writes a newline providing that we - * are not in the first column. - */ - -simple_output &simple_output::nl (void) -{ - space_or_newline(); - col += last_word.flush(fp); - if (col != 0) { - FPUTC('\n', fp); - col = 0; - } - return *this ; -} - -simple_output &simple_output::set_fixed_point(int n) -{ - assert(n >= 0 && n <= 10); - fixed_point = n; - return *this; -} - -simple_output &simple_output::put_raw_char(char c) -{ - col += last_word.flush(fp); - PUTC(c, fp); - col++; - return *this; -} - -simple_output &simple_output::put_string(const char *s, int n) -{ - last_word.add_word(s, n); - return *this; -} - -simple_output &simple_output::put_string(const char *s) -{ - last_word.add_word(s, strlen(s)); - return *this; -} - -simple_output &simple_output::put_string(const string &s) -{ - last_word.add_word(s.contents(), s.length()); - return *this; -} - -simple_output &simple_output::put_number(int n) -{ - char buf[1 + INT_DIGITS + 1]; - sprintf(buf, "%d", n); - put_string(buf); - return *this; -} - -simple_output &simple_output::put_float(double d) -{ - char buf[128]; - - sprintf(buf, "%.4f", d); - put_string(buf); - return *this; -} - -simple_output &simple_output::enable_newlines (int auto_newlines) -{ - check_newline(0); - newlines = auto_newlines; - check_newline(0); - return *this; -} - -/* - * flush_last_word - flushes the last word and adjusts the - * col position. It will insert a newline - * before the last word if allowed and if - * necessary. - */ - -void simple_output::flush_last_word (void) -{ - int len=last_word.get_length(); - - if (len > 0) { - if (newlines) { - if (col + len + 1 > max_line_length) { - FPUTS("\n", fp); - col = 0; - } else { - FPUTS(" ", fp); - col++; - } - len += last_word.flush(fp); - } else { - FPUTS(" ", fp); - col++; - col += last_word.flush(fp); - } - } -} diff --git a/contrib/groff/src/devices/grohtml/post-html.cc b/contrib/groff/src/devices/grohtml/post-html.cc deleted file mode 100644 index 4431f17..0000000 --- a/contrib/groff/src/devices/grohtml/post-html.cc +++ /dev/null @@ -1,3745 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. - * - * Gaius Mulley (gaius@glam.ac.uk) wrote post-html.cc - * but it owes a huge amount of ideas and raw code from - * James Clark (jjc@jclark.com) grops/ps.cc. - */ - -/* -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 "stringclass.h" -#include "cset.h" -#include "html.h" -#include "html-text.h" -#include "html-table.h" - -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include - -extern "C" const char *Version_string; - -#if !defined(TRUE) -# define TRUE (1==1) -#endif -#if !defined(FALSE) -# define FALSE (1==0) -#endif - -#define MAX_LINE_LENGTH 60 /* maximum characters we want in a line */ -#define SIZE_INCREMENT 2 /* font size increment = +2 */ -#define BASE_POINT_SIZE 10 /* 10 points is the base size ie html size 3 */ -#define CENTER_TOLERANCE 2 /* how many pixels off center will we still */ -#define ANCHOR_TEMPLATE "heading" /* if simple anchor is set we use this */ -#define UNICODE_DESC_START 0x80 /* all character entities above this are */ - /* either encoded by their glyph names or if */ - /* there is no name then we use &#nnn; */ -typedef enum {CENTERED, LEFT, RIGHT, INLINE} TAG_ALIGNMENT; -typedef enum {col_tag, tab_tag, tab0_tag, none} colType; - -#undef DEBUG_TABLES - - -/* - * prototypes - */ - -char *get_html_translation (font *f, const string &name); -int char_translate_to_html (font *f, char *buf, int buflen, unsigned char ch, int b, int and_single); - - -static int auto_links = TRUE; /* by default we enable automatic links at */ - /* top of the document. */ -static int auto_rule = TRUE; /* by default we enable an automatic rule */ - /* at the top and bottom of the document */ -static int simple_anchors = FALSE; /* default to anchors with heading text */ -static int manufacture_headings = FALSE; /* default is to use the Hn html headings, */ - /* rather than manufacture our own. */ -static color *default_background = NULL; /* has user requested initial bg color? */ - - -/* - * start with a few favorites - */ - -void stop () {} - -static int min (int a, int b) -{ - if (a < b) - return a; - else - return b; -} - -static int max (int a, int b) -{ - if (a > b) - return a; - else - return b; -} - -/* - * is_intersection - returns TRUE if range a1..a2 intersects with b1..b2 - */ - -static int is_intersection (int a1, int a2, int b1, int b2) -{ - // easier to prove NOT outside limits - return( ! ((a1 > b2) || (a2 < b1)) ); -} - -/* - * is_digit - returns TRUE if character, ch, is a digit. - */ - -static int is_digit (char ch) -{ - return( (ch >= '0') && (ch <= '9') ); -} - -/* - * the classes and methods for maintaining a list of files. - */ - -struct file { - FILE *fp; - file *next; - - file (FILE *f); -}; - -/* - * file - initialize all fields to NULL - */ - -file::file (FILE *f) - : fp(f), next(0) -{ -} - -class files { -public: - files (); - FILE *get_file (void); - void start_of_list (void); - void move_next (void); - void add_new_file (FILE *f); -private: - file *head; - file *tail; - file *ptr; -}; - -/* - * files - create an empty list of files. - */ - -files::files () - : head(0), tail(0), ptr(0) -{ -} - -/* - * get_file - returns the FILE associated with ptr. - */ - -FILE *files::get_file (void) -{ - if (ptr) { - return( ptr->fp ); - } else { - return( 0 ); - } -} - -/* - * start_of_list - reset the ptr to the start of the list. - */ - -void files::start_of_list (void) -{ - ptr = head; -} - -/* - * move_next - moves the ptr to the next element on the list. - */ - -void files::move_next (void) -{ - if (ptr != 0) - ptr = ptr->next; -} - -/* - * add_new_file - adds a new file, f, to the list. - */ - -void files::add_new_file (FILE *f) -{ - if (head == 0) { - head = new file(f); - tail = head; - } else { - tail->next = new file(f); - tail = tail->next; - } - ptr = tail; -} - -/* - * the class and methods for styles - */ - -struct style { - font *f; - int point_size; - int font_no; - int height; - int slant; - color col; - style (); - style (font *, int, int, int, int, color); - int operator == (const style &) const; - int operator != (const style &) const; -}; - -style::style() - : f(0) -{ -} - -style::style(font *p, int sz, int h, int sl, int no, color c) - : f(p), point_size(sz), font_no(no), height(h), slant(sl), col(c) -{ -} - -int style::operator==(const style &s) const -{ - return (f == s.f && point_size == s.point_size - && height == s.height && slant == s.slant && col == s.col); -} - -int style::operator!=(const style &s) const -{ - return !(*this == s); -} - -/* - * the class and methods for retaining ascii text - */ - -struct char_block { - enum { SIZE = 256 }; - char *buffer; - int used; - char_block *next; - - char_block(); - char_block::char_block(int length); -}; - -char_block::char_block() -: buffer(NULL), used(0), next(0) -{ -} - -char_block::char_block(int length) -: used(0), next(0) -{ - buffer = (char *)malloc(max(length, char_block::SIZE)); - if (buffer == NULL) - fatal("out of memory error"); -} - -class char_buffer { -public: - char_buffer(); - ~char_buffer(); - char *add_string(const char *, unsigned int); - char *add_string(const string &); -private: - char_block *head; - char_block *tail; -}; - -char_buffer::char_buffer() -: head(0), tail(0) -{ -} - -char_buffer::~char_buffer() -{ - while (head != 0) { - char_block *temp = head; - head = head->next; - delete temp; - } -} - -char *char_buffer::add_string (const char *s, unsigned int length) -{ - int i=0; - unsigned int old_used; - - if (s == NULL || length == 0) - return NULL; - - if (tail == 0) { - tail = new char_block(length+1); - head = tail; - } else { - if (tail->used + length+1 > char_block::SIZE) { - tail->next = new char_block(length+1); - tail = tail->next; - } - } - - old_used = tail->used; - do { - tail->buffer[tail->used] = s[i]; - tail->used++; - i++; - length--; - } while (length>0); - - // add terminating nul character - - tail->buffer[tail->used] = '\0'; - tail->used++; - - // and return start of new string - - return( &tail->buffer[old_used] ); -} - -char *char_buffer::add_string (const string &s) -{ - return add_string(s.contents(), s.length()); -} - -/* - * the classes and methods for maintaining glyph positions. - */ - -class text_glob { -public: - void text_glob_html (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void text_glob_special (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void text_glob_line (style *s, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal, - int thickness); - void text_glob_auto_image(style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void text_glob_tag (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - - text_glob (void); - ~text_glob (void); - int is_a_line (void); - int is_a_tag (void); - int is_eol (void); - int is_auto_img (void); - int is_br (void); - int is_in (void); - int is_po (void); - int is_ti (void); - int is_ce (void); - int is_eol_ce (void); - int is_col (void); - int is_tab (void); - int is_tab0 (void); - int is_ta (void); - int is_tab_ts (void); - int is_tab_te (void); - int is_nf (void); - int is_fi (void); - int get_arg (void); - int get_tab_args (char *align); - - void remember_table (html_table *t); - html_table *get_table (void); - - style text_style; - const char *text_string; - unsigned int text_length; - int minv, minh, maxv, maxh; - int is_tag; // is this a .br, .sp, .tl etc - int is_img_auto; // image created by eqn delim - int is_special; // text has come via 'x X html:' - int is_line; // is the command a ? - int thickness; // the thickness of a line - html_table *tab; // table description - -private: - text_glob (style *s, char *str, int length, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal, - bool is_troff_command, - bool is_auto_image, bool is_special_command, - bool is_a_line , int thickness); -}; - -text_glob::text_glob (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal, - bool is_troff_command, - bool is_auto_image, bool is_special_command, - bool is_a_line, int line_thickness) - : text_style(*s), text_string(str), text_length(length), - minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal), - is_tag(is_troff_command), is_img_auto(is_auto_image), is_special(is_special_command), - is_line(is_a_line), thickness(line_thickness), tab(NULL) -{ -} - -text_glob::text_glob () - : text_string(0), text_length(0), minv(-1), minh(-1), maxv(-1), maxh(-1), - is_tag(FALSE), is_special(FALSE), is_line(FALSE), thickness(0), tab(NULL) -{ -} - -text_glob::~text_glob () -{ - if (tab != NULL) - delete tab; -} - -/* - * text_glob_html - used to place html text into the glob buffer. - */ - -void text_glob::text_glob_html (style *s, char *str, int length, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, FALSE, FALSE, 0); - *this = *g; -} - -/* - * text_glob_html - used to place html specials into the glob buffer. - * This text is essentially html commands coming through - * from the macro sets, with special designated sequences of - * characters translated into html. See add_and_encode. - */ - -void text_glob::text_glob_special (style *s, char *str, int length, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, TRUE, FALSE, 0); - *this = *g; -} - -/* - * text_glob_line - record horizontal draw line commands. - */ - -void text_glob::text_glob_line (style *s, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal, - int thickness) -{ - text_glob *g = new text_glob(s, "", 0, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, FALSE, TRUE, thickness); - *this = *g; -} - -/* - * text_glob_auto_image - record the presence of a .auto-image tag command. - * Used to mark that an image has been created automatically - * by a preprocessor and (pre-grohtml/troff) combination. - * Under some circumstances images may not be created. - * (consider .EQ - * delim $$ - * .EN - * .TS - * tab(!), center; - * l!l. - * $1 over x$!recripical of x - * .TE - * - * the first auto-image marker is created via .EQ/.EN pair - * and no image is created. - * The second auto-image marker occurs at $1 over x$ - * Currently this image will not be created - * as the whole of the table is created as an image. - * (Once html tables are handled by grohtml this will change. - * Shortly this will be the case). - */ - -void text_glob::text_glob_auto_image(style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - TRUE, TRUE, FALSE, FALSE, 0); - *this = *g; -} - -/* - * text_glob_tag - records a troff tag. - */ - -void text_glob::text_glob_tag (style *s, char *str, int length, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - text_glob *g = new text_glob(s, str, length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - TRUE, FALSE, FALSE, FALSE, 0); - *this = *g; -} - -/* - * is_a_line - returns TRUE if glob should be converted into an
- */ - -int text_glob::is_a_line (void) -{ - return is_line; -} - -/* - * is_a_tag - returns TRUE if glob contains a troff directive. - */ - -int text_glob::is_a_tag (void) -{ - return is_tag; -} - -/* - * is_eol - returns TRUE if glob contains the tag eol - */ - -int text_glob::is_eol (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:eol") == 0) ); -} - -/* - * is_eol_ce - returns TRUE if glob contains the tag eol.ce - */ - -int text_glob::is_eol_ce (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:eol.ce") == 0) ); -} - - -/* - * is_nf - returns TRUE if glob contains the tag .nf - */ - -int text_glob::is_nf (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.nf") == 0) ); -} - -/* - * is_fi - returns TRUE if glob contains the tag .fi - */ - -int text_glob::is_fi (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.fi") == 0) ); -} - -/* - * is_ce - returns TRUE if glob contains the tag .ce - */ - -int text_glob::is_ce (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.ce") == 0) ); -} - -/* - * is_in - returns TRUE if glob contains the tag .in - */ - -int text_glob::is_in (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.in ", strlen("html-tag:.in ")) == 0) ); -} - -/* - * is_po - returns TRUE if glob contains the tag .po - */ - -int text_glob::is_po (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.po ", strlen("html-tag:.po ")) == 0) ); -} - -/* - * is_ti - returns TRUE if glob contains the tag .ti - */ - -int text_glob::is_ti (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.ti ", strlen("html-tag:.ti ")) == 0) ); -} - -/* - * is_col - returns TRUE if glob contains the tag .col - */ - -int text_glob::is_col (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.col", strlen("html-tag:.col")) == 0) ); -} - -/* - * is_tab_ts - returns TRUE if glob contains the tag .tab_ts - */ - -int text_glob::is_tab_ts (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.tab-ts") == 0) ); -} - -/* - * is_tab_te - returns TRUE if glob contains the tag .tab_te - */ - -int text_glob::is_tab_te (void) -{ - return( is_tag && (strcmp(text_string, "html-tag:.tab-te") == 0) ); -} - -/* - * is_ta - returns TRUE if glob contains the tag .ta - */ - -int text_glob::is_ta (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:.ta ", strlen("html-tag:.ta ")) == 0) ); -} - -/* - * is_tab - returns TRUE if glob contains the tag tab - */ - -int text_glob::is_tab (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:tab ", strlen("html-tag:tab ")) == 0) ); -} - -/* - * is_tab0 - returns TRUE if glob contains the tag tab0 - */ - -int text_glob::is_tab0 (void) -{ - return( is_tag && (strncmp(text_string, "html-tag:tab0", strlen("html-tag:tab0")) == 0) ); -} - -/* - * is_auto_img - returns TRUE if the glob contains an automatically - * generated image. - */ - -int text_glob::is_auto_img (void) -{ - return is_img_auto; -} - -/* - * is_br - returns TRUE if the glob is a tag containing a .br - * or an implied .br. Note that we do not include .nf or .fi - * as grohtml will place a .br after these commands if they - * should break the line. - */ - -int text_glob::is_br (void) -{ - return( is_a_tag() && ((strcmp ("html-tag:.br", text_string) == 0) || - (strncmp("html-tag:.sp", text_string, 11) == 0) || - (strcmp ("html-tag:.ce", text_string) == 0)) ); -} - -int text_glob::get_arg (void) -{ - if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) { - const char *p = text_string; - - while ((*p != (char)0) && (!isspace(*p))) - p++; - while ((*p != (char)0) && (isspace(*p))) - p++; - if (*p == (char)0) - return -1; - return atoi(p); - } - return -1; -} - -/* - * get_tab_args - returns the tab position and alignment of the tab tag - */ - -int text_glob::get_tab_args (char *align) -{ - if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) { - const char *p = text_string; - - // firstly the alignment C|R|L - while ((*p != (char)0) && (!isspace(*p))) - p++; - while ((*p != (char)0) && (isspace(*p))) - p++; - *align = *p; - // now the int value - while ((*p != (char)0) && (!isspace(*p))) - p++; - while ((*p != (char)0) && (isspace(*p))) - p++; - if (*p == (char)0) - return -1; - return atoi(p); - } - return -1; -} - -/* - * remember_table - saves table, t, in the text_glob. - */ - -void text_glob::remember_table (html_table *t) -{ - tab = t; -} - -/* - * get_table - returns the stored table description. - */ - -html_table *text_glob::get_table (void) -{ - return tab; -} - -/* - * the class and methods used to construct ordered double linked lists. - * In a previous implementation we used templates via #include "ordered-list.h", - * but this does assume that all C++ compilers can handle this feature. Pragmatically - * it is safer to assume this is not the case. - */ - -struct element_list { - element_list *right; - element_list *left; - text_glob *datum; - int lineno; - int minv, minh, maxv, maxh; - - element_list (text_glob *d, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - element_list (); -}; - -element_list::element_list () - : right(0), left(0), datum(0), lineno(0), minv(-1), minh(-1), maxv(-1), maxh(-1) -{ -} - -/* - * element_list - create a list element assigning the datum and region parameters. - */ - -element_list::element_list (text_glob *in, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) - : right(0), left(0), datum(in), lineno(line_number), - minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal) -{ -} - -class list { -public: - list (); - ~list (); - int is_less (element_list *a, element_list *b); - void add (text_glob *in, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void sub_move_right (void); - void move_right (void); - void move_left (void); - int is_empty (void); - int is_equal_to_tail (void); - int is_equal_to_head (void); - void start_from_head (void); - void start_from_tail (void); - void insert (text_glob *in); - void move_to (text_glob *in); - text_glob *move_right_get_data (void); - text_glob *move_left_get_data (void); - text_glob *get_data (void); -private: - element_list *head; - element_list *tail; - element_list *ptr; -}; - -/* - * list - construct an empty list. - */ - -list::list () - : head(0), tail(0), ptr(0) -{ -} - -/* - * ~list - destroy a complete list. - */ - -list::~list() -{ - element_list *temp=head; - - do { - temp = head; - if (temp != 0) { - head = head->right; - delete temp; - } - } while ((head != 0) && (head != tail)); -} - -/* - * is_less - returns TRUE if a is left of b if on the same line or - * if a is higher up the page than b. - */ - -int list::is_less (element_list *a, element_list *b) -{ - // was if (is_intersection(a->minv+1, a->maxv-1, b->minv+1, b->maxv-1)) { - if (a->lineno < b->lineno) { - return( TRUE ); - } else if (a->lineno > b->lineno) { - return( FALSE ); - } else if (is_intersection(a->minv, a->maxv, b->minv, b->maxv)) { - return( a->minh < b->minh ); - } else { - return( a->maxv < b->maxv ); - } -} - -/* - * add - adds a datum to the list in the order specified by the region position. - */ - -void list::add (text_glob *in, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal) -{ - // create a new list element with datum and position fields initialized - element_list *t = new element_list(in, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - element_list *last; - - if (head == 0) { - head = t; - tail = t; - ptr = t; - t->left = t; - t->right = t; - } else { - last = tail; - - while ((last != head) && (is_less(t, last))) { - last = last->left; - } - - if (is_less(t, last)) { - t->right = last; - last->left->right = t; - t->left = last->left; - last->left = t; - // now check for a new head - if (last == head) { - head = t; - } - } else { - // add t beyond last - t->right = last->right; - t->left = last; - last->right->left = t; - last->right = t; - // now check for a new tail - if (last == tail) { - tail = t; - } - } - } -} - -/* - * sub_move_right - removes the element which is currently pointed to by ptr - * from the list and moves ptr to the right. - */ - -void list::sub_move_right (void) -{ - element_list *t=ptr->right; - - if (head == tail) { - head = 0; - if (tail != 0) { - delete tail; - } - tail = 0; - ptr = 0; - } else { - if (head == ptr) { - head = head->right; - } - if (tail == ptr) { - tail = tail->left; - } - ptr->left->right = ptr->right; - ptr->right->left = ptr->left; - ptr=t; - } -} - -/* - * start_from_head - assigns ptr to the head. - */ - -void list::start_from_head (void) -{ - ptr = head; -} - -/* - * start_from_tail - assigns ptr to the tail. - */ - -void list::start_from_tail (void) -{ - ptr = tail; -} - -/* - * is_empty - returns TRUE if the list has no elements. - */ - -int list::is_empty (void) -{ - return( head == 0 ); -} - -/* - * is_equal_to_tail - returns TRUE if the ptr equals the tail. - */ - -int list::is_equal_to_tail (void) -{ - return( ptr == tail ); -} - -/* - * is_equal_to_head - returns TRUE if the ptr equals the head. - */ - -int list::is_equal_to_head (void) -{ - return( ptr == head ); -} - -/* - * move_left - moves the ptr left. - */ - -void list::move_left (void) -{ - ptr = ptr->left; -} - -/* - * move_right - moves the ptr right. - */ - -void list::move_right (void) -{ - ptr = ptr->right; -} - -/* - * get_datum - returns the datum referenced via ptr. - */ - -text_glob* list::get_data (void) -{ - return( ptr->datum ); -} - -/* - * move_right_get_data - returns the datum referenced via ptr and moves - * ptr right. - */ - -text_glob* list::move_right_get_data (void) -{ - ptr = ptr->right; - if (ptr == head) { - return( 0 ); - } else { - return( ptr->datum ); - } -} - -/* - * move_left_get_data - returns the datum referenced via ptr and moves - * ptr right. - */ - -text_glob* list::move_left_get_data (void) -{ - ptr = ptr->left; - if (ptr == tail) { - return( 0 ); - } else { - return( ptr->datum ); - } -} - -/* - * insert - inserts data after the current position. - */ - -void list::insert (text_glob *in) -{ - if (is_empty()) - fatal("list must not be empty if we are inserting data"); - else { - if (ptr == 0) - ptr = head; - - element_list *t = new element_list(in, ptr->lineno, ptr->minv, ptr->minh, ptr->maxv, ptr->maxh); - if (ptr == tail) - tail = t; - ptr->right->left = t; - t->right = ptr->right; - ptr->right = t; - t->left = ptr; - } -} - -/* - * move_to - moves the current position to the point where data, in, exists. - * This is an expensive method and should be used sparingly. - */ - -void list::move_to (text_glob *in) -{ - ptr = head; - while (ptr != tail && ptr->datum != in) - ptr = ptr->right; -} - -/* - * page class and methods - */ - -class page { -public: - page (void); - void add (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void add_tag (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void add_and_encode (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal); - void add_line (style *s, - int line_number, - int x1, int y1, int x2, int y2, - int thickness); - void insert_tag (const string &str); - void dump_page (void); // debugging method - - // and the data - - list glyphs; // position of glyphs and specials on page - char_buffer buffer; // all characters for this page -}; - -page::page() -{ -} - -/* - * insert_tag - inserts a tag after the current position. - */ - -void page::insert_tag (const string &str) -{ - if (str.length() > 0) { - text_glob *g=new text_glob(); - text_glob *f=glyphs.get_data(); - g->text_glob_tag(&f->text_style, buffer.add_string(str), str.length(), - f->minv, f->minh, f->maxv, f->maxh); - glyphs.insert(g); - } -} - -/* - * add - add html text to the list of glyphs. - */ - -void page::add (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - if (str.length() > 0) { - text_glob *g=new text_glob(); - g->text_glob_html(s, buffer.add_string(str), str.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - } -} - -/* - * add_tag - adds a troff tag, for example: .tl .sp .br - */ - -void page::add_tag (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - if (str.length() > 0) { - text_glob *g; - - if (strncmp((str+'\0').contents(), "html-tag:.auto-image", 20) == 0) { - g = new text_glob(); - g->text_glob_auto_image(s, buffer.add_string(str), str.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - } else { - g = new text_glob(); - g->text_glob_tag(s, buffer.add_string(str), str.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - } - glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - } -} - -/* - * add_line - adds the primitive providing that y1==y2 - */ - -void page::add_line (style *s, - int line_number, - int x1, int y1, int x2, int y2, - int thickness) -{ - if (y1 == y2) { - text_glob *g = new text_glob(); - g->text_glob_line(s, - min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2), - thickness); - glyphs.add(g, line_number, min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2)); - } -} - -/* - * to_unicode - returns a unicode translation of int, ch. - */ - -static char *to_unicode (unsigned int ch) -{ - static char buf[30]; - - sprintf(buf, "&#%u;", ch); - return buf; -} - -/* - * add_and_encode - adds a special string to the page, it translates the string - * into html glyphs. The special string will have come from x X html: - * and can contain troff character encodings which appear as - * \(char\). A sequence of \\ represents \. - * So for example we can write: - * "cost = \(Po\)3.00 file = \\foo\\bar" - * which is translated into: - * "cost = £3.00 file = \foo\bar" - */ - -void page::add_and_encode (style *s, const string &str, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) -{ - string html_string; - char *html_glyph; - int i=0; - - if (s->f == NULL) - return; - while (i < str.length()) { - if ((i+1 0) { - string troff_charname = str.substring(a, n-a); - html_glyph = get_html_translation(s->f, troff_charname); - if (html_glyph) - html_string += html_glyph; - else { - int index=s->f->name_to_index((troff_charname + '\0').contents()); - - if (s->f->contains(index) && (index != 0)) - html_string += s->f->get_code(index); - } - } - } else - html_string += str[i]; - i++; - } - if (html_string.length() > 0) { - text_glob *g=new text_glob(); - g->text_glob_special(s, buffer.add_string(html_string), html_string.length(), - min_vertical, min_horizontal, max_vertical, max_horizontal); - glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); - } -} - -/* - * dump_page - dump the page contents for debugging purposes. - */ - -void page::dump_page(void) -{ -#if defined(DEBUG_TABLES) - text_glob *old_pos = glyphs.get_data(); - text_glob *g; - - printf("\n\n"); - fflush(stdout); -#endif -} - -/* - * font classes and methods - */ - -class html_font : public font { - html_font(const char *); -public: - int encoding_index; - char *encoding; - char *reencoded_name; - ~html_font(); - static html_font *load_html_font(const char *); -}; - -html_font *html_font::load_html_font(const char *s) -{ - html_font *f = new html_font(s); - if (!f->load()) { - delete f; - return 0; - } - return f; -} - -html_font::html_font(const char *nm) -: font(nm) -{ -} - -html_font::~html_font() -{ -} - -/* - * a simple class to contain the header to this document - */ - -class title_desc { -public: - title_desc (); - ~title_desc (); - - int has_been_written; - int has_been_found; - int with_h1; - string text; -}; - - -title_desc::title_desc () - : has_been_written(FALSE), has_been_found(FALSE), with_h1(FALSE) -{ -} - -title_desc::~title_desc () -{ -} - -class header_desc { -public: - header_desc (); - ~header_desc (); - - int no_of_headings; // how many headings have we found? - char_buffer headings; // all the headings used in the document - list headers; // list of headers built from .NH and .SH - int header_level; // current header level - int written_header; // have we written the header yet? - string header_buffer; // current header text - - void write_headings (FILE *f, int force); -}; - -header_desc::header_desc () - : no_of_headings(0), header_level(2), written_header(0) -{ -} - -header_desc::~header_desc () -{ -} - -/* - * write_headings - emits a list of links for the headings in this document - */ - -void header_desc::write_headings (FILE *f, int force) -{ - text_glob *g; - - if (auto_links || force) { - if (! headers.is_empty()) { - int h=1; - - headers.start_from_head(); - do { - g = headers.get_data(); - fputs("text_string, f); - h++; - fputs("\">", f); - fputs(g->text_string, f); - fputs("
\n", f); - headers.move_right(); - } while (! headers.is_equal_to_head()); - fputs("\n", f); - } - } -} - -class html_printer : public printer { - files file_list; - simple_output html; - int res; - int space_char_index; - int space_width; - int no_of_printed_pages; - int paper_length; - string sbuf; - int sbuf_start_hpos; - int sbuf_vpos; - int sbuf_end_hpos; - int sbuf_prev_hpos; - int sbuf_kern; - style sbuf_style; - int last_sbuf_length; - int overstrike_detected; - style output_style; - int output_hpos; - int output_vpos; - int output_vpos_max; - int output_draw_point_size; - int line_thickness; - int output_line_thickness; - unsigned char output_space_code; - char *inside_font_style; - int page_number; - title_desc title; - header_desc header; - int header_indent; - int supress_sub_sup; - int cutoff_heading; - page *page_contents; - html_text *current_paragraph; - html_indent *indent; - html_table *table; - int end_center; - int end_tempindent; - TAG_ALIGNMENT next_tag; - int fill_on; - int max_linelength; - int linelength; - int pageoffset; - int indentation; - int prev_indent; - int pointsize; - int vertical_spacing; - int line_number; - color *background; - - void flush_sbuf (); - void set_style (const style &); - void set_space_code (unsigned char c); - void do_exec (char *, const environment *); - void do_import (char *, const environment *); - void do_def (char *, const environment *); - void do_mdef (char *, const environment *); - void do_file (char *, const environment *); - void set_line_thickness (const environment *); - void terminate_current_font (void); - void flush_font (void); - void add_to_sbuf (int index, const string &s); - void write_title (int in_head); - int sbuf_continuation (int index, const char *name, const environment *env, int w); - void flush_page (void); - void troff_tag (text_glob *g); - void flush_globs (void); - void emit_line (text_glob *g); - void emit_raw (text_glob *g); - void emit_html (text_glob *g); - void determine_space (text_glob *g); - void start_font (const char *name); - void end_font (const char *name); - int is_font_courier (font *f); - int is_courier_until_eol (void); - void start_size (int from, int to); - void do_font (text_glob *g); - void do_center (char *arg); - void do_break (void); - void do_eol (void); - void do_eol_ce (void); - void do_title (void); - void do_fill (int on); - void do_heading (char *arg); - void write_header (void); - void determine_header_level (int level); - void do_linelength (char *arg); - void do_pageoffset (char *arg); - void do_indentation (char *arg); - void do_tempindent (char *arg); - void do_indentedparagraph (void); - void do_verticalspacing (char *arg); - void do_pointsize (char *arg); - void do_centered_image (void); - void do_left_image (void); - void do_right_image (void); - void do_auto_image (text_glob *g, const char *filename); - void do_links (void); - void do_flush (void); - int is_in_middle (int left, int right); - void do_sup_or_sub (text_glob *g); - int start_subscript (text_glob *g); - int end_subscript (text_glob *g); - int start_superscript (text_glob *g); - int end_superscript (text_glob *g); - void outstanding_eol (int n); - int is_bold (font *f); - font *make_bold (font *f); - int overstrike (int index, const char *name, const environment *env, int w); - void do_body (void); - int next_horiz_pos (text_glob *g, int nf); - void lookahead_for_tables (void); - void insert_tab_te (void); - text_glob *insert_tab_ts (text_glob *where); - void insert_tab0_foreach_tab (void); - void insert_tab_0 (text_glob *where); - void do_indent (int in, int pageoff, int linelen); - void shutdown_table (void); - void do_tab_ts (text_glob *g); - void do_tab_te (void); - void do_col (char *s); - void do_tab (char *s); - void do_tab0 (void); - int calc_nf (text_glob *g, int nf); - void calc_po_in (text_glob *g, int nf); - void remove_tabs (void); - void remove_courier_tabs (void); - void update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g); - void add_table_end (char *debug_string); - // ADD HERE - -public: - html_printer (); - ~html_printer (); - void set_char (int i, font *f, const environment *env, int w, const char *name); - void draw (int code, int *p, int np, const environment *env); - void begin_page (int); - void end_page (int); - void special (char *arg, const environment *env, char type); - font *make_font (const char *); - void end_of_line (); -}; - -printer *make_printer() -{ - return new html_printer; -} - -static void usage(FILE *stream); - -void html_printer::set_style(const style &sty) -{ - const char *fontname = sty.f->get_name(); - if (fontname == NULL) - fatal("no internalname specified for font"); - -#if 0 - change_font(fontname, (font::res/(72*font::sizescale))*sty.point_size); -#endif -} - -/* - * is_bold - returns TRUE if font, f, is bold. - */ - -int html_printer::is_bold (font *f) -{ - const char *fontname = f->get_name(); - return (strcmp(fontname, "B") == 0) || (strcmp(fontname, "BI") == 0); -} - -/* - * make_bold - if a bold font of, f, exists then return it. - */ - -font *html_printer::make_bold (font *f) -{ - const char *fontname = f->get_name(); - - if (strcmp(fontname, "B") == 0) - return f; - if (strcmp(fontname, "I") == 0) - return font::load_font("BI"); - if (strcmp(fontname, "BI") == 0) - return f; - return NULL; -} - -void html_printer::end_of_line() -{ - flush_sbuf(); - line_number++; -} - -/* - * emit_line - writes out a horizontal rule. - */ - -void html_printer::emit_line (text_glob *g) -{ - // --fixme-- needs to know the length in percentage - html.put_string("
"); -} - -/* - * emit_raw - writes the raw html information directly to the device. - */ - -void html_printer::emit_raw (text_glob *g) -{ - do_font(g); - if (next_tag == INLINE) { - determine_space(g); - current_paragraph->do_emittext(g->text_string, g->text_length); - } else { - current_paragraph->done_para(); - switch (next_tag) { - - case CENTERED: - current_paragraph->do_para("align=center"); - break; - case LEFT: - current_paragraph->do_para(&html, "align=left", indentation, pageoffset, linelength); - break; - case RIGHT: - current_paragraph->do_para(&html, "align=right", indentation, pageoffset, linelength); - break; - default: - fatal("unknown enumeration"); - } - current_paragraph->do_emittext(g->text_string, g->text_length); - current_paragraph->done_para(); - next_tag = INLINE; - supress_sub_sup = TRUE; - if (indentation > 0) { - /* - * restore indentation - */ - int newin = indentation; - indentation = 0; - do_indent(newin, pageoffset, linelength); - } - } -} - -/* - * do_center - handle the .ce commands from troff. - */ - -void html_printer::do_center (char *arg) -{ - int n = atoi(arg); - current_paragraph->do_break(); - - if (n > 0) { - current_paragraph->done_para(); - supress_sub_sup = TRUE; - current_paragraph->do_para("align=center"); - end_center += n; - } else { - end_center = 0; - current_paragraph->remove_para_align(); - } -} - -/* - * do_centered_image - set a flag such that the next html-tag is - * placed inside a centered paragraph. - */ - -void html_printer::do_centered_image (void) -{ - next_tag = CENTERED; -} - -/* - * do_right_image - set a flag such that the next html-tag is - * placed inside a right aligned paragraph. - */ - -void html_printer::do_right_image (void) -{ - next_tag = RIGHT; -} - -/* - * do_left_image - set a flag such that the next html-tag is - * placed inside a left aligned paragraph. - */ - -void html_printer::do_left_image (void) -{ - next_tag = LEFT; -} - -/* - * exists - returns TRUE if filename exists. - */ - -static int exists (const char *filename) -{ - FILE *fp = fopen(filename, "r"); - - if (fp == 0) { - return( FALSE ); - } else { - fclose(fp); - return( TRUE ); - } -} - -/* - * generate_img_src - returns a html image tag for the filename - * providing that the image exists. - */ - -static string &generate_img_src (const char *filename) -{ - string *s = new string(""); - - while (filename && (filename[0] == ' ')) { - filename++; - } - if (exists(filename)) - *s += string(""; - return *s; -} - -/* - * do_auto_image - tests whether the image, indicated by filename, - * is present, if so then it emits an html image tag. - * An image tag may be passed through from pic, eqn - * but the corresponding image might not be created. - * Consider .EQ delim $$ .EN or an empty .PS .PE. - */ - -void html_printer::do_auto_image (text_glob *g, const char *filename) -{ - string buffer = generate_img_src(filename); - - if (! buffer.empty()) { - /* - * utilize emit_raw by creating a new text_glob. - */ - text_glob h = *g; - - h.text_string = buffer.contents(); - h.text_length = buffer.length(); - emit_raw(&h); - } else - next_tag = INLINE; -} - -/* - * outstanding_eol - call do_eol, n, times. - */ - -void html_printer::outstanding_eol (int n) -{ - while (n > 0) { - do_eol(); - n--; - } -} - -/* - * do_title - handle the .tl commands from troff. - */ - -void html_printer::do_title (void) -{ - text_glob *t; - int removed_from_head; - int eol_ce = 0; - - if (page_number == 1) { - int found_title_start = FALSE; - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.sub_move_right(); /* move onto next word */ - do { - t = page_contents->glyphs.get_data(); - removed_from_head = FALSE; - if (t->is_auto_img()) { - string img = generate_img_src((char *)(t->text_string + 20)); - - if (! img.empty()) { - if (found_title_start) - title.text += " "; - found_title_start = TRUE; - title.has_been_found = TRUE; - title.text += img; - } - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } else if (t->is_eol_ce()) { - /* process the eol associated with .ce - */ - eol_ce++; - page_contents->glyphs.sub_move_right(); /* move onto next word */ - } else if (t->is_eol()) { - /* end of title found - */ - title.has_been_found = TRUE; - outstanding_eol(eol_ce); - return; - } else if (t->is_a_tag()) { - /* end of title found, but move back so that we read this tag and process it - */ - page_contents->glyphs.move_left(); /* move backwards to last word */ - title.has_been_found = TRUE; - outstanding_eol(eol_ce); - return; - } else if (found_title_start) { - title.text += " " + string(t->text_string, t->text_length); - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } else { - title.text += string(t->text_string, t->text_length); - found_title_start = TRUE; - title.has_been_found = TRUE; - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } - } while ((! page_contents->glyphs.is_equal_to_head()) || (removed_from_head)); - } - outstanding_eol(eol_ce); - } -} - -void html_printer::write_header (void) -{ - if (! header.header_buffer.empty()) { - if (header.header_level > 7) { - header.header_level = 7; - } - - // firstly we must terminate any font and type faces - current_paragraph->done_para(); - supress_sub_sup = TRUE; - - if (cutoff_heading+2 > header.header_level) { - // now we save the header so we can issue a list of links - header.no_of_headings++; - style st; - - text_glob *h=new text_glob(); - h->text_glob_html(&st, - header.headings.add_string(header.header_buffer), - header.header_buffer.length(), - header.no_of_headings, header.header_level, - header.no_of_headings, header.header_level); - - header.headers.add(h, - header.no_of_headings, - header.no_of_headings, header.no_of_headings, - header.no_of_headings, header.no_of_headings); // and add this header to the header list - - // lastly we generate a tag - - html.nl().put_string("").nl(); - } - - if (manufacture_headings) { - // line break before a header - if (!current_paragraph->emitted_text()) - current_paragraph->do_space(); - // user wants manufactured headings which look better than - if (header.header_level<4) { - html.put_string(""); - html.put_string(header.header_buffer); - html.put_string("").nl(); - } - else { - html.put_string(""); - html.put_string(header.header_buffer); - html.put_string("").nl(); - } - } - else { - // and now we issue the real header - html.put_string(""); - html.put_string(header.header_buffer); - html.put_string("").nl(); - } - - current_paragraph->do_para(&html, "", indentation, pageoffset, linelength); - } -} - -void html_printer::determine_header_level (int level) -{ - if (level == 0) { - int i; - - for (i=0; ((iglyphs.move_right(); - if (! page_contents->glyphs.is_equal_to_head()) { - g = page_contents->glyphs.get_data(); - do { - if (g->is_auto_img()) { - string img=generate_img_src((char *)(g->text_string + 20)); - - if (! img.empty()) { - simple_anchors = TRUE; // we cannot use full heading anchors with images - if (l != 0) - header.header_buffer += " "; - - l = g; - header.header_buffer += img; - } - } else if (! (g->is_a_line() || g->is_a_tag())) { - /* - * we ignore tags commands when constructing a heading - */ - if (l != 0) - header.header_buffer += " "; - l = g; - - header.header_buffer += string(g->text_string, g->text_length); - } - page_contents->glyphs.move_right(); - g = page_contents->glyphs.get_data(); - } while ((! page_contents->glyphs.is_equal_to_head()) && - (! g->is_br())); - } - - determine_header_level(level); - write_header(); - - // finally set the output to neutral for after the header - g = page_contents->glyphs.get_data(); - page_contents->glyphs.move_left(); // so that next time we use old g -} - -/* - * is_courier_until_eol - returns TRUE if we can see a whole line which is courier - */ - -int html_printer::is_courier_until_eol (void) -{ - text_glob *orig = page_contents->glyphs.get_data(); - int result = TRUE; - text_glob *g; - - if (! page_contents->glyphs.is_equal_to_tail()) { - page_contents->glyphs.move_right(); - do { - g = page_contents->glyphs.get_data(); - if (! g->is_a_tag() && (! is_font_courier(g->text_style.f))) - result = FALSE; - page_contents->glyphs.move_right(); - } while (result && - (! page_contents->glyphs.is_equal_to_head()) && - (! g->is_fi()) && (! g->is_eol())); - - /* - * now restore our previous position. - */ - while (page_contents->glyphs.get_data() != orig) - page_contents->glyphs.move_left(); - } - return result; -} - -/* - * do_linelength - handle the .ll command from troff. - */ - -void html_printer::do_linelength (char *arg) -{ - if (max_linelength == -1) - max_linelength = atoi(arg); - - if (fill_on) - do_indent(indentation, pageoffset, atoi(arg)); -} - -/* - * do_pageoffset - handle the .po command from troff. - */ - -void html_printer::do_pageoffset (char *arg) -{ - if (fill_on) - do_indent(indentation, atoi(arg), linelength); -} - -/* - * do_indentation - handle the .in command from troff. - */ - -void html_printer::do_indentation (char *arg) -{ - if (fill_on) - do_indent(atoi(arg), pageoffset, linelength); -} - -/* - * do_tempindent - handle the .ti command from troff. - */ - -void html_printer::do_tempindent (char *arg) -{ - if (fill_on) { - end_tempindent = 1; - prev_indent = indentation; - do_indent(atoi(arg), pageoffset, linelength); - } -} - -/* - * shutdown_table - shuts down the current table. - */ - -void html_printer::shutdown_table (void) -{ - if (table != NULL) { - current_paragraph->done_para(); - table->emit_finish_table(); - // dont delete this table as it will be deleted when we destroy the text_glob - table = NULL; - } -} - -/* - * do_indent - remember the indent parameters and if - * indent is > pageoff and indent has changed - * then we start a html table to implement the indentation. - */ - -void html_printer::do_indent (int in, int pageoff, int linelen) -{ - if ((indentation != -1) && - (pageoffset+indentation != in+pageoff)) { - - current_paragraph->done_para(); - - indentation = in; - pageoffset = pageoff; - if (linelen <= max_linelength) - linelength = linelen; - - current_paragraph->do_para(&html, "", indentation, pageoffset, max_linelength); - } -} - -/* - * do_verticalspacing - handle the .vs command from troff. - */ - -void html_printer::do_verticalspacing (char *arg) -{ - vertical_spacing = atoi(arg); -} - -/* - * do_pointsize - handle the .ps command from troff. - */ - -void html_printer::do_pointsize (char *arg) -{ - pointsize = atoi(arg); -} - -/* - * do_fill - records whether troff has requested that text be filled. - */ - -void html_printer::do_fill (int on) -{ - current_paragraph->do_break(); - output_hpos = indentation+pageoffset; - supress_sub_sup = TRUE; - - if (fill_on != on) { - if (on) - current_paragraph->do_para(""); - else - current_paragraph->do_pre(); - fill_on = on; - } -} - -/* - * do_eol - handle the end of line - */ - -void html_printer::do_eol (void) -{ - if (! fill_on) { - if (current_paragraph->ever_emitted_text()) { - current_paragraph->do_newline(); - current_paragraph->do_break(); - } - } - output_hpos = indentation+pageoffset; -} - -/* - * do_eol_ce - handle end of line specifically for a .ce - */ - -void html_printer::do_eol_ce (void) -{ - if (end_center > 0) { - if (end_center > 1) - if (current_paragraph->emitted_text()) - current_paragraph->do_break(); - - end_center--; - if (end_center == 0) { - current_paragraph->done_para(); - supress_sub_sup = TRUE; - } - } -} - -/* - * do_flush - flushes all output and tags. - */ - -void html_printer::do_flush (void) -{ - current_paragraph->done_para(); -} - -/* - * do_links - moves onto a new temporary file and sets auto_links to FALSE. - */ - -void html_printer::do_links (void) -{ - current_paragraph->done_para(); - auto_links = FALSE; /* from now on only emit under user request */ - file_list.add_new_file(xtmpfile()); - html.set_file(file_list.get_file()); -} - -/* - * do_break - handles the ".br" request and also - * undoes an outstanding ".ti" command. - */ - -void html_printer::do_break (void) -{ - current_paragraph->do_break(); - if (end_tempindent > 0) { - end_tempindent--; - if (end_tempindent == 0) - do_indent(prev_indent, pageoffset, linelength); - } - output_hpos = indentation+pageoffset; - supress_sub_sup = TRUE; -} - -/* - * do_tab_ts - start a table, which will have already been defined. - */ - -void html_printer::do_tab_ts (text_glob *g) -{ - html_table *t = g->get_table(); - - if (t != NULL) { - current_paragraph->done_pre(); - current_paragraph->done_para(); - - html.simple_comment("TABS"); - - t->set_linelength(max_linelength); - t->add_indent(pageoffset); - t->emit_table_header(FALSE); - } - - table = t; -} - -/* - * do_tab_te - finish a table. - */ - -void html_printer::do_tab_te (void) -{ - if (table) { - current_paragraph->done_para(); - table->emit_finish_table(); - } - - table = NULL; - - if (indentation > 0) { - /* - * restore indentation - */ - int newin = indentation; - indentation = 0; - do_indent(newin, pageoffset, linelength); - } -} - -/* - * do_tab - handle the "html-tag:tab" tag - */ - -void html_printer::do_tab (char *s) -{ - if (table) { - while (isspace(*s)) - s++; - s++; - int col = table->find_column(atoi(s) + pageoffset + indentation); - if (col > 0) { - current_paragraph->done_para(); - table->emit_col(col); - } - } -} - -/* - * do_tab0 - handle the "html-tag:tab0" tag - */ - -void html_printer::do_tab0 (void) -{ - if (table) { - int col = table->find_column(pageoffset+indentation); - if (col > 0) { - current_paragraph->done_para(); - table->emit_col(col); - } - } -} - -/* - * do_col - start column, s. - */ - -void html_printer::do_col (char *s) -{ - if (table) { - current_paragraph->done_para(); - table->emit_col(atoi(s)); - } -} - -/* - * troff_tag - processes the troff tag and manipulates the troff state machine. - */ - -void html_printer::troff_tag (text_glob *g) -{ - /* - * firstly skip over html-tag: - */ - char *t=(char *)g->text_string+9; - - if (g->is_eol()) { - do_eol(); - } else if (g->is_eol_ce()) { - do_eol_ce(); - } else if (strncmp(t, ".sp", 3) == 0) { - if (g->get_arg() > 0) - current_paragraph->do_space(); - else - current_paragraph->do_break(); - supress_sub_sup = TRUE; - } else if (strncmp(t, ".br", 3) == 0) { - do_break(); - } else if (strcmp(t, ".centered-image") == 0) { - do_centered_image(); - } else if (strcmp(t, ".right-image") == 0) { - do_right_image(); - } else if (strcmp(t, ".left-image") == 0) { - do_left_image(); - } else if (strncmp(t, ".auto-image", 11) == 0) { - char *a = (char *)t+11; - do_auto_image(g, a); - } else if (strncmp(t, ".ce", 3) == 0) { - char *a = (char *)t+3; - supress_sub_sup = TRUE; - do_center(a); - } else if (strncmp(t, ".tl", 3) == 0) { - supress_sub_sup = TRUE; - title.with_h1 = TRUE; - do_title(); - } else if (strncmp(t, ".html-tl", 8) == 0) { - supress_sub_sup = TRUE; - title.with_h1 = FALSE; - do_title(); - } else if (strncmp(t, ".fi", 3) == 0) { - do_fill(TRUE); - } else if (strncmp(t, ".nf", 3) == 0) { - do_fill(FALSE); - } else if ((strncmp(t, ".SH", 3) == 0) || (strncmp(t, ".NH", 3) == 0)) { - char *a = (char *)t+3; - do_heading(a); - } else if (strncmp(t, ".ll", 3) == 0) { - char *a = (char *)t+3; - do_linelength(a); - } else if (strncmp(t, ".po", 3) == 0) { - char *a = (char *)t+3; - do_pageoffset(a); - } else if (strncmp(t, ".in", 3) == 0) { - char *a = (char *)t+3; - do_indentation(a); - } else if (strncmp(t, ".ti", 3) == 0) { - char *a = (char *)t+3; - do_tempindent(a); - } else if (strncmp(t, ".vs", 3) == 0) { - char *a = (char *)t+3; - do_verticalspacing(a); - } else if (strncmp(t, ".ps", 3) == 0) { - char *a = (char *)t+3; - do_pointsize(a); - } else if (strcmp(t, ".links") == 0) { - do_links(); - } else if (strcmp(t, ".no-auto-rule") == 0) { - auto_rule = FALSE; - } else if (strcmp(t, ".tab-ts") == 0) { - do_tab_ts(g); - } else if (strcmp(t, ".tab-te") == 0) { - do_tab_te(); - } else if (strncmp(t, ".col ", 5) == 0) { - char *a = (char *)t+4; - do_col(a); - } else if (strncmp(t, "tab ", 4) == 0) { - char *a = (char *)t+3; - do_tab(a); - } else if (strncmp(t, "tab0", 4) == 0) { - do_tab0(); - } -} - -/* - * is_in_middle - returns TRUE if the positions left..right are in the center of the page. - */ - -int html_printer::is_in_middle (int left, int right) -{ - return( abs(abs(left-pageoffset) - abs(pageoffset+linelength-right)) <= CENTER_TOLERANCE ); -} - -/* - * flush_globs - runs through the text glob list and emits html. - */ - -void html_printer::flush_globs (void) -{ - text_glob *g; - - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - do { - g = page_contents->glyphs.get_data(); - - if (strcmp(g->text_string, "XXXXXXX") == 0) - stop(); - - if (g->is_a_tag()) { - troff_tag(g); - } else if (g->is_a_line()) { - emit_line(g); - } else { - emit_html(g); - } - /* - * after processing the title (and removing it) the glyph list might be empty - */ - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.move_right(); - } - } while (! page_contents->glyphs.is_equal_to_head()); - } -} - -/* - * calc_nf - calculates the _no_ format flag, given the - * text glob, g. - */ - -int html_printer::calc_nf (text_glob *g, int nf) -{ - if (g != NULL) { - if (g->is_fi()) - return FALSE; - if (g->is_nf()) - return TRUE; - } - return nf; -} - -/* - * calc_po_in - calculates the, in, po, registers - */ - -void html_printer::calc_po_in (text_glob *g, int nf) -{ - if (g->is_in()) - indentation = g->get_arg(); - else if (g->is_po()) - pageoffset = g->get_arg(); - else if (g->is_ti()) { - prev_indent = indentation; - indentation = g->get_arg(); - end_tempindent = 1; - } else if (g->is_br() && ((end_tempindent > 0) || (nf && g->is_eol()))) { - end_tempindent = 0; - indentation = prev_indent; - } -} - -/* - * next_horiz_pos - returns the next horiz position. - * -1 is returned if it doesn't exist. - */ - -int html_printer::next_horiz_pos (text_glob *g, int nf) -{ - int next = -1; - - if ((g != NULL) && (g->is_br() || (nf && g->is_eol()))) - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.move_right_get_data(); - if (g == NULL) - page_contents->glyphs.start_from_head(); - else { - next = g->minh; - page_contents->glyphs.move_left(); - } - } - return next; -} - -/* - * insert_tab_ts - inserts a tab-ts before, where. - */ - -text_glob *html_printer::insert_tab_ts (text_glob *where) -{ - text_glob *start_of_table; - text_glob *old_pos = page_contents->glyphs.get_data(); - - page_contents->glyphs.move_to(where); - page_contents->glyphs.move_left(); - page_contents->insert_tag(string("html-tag:.tab-ts")); // tab table start - page_contents->glyphs.move_right(); - start_of_table = page_contents->glyphs.get_data(); - page_contents->glyphs.move_to(old_pos); - return start_of_table; -} - -/* - * insert_tab_te - inserts a tab-te before the current position - * (it skips backwards over .sp/.br) - */ - -void html_printer::insert_tab_te (void) -{ - text_glob *g = page_contents->glyphs.get_data(); - page_contents->dump_page(); - - while (page_contents->glyphs.get_data()->is_a_tag()) - page_contents->glyphs.move_left(); - - page_contents->insert_tag(string("html-tag:.tab-te")); // tab table end - while (g != page_contents->glyphs.get_data()) - page_contents->glyphs.move_right(); - page_contents->dump_page(); -} - -/* - * insert_tab_0 - inserts a tab0 before, where. - */ - -void html_printer::insert_tab_0 (text_glob *where) -{ - text_glob *old_pos = page_contents->glyphs.get_data(); - - page_contents->glyphs.move_to(where); - page_contents->glyphs.move_left(); - page_contents->insert_tag(string("html-tag:tab0")); // tab0 start of line - page_contents->glyphs.move_right(); - page_contents->glyphs.move_to(old_pos); -} - -/* - * remove_tabs - removes the tabs tags on this line. - */ - -void html_printer::remove_tabs (void) -{ - text_glob *orig = page_contents->glyphs.get_data(); - text_glob *g; - - if (! page_contents->glyphs.is_equal_to_tail()) { - do { - g = page_contents->glyphs.get_data(); - if (g->is_tab()) { - page_contents->glyphs.sub_move_right(); - if (g == orig) - orig = page_contents->glyphs.get_data(); - } else - page_contents->glyphs.move_right(); - } while ((! page_contents->glyphs.is_equal_to_head()) && - (! g->is_eol())); - - /* - * now restore our previous position. - */ - while (page_contents->glyphs.get_data() != orig) - page_contents->glyphs.move_left(); - } -} - -void html_printer::remove_courier_tabs (void) -{ - text_glob *g; - int line_start = TRUE; - int nf = FALSE; - - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - line_start = TRUE; - do { - g = page_contents->glyphs.get_data(); - - nf = calc_nf(g, nf); - - if (line_start) { - if (line_start && nf && is_courier_until_eol()) { - remove_tabs(); - g = page_contents->glyphs.get_data(); - } - } - - line_start = g->is_br() || g->is_nf() || g->is_fi() || (nf && g->is_eol()); - page_contents->glyphs.move_right(); - } while (! page_contents->glyphs.is_equal_to_head()); - } -} - -void html_printer::insert_tab0_foreach_tab (void) -{ - text_glob *start_of_line = NULL; - text_glob *g = NULL; - int seen_tab = FALSE; - int seen_col = FALSE; - int nf = FALSE; - - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - start_of_line = page_contents->glyphs.get_data(); - do { - g = page_contents->glyphs.get_data(); - - nf = calc_nf(g, nf); - - if (g->is_tab()) - seen_tab = TRUE; - - if (g->is_col()) - seen_col = TRUE; - - if (g->is_br() || (nf && g->is_eol())) { - do { - page_contents->glyphs.move_right(); - g = page_contents->glyphs.get_data(); - nf = calc_nf(g, nf); - if (page_contents->glyphs.is_equal_to_head()) { - if (seen_tab && !seen_col) - insert_tab_0(start_of_line); - return; - } - } while (g->is_br() || (nf && g->is_eol()) || g->is_ta()); - // printf("\nstart_of_line is: %s\n", g->text_string); - if (seen_tab && !seen_col) { - insert_tab_0(start_of_line); - page_contents->glyphs.move_to(g); - } - - seen_tab = FALSE; - seen_col = FALSE; - start_of_line = g; - } - page_contents->glyphs.move_right(); - } while (! page_contents->glyphs.is_equal_to_head()); - if (seen_tab && !seen_col) - insert_tab_0(start_of_line); - - } -} - -/* - * update_min_max - updates the extent of a column, given the left and right - * extents of a glyph, g. - */ - -void html_printer::update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g) -{ - switch (type_of_col) { - - case tab_tag: - break; - case tab0_tag: - *minimum = g->minh; - break; - case col_tag: - *minimum = g->minh; - *maximum = g->maxh; - break; - default: - break; - } -} - -/* - * add_table_end - moves left one glyph, adds a table end tag and adds a - * debugging string. - */ - -void html_printer::add_table_end (char *debug_string) -{ - page_contents->glyphs.move_left(); - insert_tab_te(); -#if defined(DEBUG_TABLES) - page_contents->insert_tag(string(debug_string)); -#endif -} - -/* - * lookahead_for_tables - checks for .col tags and inserts table start/end tags - */ - -void html_printer::lookahead_for_tables (void) -{ - text_glob *g; - text_glob *start_of_line = NULL; - text_glob *start_of_table = NULL; - text_glob *last = NULL; - colType type_of_col = none; - int left = 0; - int found_col = FALSE; - int seen_text = FALSE; - int ncol = 0; - int colmin; - int colmax; - html_table *table = new html_table(&html, -1); - const char *tab_defs = NULL; - char align = 'L'; - int nf = FALSE; - int old_pageoffset = pageoffset; - - remove_courier_tabs(); - page_contents->dump_page(); - insert_tab0_foreach_tab(); - page_contents->dump_page(); - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.start_from_head(); - g = page_contents->glyphs.get_data(); - do { -#if defined(DEBUG_TABLES) - fprintf(stderr, " [") ; - fprintf(stderr, g->text_string) ; - fprintf(stderr, "] ") ; - fflush(stderr); - if (strcmp(g->text_string, "XXXXXXX") == 0) - stop(); -#endif - - nf = calc_nf(g, nf); - calc_po_in(g, nf); - if (g->is_col()) { - if (type_of_col == tab_tag && start_of_table != NULL) { - page_contents->glyphs.move_left(); - insert_tab_te(); - start_of_table->remember_table(table); - table = new html_table(&html, -1); - page_contents->insert_tag(string("*** TAB -> COL ***")); - if (tab_defs != NULL) - table->tab_stops->init(tab_defs); - start_of_table = NULL; - last = NULL; - } - type_of_col = col_tag; - found_col = TRUE; - ncol = g->get_arg(); - align = 'L'; - colmin = 0; - colmax = 0; - } else if (g->is_tab()) { - type_of_col = tab_tag; - colmin = g->get_tab_args(&align); - align = 'L'; // for now as 'C' and 'R' are broken - ncol = table->find_tab_column(colmin); - colmin += pageoffset + indentation; - colmax = table->get_tab_pos(ncol+1); - if (colmax > 0) - colmax += pageoffset + indentation; - } else if (g->is_tab0()) { - if (type_of_col == col_tag && start_of_table != NULL) { - page_contents->glyphs.move_left(); - insert_tab_te(); - start_of_table->remember_table(table); - table = new html_table(&html, -1); - page_contents->insert_tag(string("*** COL -> TAB ***")); - start_of_table = NULL; - last = NULL; - } - if (tab_defs != NULL) - table->tab_stops->init(tab_defs); - - type_of_col = tab0_tag; - ncol = 1; - colmin = 0; - colmax = table->get_tab_pos(2) + pageoffset + indentation; - } else if (! g->is_a_tag()) - update_min_max(type_of_col, &colmin, &colmax, g); - - if ((! g->is_a_tag()) || g->is_tab()) - seen_text = TRUE; - - if ((g->is_col() || g->is_tab() || g->is_tab0()) - && (start_of_line != NULL) && (start_of_table == NULL)) { - start_of_table = insert_tab_ts(start_of_line); - start_of_line = NULL; - seen_text = FALSE; - } else if (g->is_ce() && (start_of_table != NULL)) { - add_table_end("*** CE ***"); - start_of_table->remember_table(table); - start_of_table = NULL; - last = NULL; - } else if (g->is_ta()) { - tab_defs = g->text_string; - if (!table->tab_stops->compatible(tab_defs)) { - if (start_of_table != NULL) { - add_table_end("*** TABS ***"); - start_of_table->remember_table(table); - table = new html_table(&html, -1); - start_of_table = NULL; - type_of_col = none; - last = NULL; - } - table->tab_stops->init(tab_defs); - } - } - - if (((! g->is_a_tag()) || g->is_tab()) && (start_of_table != NULL)) { - // we are in a table and have a glyph - if ((ncol == 0) || (! table->add_column(ncol, colmin, colmax, align))) { - if (ncol == 0) - add_table_end("*** NCOL == 0 ***"); - else - add_table_end("*** CROSSED COLS ***"); - - start_of_table->remember_table(table); - table = new html_table(&html, -1); - start_of_table = NULL; - type_of_col = none; - last = NULL; - } - } - - /* - * move onto next glob, check whether we are starting a new line - */ - g = page_contents->glyphs.move_right_get_data(); - - if (g == NULL) { - if (found_col) { - page_contents->glyphs.start_from_head(); - last = g; - found_col = FALSE; - } - } else if (g->is_br() || (nf && g->is_eol())) { - do { - g = page_contents->glyphs.move_right_get_data(); - nf = calc_nf(g, nf); - } while ((g != NULL) && (g->is_br() || (nf && g->is_eol()))); - start_of_line = g; - seen_text = FALSE; - ncol = 0; - left = next_horiz_pos(g, nf); - if (found_col) - last = g; - found_col = FALSE; - } - } while ((g != NULL) && (! page_contents->glyphs.is_equal_to_head())); - -#if defined(DEBUG_TABLES) - fprintf(stderr, "finished scanning for tables\n"); -#endif - - page_contents->glyphs.start_from_head(); - if (start_of_table != NULL) { - if (last != NULL) - while (last != page_contents->glyphs.get_data()) - page_contents->glyphs.move_left(); - - insert_tab_te(); - start_of_table->remember_table(table); - table = NULL; - page_contents->insert_tag(string("*** LAST ***")); - } - } - if (table != NULL) - delete table; - - // and reset the registers - pageoffset = old_pageoffset; - indentation = 0; - prev_indent = 0; - end_tempindent = 0; -} - -void html_printer::flush_page (void) -{ - supress_sub_sup = TRUE; - flush_sbuf(); - page_contents->dump_page(); - lookahead_for_tables(); - page_contents->dump_page(); - - flush_globs(); - current_paragraph->done_para(); - - // move onto a new page - delete page_contents; -#if defined(DEBUG_TABLES) - fprintf(stderr, "\n\n*** flushed page ***\n\n"); - - html.simple_comment("new page called"); -#endif - page_contents = new page; -} - -/* - * determine_space - works out whether we need to write a space. - * If last glyph is ajoining then no space emitted. - */ - -void html_printer::determine_space (text_glob *g) -{ - if (current_paragraph->is_in_pre()) { - /* - * .nf has been specified - */ - while (output_hpos < g->minh) { - output_hpos += space_width; - current_paragraph->emit_space(); - } - } else { - if ((output_vpos != g->minv) || (output_hpos < g->minh)) { - current_paragraph->emit_space(); - } - } -} - -/* - * is_font_courier - returns TRUE if the font, f, is courier. - */ - -int html_printer::is_font_courier (font *f) -{ - if (f != 0) { - const char *fontname = f->get_name(); - - return( (fontname != 0) && (fontname[0] == 'C') ); - } - return( FALSE ); -} - -/* - * end_font - shuts down the font corresponding to fontname. - */ - -void html_printer::end_font (const char *fontname) -{ - if (strcmp(fontname, "B") == 0) { - current_paragraph->done_bold(); - } else if (strcmp(fontname, "I") == 0) { - current_paragraph->done_italic(); - } else if (strcmp(fontname, "BI") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_italic(); - } else if (strcmp(fontname, "CR") == 0) { - current_paragraph->done_tt(); - } else if (strcmp(fontname, "CI") == 0) { - current_paragraph->done_italic(); - current_paragraph->done_tt(); - } else if (strcmp(fontname, "CB") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_tt(); - } else if (strcmp(fontname, "CBI") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_italic(); - current_paragraph->done_tt(); - } -} - -/* - * start_font - starts the font corresponding to name. - */ - -void html_printer::start_font (const char *fontname) -{ - if (strcmp(fontname, "R") == 0) { - current_paragraph->done_bold(); - current_paragraph->done_italic(); - current_paragraph->done_tt(); - } else if (strcmp(fontname, "B") == 0) { - current_paragraph->do_bold(); - } else if (strcmp(fontname, "I") == 0) { - current_paragraph->do_italic(); - } else if (strcmp(fontname, "BI") == 0) { - current_paragraph->do_bold(); - current_paragraph->do_italic(); - } else if (strcmp(fontname, "CR") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - } else if (strcmp(fontname, "CI") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - current_paragraph->do_italic(); - } else if (strcmp(fontname, "CB") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - current_paragraph->do_bold(); - } else if (strcmp(fontname, "CBI") == 0) { - if ((! fill_on) && (is_courier_until_eol())) { - current_paragraph->do_pre(); - } - current_paragraph->do_tt(); - current_paragraph->do_italic(); - current_paragraph->do_bold(); - } -} - -/* - * start_size - from is old font size, to is the new font size. - * The html increase and decrease alters the - * font size by 20%. We try and map these onto glyph sizes. - */ - -void html_printer::start_size (int from, int to) -{ - if (from < to) { - while (from < to) { - current_paragraph->do_big(); - from += SIZE_INCREMENT; - } - } else if (from > to) { - while (from > to) { - current_paragraph->do_small(); - from -= SIZE_INCREMENT; - } - } -} - -/* - * do_font - checks to see whether we need to alter the html font. - */ - -void html_printer::do_font (text_glob *g) -{ - /* - * check if the output_style.point_size has not been set yet - * this allow users to place .ps at the top of their troff files - * and grohtml can then treat the .ps value as the base font size (3) - */ - if (output_style.point_size == -1) { - output_style.point_size = pointsize; - } - - if (g->text_style.f != output_style.f) { - if (output_style.f != 0) { - end_font(output_style.f->get_name()); - } - output_style.f = g->text_style.f; - if (output_style.f != 0) { - start_font(output_style.f->get_name()); - } - } - if (output_style.point_size != g->text_style.point_size) { - do_sup_or_sub(g); - if ((output_style.point_size > 0) && - (g->text_style.point_size > 0)) { - start_size(output_style.point_size, g->text_style.point_size); - } - if (g->text_style.point_size > 0) { - output_style.point_size = g->text_style.point_size; - } - } - if (output_style.col != g->text_style.col) { - current_paragraph->done_color(); - output_style.col = g->text_style.col; - current_paragraph->do_color(&output_style.col); - } -} - -/* - * start_subscript - returns TRUE if, g, looks like a subscript start. - */ - -int html_printer::start_subscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (output_vpos < g->minv) && - (output_vpos-height > g->maxv) && - (output_style.point_size > g->text_style.point_size) ); -} - -/* - * start_superscript - returns TRUE if, g, looks like a superscript start. - */ - -int html_printer::start_superscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (output_vpos > g->minv) && - (output_vpos-height < g->maxv) && - (output_style.point_size > g->text_style.point_size) ); -} - -/* - * end_subscript - returns TRUE if, g, looks like the end of a subscript. - */ - -int html_printer::end_subscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (g->minv < output_vpos) && - (output_vpos-height > g->maxv) && - (output_style.point_size < g->text_style.point_size) ); -} - -/* - * end_superscript - returns TRUE if, g, looks like the end of a superscript. - */ - -int html_printer::end_superscript (text_glob *g) -{ - int r = font::res; - int height = output_style.point_size*r/72; - - return( (output_style.point_size != 0) && - (g->minv > output_vpos) && - (output_vpos-height < g->maxv) && - (output_style.point_size < g->text_style.point_size) ); -} - -/* - * do_sup_or_sub - checks to see whether the next glyph is a subscript/superscript - * start/end and it calls the services of html-text to issue the - * appropriate tags. - */ - -void html_printer::do_sup_or_sub (text_glob *g) -{ - if (! supress_sub_sup) { - if (start_subscript(g)) { - current_paragraph->do_sub(); - } else if (start_superscript(g)) { - current_paragraph->do_sup(); - } else if (end_subscript(g)) { - current_paragraph->done_sub(); - } else if (end_superscript(g)) { - current_paragraph->done_sup(); - } - } -} - -/* - * emit_html - write out the html text - */ - -void html_printer::emit_html (text_glob *g) -{ - do_font(g); - determine_space(g); - current_paragraph->do_emittext(g->text_string, g->text_length); - output_vpos = g->minv; - output_hpos = g->maxh; - output_vpos_max = g->maxv; - supress_sub_sup = FALSE; -} - -/* - * flush_sbuf - flushes the current sbuf into the list of glyphs. - */ - -void html_printer::flush_sbuf() -{ - if (sbuf.length() > 0) { - int r=font::res; // resolution of the device - set_style(sbuf_style); - if (overstrike_detected && (! is_bold(sbuf_style.f))) { - font *bold_font = make_bold(sbuf_style.f); - if (bold_font != NULL) - sbuf_style.f = bold_font; - } - - page_contents->add(&sbuf_style, sbuf, - line_number, - sbuf_vpos-sbuf_style.point_size*r/72, sbuf_start_hpos, - sbuf_vpos , sbuf_end_hpos); - - output_hpos = sbuf_end_hpos; - output_vpos = sbuf_vpos; - last_sbuf_length = 0; - sbuf_prev_hpos = sbuf_end_hpos; - overstrike_detected = FALSE; - sbuf.clear(); - } -} - -void html_printer::set_line_thickness(const environment *env) -{ - line_thickness = env->size; -} - -void html_printer::draw(int code, int *p, int np, const environment *env) -{ - switch (code) { - - case 'l': -# if 0 - if (np == 2) { - page_contents->add_line(&sbuf_style, - line_number, - env->hpos, env->vpos, env->hpos+p[0], env->vpos+p[1], line_thickness); - } else { - error("2 arguments required for line"); - } -# endif - break; - case 't': - { - if (np == 0) { - line_thickness = -1; - } else { - // troff gratuitously adds an extra 0 - if (np != 1 && np != 2) { - error("0 or 1 argument required for thickness"); - break; - } - line_thickness = p[0]; - } - break; - } - - case 'P': - break; - case 'p': - break; - case 'E': - break; - case 'e': - break; - case 'C': - break; - case 'c': - break; - case 'a': - break; - case '~': - break; - case 'f': - break; - case 'F': - // fill with color env->fill - if (background != NULL) - delete background; - background = new color; - *background = *env->fill; - break; - - default: - error("unrecognised drawing command `%1'", char(code)); - break; - } -} - -html_printer::html_printer() -: html(0, MAX_LINE_LENGTH), - no_of_printed_pages(0), - last_sbuf_length(0), - overstrike_detected(FALSE), - output_hpos(-1), - output_vpos(-1), - output_vpos_max(-1), - line_thickness(-1), - inside_font_style(0), - page_number(0), - header_indent(-1), - supress_sub_sup(TRUE), - cutoff_heading(100), - indent(NULL), - table(NULL), - end_center(0), - end_tempindent(0), - next_tag(INLINE), - fill_on(TRUE), - max_linelength(-1), - linelength(0), - pageoffset(0), - indentation(0), - prev_indent(0), - pointsize(0), - line_number(0), - background(default_background) -{ - file_list.add_new_file(xtmpfile()); - html.set_file(file_list.get_file()); - if (font::hor != 24) - fatal("horizontal resolution must be 24"); - if (font::vert != 40) - fatal("vertical resolution must be 40"); -#if 0 - // should be sorted html.. - if (font::res % (font::sizescale*72) != 0) - fatal("res must be a multiple of 72*sizescale"); -#endif - int r = font::res; - int point = 0; - while (r % 10 == 0) { - r /= 10; - point++; - } - res = r; - html.set_fixed_point(point); - space_char_index = font::name_to_index("space"); - space_width = font::hor; - paper_length = font::paperlength; - linelength = font::res*13/2; - if (paper_length == 0) - paper_length = 11*font::res; - - page_contents = new page(); -} - -/* - * add_to_sbuf - adds character code or name to the sbuf. - */ - -void html_printer::add_to_sbuf (int index, const string &s) -{ - if (sbuf_style.f == NULL) - return; - - char *html_glyph = NULL; - unsigned int code = sbuf_style.f->get_code(index); - - if (s.empty()) { - if (sbuf_style.f->contains(index)) - html_glyph = (char *)sbuf_style.f->get_special_device_encoding(index); - else - html_glyph = NULL; - - if ((html_glyph == NULL) && (code >= UNICODE_DESC_START)) - html_glyph = to_unicode(code); - } else - html_glyph = get_html_translation(sbuf_style.f, s); - - last_sbuf_length = sbuf.length(); - if (html_glyph == NULL) - sbuf += ((char)code); - else - sbuf += html_glyph; -} - -int html_printer::sbuf_continuation (int index, const char *name, - const environment *env, int w) -{ - /* - * lets see whether the glyph is closer to the end of sbuf - */ - if ((sbuf_end_hpos == env->hpos) - || ((sbuf_prev_hpos < sbuf_end_hpos) - && (env->hpos < sbuf_end_hpos) - && ((sbuf_end_hpos-env->hpos < env->hpos-sbuf_prev_hpos)))) { - add_to_sbuf(index, name); - sbuf_prev_hpos = sbuf_end_hpos; - sbuf_end_hpos += w + sbuf_kern; - return TRUE; - } else { - if ((env->hpos >= sbuf_end_hpos) && - ((sbuf_kern == 0) || (sbuf_end_hpos - sbuf_kern != env->hpos))) { - /* - * lets see whether a space is needed or not - */ - - if (env->hpos-sbuf_end_hpos < space_width) { - add_to_sbuf(index, name); - sbuf_prev_hpos = sbuf_end_hpos; - sbuf_end_hpos = env->hpos + w; - return TRUE; - } - } - } - return FALSE ; -} - -/* - * get_html_translation - given the position of the character and its name - * return the device encoding for such character. - */ - -char *get_html_translation (font *f, const string &name) -{ - int index; - - if ((f == 0) || name.empty()) - return NULL; - else { - index = f->name_to_index((char *)(name + '\0').contents()); - if (index == 0) { - error("character `%s' not found", (name + '\0').contents()); - return NULL; - } else - if (f->contains(index)) - return (char *)f->get_special_device_encoding(index); - else - return NULL; - } -} - -/* - * overstrike - returns TRUE if the glyph (i, name) is going to overstrike - * a previous glyph in sbuf. - * If TRUE the font is changed to bold and the previous sbuf - * is flushed. - */ - -int html_printer::overstrike(int index, const char *name, const environment *env, int w) -{ - if ((env->hpos < sbuf_end_hpos) - || ((sbuf_kern != 0) && (sbuf_end_hpos - sbuf_kern < env->hpos))) { - /* - * at this point we have detected an overlap - */ - if (overstrike_detected) { - /* already detected, remove previous glyph and use this glyph */ - sbuf.set_length(last_sbuf_length); - add_to_sbuf(index, name); - sbuf_end_hpos = env->hpos + w; - return TRUE; - } else { - /* first time we have detected an overstrike in the sbuf */ - sbuf.set_length(last_sbuf_length); /* remove previous glyph */ - if (! is_bold(sbuf_style.f)) - flush_sbuf(); - overstrike_detected = TRUE; - add_to_sbuf(index, name); - sbuf_end_hpos = env->hpos + w; - return TRUE; - } - } - return FALSE ; -} - -/* - * set_char - adds a character into the sbuf if it is a continuation with the previous - * word otherwise flush the current sbuf and add character anew. - */ - -void html_printer::set_char(int i, font *f, const environment *env, int w, const char *name) -{ - style sty(f, env->size, env->height, env->slant, env->fontno, *env->col); - if (sty.slant != 0) { - if (sty.slant > 80 || sty.slant < -80) { - error("silly slant `%1' degrees", sty.slant); - sty.slant = 0; - } - } - if (((! sbuf.empty()) && (sty == sbuf_style) && (sbuf_vpos == env->vpos)) - && (sbuf_continuation(i, name, env, w) || overstrike(i, name, env, w))) - return; - - flush_sbuf(); - add_to_sbuf(i, name); - sbuf_end_hpos = env->hpos + w; - sbuf_start_hpos = env->hpos; - sbuf_prev_hpos = env->hpos; - sbuf_vpos = env->vpos; - sbuf_style = sty; - sbuf_kern = 0; -} - -/* - * write_title - writes the title to this document - */ - -void html_printer::write_title (int in_head) -{ - if (title.has_been_found) { - if (in_head) { - html.put_string(""); - html.put_string(title.text); - html.put_string("").nl().nl(); - } else { - title.has_been_written = TRUE; - if (title.with_h1) { - html.put_string("

"); - html.put_string(title.text); - html.put_string("

").nl().nl(); - } - } - } else if (in_head) { - // place empty title tags to help conform to `tidy' - html.put_string("").nl(); - } -} - -/* - * write_rule - emits a html rule tag, if the auto_rule boolean is true. - */ - -static void write_rule (void) -{ - if (auto_rule) - fputs("
\n", stdout); -} - -void html_printer::begin_page(int n) -{ - page_number = n; -#if defined(DEBUGGING) - html.begin_comment("Page: ").put_string(i_to_a(page_number)).end_comment();; -#endif - no_of_printed_pages++; - - output_style.f = 0; - output_style.point_size= -1; - output_space_code = 32; - output_draw_point_size = -1; - output_line_thickness = -1; - output_hpos = -1; - output_vpos = -1; - output_vpos_max = -1; - current_paragraph = new html_text(&html); - do_indent(indentation, pageoffset, linelength); - current_paragraph->do_para(""); -} - -void html_printer::end_page(int) -{ - flush_sbuf(); - flush_page(); -} - -font *html_printer::make_font(const char *nm) -{ - return html_font::load_html_font(nm); -} - -void html_printer::do_body (void) -{ - if (background == NULL) - fputs("\n\n", stdout); - else { - unsigned int r, g, b; - char buf[6+1]; - - background->get_rgb(&r, &g, &b); - // we have to scale 0..0xFFFF to 0..0xFF - sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101); - - fputs("\n\n", stdout); - } -} - -html_printer::~html_printer() -{ -#ifdef LONG_FOR_TIME_T - long t; -#else - time_t t; -#endif - - current_paragraph->flush_text(); - html.end_line(); - html.set_file(stdout); - html.begin_comment("Creator : ") - .put_string("groff ") - .put_string("version ") - .put_string(Version_string) - .end_comment(); - - t = time(0); - html.begin_comment("CreationDate: ") - .put_string(ctime(&t), strlen(ctime(&t))-1) - .end_comment(); - - /* - * 'HTML: The definitive guide', O'Reilly, p47. advises against specifying - * the dtd. - */ - // fputs("\n", stdout); - fputs("\n", stdout); - fputs("\n", stdout); - fputs("\n", stdout); - fputs("\n", stdout); - write_title(TRUE); - fputs("\n", stdout); - do_body(); - - write_title(FALSE); - header.write_headings(stdout, FALSE); - write_rule(); -#if defined(DEBUGGING) - html.begin_comment("Total number of pages: ").put_string(i_to_a(no_of_printed_pages)).end_comment(); -#endif - html.end_line(); - html.end_line(); - /* - * now run through the file list copying each temporary file in turn and emitting the links. - */ - file_list.start_of_list(); - while (file_list.get_file() != 0) { - if (fseek(file_list.get_file(), 0L, 0) < 0) - fatal("fseek on temporary file failed"); - html.copy_file(file_list.get_file()); - fclose(file_list.get_file()); - file_list.move_next(); - if (file_list.get_file() != 0) - header.write_headings(stdout, TRUE); - } - write_rule(); - fputs("\n", stdout); - fputs("\n", stdout); -} - -/* - * special - handle all x X requests from troff. For post-html they allow users - * to pass raw html commands, turn auto linked headings off/on and - * also allow troff to emit tags to indicate when a: .br, .sp etc occurs. - */ - -void html_printer::special(char *s, const environment *env, char type) -{ - if (type != 'p') - return; - if (s != 0) { - flush_sbuf(); - if (env->fontno >= 0) { - style sty(get_font_from_index(env->fontno), env->size, env->height, - env->slant, env->fontno, *env->col); - sbuf_style = sty; - } - - if (strncmp(s, "html:", 5) == 0) { - int r=font::res; /* resolution of the device */ - font *f=sbuf_style.f; - - if (f == NULL) { - int found=FALSE; - - f = font::load_font("TR", &found); - } - - /* - * need to pass rest of string through to html output during flush - */ - page_contents->add_and_encode(&sbuf_style, string(&s[5]), - line_number, - env->vpos-env->size*r/72, env->hpos, - env->vpos , env->hpos); - - /* - * assume that the html command has no width, if it does then hopefully troff - * will have fudged this in a macro by requesting that the formatting move right by - * the appropriate amount. - */ - } else if (strncmp(s, "index:", 6) == 0) { - cutoff_heading = atoi(&s[6]); - } else if (strncmp(s, "html-tag:", 9) == 0) { - int r=font::res; /* resolution of the device */ - - page_contents->add_tag(&sbuf_style, string(s), - line_number, - env->vpos-env->size*r/72, env->hpos, - env->vpos , env->hpos); - } - } -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int c; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((c = getopt_long(argc, argv, "a:g:o:i:I:D:F:vbdhlrnp", long_options, NULL)) - != EOF) - switch(c) { - case 'v': - printf("GNU post-grohtml (groff) version %s\n", Version_string); - exit(0); - break; - case 'a': - /* text antialiasing bits - handled by pre-html */ - break; - case 'g': - /* graphic antialiasing bits - handled by pre-html */ - break; - case 'b': - // set background color to white - default_background = new color; - default_background->set_gray(color::MAX_COLOR_VAL); - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'l': - auto_links = FALSE; - break; - case 'r': - auto_rule = FALSE; - break; - case 'd': - /* handled by pre-html */ - break; - case 'h': - /* do not use the Hn headings of html, but manufacture our own */ - manufacture_headings = TRUE; - break; - case 'o': - /* handled by pre-html */ - break; - case 'p': - /* handled by pre-html */ - break; - case 'i': - /* handled by pre-html */ - break; - case 'I': - /* handled by pre-html */ - break; - case 'D': - /* handled by pre-html */ - break; - case 'n': - simple_anchors = TRUE; - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - if (optind >= argc) { - do_file("-"); - } else { - for (int i = optind; i < argc; i++) - do_file(argv[i]); - } - delete pr; - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-vblnh] [-D dir] [-I image_stem] [-F dir] [files ...]\n", - program_name); -} diff --git a/contrib/groff/src/devices/grolbp/lbp.cc b/contrib/groff/src/devices/grolbp/lbp.cc deleted file mode 100644 index 76db32a..0000000 --- a/contrib/groff/src/devices/grolbp/lbp.cc +++ /dev/null @@ -1,740 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1994, 2000, 2001, 2002 Free Software Foundation, Inc. - Written by Francisco Andrés Verdú with many ideas - taken from the other groff drivers. - - -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. */ - -/* -TODO - - - Add X command to include bitmaps -*/ -#define _GNU_SOURCE - -#include "driver.h" -#include "lbp.h" -#include "charset.h" -#include "paper.h" - -#include "nonposix.h" - -extern "C" const char *Version_string; - -static int user_papersize = -1; // papersize -static int orientation = -1; // orientation -static double user_paperlength = 0; // Custom Paper size -static double user_paperwidth = 0; -static int ncopies = 1; // Number of copies - -#define DEFAULT_LINEWIDTH_FACTOR 40 // 0.04em -static int linewidth_factor = DEFAULT_LINEWIDTH_FACTOR; - -static int set_papersize(const char *paperformat); - -class lbp_font : public font { -public: - ~lbp_font(); - void handle_unknown_font_command(const char *command, const char *arg, - const char *filename, int lineno); - static lbp_font *load_lbp_font(const char *); - char *lbpname; - char is_scalable; -private: - lbp_font(const char *); -}; - -class lbp_printer : public printer { -public: - lbp_printer(int, double, double); - ~lbp_printer(); - void set_char(int, font *, const environment *, int, const char *name); - void draw(int code, int *p, int np, const environment *env); - void begin_page(int); - void end_page(int page_length); - font *make_font(const char *); - void end_of_line(); -private: - void set_line_thickness(int size,const environment *env); - void vdmstart(); - void vdmflush(); // the name vdmend was already used in lbp.h - void setfillmode(int mode); - void polygon( int hpos,int vpos,int np,int *p); - char *font_name(const lbp_font *f, const int siz); - - int fill_pattern; - int fill_mode; - int cur_hpos; - int cur_vpos; - lbp_font *cur_font; - int cur_size; - unsigned short cur_symbol_set; - int line_thickness; - int req_linethickness; // requested line thickness - int papersize; - int paperlength; // custom paper size - int paperwidth; -}; - -// Compatibility section. -// -// Here we define some functions not present in some of the targets -// platforms -#ifndef HAVE_STRSEP -// Solaris 8 doesn't have the strsep function -static char *strsep(char **pcadena, const char *delim) -{ - char *p; - p = strtok(*pcadena, delim); - *pcadena = strtok(NULL, delim); - return p; -} -#endif - -lbp_font::lbp_font(const char *nm) -: font(nm) -{ -} - -lbp_font::~lbp_font() -{ -} - -lbp_font *lbp_font::load_lbp_font(const char *s) -{ - lbp_font *f = new lbp_font(s); - f->lbpname = NULL; - f->is_scalable = 1; // Default is that fonts are scalable - if (!f->load()) { - delete f; - return 0; - } - return f; -} - - -void lbp_font::handle_unknown_font_command(const char *command, - const char *arg, - const char *filename, int lineno) -{ - if (strcmp(command, "lbpname") == 0) { - if (arg == 0) - fatal_with_file_and_line(filename, lineno, - "`%1' command requires an argument", - command); - this->lbpname = new char[strlen(arg) + 1]; - strcpy(this->lbpname, arg); - // we recognize bitmapped fonts by the first character of its name - if (arg[0] == 'N') - this->is_scalable = 0; - // fprintf(stderr, "Loading font \"%s\" \n", arg); - } - // fprintf(stderr, "Loading font %s \"%s\" in %s at %d\n", - // command, arg, filename, lineno); -} - -static void wp54charset() -{ - unsigned int i; - lbpputs("\033[714;100;29;0;32;120.}"); - for (i = 0; i < sizeof(symset); i++) - lbpputc(symset[i]); - lbpputs("\033[100;0 D"); - return; -} - -lbp_printer::lbp_printer(int ps, double pw, double pl) -: fill_pattern(1), - fill_mode(0), - cur_hpos(-1), - cur_font(0), - cur_size(0), - cur_symbol_set(0), - req_linethickness(-1) -{ -#ifdef SET_BINARY - SET_BINARY(fileno(stdout)); -#endif - lbpinit(stdout); - lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h"); - wp54charset(); // Define the new symbol set - lbpputs("\033[7 I\033[?32h\033[?33h\033[11h"); - // Paper size handling - if (orientation < 0) - orientation = 0; // Default orientation is portrait - papersize = 14; // Default paper size is A4 - if (font::papersize) { - papersize = set_papersize(font::papersize); - paperlength = font::paperlength; - paperwidth = font::paperwidth; - } - if (ps >= 0) { - papersize = ps; - paperlength = int(pl * font::res + 0.5); - paperwidth = int(pw * font::res + 0.5); - } - if (papersize < 80) // standard paper - lbpprintf("\033[%dp", (papersize | orientation)); - else // Custom paper - lbpprintf("\033[%d;%d;%dp", (papersize | orientation), - paperlength, paperwidth); - // Number of copies - lbpprintf("\033[%dv\n", ncopies); - lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\"); - lbpmoveabs(0, 0); - lbpputs("\033[0t\033[2t"); - lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML - // Secondary symbol set IBMR1 - cur_symbol_set = 0; -} - -lbp_printer::~lbp_printer() -{ - lbpputs("\033P1y\033\\"); - lbpputs("\033c\033<"); -} - -void lbp_printer::begin_page(int) -{ -} - -void lbp_printer::end_page(int) -{ - if (vdminited()) - vdmflush(); - lbpputc('\f'); - cur_hpos = -1; -} - -void lbp_printer::end_of_line() -{ - cur_hpos = -1; // force absolute motion -} - -char *lbp_printer::font_name(const lbp_font *f, const int siz) -{ - static char bfont_name[255]; // The resulting font name - char type, // Italic, Roman, Bold - ori, // Normal or Rotated - *nam; // The font name without other data. - int cpi; // The font size in characters per inch - // (bitmapped fonts are monospaced). - /* Bitmap font selection is ugly in this printer, so don't expect - this function to be elegant. */ - bfont_name[0] = 0x00; - if (orientation) // Landscape - ori = 'R'; - else // Portrait - ori = 'N'; - type = f->lbpname[strlen(f->lbpname) - 1]; - nam = new char[strlen(f->lbpname) - 2]; - strncpy(nam, &(f->lbpname[1]), strlen(f->lbpname) - 2); - nam[strlen(f->lbpname) - 2] = 0x00; - // fprintf(stderr, "Bitmap font '%s' %d %c %c \n", nam, siz, type, ori); - /* Since these fonts are available only at certain sizes, - 10 and 17 cpi for courier, 12 and 17 cpi for elite, - we adjust the resulting size. */ - cpi = 17; - // Fortunately there are only two bitmapped fonts shipped with the printer. - if (!strcasecmp(nam, "courier")) { - // Courier font - if (siz >= 12) - cpi = 10; - else cpi = 17; - } - if (!strcasecmp(nam, "elite")) { - if (siz >= 10) - cpi = 12; - else cpi = 17; - } - // Now that we have all the data, let's generate the font name. - if ((type != 'B') && (type != 'I')) // Roman font - sprintf(bfont_name, "%c%s%d", ori, nam, cpi); - else - sprintf(bfont_name, "%c%s%d%c", ori, nam, cpi, type); - return bfont_name; -} - -void lbp_printer::set_char(int index, font *f, const environment *env, - int w, const char *name) -{ - int code = f->get_code(index); - unsigned char ch = code & 0xff; - unsigned short symbol_set = code >> 8; - if (f != cur_font) { - lbp_font *psf = (lbp_font *)f; - // fprintf(stderr, "Loading font %s \"%d\" \n", psf->lbpname, env->size); - if (psf->is_scalable) { - // Scalable font selection is different from bitmaped - lbpprintf("\033Pz%s.IBML\033\\\033[%d C", psf->lbpname, - (int)((env->size * font::res) / 72)); - } - else - // bitmapped font - lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf, env->size)); - lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set - cur_font = psf; - cur_symbol_set = 0; - // Update the line thickness if needed - if ((req_linethickness < 0 ) && (env->size != cur_size)) - set_line_thickness(req_linethickness,env); - cur_size = env->size; - } - if (symbol_set != cur_symbol_set) { - if (cur_symbol_set == 3) - // if current symbol set is Symbol we must restore the font - lbpprintf("\033Pz%s.IBML\033\\\033[%d C", cur_font->lbpname, - (int)((env->size * font::res) / 72)); - switch (symbol_set) { - case 0: - lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets - break; - case 1: - lbpputs("\033(d\033)' 1"); // Select wp54 symbol set - break; - case 2: - lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set - break; - case 3: - lbpprintf("\033PzSymbol.SYML\033\\\033[%d C", - (int)((env->size * font::res) / 72)); - lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font - break; - case 4: - lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set - break; - } - cur_symbol_set = symbol_set; - } - if (env->size != cur_size) { - if (!cur_font->is_scalable) - lbpprintf("\033Pz%s.IBML\033\\\n", font_name(cur_font, env->size)); - else - lbpprintf("\033[%d C", (int)((env->size * font::res) / 72)); - cur_size = env->size; - // Update the line thickness if needed - if (req_linethickness < 0 ) - set_line_thickness(req_linethickness,env); - } - if ((env->hpos != cur_hpos) || (env->vpos != cur_vpos)) { - // lbpmoveabs(env->hpos - ((5 * 300) / 16), env->vpos); - lbpmoveabs(env->hpos - 64, env->vpos - 64); - cur_vpos = env->vpos; - cur_hpos = env->hpos; - } - if ((ch & 0x7F) < 32) - lbpputs("\033[1.v"); - lbpputc(ch); - cur_hpos += w; -} - -void lbp_printer::vdmstart() -{ - FILE *f; - static int changed_origin = 0; - errno = 0; - f = tmpfile(); - // f = fopen("/tmp/gtmp","w+"); - if (f == NULL) - perror("Opening temporary file"); - vdminit(f); - if (!changed_origin) { // we should change the origin only one time - changed_origin = 1; - vdmorigin(-63, 0); - } - vdmlinewidth(line_thickness); -} - -void -lbp_printer::vdmflush() -{ - char buffer[1024]; - int bytes_read = 1; - vdmend(); - fflush(lbpoutput); - /* let's copy the vdm code to the output */ - rewind(vdmoutput); - do { - bytes_read = fread(buffer, 1, sizeof(buffer), vdmoutput); - bytes_read = fwrite(buffer, 1, bytes_read, lbpoutput); - } while (bytes_read == sizeof(buffer)); - fclose(vdmoutput); // This will also delete the file, - // since it is created by tmpfile() - vdmoutput = NULL; -} - -inline void lbp_printer::setfillmode(int mode) -{ - if (mode != fill_mode) { - if (mode != 1) - vdmsetfillmode(mode, 1, 0); - else - vdmsetfillmode(mode, 1, 1); // To get black we must use white - // inverted - fill_mode = mode; - } -} - -inline void lbp_printer::polygon(int hpos, int vpos, int np, int *p) -{ - int *points, i; - points = new int[np + 2]; - points[0] = hpos; - points[1] = vpos; - // fprintf(stderr, "Poligon (%d,%d) ", points[0], points[1]); - for (i = 0; i < np; i++) - points[i + 2] = p[i]; - // for (i = 0; i < np; i++) fprintf(stderr, " %d ", p[i]); - // fprintf(stderr, "\n"); - vdmpolygon((np /2) + 1, points); -} - -inline void lbp_printer::set_line_thickness(int size,const environment *env) -{ - if (size == 0) - line_thickness = 1; - else { - if (size < 0) - // line_thickness = - // (env->size * (font::res/72)) * (linewidth_factor/1000) - // we ought to check for overflow - line_thickness = - env->size * linewidth_factor * font::res / 72000; - else // size > 0 - line_thickness = size; - } // else from if (size == 0) - if (line_thickness < 1) - line_thickness = 1; - if (vdminited()) - vdmlinewidth(line_thickness); - req_linethickness = size; // an size requested - /* fprintf(stderr, "thickness: %d == %d, size %d, %d \n", - size, line_thickness, env->size,req_linethickness); */ - return; -}; // lbp_printer::set_line_thickness - -void lbp_printer::draw(int code, int *p, int np, const environment *env) -{ - if ((req_linethickness < 0 ) && (env->size != cur_size)) - set_line_thickness(req_linethickness,env); - - switch (code) { - case 't': - if (np == 0) - line_thickness = 1; - else { // troff gratuitously adds an extra 0 - if (np != 1 && np != 2) { - error("0 or 1 argument required for thickness"); - break; - }; - set_line_thickness(p[0],env); - }; - break; - case 'l': // Line - if (np != 2) { - error("2 arguments required for line"); - break; - } - if (!vdminited()) - vdmstart(); - vdmline(env->hpos, env->vpos, p[0], p[1]); -/* fprintf(stderr, "\nline: %d,%d - %d,%d thickness %d == %d\n", - env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0], - env->vpos -64 + p[1], env->size, line_thickness);*/ - break; - case 'R': // Rule - if (np != 2) { - error("2 arguments required for Rule"); - break; - } - if (vdminited()) { - setfillmode(fill_pattern); // Solid Rule - vdmrectangle(env->hpos, env->vpos, p[0], p[1]); - } - else { - lbpruleabs(env->hpos - 64, env->vpos -64, p[0], p[1]); - cur_vpos = p[1]; - cur_hpos = p[0]; - } - // fprintf(stderr, "\nrule: thickness %d == %d\n", - // env->size, line_thickness); - break; - case 'P': // Filled Polygon - if (!vdminited()) - vdmstart(); - setfillmode(fill_pattern); - polygon(env->hpos, env->vpos, np, p); - break; - case 'p': // Empty Polygon - if (!vdminited()) - vdmstart(); - setfillmode(0); - polygon(env->hpos, env->vpos, np, p); - break; - case 'C': // Filled Circle - if (!vdminited()) - vdmstart(); - // fprintf(stderr, "Circle (%d,%d) Fill %d\n", - // env->hpos, env->vpos, fill_pattern); - setfillmode(fill_pattern); - vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2); - break; - case 'c': // Empty Circle - if (!vdminited()) - vdmstart(); - setfillmode(0); - vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2); - break; - case 'E': // Filled Ellipse - if (!vdminited()) - vdmstart(); - setfillmode(fill_pattern); - vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0); - break; - case 'e': // Empty Ellipse - if (!vdminited()) - vdmstart(); - setfillmode(0); - vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0); - break; - case 'a': // Arc - if (!vdminited()) - vdmstart(); - setfillmode(0); - // VDM draws arcs clockwise and pic counterclockwise - // We must compensate for that, exchanging the starting and - // ending points - vdmvarc(env->hpos + p[0], env->vpos+p[1], - int(sqrt(double((p[0]*p[0]) + (p[1]*p[1])))), - p[2], p[3], - (-p[0]), (-p[1]), 1, 2); - break; - case '~': // Spline - if (!vdminited()) - vdmstart(); - setfillmode(0); - vdmspline(np/2, env->hpos, env->vpos, p); - break; - case 'f': - if (np != 1 && np != 2) { - error("1 argument required for fill"); - break; - } - // fprintf(stderr, "Fill %d\n", p[0]); - if ((p[0] == 1) || (p[0] >= 1000)) { // Black - fill_pattern = 1; - break; - } - if (p[0] == 0) { // White - fill_pattern = 0; - break; - } - if ((p[0] > 1) && (p[0] < 1000)) - { - if (p[0] >= 990) fill_pattern = -23; - else if (p[0] >= 700) fill_pattern = -28; - else if (p[0] >= 500) fill_pattern = -27; - else if (p[0] >= 400) fill_pattern = -26; - else if (p[0] >= 300) fill_pattern = -25; - else if (p[0] >= 200) fill_pattern = -22; - else if (p[0] >= 100) fill_pattern = -24; - else fill_pattern = -21; - } - break; - case 'F': - // not implemented yet - break; - default: - error("unrecognised drawing command `%1'", char(code)); - break; - } - return; -} - -font *lbp_printer::make_font(const char *nm) -{ - return lbp_font::load_lbp_font(nm); -} - -printer *make_printer() -{ - return new lbp_printer(user_papersize, user_paperwidth, user_paperlength); -} - -static struct { - const char *name; - int code; -} lbp_papersizes[] = - {{ "A4", 14 }, - { "letter", 30 }, - { "legal", 32 }, - { "executive", 40 }, - }; - -static int set_papersize(const char *paperformat) -{ - unsigned int i; - // First test for a standard (i.e. supported directly by the printer) - // paper size - for (i = 0 ; i < sizeof(lbp_papersizes) / sizeof(lbp_papersizes[0]); i++) - { - if (strcasecmp(lbp_papersizes[i].name,paperformat) == 0) - return lbp_papersizes[i].code; - } - // Otherwise, we assume a custom paper size - return 82; -} - -static void handle_unknown_desc_command(const char *command, const char *arg, - const char *filename, int lineno) -{ - // orientation command - if (strcasecmp(command, "orientation") == 0) { - // We give priority to command line options - if (orientation > 0) - return; - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`orientation' command requires an argument"); - else { - if (strcasecmp(arg, "portrait") == 0) - orientation = 0; - else { - if (strcasecmp(arg, "landscape") == 0) - orientation = 1; - else - error_with_file_and_line(filename, lineno, - "invalid argument to `orientation' command"); - } - } - } -} - -static struct option long_options[] = { - { "orientation", required_argument, NULL, 'o' }, - { "version", no_argument, NULL, 'v' }, - { "copies", required_argument, NULL, 'c' }, - { "landscape", no_argument, NULL, 'l' }, - { "papersize", required_argument, NULL, 'p' }, - { "linewidth", required_argument, NULL, 'w' }, - { "fontdir", required_argument, NULL, 'F' }, - { "help", no_argument, NULL, 'h' }, - { NULL, 0, 0, 0 } -}; - -static void usage(FILE *stream) -{ - fprintf(stream, - "usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or]\n" - " [-w width] [files ...]\n" - "\n" - " -o --orientation=[portrait|landscape]\n" - " -v --version\n" - " -c --copies=numcopies\n" - " -l --landscape\n" - " -p --papersize=paper_size\n" - " -w --linewidth=width\n" - " -F --fontdir=dir\n" - " -h --help\n", - program_name); -} - -int main(int argc, char **argv) -{ - if (program_name == NULL) - program_name = strsave(argv[0]); - font::set_unknown_desc_command_handler(handle_unknown_desc_command); - // command line parsing - int c = 0; - int option_index = 0; - while (c >= 0) { - c = getopt_long (argc, argv, "F:p:lvo:c:hw:", - long_options, &option_index); - switch (c) { - case 'F': - font::command_line_font_dir(optarg); - break; - case 'p': - { - const char *s; - if (!font::scan_papersize(optarg, &s, - &user_paperlength, &user_paperwidth)) - error("invalid paper size `%1' ignored", optarg); - else - user_papersize = set_papersize(s); - break; - } - case 'l': - orientation = 1; - break; - case 'v': - printf("GNU grolbp (groff) version %s\n", Version_string); - exit(0); - break; - case 'o': - if (strcasecmp(optarg, "portrait") == 0) - orientation = 0; - else { - if (strcasecmp(optarg, "landscape") == 0) - orientation = 1; - else - error("unknown orientation '%1'", optarg); - }; - break; - case 'c': - { - char *ptr; - long n = strtol(optarg, &ptr, 10); - if ((n <= 0) && (ptr == optarg)) - error("argument for -c must be a positive integer"); - else if (n <= 0 || n > 32767) - error("out of range argument for -c"); - else - ncopies = unsigned(n); - break; - } - case 'w': - { - char *ptr; - long n = strtol(optarg, &ptr, 10); - if (n == 0 && ptr == optarg) - error("argument for -w must be a non-negative integer"); - else if (n < 0 || n > INT_MAX) - error("out of range argument for -w"); - else - linewidth_factor = int(n); - break; - } - case 'h': - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - } - } - if (optind >= argc) - do_file("-"); - while (optind < argc) - do_file(argv[optind++]); - lbpputs("\033c\033<"); - delete pr; - return 0; -} diff --git a/contrib/groff/src/devices/grolj4/lj4.cc b/contrib/groff/src/devices/grolj4/lj4.cc deleted file mode 100644 index 0c3150d..0000000 --- a/contrib/groff/src/devices/grolj4/lj4.cc +++ /dev/null @@ -1,708 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1994, 2000, 2001, 2002 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. */ - -/* -TODO - -option to use beziers for circle/ellipse/arc -option to use lines for spline (for LJ3) -left/top offset registration -output bin selection option -paper source option -output non-integer parameters using fixed point numbers -X command to insert contents of file -X command to specify inline escape sequence (how to specify unprintable chars?) -X command to include bitmap graphics -*/ - -#include "driver.h" -#include "nonposix.h" - -extern "C" const char *Version_string; - -static struct { - const char *name; - int code; - // at 300dpi - int x_offset_portrait; - int x_offset_landscape; -} paper_table[] = { - { "letter", 2, 75, 60 }, - { "legal", 3, 75, 60 }, - { "executive", 1, 75, 60 }, - { "a4", 26, 71, 59 }, - { "com10", 81, 75, 60 }, - { "monarch", 80, 75, 60 }, - { "c5", 91, 71, 59 }, - { "b5", 100, 71, 59 }, - { "dl", 90, 71, 59 }, -}; - -static int user_paper_size = -1; -static int landscape_flag = 0; -static int duplex_flag = 0; - -// An upper limit on the paper size in centipoints, -// used for setting HPGL picture frame. -#define MAX_PAPER_WIDTH (12*720) -#define MAX_PAPER_HEIGHT (17*720) - -// Dotted lines that are thinner than this don't work right. -#define MIN_DOT_PEN_WIDTH .351 - -#ifndef DEFAULT_LINE_WIDTH_FACTOR -// in ems/1000 -#define DEFAULT_LINE_WIDTH_FACTOR 40 -#endif - -const int DEFAULT_HPGL_UNITS = 1016; -int line_width_factor = DEFAULT_LINE_WIDTH_FACTOR; -unsigned ncopies = 0; // 0 means don't send ncopies command - -static int lookup_paper_size(const char *); - -class lj4_font : public font { -public: - ~lj4_font(); - void handle_unknown_font_command(const char *command, const char *arg, - const char *filename, int lineno); - static lj4_font *load_lj4_font(const char *); - int weight; - int style; - int proportional; - int typeface; -private: - lj4_font(const char *); -}; - -lj4_font::lj4_font(const char *nm) -: font(nm), weight(0), style(0), proportional(0), typeface(0) -{ -} - -lj4_font::~lj4_font() -{ -} - -lj4_font *lj4_font::load_lj4_font(const char *s) -{ - lj4_font *f = new lj4_font(s); - if (!f->load()) { - delete f; - return 0; - } - return f; -} - -static struct { - const char *s; - int lj4_font::*ptr; - int min; - int max; -} command_table[] = { - { "pclweight", &lj4_font::weight, -7, 7 }, - { "pclstyle", &lj4_font::style, 0, 32767 }, - { "pclproportional", &lj4_font::proportional, 0, 1 }, - { "pcltypeface", &lj4_font::typeface, 0, 65535 }, -}; - -void lj4_font::handle_unknown_font_command(const char *command, - const char *arg, - const char *filename, int lineno) -{ - for (unsigned int i = 0; - i < sizeof(command_table)/sizeof(command_table[0]); i++) { - if (strcmp(command, command_table[i].s) == 0) { - if (arg == 0) - fatal_with_file_and_line(filename, lineno, - "`%1' command requires an argument", - command); - char *ptr; - long n = strtol(arg, &ptr, 10); - if (n == 0 && ptr == arg) - fatal_with_file_and_line(filename, lineno, - "`%1' command requires numeric argument", - command); - if (n < command_table[i].min) { - error_with_file_and_line(filename, lineno, - "argument for `%1' command must not be less than %2", - command, command_table[i].min); - n = command_table[i].min; - } - else if (n > command_table[i].max) { - error_with_file_and_line(filename, lineno, - "argument for `%1' command must not be greater than %2", - command, command_table[i].max); - n = command_table[i].max; - } - this->*command_table[i].ptr = int(n); - break; - } - } -} - -class lj4_printer : public printer { -public: - lj4_printer(int); - ~lj4_printer(); - void set_char(int, font *, const environment *, int, const char *name); - void draw(int code, int *p, int np, const environment *env); - void begin_page(int); - void end_page(int page_length); - font *make_font(const char *); - void end_of_line(); -private: - void set_line_thickness(int size, int dot = 0); - void hpgl_init(); - void hpgl_start(); - void hpgl_end(); - int moveto(int hpos, int vpos); - int moveto1(int hpos, int vpos); - - int cur_hpos; - int cur_vpos; - lj4_font *cur_font; - int cur_size; - unsigned short cur_symbol_set; - int x_offset; - int line_thickness; - double pen_width; - double hpgl_scale; - int hpgl_inited; - int paper_size; -}; - -inline -int lj4_printer::moveto(int hpos, int vpos) -{ - if (cur_hpos != hpos || cur_vpos != vpos || cur_hpos < 0) - return moveto1(hpos, vpos); - else - return 1; -} - -inline -void lj4_printer::hpgl_start() -{ - fputs("\033%1B", stdout); -} - -inline -void lj4_printer::hpgl_end() -{ - fputs(";\033%0A", stdout); -} - -lj4_printer::lj4_printer(int ps) -: cur_hpos(-1), - cur_font(0), - cur_size(0), - cur_symbol_set(0), - line_thickness(-1), - pen_width(-1.0), - hpgl_inited(0) -{ - if (7200 % font::res != 0) - fatal("invalid resolution %1: resolution must be a factor of 7200", - font::res); - fputs("\033E", stdout); // reset - if (font::res != 300) - printf("\033&u%dD", font::res); // unit of measure - if (ncopies > 0) - printf("\033&l%uX", ncopies); - paper_size = 0; // default to letter - if (font::papersize) { - int n = lookup_paper_size(font::papersize); - if (n < 0) - error("unknown paper size `%1'", font::papersize); - else - paper_size = n; - } - if (ps >= 0) - paper_size = ps; - printf("\033&l%dA" // paper size - "\033&l%dO" // orientation - "\033&l0E", // no top margin - paper_table[paper_size].code, - landscape_flag != 0); - if (landscape_flag) - x_offset = paper_table[paper_size].x_offset_landscape; - else - x_offset = paper_table[paper_size].x_offset_portrait; - x_offset = (x_offset * font::res) / 300; - if (duplex_flag) - printf("\033&l%dS", duplex_flag); -} - -lj4_printer::~lj4_printer() -{ - fputs("\033E", stdout); -} - -void lj4_printer::begin_page(int) -{ -} - -void lj4_printer::end_page(int) -{ - putchar('\f'); - cur_hpos = -1; -} - -void lj4_printer::end_of_line() -{ - cur_hpos = -1; // force absolute motion -} - -inline -int is_unprintable(unsigned char c) -{ - return c < 32 && (c == 0 || (7 <= c && c <= 15) || c == 27); -} - -void lj4_printer::set_char(int index, font *f, const environment *env, - int w, const char *name) -{ - int code = f->get_code(index); - - unsigned char ch = code & 0xff; - unsigned short symbol_set = code >> 8; - if (symbol_set != cur_symbol_set) { - printf("\033(%d%c", symbol_set/32, (symbol_set & 31) + 64); - cur_symbol_set = symbol_set; - } - if (f != cur_font) { - lj4_font *psf = (lj4_font *)f; - // FIXME only output those that are needed - printf("\033(s%dp%ds%db%dT", - psf->proportional, - psf->style, - psf->weight, - psf->typeface); - if (!psf->proportional || !cur_font || !cur_font->proportional) - cur_size = 0; - cur_font = psf; - } - if (env->size != cur_size) { - if (cur_font->proportional) { - static const char *quarters[] = { "", ".25", ".5", ".75" }; - printf("\033(s%d%sV", env->size/4, quarters[env->size & 3]); - } - else { - double pitch = double(font::res)/w; - // PCL uses the next largest pitch, so round it down. - pitch = floor(pitch*100.0)/100.0; - printf("\033(s%.2fH", pitch); - } - cur_size = env->size; - } - if (!moveto(env->hpos, env->vpos)) - return; - if (is_unprintable(ch)) - fputs("\033&p1X", stdout); - putchar(ch); - cur_hpos += w; -} - -int lj4_printer::moveto1(int hpos, int vpos) -{ - if (hpos < x_offset || vpos < 0) - return 0; - fputs("\033*p", stdout); - if (cur_hpos < 0) - printf("%dx%dY", hpos - x_offset, vpos); - else { - if (cur_hpos != hpos) - printf("%s%d%c", hpos > cur_hpos ? "+" : "", - hpos - cur_hpos, vpos == cur_vpos ? 'X' : 'x'); - if (cur_vpos != vpos) - printf("%s%dY", vpos > cur_vpos ? "+" : "", vpos - cur_vpos); - } - cur_hpos = hpos; - cur_vpos = vpos; - return 1; -} - -void lj4_printer::draw(int code, int *p, int np, const environment *env) -{ - switch (code) { - case 'R': - { - if (np != 2) { - error("2 arguments required for rule"); - break; - } - int hpos = env->hpos; - int vpos = env->vpos; - int hsize = p[0]; - int vsize = p[1]; - if (hsize < 0) { - hpos += hsize; - hsize = -hsize; - } - if (vsize < 0) { - vpos += vsize; - vsize = -vsize; - } - if (!moveto(hpos, vpos)) - return; - printf("\033*c%da%db0P", hsize, vsize); - break; - } - case 'l': - if (np != 2) { - error("2 arguments required for line"); - break; - } - hpgl_init(); - if (!moveto(env->hpos, env->vpos)) - return; - hpgl_start(); - set_line_thickness(env->size, p[0] == 0 && p[1] == 0); - printf("PD%d,%d", p[0], p[1]); - hpgl_end(); - break; - case 'p': - case 'P': - { - if (np & 1) { - error("even number of arguments required for polygon"); - break; - } - if (np == 0) { - error("no arguments for polygon"); - break; - } - hpgl_init(); - if (!moveto(env->hpos, env->vpos)) - return; - hpgl_start(); - if (code == 'p') - set_line_thickness(env->size); - printf("PMPD%d", p[0]); - for (int i = 1; i < np; i++) - printf(",%d", p[i]); - printf("PM2%cP", code == 'p' ? 'E' : 'F'); - hpgl_end(); - break; - } - case '~': - { - if (np & 1) { - error("even number of arguments required for spline"); - break; - } - if (np == 0) { - error("no arguments for spline"); - break; - } - hpgl_init(); - if (!moveto(env->hpos, env->vpos)) - return; - hpgl_start(); - set_line_thickness(env->size); - printf("PD%d,%d", p[0]/2, p[1]/2); - const int tnum = 2; - const int tden = 3; - if (np > 2) { - fputs("BR", stdout); - for (int i = 0; i < np - 2; i += 2) { - if (i != 0) - putchar(','); - printf("%d,%d,%d,%d,%d,%d", - (p[i]*tnum)/(2*tden), - (p[i + 1]*tnum)/(2*tden), - p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden), - p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden), - (p[i] - p[i]/2) + p[i + 2]/2, - (p[i + 1] - p[i + 1]/2) + p[i + 3]/2); - } - } - printf("PR%d,%d", p[np - 2] - p[np - 2]/2, p[np - 1] - p[np - 1]/2); - hpgl_end(); - break; - } - case 'c': - case 'C': - // troff adds an extra argument to C - if (np != 1 && !(code == 'C' && np == 2)) { - error("1 argument required for circle"); - break; - } - hpgl_init(); - if (!moveto(env->hpos + p[0]/2, env->vpos)) - return; - hpgl_start(); - if (code == 'c') { - set_line_thickness(env->size); - printf("CI%d", p[0]/2); - } - else - printf("WG%d,0,360", p[0]/2); - hpgl_end(); - break; - case 'e': - case 'E': - if (np != 2) { - error("2 arguments required for ellipse"); - break; - } - hpgl_init(); - if (!moveto(env->hpos + p[0]/2, env->vpos)) - return; - hpgl_start(); - printf("SC0,%.4f,0,-%.4f,2", hpgl_scale * double(p[0])/p[1], hpgl_scale); - if (code == 'e') { - set_line_thickness(env->size); - printf("CI%d", p[1]/2); - } - else - printf("WG%d,0,360", p[1]/2); - printf("SC0,%.4f,0,-%.4f,2", hpgl_scale, hpgl_scale); - hpgl_end(); - break; - case 'a': - { - if (np != 4) { - error("4 arguments required for arc"); - break; - } - hpgl_init(); - if (!moveto(env->hpos, env->vpos)) - return; - hpgl_start(); - set_line_thickness(env->size); - double c[2]; - if (adjust_arc_center(p, c)) { - double sweep = ((atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]) - - atan2(-c[1], -c[0])) - * 180.0/PI); - if (sweep > 0.0) - sweep -= 360.0; - printf("PDAR%d,%d,%f", int(c[0]), int(c[1]), sweep); - } - else - printf("PD%d,%d", p[0] + p[2], p[1] + p[3]); - hpgl_end(); - } - break; - case 'f': - if (np != 1 && np != 2) { - error("1 argument required for fill"); - break; - } - hpgl_init(); - hpgl_start(); - if (p[0] >= 0 && p[0] <= 1000) - printf("FT10,%d", p[0]/10); - hpgl_end(); - break; - case 'F': - // not implemented yet - break; - case 't': - { - if (np == 0) { - line_thickness = -1; - } - else { - // troff gratuitously adds an extra 0 - if (np != 1 && np != 2) { - error("0 or 1 argument required for thickness"); - break; - } - line_thickness = p[0]; - } - break; - } - default: - error("unrecognised drawing command `%1'", char(code)); - break; - } -} - -void lj4_printer::hpgl_init() -{ - if (hpgl_inited) - return; - hpgl_inited = 1; - hpgl_scale = double(DEFAULT_HPGL_UNITS)/font::res; - printf("\033&f0S" // push position - "\033*p0x0Y" // move to 0,0 - "\033*c%dx%dy0T" // establish picture frame - "\033%%1B" // switch to HPGL - "SP1SC0,%.4f,0,-%.4f,2IR0,100,0,100" // set up scaling - "LA1,4,2,4" // round line ends and joins - "PR" // relative plotting - "TR0" // opaque - ";\033%%1A" // back to PCL - "\033&f1S", // pop position - MAX_PAPER_WIDTH, MAX_PAPER_HEIGHT, - hpgl_scale, hpgl_scale); -} - -void lj4_printer::set_line_thickness(int size, int dot) -{ - double pw; - if (line_thickness < 0) - pw = (size * (line_width_factor * 25.4))/(font::sizescale * 72000.0); - else - pw = line_thickness*25.4/font::res; - if (dot && pw < MIN_DOT_PEN_WIDTH) - pw = MIN_DOT_PEN_WIDTH; - if (pw != pen_width) { - printf("PW%f", pw); - pen_width = pw; - } -} - -font *lj4_printer::make_font(const char *nm) -{ - return lj4_font::load_lj4_font(nm); -} - -printer *make_printer() -{ - return new lj4_printer(user_paper_size); -} - -static -int lookup_paper_size(const char *s) -{ - for (unsigned int i = 0; - i < sizeof(paper_table)/sizeof(paper_table[0]); i++) { - // FIXME Perhaps allow unique prefix. - if (strcasecmp(s, paper_table[i].name) == 0) - return i; - } - return -1; -} - -static void usage(FILE *stream); - -extern "C" int optopt, optind; - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int c; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((c = getopt_long(argc, argv, ":F:p:d:lvw:c:", long_options, NULL)) - != EOF) - switch(c) { - case 'l': - landscape_flag = 1; - break; - case ':': - if (optopt == 'd') { - fprintf(stderr, "duplex assumed to be long-side\n"); - duplex_flag = 1; - } else - fprintf(stderr, "option -%c requires an operand\n", optopt); - fflush(stderr); - break; - case 'd': - if (!isdigit(*optarg)) // this ugly hack prevents -d without - optind--; // args from messing up the arg list - duplex_flag = atoi(optarg); - if (duplex_flag != 1 && duplex_flag != 2) { - fprintf(stderr, "odd value for duplex; assumed to be long-side\n"); - duplex_flag = 1; - } - break; - case 'p': - { - int n = lookup_paper_size(optarg); - if (n < 0) - error("unknown paper size `%1'", optarg); - else - user_paper_size = n; - break; - } - case 'v': - { - printf("GNU grolj4 (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'F': - font::command_line_font_dir(optarg); - break; - case 'c': - { - char *ptr; - long n = strtol(optarg, &ptr, 10); - if (n == 0 && ptr == optarg) - error("argument for -c must be a positive integer"); - else if (n <= 0 || n > 32767) - error("out of range argument for -c"); - else - ncopies = unsigned(n); - break; - } - case 'w': - { - char *ptr; - long n = strtol(optarg, &ptr, 10); - if (n == 0 && ptr == optarg) - error("argument for -w must be a non-negative integer"); - else if (n < 0 || n > INT_MAX) - error("out of range argument for -w"); - else - line_width_factor = int(n); - break; - } - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } -#ifdef SET_BINARY - SET_BINARY(fileno(stdout)); -#endif - if (optind >= argc) - do_file("-"); - else { - for (int i = optind; i < argc; i++) - do_file(argv[i]); - } - delete pr; - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, - "usage: %s [-lv] [-d [n]] [-c n] [-p paper_size]\n" - " [-w n] [-F dir] [files ...]\n", - program_name); -} diff --git a/contrib/groff/src/devices/grops/ps.cc b/contrib/groff/src/devices/grops/ps.cc deleted file mode 100644 index 47d1f65..0000000 --- a/contrib/groff/src/devices/grops/ps.cc +++ /dev/null @@ -1,1642 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "stringclass.h" -#include "cset.h" -#include "nonposix.h" -#include "paper.h" - -#include "ps.h" -#include - -#ifdef NEED_DECLARATION_PUTENV -extern "C" { - int putenv(const char *); -} -#endif /* NEED_DECLARATION_PUTENV */ - -extern "C" const char *Version_string; - -static int landscape_flag = 0; -static int manual_feed_flag = 0; -static int ncopies = 1; -static int linewidth = -1; -// Non-zero means generate PostScript code that guesses the paper -// length using the imageable area. -static int guess_flag = 0; -static double user_paper_length = 0; - -// Non-zero if -b was specified on the command line. -static int bflag = 0; -unsigned broken_flags = 0; - -#define DEFAULT_LINEWIDTH 40 /* in ems/1000 */ -#define MAX_LINE_LENGTH 72 -#define FILL_MAX 1000 - -const char *const dict_name = "grops"; -const char *const defs_dict_name = "DEFS"; -const int DEFS_DICT_SPARE = 50; - -double degrees(double r) -{ - return r*180.0/PI; -} - -double radians(double d) -{ - return d*PI/180.0; -} - -inline double transform_fill(int fill) -{ - return 1 - fill/double(FILL_MAX); -} - -// This is used for testing whether a character should be output in the -// PostScript file using \nnn, so we really want the character to be -// less than 0200. - -inline int is_ascii(char c) -{ - return (unsigned char)c < 0200; -} - -ps_output::ps_output(FILE *f, int n) -: fp(f), col(0), max_line_length(n), need_space(0), fixed_point(0) -{ -} - -ps_output &ps_output::set_file(FILE *f) -{ - fp = f; - col = 0; - return *this; -} - -ps_output &ps_output::copy_file(FILE *infp) -{ - int c; - while ((c = getc(infp)) != EOF) - putc(c, fp); - return *this; -} - -ps_output &ps_output::end_line() -{ - if (col != 0) { - putc('\n', fp); - col = 0; - need_space = 0; - } - return *this; -} - -ps_output &ps_output::special(const char *s) -{ - if (s == 0 || *s == '\0') - return *this; - if (col != 0) { - putc('\n', fp); - col = 0; - } - fputs(s, fp); - if (strchr(s, '\0')[-1] != '\n') - putc('\n', fp); - need_space = 0; - return *this; -} - -ps_output &ps_output::simple_comment(const char *s) -{ - if (col != 0) - putc('\n', fp); - putc('%', fp); - putc('%', fp); - fputs(s, fp); - putc('\n', fp); - col = 0; - need_space = 0; - return *this; -} - -ps_output &ps_output::begin_comment(const char *s) -{ - if (col != 0) - putc('\n', fp); - putc('%', fp); - putc('%', fp); - fputs(s, fp); - col = 2 + strlen(s); - return *this; -} - -ps_output &ps_output::end_comment() -{ - if (col != 0) { - putc('\n', fp); - col = 0; - } - need_space = 0; - return *this; -} - -ps_output &ps_output::comment_arg(const char *s) -{ - int len = strlen(s); - if (col + len + 1 > max_line_length) { - putc('\n', fp); - fputs("%%+", fp); - col = 3; - } - putc(' ', fp); - fputs(s, fp); - col += len + 1; - return *this; -} - -ps_output &ps_output::set_fixed_point(int n) -{ - assert(n >= 0 && n <= 10); - fixed_point = n; - return *this; -} - -ps_output &ps_output::put_delimiter(char c) -{ - if (col + 1 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc(c, fp); - col++; - need_space = 0; - return *this; -} - -ps_output &ps_output::put_string(const char *s, int n) -{ - int len = 0; - int i; - for (i = 0; i < n; i++) { - char c = s[i]; - if (is_ascii(c) && csprint(c)) { - if (c == '(' || c == ')' || c == '\\') - len += 2; - else - len += 1; - } - else - len += 4; - } - if (len > n*2) { - if (col + n*2 + 2 > max_line_length && n*2 + 2 <= max_line_length) { - putc('\n', fp); - col = 0; - } - if (col + 1 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc('<', fp); - col++; - for (i = 0; i < n; i++) { - if (col + 2 > max_line_length) { - putc('\n', fp); - col = 0; - } - fprintf(fp, "%02x", s[i] & 0377); - col += 2; - } - putc('>', fp); - col++; - } - else { - if (col + len + 2 > max_line_length && len + 2 <= max_line_length) { - putc('\n', fp); - col = 0; - } - if (col + 2 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc('(', fp); - col++; - for (i = 0; i < n; i++) { - char c = s[i]; - if (is_ascii(c) && csprint(c)) { - if (c == '(' || c == ')' || c == '\\') - len = 2; - else - len = 1; - } - else - len = 4; - if (col + len + 1 > max_line_length) { - putc('\\', fp); - putc('\n', fp); - col = 0; - } - switch (len) { - case 1: - putc(c, fp); - break; - case 2: - putc('\\', fp); - putc(c, fp); - break; - case 4: - fprintf(fp, "\\%03o", c & 0377); - break; - default: - assert(0); - } - col += len; - } - putc(')', fp); - col++; - } - need_space = 0; - return *this; -} - -ps_output &ps_output::put_number(int n) -{ - char buf[1 + INT_DIGITS + 1]; - sprintf(buf, "%d", n); - int len = strlen(buf); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(buf, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_fix_number(int i) -{ - const char *p = if_to_a(i, fixed_point); - int len = strlen(p); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(p, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_float(double d) -{ - char buf[128]; - sprintf(buf, "%.3g", d); - int len = strlen(buf); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(buf, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_symbol(const char *s) -{ - int len = strlen(s); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(s, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_color(unsigned int c) -{ - char buf[128]; - sprintf(buf, "%.3g", double(c) / color::MAX_COLOR_VAL); - int len = strlen(buf); - if (col > 0 && col + len + need_space > max_line_length) { - putc('\n', fp); - col = 0; - need_space = 0; - } - if (need_space) { - putc(' ', fp); - col++; - } - fputs(buf, fp); - col += len; - need_space = 1; - return *this; -} - -ps_output &ps_output::put_literal_symbol(const char *s) -{ - int len = strlen(s); - if (col > 0 && col + len + 1 > max_line_length) { - putc('\n', fp); - col = 0; - } - putc('/', fp); - fputs(s, fp); - col += len + 1; - need_space = 1; - return *this; -} - -class ps_font : public font { - ps_font(const char *); -public: - int encoding_index; - char *encoding; - char *reencoded_name; - ~ps_font(); - void handle_unknown_font_command(const char *command, const char *arg, - const char *filename, int lineno); - static ps_font *load_ps_font(const char *); -}; - -ps_font *ps_font::load_ps_font(const char *s) -{ - ps_font *f = new ps_font(s); - if (!f->load()) { - delete f; - return 0; - } - return f; -} - -ps_font::ps_font(const char *nm) -: font(nm), encoding_index(-1), encoding(0), reencoded_name(0) -{ -} - -ps_font::~ps_font() -{ - a_delete encoding; - a_delete reencoded_name; -} - -void ps_font::handle_unknown_font_command(const char *command, const char *arg, - const char *filename, int lineno) -{ - if (strcmp(command, "encoding") == 0) { - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`encoding' command requires an argument"); - else - encoding = strsave(arg); - } -} - -static void handle_unknown_desc_command(const char *command, const char *arg, - const char *filename, int lineno) -{ - if (strcmp(command, "broken") == 0) { - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`broken' command requires an argument"); - else if (!bflag) - broken_flags = atoi(arg); - } -} - -struct style { - font *f; - int point_size; - int height; - int slant; - style(); - style(font *, int, int, int); - int operator==(const style &) const; - int operator!=(const style &) const; -}; - -style::style() : f(0) -{ -} - -style::style(font *p, int sz, int h, int sl) -: f(p), point_size(sz), height(h), slant(sl) -{ -} - -int style::operator==(const style &s) const -{ - return (f == s.f && point_size == s.point_size - && height == s.height && slant == s.slant); -} - -int style::operator!=(const style &s) const -{ - return !(*this == s); -} - -class ps_printer : public printer { - FILE *tempfp; - ps_output out; - int res; - int space_char_index; - int pages_output; - int paper_length; - int equalise_spaces; - enum { SBUF_SIZE = 256 }; - char sbuf[SBUF_SIZE]; - int sbuf_len; - int sbuf_start_hpos; - int sbuf_vpos; - int sbuf_end_hpos; - int sbuf_space_width; - int sbuf_space_count; - int sbuf_space_diff_count; - int sbuf_space_code; - int sbuf_kern; - style sbuf_style; - color sbuf_color; // the current PS color - style output_style; - int output_hpos; - int output_vpos; - int output_draw_point_size; - int line_thickness; - int output_line_thickness; - unsigned char output_space_code; - enum { MAX_DEFINED_STYLES = 50 }; - style defined_styles[MAX_DEFINED_STYLES]; - int ndefined_styles; - int next_encoding_index; - string defs; - int ndefs; - resource_manager rm; - int invis_count; - - void flush_sbuf(); - void set_style(const style &); - void set_space_code(unsigned char c); - int set_encoding_index(ps_font *); - void do_exec(char *, const environment *); - void do_import(char *, const environment *); - void do_def(char *, const environment *); - void do_mdef(char *, const environment *); - void do_file(char *, const environment *); - void do_invis(char *, const environment *); - void do_endinvis(char *, const environment *); - void set_line_thickness_and_color(const environment *); - void fill_path(const environment *); - void encode_fonts(); - void define_encoding(const char *, int); - void reencode_font(ps_font *); - void set_color(color *c, int fill = 0); - -public: - ps_printer(double); - ~ps_printer(); - void set_char(int i, font *f, const environment *env, int w, const char *name); - void draw(int code, int *p, int np, const environment *env); - void begin_page(int); - void end_page(int); - void special(char *arg, const environment *env, char type); - font *make_font(const char *); - void end_of_line(); -}; - -// `pl' is in inches -ps_printer::ps_printer(double pl) -: out(0, MAX_LINE_LENGTH), - pages_output(0), - sbuf_len(0), - output_hpos(-1), - output_vpos(-1), - line_thickness(-1), - ndefined_styles(0), - next_encoding_index(0), - ndefs(0), - invis_count(0) -{ - tempfp = xtmpfile(); - out.set_file(tempfp); - if (linewidth < 0) - linewidth = DEFAULT_LINEWIDTH; - if (font::hor != 1) - fatal("horizontal resolution must be 1"); - if (font::vert != 1) - fatal("vertical resolution must be 1"); - if (font::res % (font::sizescale*72) != 0) - fatal("res must be a multiple of 72*sizescale"); - int r = font::res; - int point = 0; - while (r % 10 == 0) { - r /= 10; - point++; - } - res = r; - out.set_fixed_point(point); - space_char_index = font::name_to_index("space"); - if (pl == 0) - paper_length = font::paperlength; - else - paper_length = int(pl * font::res + 0.5); - if (paper_length == 0) - paper_length = 11 * font::res; - equalise_spaces = font::res >= 72000; -} - -int ps_printer::set_encoding_index(ps_font *f) -{ - if (f->encoding_index >= 0) - return f->encoding_index; - for (font_pointer_list *p = font_list; p; p = p->next) - if (p->p != f) { - char *encoding = ((ps_font *)p->p)->encoding; - int encoding_index = ((ps_font *)p->p)->encoding_index; - if (encoding != 0 && encoding_index >= 0 - && strcmp(f->encoding, encoding) == 0) { - return f->encoding_index = encoding_index; - } - } - return f->encoding_index = next_encoding_index++; -} - -void ps_printer::set_char(int i, font *f, const environment *env, int w, const char *name) -{ - if (i == space_char_index || invis_count > 0) - return; - unsigned char code = f->get_code(i); - style sty(f, env->size, env->height, env->slant); - if (sty.slant != 0) { - if (sty.slant > 80 || sty.slant < -80) { - error("silly slant `%1' degrees", sty.slant); - sty.slant = 0; - } - } - if (sbuf_len > 0) { - if (sbuf_len < SBUF_SIZE - && sty == sbuf_style - && sbuf_vpos == env->vpos - && sbuf_color == *env->col) { - if (sbuf_end_hpos == env->hpos) { - sbuf[sbuf_len++] = code; - sbuf_end_hpos += w + sbuf_kern; - return; - } - if (sbuf_len == 1 && sbuf_kern == 0) { - sbuf_kern = env->hpos - sbuf_end_hpos; - sbuf_end_hpos = env->hpos + sbuf_kern + w; - sbuf[sbuf_len++] = code; - return; - } - /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off - starting a new string. */ - if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos - && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) { - if (sbuf_space_code < 0) { - if (f->contains(space_char_index)) { - sbuf_space_code = f->get_code(space_char_index); - sbuf_space_width = env->hpos - sbuf_end_hpos; - sbuf_end_hpos = env->hpos + w + sbuf_kern; - sbuf[sbuf_len++] = sbuf_space_code; - sbuf[sbuf_len++] = code; - sbuf_space_count++; - return; - } - } - else { - int diff = env->hpos - sbuf_end_hpos - sbuf_space_width; - if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) { - sbuf_end_hpos = env->hpos + w + sbuf_kern; - sbuf[sbuf_len++] = sbuf_space_code; - sbuf[sbuf_len++] = code; - sbuf_space_count++; - if (diff == 1) - sbuf_space_diff_count++; - else if (diff == -1) - sbuf_space_diff_count--; - return; - } - } - } - } - flush_sbuf(); - } - sbuf_len = 1; - sbuf[0] = code; - sbuf_end_hpos = env->hpos + w; - sbuf_start_hpos = env->hpos; - sbuf_vpos = env->vpos; - sbuf_style = sty; - sbuf_space_code = -1; - sbuf_space_width = 0; - sbuf_space_count = sbuf_space_diff_count = 0; - sbuf_kern = 0; - if (sbuf_color != *env->col) - set_color(env->col); -} - -static char *make_encoding_name(int encoding_index) -{ - static char buf[3 + INT_DIGITS + 1]; - sprintf(buf, "ENC%d", encoding_index); - return buf; -} - -const char *const WS = " \t\n\r"; - -void ps_printer::define_encoding(const char *encoding, int encoding_index) -{ - char *vec[256]; - int i; - for (i = 0; i < 256; i++) - vec[i] = 0; - char *path; - FILE *fp = font::open_file(encoding, &path); - if (fp == 0) - fatal("can't open encoding file `%1'", encoding); - int lineno = 1; - char buf[256]; - while (fgets(buf, 512, fp) != 0) { - char *p = buf; - while (csspace(*p)) - p++; - if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) { - char *q = strtok(0, WS); - int n; - if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256) - fatal_with_file_and_line(path, lineno, "bad second field"); - vec[n] = new char[strlen(p) + 1]; - strcpy(vec[n], p); - } - lineno++; - } - a_delete path; - out.put_literal_symbol(make_encoding_name(encoding_index)); - out.put_delimiter('['); - for (i = 0; i < 256; i++) { - if (vec[i] == 0) - out.put_literal_symbol(".notdef"); - else { - out.put_literal_symbol(vec[i]); - a_delete vec[i]; - } - } - out.put_delimiter(']') - .put_symbol("def"); -} - -void ps_printer::reencode_font(ps_font *f) -{ - out.put_literal_symbol(f->reencoded_name) - .put_symbol(make_encoding_name(f->encoding_index)) - .put_literal_symbol(f->get_internal_name()) - .put_symbol("RE"); -} - -void ps_printer::encode_fonts() -{ - if (next_encoding_index == 0) - return; - char *done_encoding = new char[next_encoding_index]; - for (int i = 0; i < next_encoding_index; i++) - done_encoding[i] = 0; - for (font_pointer_list *f = font_list; f; f = f->next) { - int encoding_index = ((ps_font *)f->p)->encoding_index; - if (encoding_index >= 0) { - assert(encoding_index < next_encoding_index); - if (!done_encoding[encoding_index]) { - done_encoding[encoding_index] = 1; - define_encoding(((ps_font *)f->p)->encoding, encoding_index); - } - reencode_font((ps_font *)f->p); - } - } - a_delete done_encoding; -} - -void ps_printer::set_style(const style &sty) -{ - char buf[1 + INT_DIGITS + 1]; - for (int i = 0; i < ndefined_styles; i++) - if (sty == defined_styles[i]) { - sprintf(buf, "F%d", i); - out.put_symbol(buf); - return; - } - if (ndefined_styles >= MAX_DEFINED_STYLES) - ndefined_styles = 0; - sprintf(buf, "F%d", ndefined_styles); - out.put_literal_symbol(buf); - const char *psname = sty.f->get_internal_name(); - if (psname == 0) - fatal("no internalname specified for font `%1'", sty.f->get_name()); - char *encoding = ((ps_font *)sty.f)->encoding; - if (encoding != 0) { - char *s = ((ps_font *)sty.f)->reencoded_name; - if (s == 0) { - int ei = set_encoding_index((ps_font *)sty.f); - char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1]; - sprintf(tem, "%s@%d", psname, ei); - psname = tem; - ((ps_font *)sty.f)->reencoded_name = tem; - } - else - psname = s; - } - out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size); - if (sty.height != 0 || sty.slant != 0) { - int h = sty.height == 0 ? sty.point_size : sty.height; - h *= font::res/(72*font::sizescale); - int c = int(h*tan(radians(sty.slant)) + .5); - out.put_fix_number(c) - .put_fix_number(h) - .put_literal_symbol(psname) - .put_symbol("MF"); - } - else { - out.put_literal_symbol(psname) - .put_symbol("SF"); - } - defined_styles[ndefined_styles++] = sty; -} - -void ps_printer::set_color(color *col, int fill) -{ - sbuf_color = *col; - unsigned int components[4]; - char s[3]; - color_scheme cs = col->get_components(components); - s[0] = fill ? 'F' : 'C'; - s[2] = 0; - switch (cs) { - case DEFAULT: // black - out.put_symbol("0"); - s[1] = 'g'; - break; - case RGB: - out.put_color(Red) - .put_color(Green) - .put_color(Blue); - s[1] = 'r'; - break; - case CMY: - col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); - // fall through - case CMYK: - out.put_color(Cyan) - .put_color(Magenta) - .put_color(Yellow) - .put_color(Black); - s[1] = 'k'; - break; - case GRAY: - out.put_color(Gray); - s[1] = 'g'; - break; - } - out.put_symbol(s); -} - -void ps_printer::set_space_code(unsigned char c) -{ - out.put_literal_symbol("SC") - .put_number(c) - .put_symbol("def"); -} - -void ps_printer::end_of_line() -{ - flush_sbuf(); - // this ensures that we do an absolute motion to the beginning of a line - output_vpos = output_hpos = -1; -} - -void ps_printer::flush_sbuf() -{ - enum { - NONE, - RELATIVE_H, - RELATIVE_V, - RELATIVE_HV, - ABSOLUTE - } motion = NONE; - int space_flag = 0; - if (sbuf_len == 0) - return; - if (output_style != sbuf_style) { - set_style(sbuf_style); - output_style = sbuf_style; - } - int extra_space = 0; - if (output_hpos < 0 || output_vpos < 0) - motion = ABSOLUTE; - else { - if (output_hpos != sbuf_start_hpos) - motion = RELATIVE_H; - if (output_vpos != sbuf_vpos) { - if (motion != NONE) - motion = RELATIVE_HV; - else - motion = RELATIVE_V; - } - } - if (sbuf_space_code >= 0) { - int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size); - if (w + sbuf_kern != sbuf_space_width) { - if (sbuf_space_code != output_space_code) { - set_space_code(sbuf_space_code); - output_space_code = sbuf_space_code; - } - space_flag = 1; - extra_space = sbuf_space_width - w - sbuf_kern; - if (sbuf_space_diff_count > sbuf_space_count/2) - extra_space++; - else if (sbuf_space_diff_count < -(sbuf_space_count/2)) - extra_space--; - } - } - if (space_flag) - out.put_fix_number(extra_space); - if (sbuf_kern != 0) - out.put_fix_number(sbuf_kern); - out.put_string(sbuf, sbuf_len); - char command_array[] = {'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T'}; - char sym[2]; - sym[0] = command_array[motion*4 + space_flag + 2*(sbuf_kern != 0)]; - sym[1] = '\0'; - switch (motion) { - case NONE: - break; - case ABSOLUTE: - out.put_fix_number(sbuf_start_hpos) - .put_fix_number(sbuf_vpos); - break; - case RELATIVE_H: - out.put_fix_number(sbuf_start_hpos - output_hpos); - break; - case RELATIVE_V: - out.put_fix_number(sbuf_vpos - output_vpos); - break; - case RELATIVE_HV: - out.put_fix_number(sbuf_start_hpos - output_hpos) - .put_fix_number(sbuf_vpos - output_vpos); - break; - default: - assert(0); - } - out.put_symbol(sym); - output_hpos = sbuf_end_hpos; - output_vpos = sbuf_vpos; - sbuf_len = 0; -} - -void ps_printer::set_line_thickness_and_color(const environment *env) -{ - if (line_thickness < 0) { - if (output_draw_point_size != env->size) { - // we ought to check for overflow here - int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000; - out.put_fix_number(lw) - .put_symbol("LW"); - output_draw_point_size = env->size; - output_line_thickness = -1; - } - } - else { - if (output_line_thickness != line_thickness) { - out.put_fix_number(line_thickness) - .put_symbol("LW"); - output_line_thickness = line_thickness; - output_draw_point_size = -1; - } - } - if (sbuf_color != *env->col) - set_color(env->col); -} - -void ps_printer::fill_path(const environment *env) -{ - if (sbuf_color == *env->fill) - out.put_symbol("FL"); - else - set_color(env->fill, 1); -} - -void ps_printer::draw(int code, int *p, int np, const environment *env) -{ - if (invis_count > 0) - return; - flush_sbuf(); - int fill_flag = 0; - switch (code) { - case 'C': - fill_flag = 1; - // fall through - case 'c': - // troff adds an extra argument to C - if (np != 1 && !(code == 'C' && np == 2)) { - error("1 argument required for circle"); - break; - } - out.put_fix_number(env->hpos + p[0]/2) - .put_fix_number(env->vpos) - .put_fix_number(p[0]/2) - .put_symbol("DC"); - if (fill_flag) - fill_path(env); - else { - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - break; - case 'l': - if (np != 2) { - error("2 arguments required for line"); - break; - } - set_line_thickness_and_color(env); - out.put_fix_number(p[0] + env->hpos) - .put_fix_number(p[1] + env->vpos) - .put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("DL"); - break; - case 'E': - fill_flag = 1; - // fall through - case 'e': - if (np != 2) { - error("2 arguments required for ellipse"); - break; - } - out.put_fix_number(p[0]) - .put_fix_number(p[1]) - .put_fix_number(env->hpos + p[0]/2) - .put_fix_number(env->vpos) - .put_symbol("DE"); - if (fill_flag) - fill_path(env); - else { - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - break; - case 'P': - fill_flag = 1; - // fall through - case 'p': - { - if (np & 1) { - error("even number of arguments required for polygon"); - break; - } - if (np == 0) { - error("no arguments for polygon"); - break; - } - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("MT"); - for (int i = 0; i < np; i += 2) - out.put_fix_number(p[i]) - .put_fix_number(p[i+1]) - .put_symbol("RL"); - out.put_symbol("CL"); - if (fill_flag) - fill_path(env); - else { - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - break; - } - case '~': - { - if (np & 1) { - error("even number of arguments required for spline"); - break; - } - if (np == 0) { - error("no arguments for spline"); - break; - } - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("MT"); - out.put_fix_number(p[0]/2) - .put_fix_number(p[1]/2) - .put_symbol("RL"); - /* tnum/tden should be between 0 and 1; the closer it is to 1 - the tighter the curve will be to the guiding lines; 2/3 - is the standard value */ - const int tnum = 2; - const int tden = 3; - for (int i = 0; i < np - 2; i += 2) { - out.put_fix_number((p[i]*tnum)/(2*tden)) - .put_fix_number((p[i + 1]*tnum)/(2*tden)) - .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden)) - .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden)) - .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2) - .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2) - .put_symbol("RC"); - } - out.put_fix_number(p[np - 2] - p[np - 2]/2) - .put_fix_number(p[np - 1] - p[np - 1]/2) - .put_symbol("RL"); - set_line_thickness_and_color(env); - out.put_symbol("ST"); - } - break; - case 'a': - { - if (np != 4) { - error("4 arguments required for arc"); - break; - } - set_line_thickness_and_color(env); - double c[2]; - if (adjust_arc_center(p, c)) - out.put_fix_number(env->hpos + int(c[0])) - .put_fix_number(env->vpos + int(c[1])) - .put_fix_number(int(sqrt(c[0]*c[0] + c[1]*c[1]))) - .put_float(degrees(atan2(-c[1], -c[0]))) - .put_float(degrees(atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]))) - .put_symbol("DA"); - else - out.put_fix_number(p[0] + p[2] + env->hpos) - .put_fix_number(p[1] + p[3] + env->vpos) - .put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("DL"); - } - break; - case 't': - if (np == 0) - line_thickness = -1; - else { - // troff gratuitously adds an extra 0 - if (np != 1 && np != 2) { - error("0 or 1 argument required for thickness"); - break; - } - line_thickness = p[0]; - } - break; - default: - error("unrecognised drawing command `%1'", char(code)); - break; - } - output_hpos = output_vpos = -1; -} - -void ps_printer::begin_page(int n) -{ - out.begin_comment("Page:") - .comment_arg(i_to_a(n)); - out.comment_arg(i_to_a(++pages_output)) - .end_comment(); - output_style.f = 0; - output_space_code = 32; - output_draw_point_size = -1; - output_line_thickness = -1; - output_hpos = output_vpos = -1; - ndefined_styles = 0; - out.simple_comment("BeginPageSetup") - .put_symbol("BP") - .simple_comment("EndPageSetup"); - if (sbuf_color != default_color) - set_color(&sbuf_color); -} - -void ps_printer::end_page(int) -{ - flush_sbuf(); - set_color(&default_color); - out.put_symbol("EP"); - if (invis_count != 0) { - error("missing `endinvis' command"); - invis_count = 0; - } -} - -font *ps_printer::make_font(const char *nm) -{ - return ps_font::load_ps_font(nm); -} - -ps_printer::~ps_printer() -{ - out.simple_comment("Trailer") - .put_symbol("end") - .simple_comment("EOF"); - if (fseek(tempfp, 0L, 0) < 0) - fatal("fseek on temporary file failed"); - fputs("%!PS-Adobe-", stdout); - fputs((broken_flags & USE_PS_ADOBE_2_0) ? "2.0" : "3.0", stdout); - putchar('\n'); - out.set_file(stdout); - { - out.begin_comment("Creator:") - .comment_arg("groff") - .comment_arg("version") - .comment_arg(Version_string) - .end_comment(); - } - { - fputs("%%CreationDate: ", out.get_file()); -#ifdef LONG_FOR_TIME_T - long -#else - time_t -#endif - t = time(0); - fputs(ctime(&t), out.get_file()); - } - for (font_pointer_list *f = font_list; f; f = f->next) { - ps_font *psf = (ps_font *)(f->p); - rm.need_font(psf->get_internal_name()); - } - rm.print_header_comments(out); - out.begin_comment("Pages:") - .comment_arg(i_to_a(pages_output)) - .end_comment(); - out.begin_comment("PageOrder:") - .comment_arg("Ascend") - .end_comment(); -#if 0 - fprintf(out.get_file(), "%%%%DocumentMedia: () %g %g 0 () ()\n", - font::paperwidth*72.0/font::res, - paper_length*72.0/font::res); -#endif - out.begin_comment("Orientation:") - .comment_arg(landscape_flag ? "Landscape" : "Portrait") - .end_comment(); - if (ncopies != 1) { - out.end_line(); - fprintf(out.get_file(), "%%%%Requirements: numcopies(%d)\n", ncopies); - } - out.simple_comment("EndComments"); - out.simple_comment("BeginProlog"); - rm.output_prolog(out); - if (!(broken_flags & NO_SETUP_SECTION)) { - out.simple_comment("EndProlog"); - out.simple_comment("BeginSetup"); - } - rm.document_setup(out); - out.put_symbol(dict_name) - .put_symbol("begin"); - if (ndefs > 0) - ndefs += DEFS_DICT_SPARE; - out.put_literal_symbol(defs_dict_name) - .put_number(ndefs + 1) - .put_symbol("dict") - .put_symbol("def"); - out.put_symbol(defs_dict_name) - .put_symbol("begin"); - out.put_literal_symbol("u") - .put_delimiter('{') - .put_fix_number(1) - .put_symbol("mul") - .put_delimiter('}') - .put_symbol("bind") - .put_symbol("def"); - defs += '\0'; - out.special(defs.contents()); - out.put_symbol("end"); - if (ncopies != 1) - out.put_literal_symbol("#copies") - .put_number(ncopies) - .put_symbol("def"); - out.put_literal_symbol("RES") - .put_number(res) - .put_symbol("def"); - out.put_literal_symbol("PL"); - if (guess_flag) - out.put_symbol("PLG"); - else - out.put_fix_number(paper_length); - out.put_symbol("def"); - out.put_literal_symbol("LS") - .put_symbol(landscape_flag ? "true" : "false") - .put_symbol("def"); - if (manual_feed_flag) { - out.begin_comment("BeginFeature:") - .comment_arg("*ManualFeed") - .comment_arg("True") - .end_comment() - .put_symbol("MANUAL") - .simple_comment("EndFeature"); - } - encode_fonts(); - out.simple_comment((broken_flags & NO_SETUP_SECTION) - ? "EndProlog" - : "EndSetup"); - out.end_line(); - out.copy_file(tempfp); - fclose(tempfp); -} - -void ps_printer::special(char *arg, const environment *env, char type) -{ - if (type != 'p') - return; - typedef void (ps_printer::*SPECIAL_PROCP)(char *, const environment *); - static struct { - const char *name; - SPECIAL_PROCP proc; - } proc_table[] = { - { "exec", &ps_printer::do_exec }, - { "def", &ps_printer::do_def }, - { "mdef", &ps_printer::do_mdef }, - { "import", &ps_printer::do_import }, - { "file", &ps_printer::do_file }, - { "invis", &ps_printer::do_invis }, - { "endinvis", &ps_printer::do_endinvis }, - }; - char *p; - for (p = arg; *p == ' ' || *p == '\n'; p++) - ; - char *tag = p; - for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++) - ; - if (*p == '\0' || strncmp(tag, "ps", p - tag) != 0) { - error("X command without `ps:' tag ignored"); - return; - } - p++; - for (; *p == ' ' || *p == '\n'; p++) - ; - char *command = p; - for (; *p != '\0' && *p != ' ' && *p != '\n'; p++) - ; - if (*command == '\0') { - error("empty X command ignored"); - return; - } - for (unsigned int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++) - if (strncmp(command, proc_table[i].name, p - command) == 0) { - (this->*(proc_table[i].proc))(p, env); - return; - } - error("X command `%1' not recognised", command); -} - -// A conforming PostScript document must not have lines longer -// than 255 characters (excluding line termination characters). - -static int check_line_lengths(const char *p) -{ - for (;;) { - const char *end = strchr(p, '\n'); - if (end == 0) - end = strchr(p, '\0'); - if (end - p > 255) - return 0; - if (*end == '\0') - break; - p = end + 1; - } - return 1; -} - -void ps_printer::do_exec(char *arg, const environment *env) -{ - flush_sbuf(); - while (csspace(*arg)) - arg++; - if (*arg == '\0') { - error("missing argument to X exec command"); - return; - } - if (!check_line_lengths(arg)) { - error("lines in X exec command must not be more than 255 characters long"); - return; - } - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("EBEGIN") - .special(arg) - .put_symbol("EEND"); - output_hpos = output_vpos = -1; - output_style.f = 0; - output_draw_point_size = -1; - output_line_thickness = -1; - ndefined_styles = 0; - if (!ndefs) - ndefs = 1; -} - -void ps_printer::do_file(char *arg, const environment *env) -{ - flush_sbuf(); - while (csspace(*arg)) - arg++; - if (*arg == '\0') { - error("missing argument to X file command"); - return; - } - const char *filename = arg; - do { - ++arg; - } while (*arg != '\0' && *arg != ' ' && *arg != '\n'); - out.put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("EBEGIN"); - rm.import_file(filename, out); - out.put_symbol("EEND"); - output_hpos = output_vpos = -1; - output_style.f = 0; - output_draw_point_size = -1; - output_line_thickness = -1; - ndefined_styles = 0; - if (!ndefs) - ndefs = 1; -} - -void ps_printer::do_def(char *arg, const environment *) -{ - flush_sbuf(); - while (csspace(*arg)) - arg++; - if (!check_line_lengths(arg)) { - error("lines in X def command must not be more than 255 characters long"); - return; - } - defs += arg; - if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') - defs += '\n'; - ndefs++; -} - -// Like def, but the first argument says how many definitions it contains. - -void ps_printer::do_mdef(char *arg, const environment *) -{ - flush_sbuf(); - char *p; - int n = (int)strtol(arg, &p, 10); - if (n == 0 && p == arg) { - error("first argument to X mdef must be an integer"); - return; - } - if (n < 0) { - error("out of range argument `%1' to X mdef command", int(n)); - return; - } - arg = p; - while (csspace(*arg)) - arg++; - if (!check_line_lengths(arg)) { - error("lines in X mdef command must not be more than 255 characters long"); - return; - } - defs += arg; - if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') - defs += '\n'; - ndefs += n; -} - -void ps_printer::do_import(char *arg, const environment *env) -{ - flush_sbuf(); - while (*arg == ' ' || *arg == '\n') - arg++; - char *p; - for (p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++) - ; - if (*p != '\0') - *p++ = '\0'; - int parms[6]; - int nparms = 0; - while (nparms < 6) { - char *end; - long n = strtol(p, &end, 10); - if (n == 0 && end == p) - break; - parms[nparms++] = int(n); - p = end; - } - if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) { - error("scaling indicators not allowed in arguments for X import command"); - return; - } - while (*p == ' ' || *p == '\n') - p++; - if (nparms < 5) { - if (*p == '\0') - error("too few arguments for X import command"); - else - error("invalid argument `%1' for X import command", p); - return; - } - if (*p != '\0') { - error("superflous argument `%1' for X import command", p); - return; - } - int llx = parms[0]; - int lly = parms[1]; - int urx = parms[2]; - int ury = parms[3]; - int desired_width = parms[4]; - int desired_height = parms[5]; - if (desired_width <= 0) { - error("bad width argument `%1' for X import command: must be > 0", - desired_width); - return; - } - if (nparms == 6 && desired_height <= 0) { - error("bad height argument `%1' for X import command: must be > 0", - desired_height); - return; - } - if (llx == urx) { - error("llx and urx arguments for X import command must not be equal"); - return; - } - if (lly == ury) { - error("lly and ury arguments for X import command must not be equal"); - return; - } - if (nparms == 5) { - int old_wid = urx - llx; - int old_ht = ury - lly; - if (old_wid < 0) - old_wid = -old_wid; - if (old_ht < 0) - old_ht = -old_ht; - desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5); - } - if (env->vpos - desired_height < 0) - warning("top of imported graphic is above the top of the page"); - out.put_number(llx) - .put_number(lly) - .put_fix_number(desired_width) - .put_number(urx - llx) - .put_fix_number(-desired_height) - .put_number(ury - lly) - .put_fix_number(env->hpos) - .put_fix_number(env->vpos) - .put_symbol("PBEGIN"); - rm.import_file(arg, out); - // do this here just in case application defines PEND - out.put_symbol("end"); - out.put_symbol("PEND"); -} - -void ps_printer::do_invis(char *, const environment *) -{ - invis_count++; -} - -void ps_printer::do_endinvis(char *, const environment *) -{ - if (invis_count == 0) - error("unbalanced `endinvis' command"); - else - --invis_count; -} - -printer *make_printer() -{ - return new ps_printer(user_paper_length); -} - -static void usage(FILE *stream); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - string env; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int c; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((c = getopt_long(argc, argv, "b:c:F:glmp:P:vw:", long_options, NULL)) - != EOF) - switch(c) { - case 'b': - // XXX check this - broken_flags = atoi(optarg); - bflag = 1; - break; - case 'c': - if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) { - error("bad number of copies `%s'", optarg); - ncopies = 1; - } - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'g': - guess_flag = 1; - break; - case 'l': - landscape_flag = 1; - break; - case 'm': - manual_feed_flag = 1; - break; - case 'p': - if (!font::scan_papersize(optarg, 0, &user_paper_length, 0)) - error("invalid custom paper size `%1' ignored", optarg); - break; - case 'P': - env = "GROPS_PROLOGUE"; - env += '='; - env += optarg; - env += '\0'; - if (putenv(strsave(env.contents()))) - fatal("putenv failed"); - break; - case 'v': - printf("GNU grops (groff) version %s\n", Version_string); - exit(0); - break; - case 'w': - if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) { - error("bad linewidth `%1'", optarg); - linewidth = -1; - } - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - font::set_unknown_desc_command_handler(handle_unknown_desc_command); -#ifdef SET_BINARY - SET_BINARY(fileno(stdout)); -#endif - if (optind >= argc) - do_file("-"); - else { - for (int i = optind; i < argc; i++) - do_file(argv[i]); - } - delete pr; - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, - "usage: %s [-glmv] [-b n] [-c n] [-w n] [-P prologue] [-F dir] [files ...]\n", - program_name); -} diff --git a/contrib/groff/src/devices/grops/psrm.cc b/contrib/groff/src/devices/grops/psrm.cc deleted file mode 100644 index f2177da..0000000 --- a/contrib/groff/src/devices/grops/psrm.cc +++ /dev/null @@ -1,1147 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "stringclass.h" -#include "cset.h" - -#include "ps.h" - -#ifdef NEED_DECLARATION_PUTENV -extern "C" { - int putenv(const char *); -} -#endif /* NEED_DECLARATION_PUTENV */ - -#define GROPS_PROLOGUE "prologue" - -static void print_ps_string(const string &s, FILE *outfp); - -cset white_space("\n\r \t"); -string an_empty_string; - -const char *extension_table[] = { - "DPS", - "CMYK", - "Composite", - "FileSystem", -}; - -const int NEXTENSIONS = sizeof(extension_table)/sizeof(extension_table[0]); - -const char *resource_table[] = { - "font", - "procset", - "file", - "encoding", - "form", - "pattern", -}; - -const int NRESOURCES = sizeof(resource_table)/sizeof(resource_table[0]); - -static int read_uint_arg(const char **pp, unsigned *res) -{ - while (white_space(**pp)) - *pp += 1; - if (**pp == '\0') { - error("missing argument"); - return 0; - } - const char *start = *pp; - // XXX use strtoul - long n = strtol(start, (char **)pp, 10); - if (n == 0 && *pp == start) { - error("not an integer"); - return 0; - } - if (n < 0) { - error("argument must not be negative"); - return 0; - } - *res = unsigned(n); - return 1; -} - -struct resource { - resource *next; - resource_type type; - string name; - enum { NEEDED = 01, SUPPLIED = 02, FONT_NEEDED = 04, BUSY = 010 }; - unsigned flags; - string version; - unsigned revision; - char *filename; - int rank; - resource(resource_type, string &, string & = an_empty_string, unsigned = 0); - ~resource(); - void print_type_and_name(FILE *outfp); -}; - -resource::resource(resource_type t, string &n, string &v, unsigned r) -: next(0), type(t), flags(0), revision(r), filename(0), rank(-1) -{ - name.move(n); - version.move(v); - if (type == RESOURCE_FILE) { - if (name.search('\0') >= 0) - error("filename contains a character with code 0"); - filename = name.extract(); - } -} - -resource::~resource() -{ - a_delete filename; -} - -void resource::print_type_and_name(FILE *outfp) -{ - fputs(resource_table[type], outfp); - putc(' ', outfp); - print_ps_string(name, outfp); - if (type == RESOURCE_PROCSET) { - putc(' ', outfp); - print_ps_string(version, outfp); - fprintf(outfp, " %u", revision); - } -} - -resource_manager::resource_manager() -: extensions(0), language_level(0), resource_list(0) -{ - read_download_file(); - string procset_name("grops"); - extern const char *version_string; - extern const char *revision_string; - unsigned revision_uint; - if ( !read_uint_arg( &revision_string, &revision_uint) ) - revision_uint = 0; - string procset_version(version_string); - procset_resource = lookup_resource(RESOURCE_PROCSET, procset_name, - procset_version, revision_uint); - procset_resource->flags |= resource::SUPPLIED; -} - -resource_manager::~resource_manager() -{ - while (resource_list) { - resource *tem = resource_list; - resource_list = resource_list->next; - delete tem; - } -} - -resource *resource_manager::lookup_resource(resource_type type, - string &name, - string &version, - unsigned revision) -{ - resource *r; - for (r = resource_list; r; r = r->next) - if (r->type == type - && r->name == name - && r->version == version - && r->revision == revision) - return r; - r = new resource(type, name, version, revision); - r->next = resource_list; - resource_list = r; - return r; -} - -// Just a specialized version of lookup_resource(). - -resource *resource_manager::lookup_font(const char *name) -{ - resource *r; - for (r = resource_list; r; r = r->next) - if (r->type == RESOURCE_FONT - && strlen(name) == (size_t)r->name.length() - && memcmp(name, r->name.contents(), r->name.length()) == 0) - return r; - string s(name); - r = new resource(RESOURCE_FONT, s); - r->next = resource_list; - resource_list = r; - return r; -} - -void resource_manager::need_font(const char *name) -{ - lookup_font(name)->flags |= resource::FONT_NEEDED; -} - -typedef resource *Presource; // Work around g++ bug. - -void resource_manager::document_setup(ps_output &out) -{ - int nranks = 0; - resource *r; - for (r = resource_list; r; r = r->next) - if (r->rank >= nranks) - nranks = r->rank + 1; - if (nranks > 0) { - // Sort resource_list in reverse order of rank. - Presource *head = new Presource[nranks + 1]; - Presource **tail = new Presource *[nranks + 1]; - int i; - for (i = 0; i < nranks + 1; i++) { - head[i] = 0; - tail[i] = &head[i]; - } - for (r = resource_list; r; r = r->next) { - i = r->rank < 0 ? 0 : r->rank + 1; - *tail[i] = r; - tail[i] = &(*tail[i])->next; - } - resource_list = 0; - for (i = 0; i < nranks + 1; i++) - if (head[i]) { - *tail[i] = resource_list; - resource_list = head[i]; - } - a_delete head; - a_delete tail; - // check it - for (r = resource_list; r; r = r->next) - if (r->next) - assert(r->rank >= r->next->rank); - for (r = resource_list; r; r = r->next) - if (r->type == RESOURCE_FONT && r->rank >= 0) - supply_resource(r, -1, out.get_file()); - } -} - -void resource_manager::print_resources_comment(unsigned flag, FILE *outfp) -{ - int continued = 0; - for (resource *r = resource_list; r; r = r->next) - if (r->flags & flag) { - if (continued) - fputs("%%+ ", outfp); - else { - fputs(flag == resource::NEEDED - ? "%%DocumentNeededResources: " - : "%%DocumentSuppliedResources: ", - outfp); - continued = 1; - } - r->print_type_and_name(outfp); - putc('\n', outfp); - } -} - -void resource_manager::print_header_comments(ps_output &out) -{ - for (resource *r = resource_list; r; r = r->next) - if (r->type == RESOURCE_FONT && (r->flags & resource::FONT_NEEDED)) - supply_resource(r, 0, 0); - print_resources_comment(resource::NEEDED, out.get_file()); - print_resources_comment(resource::SUPPLIED, out.get_file()); - print_language_level_comment(out.get_file()); - print_extensions_comment(out.get_file()); -} - -void resource_manager::output_prolog(ps_output &out) -{ - FILE *outfp = out.get_file(); - out.end_line(); - char *path; - if (!getenv("GROPS_PROLOGUE")) { - string e = "GROPS_PROLOGUE"; - e += '='; - e += GROPS_PROLOGUE; - e += '\0'; - if (putenv(strsave(e.contents()))) - fatal("putenv failed"); - } - char *prologue = getenv("GROPS_PROLOGUE"); - FILE *fp = font::open_file(prologue, &path); - if (!fp) - fatal("can't find `%1'", prologue); - fputs("%%BeginResource: ", outfp); - procset_resource->print_type_and_name(outfp); - putc('\n', outfp); - process_file(-1, fp, path, outfp); - fclose(fp); - a_delete path; - fputs("%%EndResource\n", outfp); -} - -void resource_manager::import_file(const char *filename, ps_output &out) -{ - out.end_line(); - string name(filename); - resource *r = lookup_resource(RESOURCE_FILE, name); - supply_resource(r, -1, out.get_file(), 1); -} - -void resource_manager::supply_resource(resource *r, int rank, FILE *outfp, - int is_document) -{ - if (r->flags & resource::BUSY) { - r->name += '\0'; - fatal("loop detected in dependency graph for %1 `%2'", - resource_table[r->type], - r->name.contents()); - } - r->flags |= resource::BUSY; - if (rank > r->rank) - r->rank = rank; - char *path; - FILE *fp = 0; - if (r->filename != 0) { - if (r->type == RESOURCE_FONT) { - fp = font::open_file(r->filename, &path); - if (!fp) { - error("can't find `%1'", r->filename); - a_delete r->filename; - r->filename = 0; - } - } - else { - errno = 0; - fp = fopen(r->filename, "r"); - if (!fp) { - error("can't open `%1': %2", r->filename, strerror(errno)); - a_delete r->filename; - r->filename = 0; - } - else - path = r->filename; - } - } - if (fp) { - if (outfp) { - if (r->type == RESOURCE_FILE && is_document) { - fputs("%%BeginDocument: ", outfp); - print_ps_string(r->name, outfp); - putc('\n', outfp); - } - else { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - process_file(rank, fp, path, outfp); - fclose(fp); - if (r->type == RESOURCE_FONT) - a_delete path; - if (outfp) { - if (r->type == RESOURCE_FILE && is_document) - fputs("%%EndDocument\n", outfp); - else - fputs("%%EndResource\n", outfp); - } - r->flags |= resource::SUPPLIED; - } - else { - if (outfp) { - if (r->type == RESOURCE_FILE && is_document) { - fputs("%%IncludeDocument: ", outfp); - print_ps_string(r->name, outfp); - putc('\n', outfp); - } - else { - fputs("%%IncludeResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - r->flags |= resource::NEEDED; - } - r->flags &= ~resource::BUSY; -} - - -#define PS_LINE_MAX 255 -#define PS_MAGIC "%!PS-Adobe-" - -static int ps_get_line(char *buf, FILE *fp) -{ - int c = getc(fp); - if (c == EOF) { - buf[0] = '\0'; - return 0; - } - current_lineno++; - int i = 0; - int err = 0; - while (c != '\r' && c != '\n' && c != EOF) { - if ((c < 0x1b && !white_space(c)) || c == 0x7f) - error("invalid input character code %1", int(c)); - else if (i < PS_LINE_MAX) - buf[i++] = c; - else if (!err) { - err = 1; - error("PostScript file non-conforming " - "because length of line exceeds 255"); - } - c = getc(fp); - } - buf[i++] = '\n'; - buf[i] = '\0'; - if (c == '\r') { - c = getc(fp); - if (c != EOF && c != '\n') - ungetc(c, fp); - } - return 1; -} - -static int read_text_arg(const char **pp, string &res) -{ - res.clear(); - while (white_space(**pp)) - *pp += 1; - if (**pp == '\0') { - error("missing argument"); - return 0; - } - if (**pp != '(') { - for (; **pp != '\0' && !white_space(**pp); *pp += 1) - res += **pp; - return 1; - } - *pp += 1; - res.clear(); - int level = 0; - for (;;) { - if (**pp == '\0' || **pp == '\r' || **pp == '\n') { - error("missing ')'"); - return 0; - } - if (**pp == ')') { - if (level == 0) { - *pp += 1; - break; - } - res += **pp; - level--; - } - else if (**pp == '(') { - level++; - res += **pp; - } - else if (**pp == '\\') { - *pp += 1; - switch (**pp) { - case 'n': - res += '\n'; - break; - case 'r': - res += '\n'; - break; - case 't': - res += '\t'; - break; - case 'b': - res += '\b'; - break; - case 'f': - res += '\f'; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int val = **pp - '0'; - if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { - *pp += 1; - val = val*8 + (**pp - '0'); - if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { - *pp += 1; - val = val*8 + (**pp - '0'); - } - } - } - break; - default: - res += **pp; - break; - } - } - else - res += **pp; - *pp += 1; - } - return 1; -} - -resource *resource_manager::read_file_arg(const char **ptr) -{ - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - return lookup_resource(RESOURCE_FILE, arg); -} - -resource *resource_manager::read_font_arg(const char **ptr) -{ - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - return lookup_resource(RESOURCE_FONT, arg); -} - -resource *resource_manager::read_procset_arg(const char **ptr) -{ - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - string version; - if (!read_text_arg(ptr, version)) - return 0; - unsigned revision; - if (!read_uint_arg(ptr, &revision)) - return 0; - return lookup_resource(RESOURCE_PROCSET, arg, version, revision); -} - -resource *resource_manager::read_resource_arg(const char **ptr) -{ - while (white_space(**ptr)) - *ptr += 1; - const char *name = *ptr; - while (**ptr != '\0' && !white_space(**ptr)) - *ptr += 1; - if (name == *ptr) { - error("missing resource type"); - return 0; - } - int ri; - for (ri = 0; ri < NRESOURCES; ri++) - if (strlen(resource_table[ri]) == size_t(*ptr - name) - && memcmp(resource_table[ri], name, *ptr - name) == 0) - break; - if (ri >= NRESOURCES) { - error("unknown resource type"); - return 0; - } - if (ri == RESOURCE_PROCSET) - return read_procset_arg(ptr); - string arg; - if (!read_text_arg(ptr, arg)) - return 0; - return lookup_resource(resource_type(ri), arg); -} - -static const char *matches_comment(const char *buf, const char *comment) -{ - if (buf[0] != '%' || buf[1] != '%') - return 0; - for (buf += 2; *comment; comment++, buf++) - if (*buf != *comment) - return 0; - if (comment[-1] == ':') - return buf; - if (*buf == '\0' || white_space(*buf)) - return buf; - return 0; -} - -// Return 1 if the line should be copied out. - -int resource_manager::do_begin_resource(const char *ptr, int, FILE *, - FILE *) -{ - resource *r = read_resource_arg(&ptr); - if (r) - r->flags |= resource::SUPPLIED; - return 1; -} - -int resource_manager::do_include_resource(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_resource_arg(&ptr); - if (r) { - if (r->type == RESOURCE_FONT) { - if (rank >= 0) - supply_resource(r, rank + 1, outfp); - else - r->flags |= resource::FONT_NEEDED; - } - else - supply_resource(r, rank, outfp); - } - return 0; -} - -int resource_manager::do_begin_document(const char *ptr, int, FILE *, - FILE *) -{ - resource *r = read_file_arg(&ptr); - if (r) - r->flags |= resource::SUPPLIED; - return 1; -} - -int resource_manager::do_include_document(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_file_arg(&ptr); - if (r) - supply_resource(r, rank, outfp, 1); - return 0; -} - -int resource_manager::do_begin_procset(const char *ptr, int, FILE *, - FILE *outfp) -{ - resource *r = read_procset_arg(&ptr); - if (r) { - r->flags |= resource::SUPPLIED; - if (outfp) { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - return 0; -} - -int resource_manager::do_include_procset(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_procset_arg(&ptr); - if (r) - supply_resource(r, rank, outfp); - return 0; -} - -int resource_manager::do_begin_file(const char *ptr, int, FILE *, - FILE *outfp) -{ - resource *r = read_file_arg(&ptr); - if (r) { - r->flags |= resource::SUPPLIED; - if (outfp) { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - return 0; -} - -int resource_manager::do_include_file(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_file_arg(&ptr); - if (r) - supply_resource(r, rank, outfp); - return 0; -} - -int resource_manager::do_begin_font(const char *ptr, int, FILE *, - FILE *outfp) -{ - resource *r = read_font_arg(&ptr); - if (r) { - r->flags |= resource::SUPPLIED; - if (outfp) { - fputs("%%BeginResource: ", outfp); - r->print_type_and_name(outfp); - putc('\n', outfp); - } - } - return 0; -} - -int resource_manager::do_include_font(const char *ptr, int rank, FILE *, - FILE *outfp) -{ - resource *r = read_font_arg(&ptr); - if (r) { - if (rank >= 0) - supply_resource(r, rank + 1, outfp); - else - r->flags |= resource::FONT_NEEDED; - } - return 0; -} - -int resource_manager::change_to_end_resource(const char *, int, FILE *, - FILE *outfp) -{ - if (outfp) - fputs("%%EndResource\n", outfp); - return 0; -} - -int resource_manager::do_begin_preview(const char *, int, FILE *fp, FILE *) -{ - char buf[PS_LINE_MAX + 2]; - do { - if (!ps_get_line(buf, fp)) { - error("end of file in preview section"); - break; - } - } while (!matches_comment(buf, "EndPreview")); - return 0; -} - -int read_one_of(const char **ptr, const char **s, int n) -{ - while (white_space(**ptr)) - *ptr += 1; - if (**ptr == '\0') - return -1; - const char *start = *ptr; - do { - ++(*ptr); - } while (**ptr != '\0' && !white_space(**ptr)); - for (int i = 0; i < n; i++) - if (strlen(s[i]) == size_t(*ptr - start) - && memcmp(s[i], start, *ptr - start) == 0) - return i; - return -1; -} - -void skip_possible_newline(const char *ptr, FILE *fp, FILE *outfp) -{ - int c = getc(fp); - if (c == '\r') { - current_lineno++; - if (outfp) - putc(c, outfp); - int cc = getc(fp); - if (cc != '\n') { - if (cc != EOF) - ungetc(cc, fp); - } - else { - if (outfp) - putc(cc, outfp); - } - } - else if (c == '\n') { - current_lineno++; - if (outfp) - putc(c, outfp); - } - else if (c != EOF) - ungetc(c, fp); -} - -int resource_manager::do_begin_data(const char *ptr, int, FILE *fp, - FILE *outfp) -{ - while (white_space(*ptr)) - ptr++; - const char *start = ptr; - unsigned numberof; - if (!read_uint_arg(&ptr, &numberof)) - return 0; - static const char *types[] = { "Binary", "Hex", "ASCII" }; - const int Binary = 0; - int type = 0; - static const char *units[] = { "Bytes", "Lines" }; - const int Bytes = 0; - int unit = Bytes; - while (white_space(*ptr)) - ptr++; - if (*ptr != '\0') { - type = read_one_of(&ptr, types, 3); - if (type < 0) { - error("bad data type"); - return 0; - } - while (white_space(*ptr)) - ptr++; - if (*ptr != '\0') { - unit = read_one_of(&ptr, units, 2); - if (unit < 0) { - error("expected `Bytes' or `Lines'"); - return 0; - } - } - } - if (type != Binary) - return 1; - if (outfp) { - fputs("%%BeginData: ", outfp); - fputs(start, outfp); - } - if (numberof > 0) { - unsigned bytecount = 0; - unsigned linecount = 0; - do { - int c = getc(fp); - if (c == EOF) { - error("end of file within data section"); - return 0; - } - if (outfp) - putc(c, outfp); - bytecount++; - if (c == '\r') { - int cc = getc(fp); - if (cc != '\n') { - linecount++; - current_lineno++; - } - if (cc != EOF) - ungetc(c, fp); - } - else if (c == '\n') { - linecount++; - current_lineno++; - } - } while ((unit == Bytes ? bytecount : linecount) < numberof); - } - skip_possible_newline(ptr, fp, outfp); - char buf[PS_LINE_MAX + 2]; - if (!ps_get_line(buf, fp)) { - error("missing %%%%EndData line"); - return 0; - } - if (!matches_comment(buf, "EndData")) - error("bad %%%%EndData line"); - if (outfp) - fputs(buf, outfp); - return 0; -} - -int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp, - FILE *outfp) -{ - if (!outfp) - return 0; - unsigned count; - if (!read_uint_arg(&ptr, &count)) - return 0; - if (outfp) - fprintf(outfp, "%%%%BeginData: %u Binary Bytes\n", count); - while (count != 0) { - int c = getc(fp); - if (c == EOF) { - error("end of file within binary section"); - return 0; - } - if (outfp) - putc(c, outfp); - --count; - if (c == '\r') { - int cc = getc(fp); - if (cc != '\n') - current_lineno++; - if (cc != EOF) - ungetc(cc, fp); - } - else if (c == '\n') - current_lineno++; - } - skip_possible_newline(ptr, fp, outfp); - char buf[PS_LINE_MAX + 2]; - if (!ps_get_line(buf, fp)) { - error("missing %%%%EndBinary line"); - return 0; - } - if (!matches_comment(buf, "EndBinary")) { - error("bad %%%%EndBinary line"); - if (outfp) - fputs(buf, outfp); - } - else if (outfp) - fputs("%%EndData\n", outfp); - return 0; -} - -static unsigned parse_extensions(const char *ptr) -{ - unsigned flags = 0; - for (;;) { - while (white_space(*ptr)) - ptr++; - if (*ptr == '\0') - break; - const char *name = ptr; - do { - ++ptr; - } while (*ptr != '\0' && !white_space(*ptr)); - int i; - for (i = 0; i < NEXTENSIONS; i++) - if (strlen(extension_table[i]) == size_t(ptr - name) - && memcmp(extension_table[i], name, ptr - name) == 0) { - flags |= (1 << i); - break; - } - if (i >= NEXTENSIONS) { - string s(name, ptr - name); - s += '\0'; - error("unknown extension `%1'", s.contents()); - } - } - return flags; -} - -// XXX if it has not been surrounded with {Begin,End}Document need to strip -// out Page: Trailer {Begin,End}Prolog {Begin,End}Setup sections. - -// XXX Perhaps the decision whether to use BeginDocument or -// BeginResource: file should be postponed till we have seen -// the first line of the file. - -void resource_manager::process_file(int rank, FILE *fp, const char *filename, - FILE *outfp) -{ - // If none of these comments appear in the header section, and we are - // just analyzing the file (ie outfp is 0), then we can return immediately. - static const char *header_comment_table[] = { - "DocumentNeededResources:", - "DocumentSuppliedResources:", - "DocumentNeededFonts:", - "DocumentSuppliedFonts:", - "DocumentNeededProcSets:", - "DocumentSuppliedProcSets:", - "DocumentNeededFiles:", - "DocumentSuppliedFiles:", - }; - - const int NHEADER_COMMENTS = (sizeof(header_comment_table) - / sizeof(header_comment_table[0])); - struct comment_info { - const char *name; - int (resource_manager::*proc)(const char *, int, FILE *, FILE *); - }; - - static comment_info comment_table[] = { - { "BeginResource:", &resource_manager::do_begin_resource }, - { "IncludeResource:", &resource_manager::do_include_resource }, - { "BeginDocument:", &resource_manager::do_begin_document }, - { "IncludeDocument:", &resource_manager::do_include_document }, - { "BeginProcSet:", &resource_manager::do_begin_procset }, - { "IncludeProcSet:", &resource_manager::do_include_procset }, - { "BeginFont:", &resource_manager::do_begin_font }, - { "IncludeFont:", &resource_manager::do_include_font }, - { "BeginFile:", &resource_manager::do_begin_file }, - { "IncludeFile:", &resource_manager::do_include_file }, - { "EndProcSet", &resource_manager::change_to_end_resource }, - { "EndFont", &resource_manager::change_to_end_resource }, - { "EndFile", &resource_manager::change_to_end_resource }, - { "BeginPreview:", &resource_manager::do_begin_preview }, - { "BeginData:", &resource_manager::do_begin_data }, - { "BeginBinary:", &resource_manager::do_begin_binary }, - }; - - const int NCOMMENTS = sizeof(comment_table)/sizeof(comment_table[0]); - char buf[PS_LINE_MAX + 2]; - int saved_lineno = current_lineno; - const char *saved_filename = current_filename; - current_filename = filename; - current_lineno = 0; - if (!ps_get_line(buf, fp)) { - current_filename = saved_filename; - current_lineno = saved_lineno; - return; - } - if (strlen(buf) < sizeof(PS_MAGIC) - 1 - || memcmp(buf, PS_MAGIC, sizeof(PS_MAGIC) - 1) != 0) { - if (outfp) { - do { - if (!(broken_flags & STRIP_PERCENT_BANG) - || buf[0] != '%' || buf[1] != '!') - fputs(buf, outfp); - } while (ps_get_line(buf, fp)); - } - } - else { - if (!(broken_flags & STRIP_PERCENT_BANG) && outfp) - fputs(buf, outfp); - int in_header = 1; - int interesting = 0; - int had_extensions_comment = 0; - int had_language_level_comment = 0; - for (;;) { - if (!ps_get_line(buf, fp)) - break; - int copy_this_line = 1; - if (buf[0] == '%') { - if (buf[1] == '%') { - const char *ptr; - int i; - for (i = 0; i < NCOMMENTS; i++) - if ((ptr = matches_comment(buf, comment_table[i].name))) { - copy_this_line - = (this->*(comment_table[i].proc))(ptr, rank, fp, outfp); - break; - } - if (i >= NCOMMENTS && in_header) { - if ((ptr = matches_comment(buf, "EndComments"))) - in_header = 0; - else if (!had_extensions_comment - && (ptr = matches_comment(buf, "Extensions:"))) { - extensions |= parse_extensions(ptr); - // XXX handle possibility that next line is %%+ - had_extensions_comment = 1; - } - else if (!had_language_level_comment - && (ptr = matches_comment(buf, "LanguageLevel:"))) { - unsigned ll; - if (read_uint_arg(&ptr, &ll) && ll > language_level) - language_level = ll; - had_language_level_comment = 1; - } - else { - for (i = 0; i < NHEADER_COMMENTS; i++) - if (matches_comment(buf, header_comment_table[i])) { - interesting = 1; - break; - } - } - } - if ((broken_flags & STRIP_STRUCTURE_COMMENTS) - && (matches_comment(buf, "EndProlog") - || matches_comment(buf, "Page:") - || matches_comment(buf, "Trailer"))) - copy_this_line = 0; - } - else if (buf[1] == '!') { - if (broken_flags & STRIP_PERCENT_BANG) - copy_this_line = 0; - } - } - else - in_header = 0; - if (!outfp && !in_header && !interesting) - break; - if (copy_this_line && outfp) - fputs(buf, outfp); - } - } - current_filename = saved_filename; - current_lineno = saved_lineno; -} - -void resource_manager::read_download_file() -{ - char *path = 0; - FILE *fp = font::open_file("download", &path); - if (!fp) - fatal("can't find `download'"); - char buf[512]; - int lineno = 0; - while (fgets(buf, sizeof(buf), fp)) { - lineno++; - char *p = strtok(buf, " \t\r\n"); - if (p == 0 || *p == '#') - continue; - char *q = strtok(0, " \t\r\n"); - if (!q) - fatal_with_file_and_line(path, lineno, "missing filename"); - lookup_font(p)->filename = strsave(q); - } - a_delete path; - fclose(fp); -} - -// XXX Can we share some code with ps_output::put_string()? - -static void print_ps_string(const string &s, FILE *outfp) -{ - int len = s.length(); - const char *str = s.contents(); - int funny = 0; - if (str[0] == '(') - funny = 1; - else { - for (int i = 0; i < len; i++) - if (str[i] <= 040 || str[i] > 0176) { - funny = 1; - break; - } - } - if (!funny) { - put_string(s, outfp); - return; - } - int level = 0; - int i; - for (i = 0; i < len; i++) - if (str[i] == '(') - level++; - else if (str[i] == ')' && --level < 0) - break; - putc('(', outfp); - for (i = 0; i < len; i++) - switch (str[i]) { - case '(': - case ')': - if (level != 0) - putc('\\', outfp); - putc(str[i], outfp); - break; - case '\\': - fputs("\\\\", outfp); - break; - case '\n': - fputs("\\n", outfp); - break; - case '\r': - fputs("\\r", outfp); - break; - case '\t': - fputs("\\t", outfp); - break; - case '\b': - fputs("\\b", outfp); - break; - case '\f': - fputs("\\f", outfp); - break; - default: - if (str[i] < 040 || str[i] > 0176) - fprintf(outfp, "\\%03o", str[i] & 0377); - else - putc(str[i], outfp); - break; - } - putc(')', outfp); -} - -void resource_manager::print_extensions_comment(FILE *outfp) -{ - if (extensions) { - fputs("%%Extensions:", outfp); - for (int i = 0; i < NEXTENSIONS; i++) - if (extensions & (1 << i)) { - putc(' ', outfp); - fputs(extension_table[i], outfp); - } - putc('\n', outfp); - } -} - -void resource_manager::print_language_level_comment(FILE *outfp) -{ - if (language_level) - fprintf(outfp, "%%%%LanguageLevel: %u\n", language_level); -} - diff --git a/contrib/groff/src/devices/grotty/tty.cc b/contrib/groff/src/devices/grotty/tty.cc deleted file mode 100644 index 7cfb658..0000000 --- a/contrib/groff/src/devices/grotty/tty.cc +++ /dev/null @@ -1,776 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-2000, 2001, 2002 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" - -extern "C" const char *Version_string; - -#define putstring(s) fputs(s, stdout) - -#ifndef SHRT_MIN -#define SHRT_MIN (-32768) -#endif - -#ifndef SHRT_MAX -#define SHRT_MAX 32767 -#endif - -#define TAB_WIDTH 8 - -static int horizontal_tab_flag = 0; -static int form_feed_flag = 0; -static int bold_flag = 1; -static int underline_flag = 1; -static int overstrike_flag = 1; -static int draw_flag = 1; -static int italic_flag = 0; -static int reverse_flag = 0; -static int old_drawing_scheme = 0; - -enum { - UNDERLINE_MODE = 0x01, - BOLD_MODE = 0x02, - VDRAW_MODE = 0x04, - HDRAW_MODE = 0x08, - CU_MODE = 0x10, - COLOR_CHANGE = 0x20 -}; - -// Mode to use for bold-underlining. -static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE; - -#ifndef IS_EBCDIC_HOST -#define CSI "\033[" -#else -#define CSI "\047[" -#endif - -// SGR handling (ISO 6429) -#define SGR_BOLD CSI "1m" -#define SGR_NO_BOLD CSI "22m" -#define SGR_ITALIC CSI "3m" -#define SGR_NO_ITALIC CSI "23m" -#define SGR_UNDERLINE CSI "4m" -#define SGR_NO_UNDERLINE CSI "24m" -#define SGR_REVERSE CSI "7m" -#define SGR_NO_REVERSE CSI "27m" -// many terminals can't handle `CSI 39 m' and `CSI 49 m' to reset -// the foreground and bachground color, respectively; thus we use -// `CSI 0 m' exclusively -#define SGR_DEFAULT CSI "0m" - -#define TTY_MAX_COLORS 8 -#define DEFAULT_COLOR_IDX TTY_MAX_COLORS - -class tty_font : public font { - tty_font(const char *); - unsigned char mode; -public: - ~tty_font(); - unsigned char get_mode() { return mode; } -#if 0 - void handle_x_command(int argc, const char **argv); -#endif - static tty_font *load_tty_font(const char *); -}; - -tty_font *tty_font::load_tty_font(const char *s) -{ - tty_font *f = new tty_font(s); - if (!f->load()) { - delete f; - return 0; - } - const char *num = f->get_internal_name(); - long n; - if (num != 0 && (n = strtol(num, 0, 0)) != 0) - f->mode = int(n & (BOLD_MODE|UNDERLINE_MODE)); - if (!underline_flag) - f->mode &= ~UNDERLINE_MODE; - if (!bold_flag) - f->mode &= ~BOLD_MODE; - if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE)) - f->mode = (f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) | bold_underline_mode; - return f; -} - -tty_font::tty_font(const char *nm) -: font(nm), mode(0) -{ -} - -tty_font::~tty_font() -{ -} - -#if 0 -void tty_font::handle_x_command(int argc, const char **argv) -{ - if (argc >= 1 && strcmp(argv[0], "bold") == 0) - mode |= BOLD_MODE; - else if (argc >= 1 && strcmp(argv[0], "underline") == 0) - mode |= UNDERLINE_MODE; -} -#endif - -class glyph { - static glyph *free_list; -public: - glyph *next; - short hpos; - unsigned int code; - unsigned char mode; - unsigned char back_color_idx; - unsigned char fore_color_idx; - void *operator new(size_t); - void operator delete(void *); - inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); } - inline int order() { - return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE|COLOR_CHANGE); } -}; - -glyph *glyph::free_list = 0; - -void *glyph::operator new(size_t) -{ - if (!free_list) { - const int BLOCK = 1024; - free_list = (glyph *)new char[sizeof(glyph) * BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK - 1].next = 0; - } - glyph *p = free_list; - free_list = free_list->next; - p->next = 0; - return p; -} - -void glyph::operator delete(void *p) -{ - if (p) { - ((glyph *)p)->next = free_list; - free_list = (glyph *)p; - } -} - -class tty_printer : public printer { - int is_utf8; - glyph **lines; - int nlines; - int cached_v; - int cached_vpos; - unsigned char curr_fore_idx; - unsigned char curr_back_idx; - int is_underline; - int is_bold; - int cu_flag; - color tty_colors[TTY_MAX_COLORS]; - void make_underline(); - void make_bold(unsigned int); - unsigned char color_to_idx(color *col); - void add_char(unsigned int, int, int, color *, color *, unsigned char); -public: - tty_printer(const char *device); - ~tty_printer(); - void set_char(int, font *, const environment *, int, const char *name); - void draw(int code, int *p, int np, const environment *env); - void special(char *arg, const environment *env, char type); - void change_color(const environment *env); - void change_fill_color(const environment *env); - void put_char(unsigned int); - void put_color(unsigned char, int); - void begin_page(int) { } - void end_page(int page_length); - font *make_font(const char *); -}; - -tty_printer::tty_printer(const char *device) : cached_v(0) -{ - is_utf8 = !strcmp(device, "utf8"); - tty_colors[0].set_rgb(0, // black - 0, - 0); - tty_colors[1].set_rgb(color::MAX_COLOR_VAL, // red - 0, - 0); - tty_colors[2].set_rgb(0, // green - color::MAX_COLOR_VAL, - 0); - tty_colors[3].set_rgb(color::MAX_COLOR_VAL, // yellow - color::MAX_COLOR_VAL, - 0); - tty_colors[4].set_rgb(0, // blue - 0, - color::MAX_COLOR_VAL); - tty_colors[5].set_rgb(color::MAX_COLOR_VAL, // magenta - 0, - color::MAX_COLOR_VAL); - tty_colors[6].set_rgb(0, // cyan - color::MAX_COLOR_VAL, - color::MAX_COLOR_VAL); - tty_colors[7].set_rgb(color::MAX_COLOR_VAL, // white - color::MAX_COLOR_VAL, - color::MAX_COLOR_VAL); - nlines = 66; - lines = new glyph *[nlines]; - for (int i = 0; i < nlines; i++) - lines[i] = 0; - cu_flag = 0; -} - -tty_printer::~tty_printer() -{ - a_delete lines; -} - -void tty_printer::make_underline() -{ - if (old_drawing_scheme) { - putchar('_'); - putchar('\b'); - } - else { - if (!is_underline) { - if (italic_flag) - putstring(SGR_ITALIC); - else if (reverse_flag) - putstring(SGR_REVERSE); - else - putstring(SGR_UNDERLINE); - } - is_underline = 1; - } -} - -void tty_printer::make_bold(unsigned int c) -{ - if (old_drawing_scheme) { - put_char(c); - putchar('\b'); - } - else { - if (!is_bold) - putstring(SGR_BOLD); - is_bold = 1; - } -} - -unsigned char tty_printer::color_to_idx(color *col) -{ - if (col->is_default()) - return DEFAULT_COLOR_IDX; - for (int i = 0; i < TTY_MAX_COLORS; i++) - if (*col == tty_colors[i]) - return (unsigned char)i; - unsigned r, g, b; - col->get_rgb(&r, &g, &b); - error("Unknown color (%1, %2, %3) mapped to default", r, g, b); - return DEFAULT_COLOR_IDX; -} - -void tty_printer::set_char(int i, font *f, const environment *env, - int w, const char *name) -{ - if (w != font::hor) - fatal("width of character not equal to horizontal resolution"); - add_char(f->get_code(i), - env->hpos, env->vpos, - env->col, env->fill, - ((tty_font *)f)->get_mode()); -} - -void tty_printer::add_char(unsigned int c, - int h, int v, - color *fore, color *back, - unsigned char mode) -{ -#if 0 - // This is too expensive. - if (h % font::hor != 0) - fatal("horizontal position not a multiple of horizontal resolution"); -#endif - int hpos = h / font::hor; - if (hpos < SHRT_MIN || hpos > SHRT_MAX) { - error("character with ridiculous horizontal position discarded"); - return; - } - int vpos; - if (v == cached_v && cached_v != 0) - vpos = cached_vpos; - else { - if (v % font::vert != 0) - fatal("vertical position not a multiple of vertical resolution"); - vpos = v / font::vert; - if (vpos > nlines) { - glyph **old_lines = lines; - lines = new glyph *[vpos + 1]; - memcpy(lines, old_lines, nlines * sizeof(glyph *)); - for (int i = nlines; i <= vpos; i++) - lines[i] = 0; - a_delete old_lines; - nlines = vpos + 1; - } - // Note that the first output line corresponds to groff - // position font::vert. - if (vpos <= 0) { - error("character above first line discarded"); - return; - } - cached_v = v; - cached_vpos = vpos; - } - glyph *g = new glyph; - g->hpos = hpos; - g->code = c; - g->fore_color_idx = color_to_idx(fore); - g->back_color_idx = color_to_idx(back); - g->mode = mode; - - // The list will be reversed later. After reversal, it must be in - // increasing order of hpos, with COLOR_CHANGE and CU specials before - // HDRAW characters before VDRAW characters before normal characters - // at each hpos, and otherwise in order of occurrence. - - glyph **pp; - for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next) - if ((*pp)->hpos < hpos - || ((*pp)->hpos == hpos && (*pp)->order() >= g->order())) - break; - g->next = *pp; - *pp = g; -} - -void tty_printer::special(char *arg, const environment *env, char type) -{ - if (type == 'u') { - add_char(*arg - '0', env->hpos, env->vpos, env->col, env->fill, CU_MODE); - return; - } - if (type != 'p') - return; - char *p; - for (p = arg; *p == ' ' || *p == '\n'; p++) - ; - char *tag = p; - for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++) - ; - if (*p == '\0' || strncmp(tag, "tty", p - tag) != 0) { - error("X command without `tty:' tag ignored"); - return; - } - p++; - for (; *p == ' ' || *p == '\n'; p++) - ; - char *command = p; - for (; *p != '\0' && *p != ' ' && *p != '\n'; p++) - ; - if (*command == '\0') { - error("empty X command ignored"); - return; - } - if (strncmp(command, "sgr", p - command) == 0) { - for (; *p == ' ' || *p == '\n'; p++) - ; - int n; - if (*p != '\0' && sscanf(p, "%d", &n) == 1 && n == 0) - old_drawing_scheme = 1; - else - old_drawing_scheme = 0; - } -} - -void tty_printer::change_color(const environment *env) -{ - add_char(0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE); -} - -void tty_printer::change_fill_color(const environment *env) -{ - add_char(0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE); -} - -void tty_printer::draw(int code, int *p, int np, const environment *env) -{ - if (code != 'l' || !draw_flag) - return; - if (np != 2) { - error("2 arguments required for line"); - return; - } - if (p[0] == 0) { - // vertical line - int v = env->vpos; - int len = p[1]; - if (len < 0) { - v += len; - len = -len; - } - while (len >= 0) { - add_char('|', env->hpos, v, env->col, env->fill, VDRAW_MODE); - len -= font::vert; - v += font::vert; - } - } - if (p[1] == 0) { - // horizontal line - int h = env->hpos; - int len = p[0]; - if (len < 0) { - h += len; - len = -len; - } - while (len >= 0) { - add_char('-', h, env->vpos, env->col, env->fill, HDRAW_MODE); - len -= font::hor; - h += font::hor; - } - } -} - -void tty_printer::put_char(unsigned int wc) -{ - if (is_utf8 && wc >= 0x80) { - char buf[6 + 1]; - int count; - char *p = buf; - if (wc < 0x800) - count = 1, *p = (unsigned char)((wc >> 6) | 0xc0); - else if (wc < 0x10000) - count = 2, *p = (unsigned char)((wc >> 12) | 0xe0); - else if (wc < 0x200000) - count = 3, *p = (unsigned char)((wc >> 18) | 0xf0); - else if (wc < 0x4000000) - count = 4, *p = (unsigned char)((wc >> 24) | 0xf8); - else if (wc <= 0x7fffffff) - count = 5, *p = (unsigned char)((wc >> 30) | 0xfC); - else - return; - do *++p = (unsigned char)(((wc >> (6 * --count)) & 0x3f) | 0x80); - while (count > 0); - *++p = '\0'; - putstring(buf); - } - else - putchar(wc); -} - -void tty_printer::put_color(unsigned char color_index, int back) -{ - if (color_index == DEFAULT_COLOR_IDX) { - putstring(SGR_DEFAULT); - // set bold and underline again - if (is_bold) - putstring(SGR_BOLD); - if (is_underline) { - if (italic_flag) - putstring(SGR_ITALIC); - else if (reverse_flag) - putstring(SGR_REVERSE); - else - putstring(SGR_UNDERLINE); - } - // set other color again - back = !back; - color_index = back ? curr_back_idx : curr_fore_idx; - } - putstring(CSI); - if (back) - putchar('4'); - else - putchar('3'); - putchar(color_index + '0'); - putchar('m'); -} - -void tty_printer::end_page(int page_length) -{ - if (page_length % font::vert != 0) - error("vertical position at end of page not multiple of vertical resolution"); - int lines_per_page = page_length / font::vert; - int last_line; - for (last_line = nlines; last_line > 0; last_line--) - if (lines[last_line - 1]) - break; -#if 0 - if (last_line > lines_per_page) { - error("characters past last line discarded"); - do { - --last_line; - while (lines[last_line]) { - glyph *tem = lines[last_line]; - lines[last_line] = tem->next; - delete tem; - } - } while (last_line > lines_per_page); - } -#endif - for (int i = 0; i < last_line; i++) { - glyph *p = lines[i]; - lines[i] = 0; - glyph *g = 0; - while (p) { - glyph *tem = p->next; - p->next = g; - g = p; - p = tem; - } - int hpos = 0; - glyph *nextp; - curr_fore_idx = DEFAULT_COLOR_IDX; - curr_back_idx = DEFAULT_COLOR_IDX; - is_underline = 0; - is_bold = 0; - for (p = g; p; delete p, p = nextp) { - nextp = p->next; - if (p->mode & CU_MODE) { - cu_flag = p->code; - continue; - } - if (nextp && p->hpos == nextp->hpos) { - if (p->draw_mode() == HDRAW_MODE && - nextp->draw_mode() == VDRAW_MODE) { - nextp->code = '+'; - continue; - } - if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) { - nextp->code = p->code; - continue; - } - if (!overstrike_flag) - continue; - } - if (hpos > p->hpos) { - do { - putchar('\b'); - hpos--; - } while (hpos > p->hpos); - } - else { - if (horizontal_tab_flag) { - for (;;) { - int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH; - if (next_tab_pos > p->hpos) - break; - if (cu_flag) - make_underline(); - else if (!old_drawing_scheme && is_underline) { - if (italic_flag) - putstring(SGR_NO_ITALIC); - else if (reverse_flag) - putstring(SGR_NO_REVERSE); - else - putstring(SGR_NO_UNDERLINE); - is_underline = 0; - } - putchar('\t'); - hpos = next_tab_pos; - } - } - for (; hpos < p->hpos; hpos++) { - if (cu_flag) - make_underline(); - else if (!old_drawing_scheme && is_underline) { - if (italic_flag) - putstring(SGR_NO_ITALIC); - else if (reverse_flag) - putstring(SGR_NO_REVERSE); - else - putstring(SGR_NO_UNDERLINE); - is_underline = 0; - } - putchar(' '); - } - } - assert(hpos == p->hpos); - if (p->mode & COLOR_CHANGE) { - if (!old_drawing_scheme) { - if (p->fore_color_idx != curr_fore_idx) { - put_color(p->fore_color_idx, 0); - curr_fore_idx = p->fore_color_idx; - } - if (p->back_color_idx != curr_back_idx) { - put_color(p->back_color_idx, 1); - curr_back_idx = p->back_color_idx; - } - } - continue; - } - if (p->mode & UNDERLINE_MODE) - make_underline(); - else if (!old_drawing_scheme && is_underline) { - if (italic_flag) - putstring(SGR_NO_ITALIC); - else if (reverse_flag) - putstring(SGR_NO_REVERSE); - else - putstring(SGR_NO_UNDERLINE); - is_underline = 0; - } - if (p->mode & BOLD_MODE) - make_bold(p->code); - else if (!old_drawing_scheme && is_bold) { - putstring(SGR_NO_BOLD); - is_bold = 0; - } - if (!old_drawing_scheme) { - if (p->fore_color_idx != curr_fore_idx) { - put_color(p->fore_color_idx, 0); - curr_fore_idx = p->fore_color_idx; - } - if (p->back_color_idx != curr_back_idx) { - put_color(p->back_color_idx, 1); - curr_back_idx = p->back_color_idx; - } - } - put_char(p->code); - hpos++; - } - if (!old_drawing_scheme - && (is_bold || is_underline - || curr_fore_idx != DEFAULT_COLOR_IDX - || curr_back_idx != DEFAULT_COLOR_IDX)) - putstring(SGR_DEFAULT); - putchar('\n'); - } - if (form_feed_flag) { - if (last_line < lines_per_page) - putchar('\f'); - } - else { - for (; last_line < lines_per_page; last_line++) - putchar('\n'); - } -} - -font *tty_printer::make_font(const char *nm) -{ - return tty_font::load_tty_font(nm); -} - -printer *make_printer() -{ - return new tty_printer(device); -} - -static void usage(FILE *stream); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - if (getenv("GROFF_NO_SGR")) - old_drawing_scheme = 1; - setbuf(stderr, stderr_buf); - int c; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((c = getopt_long(argc, argv, "bBcdfF:hioruUv", long_options, NULL)) - != EOF) - switch(c) { - case 'v': - printf("GNU grotty (groff) version %s\n", Version_string); - exit(0); - break; - case 'i': - // Use italic font instead of underlining. - italic_flag = 1; - break; - case 'b': - // Do not embolden by overstriking. - bold_flag = 0; - break; - case 'c': - // Use old scheme for emboldening and underline. - old_drawing_scheme = 1; - break; - case 'u': - // Do not underline. - underline_flag = 0; - break; - case 'o': - // Do not overstrike (other than emboldening and underlining). - overstrike_flag = 0; - break; - case 'r': - // Use reverse mode instead of underlining. - reverse_flag = 1; - break; - case 'B': - // Do bold-underlining as bold. - bold_underline_mode = BOLD_MODE; - break; - case 'U': - // Do bold-underlining as underlining. - bold_underline_mode = UNDERLINE_MODE; - break; - case 'h': - // Use horizontal tabs. - horizontal_tab_flag = 1; - break; - case 'f': - form_feed_flag = 1; - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'd': - // Ignore \D commands. - draw_flag = 0; - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - if (old_drawing_scheme) { - italic_flag = 0; - reverse_flag = 0; - } - else { - bold_underline_mode = BOLD_MODE|UNDERLINE_MODE; - bold_flag = 1; - underline_flag = 1; - } - if (optind >= argc) - do_file("-"); - else { - for (int i = optind; i < argc; i++) - do_file(argv[i]); - } - delete pr; - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-bBcdfhioruUv] [-F dir] [files ...]\n", - program_name); -} diff --git a/contrib/groff/src/libs/libbib/common.cc b/contrib/groff/src/libs/libbib/common.cc deleted file mode 100644 index 4b2bcca..0000000 --- a/contrib/groff/src/libs/libbib/common.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* 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. */ - -unsigned hash(const char *s, int len) -{ -#if 0 - unsigned h = 0, g; - while (*s != '\0') { - h <<= 4; - h += *s++; - if ((g = h & 0xf0000000) != 0) { - h ^= g >> 24; - h ^= g; - } - } -#endif - unsigned h = 0; - while (--len >= 0) - h = *s++ + 65587*h; - return h; -} - diff --git a/contrib/groff/src/libs/libbib/index.cc b/contrib/groff/src/libs/libbib/index.cc deleted file mode 100644 index 3633df1..0000000 --- a/contrib/groff/src/libs/libbib/index.cc +++ /dev/null @@ -1,640 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001 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 "lib.h" - -#include -#include - -#include "posix.h" -#include "cset.h" -#include "cmap.h" -#include "errarg.h" -#include "error.h" - -#include "refid.h" -#include "search.h" -#include "index.h" -#include "defs.h" - -#include "nonposix.h" - -// Interface to mmap. -extern "C" { - void *mapread(int fd, int len); - int unmap(void *, int len); -} - -#if 0 -const -#endif -int minus_one = -1; - -int verify_flag = 0; - -struct word_list; - -class index_search_item : public search_item { - search_item *out_of_date_files; - index_header header; - char *buffer; - void *map_addr; - int map_len; - tag *tags; - int *table; - int *lists; - char *pool; - char *key_buffer; - char *filename_buffer; - int filename_buflen; - char **common_words_table; - int common_words_table_size; - const char *ignore_fields; - time_t mtime; - - const char *do_verify(); - const int *search1(const char **pp, const char *end); - const int *search(const char *ptr, int length, int **temp_listp); - const char *munge_filename(const char *); - void read_common_words_file(); - void add_out_of_date_file(int fd, const char *filename, int fid); -public: - index_search_item(const char *, int); - ~index_search_item(); - int load(int fd); - search_item_iterator *make_search_item_iterator(const char *); - int verify(); - void check_files(); - int next_filename_id() const; - friend class index_search_item_iterator; -}; - -class index_search_item_iterator : public search_item_iterator { - index_search_item *indx; - search_item_iterator *out_of_date_files_iter; - search_item *next_out_of_date_file; - const int *found_list; - int *temp_list; - char *buf; - int buflen; - linear_searcher searcher; - char *query; - int get_tag(int tagno, const linear_searcher &, const char **, int *, - reference_id *); -public: - index_search_item_iterator(index_search_item *, const char *); - ~index_search_item_iterator(); - int next(const linear_searcher &, const char **, int *, reference_id *); -}; - - -index_search_item::index_search_item(const char *filename, int fid) -: search_item(filename, fid), out_of_date_files(0), buffer(0), map_addr(0), - map_len(0), key_buffer(0), filename_buffer(0), filename_buflen(0), - common_words_table(0) -{ -} - -index_search_item::~index_search_item() -{ - if (buffer) - free(buffer); - if (map_addr) { - if (unmap(map_addr, map_len) < 0) - error("unmap: %1", strerror(errno)); - } - while (out_of_date_files) { - search_item *tem = out_of_date_files; - out_of_date_files = out_of_date_files->next; - delete tem; - } - a_delete filename_buffer; - a_delete key_buffer; - if (common_words_table) { - for (int i = 0; i < common_words_table_size; i++) - a_delete common_words_table[i]; - a_delete common_words_table; - } -} - -class file_closer { - int *fdp; -public: - file_closer(int &fd) : fdp(&fd) { } - ~file_closer() { close(*fdp); } -}; - -// Tell the compiler that a variable is intentionally unused. -inline void unused(void *) { } - -int index_search_item::load(int fd) -{ - file_closer fd_closer(fd); // close fd on return - unused(&fd_closer); - struct stat sb; - if (fstat(fd, &sb) < 0) { - error("can't fstat `%1': %2", name, strerror(errno)); - return 0; - } - if (!S_ISREG(sb.st_mode)) { - error("`%1' is not a regular file", name); - return 0; - } - mtime = sb.st_mtime; - int size = int(sb.st_size); - char *addr; - map_addr = mapread(fd, size); - if (map_addr) { - addr = (char *)map_addr; - map_len = size; - } - else { - addr = buffer = (char *)malloc(size); - if (buffer == 0) { - error("can't allocate buffer for `%1'", name); - return 0; - } - char *ptr = buffer; - int bytes_to_read = size; - while (bytes_to_read > 0) { - int nread = read(fd, ptr, bytes_to_read); - if (nread == 0) { - error("unexpected EOF on `%1'", name); - return 0; - } - if (nread < 0) { - error("read error on `%1': %2", name, strerror(errno)); - return 0; - } - bytes_to_read -= nread; - ptr += nread; - } - } - header = *(index_header *)addr; - if (header.magic != INDEX_MAGIC) { - error("`%1' is not an index file: wrong magic number", name); - return 0; - } - if (header.version != INDEX_VERSION) { - error("version number in `%1' is wrong: was %2, should be %3", - name, header.version, INDEX_VERSION); - return 0; - } - int sz = (header.tags_size * sizeof(tag) - + header.lists_size * sizeof(int) - + header.table_size * sizeof(int) - + header.strings_size - + sizeof(header)); - if (sz != size) { - error("size of `%1' is wrong: was %2, should be %3", - name, size, sz); - return 0; - } - tags = (tag *)(addr + sizeof(header)); - lists = (int *)(tags + header.tags_size); - table = (int *)(lists + header.lists_size); - pool = (char *)(table + header.table_size); - ignore_fields = strchr(strchr(pool, '\0') + 1, '\0') + 1; - key_buffer = new char[header.truncate]; - read_common_words_file(); - return 1; -} - -const char *index_search_item::do_verify() -{ - if (tags == 0) - return "not loaded"; - if (lists[header.lists_size - 1] >= 0) - return "last list element not negative"; - int i; - for (i = 0; i < header.table_size; i++) { - int li = table[i]; - if (li >= header.lists_size) - return "bad list index"; - if (li >= 0) { - for (int *ptr = lists + li; *ptr >= 0; ptr++) { - if (*ptr >= header.tags_size) - return "bad tag index"; - if (*ptr >= ptr[1] && ptr[1] >= 0) - return "list not ordered"; - } - } - } - for (i = 0; i < header.tags_size; i++) { - if (tags[i].filename_index >= header.strings_size) - return "bad index in tags"; - if (tags[i].length < 0) - return "bad length in tags"; - if (tags[i].start < 0) - return "bad start in tags"; - } - if (pool[header.strings_size - 1] != '\0') - return "last character in pool not nul"; - return 0; -} - -int index_search_item::verify() -{ - const char *reason = do_verify(); - if (!reason) - return 1; - error("`%1' is bad: %2", name, reason); - return 0; -} - -int index_search_item::next_filename_id() const -{ - return filename_id + header.strings_size + 1; -} - -search_item_iterator *index_search_item::make_search_item_iterator( - const char *query) -{ - return new index_search_item_iterator(this, query); -} - -search_item *make_index_search_item(const char *filename, int fid) -{ - char *index_filename = new char[strlen(filename) + sizeof(INDEX_SUFFIX)]; - strcpy(index_filename, filename); - strcat(index_filename, INDEX_SUFFIX); - int fd = open(index_filename, O_RDONLY | O_BINARY); - if (fd < 0) - return 0; - index_search_item *item = new index_search_item(index_filename, fid); - a_delete index_filename; - if (!item->load(fd)) { - close(fd); - delete item; - return 0; - } - else if (verify_flag && !item->verify()) { - delete item; - return 0; - } - else { - item->check_files(); - return item; - } -} - - -index_search_item_iterator::index_search_item_iterator(index_search_item *ind, - const char *q) -: indx(ind), out_of_date_files_iter(0), next_out_of_date_file(0), temp_list(0), - buf(0), buflen(0), - searcher(q, strlen(q), ind->ignore_fields, ind->header.truncate), - query(strsave(q)) -{ - found_list = indx->search(q, strlen(q), &temp_list); - if (!found_list) { - found_list = &minus_one; - warning("all keys would have been discarded in constructing index `%1'", - indx->name); - } -} - -index_search_item_iterator::~index_search_item_iterator() -{ - a_delete temp_list; - a_delete buf; - a_delete query; - delete out_of_date_files_iter; -} - -int index_search_item_iterator::next(const linear_searcher &, - const char **pp, int *lenp, - reference_id *ridp) -{ - if (found_list) { - for (;;) { - int tagno = *found_list; - if (tagno == -1) - break; - found_list++; - if (get_tag(tagno, searcher, pp, lenp, ridp)) - return 1; - } - found_list = 0; - next_out_of_date_file = indx->out_of_date_files; - } - while (next_out_of_date_file) { - if (out_of_date_files_iter == 0) - out_of_date_files_iter - = next_out_of_date_file->make_search_item_iterator(query); - if (out_of_date_files_iter->next(searcher, pp, lenp, ridp)) - return 1; - delete out_of_date_files_iter; - out_of_date_files_iter = 0; - next_out_of_date_file = next_out_of_date_file->next; - } - return 0; -} - -int index_search_item_iterator::get_tag(int tagno, - const linear_searcher &searcher, - const char **pp, int *lenp, - reference_id *ridp) -{ - if (tagno < 0 || tagno >= indx->header.tags_size) { - error("bad tag number"); - return 0; - } - tag *tp = indx->tags + tagno; - const char *filename = indx->munge_filename(indx->pool + tp->filename_index); - int fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) { - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } - struct stat sb; - if (fstat(fd, &sb) < 0) { - error("can't fstat: %1", strerror(errno)); - close(fd); - return 0; - } - time_t mtime = sb.st_mtime; - if (mtime > indx->mtime) { - indx->add_out_of_date_file(fd, filename, - indx->filename_id + tp->filename_index); - return 0; - } - int res = 0; - FILE *fp = fdopen(fd, FOPEN_RB); - if (!fp) { - error("fdopen failed"); - close(fd); - return 0; - } - if (tp->start != 0 && fseek(fp, long(tp->start), 0) < 0) - error("can't seek on `%1': %2", filename, strerror(errno)); - else { - int length = tp->length; - int err = 0; - if (length == 0) { - struct stat sb; - if (fstat(fileno(fp), &sb) < 0) { - error("can't stat `%1': %2", filename, strerror(errno)); - err = 1; - } - else if (!S_ISREG(sb.st_mode)) { - error("`%1' is not a regular file", filename); - err = 1; - } - else - length = int(sb.st_size); - } - if (!err) { - if (length + 2 > buflen) { - a_delete buf; - buflen = length + 2; - buf = new char[buflen]; - } - if (fread(buf + 1, 1, length, fp) != (size_t)length) - error("fread on `%1' failed: %2", filename, strerror(errno)); - else { - buf[0] = '\n'; - // Remove the CR characters from CRLF pairs. - int sidx = 1, didx = 1; - for ( ; sidx < length + 1; sidx++, didx++) - { - if (buf[sidx] == '\r') - { - if (buf[++sidx] != '\n') - buf[didx++] = '\r'; - else - length--; - } - if (sidx != didx) - buf[didx] = buf[sidx]; - } - buf[length + 1] = '\n'; - res = searcher.search(buf + 1, buf + 2 + length, pp, lenp); - if (res && ridp) - *ridp = reference_id(indx->filename_id + tp->filename_index, - tp->start); - } - } - } - fclose(fp); - return res; -} - -const char *index_search_item::munge_filename(const char *filename) -{ - if (IS_ABSOLUTE(filename)) - return filename; - const char *cwd = pool; - int need_slash = (cwd[0] != 0 - && strchr(DIR_SEPS, strchr(cwd, '\0')[-1]) == 0); - int len = strlen(cwd) + strlen(filename) + need_slash + 1; - if (len > filename_buflen) { - a_delete filename_buffer; - filename_buflen = len; - filename_buffer = new char[len]; - } - strcpy(filename_buffer, cwd); - if (need_slash) - strcat(filename_buffer, "/"); - strcat(filename_buffer, filename); - return filename_buffer; -} - -const int *index_search_item::search1(const char **pp, const char *end) -{ - while (*pp < end && !csalnum(**pp)) - *pp += 1; - if (*pp >= end) - return 0; - const char *start = *pp; - while (*pp < end && csalnum(**pp)) - *pp += 1; - int len = *pp - start; - if (len < header.shortest) - return 0; - if (len > header.truncate) - len = header.truncate; - int is_number = 1; - for (int i = 0; i < len; i++) - if (csdigit(start[i])) - key_buffer[i] = start[i]; - else { - key_buffer[i] = cmlower(start[i]); - is_number = 0; - } - if (is_number && !(len == 4 && start[0] == '1' && start[1] == '9')) - return 0; - unsigned hc = hash(key_buffer, len); - if (common_words_table) { - for (int h = hc % common_words_table_size; - common_words_table[h]; - --h) { - if (strlen(common_words_table[h]) == (size_t)len - && memcmp(common_words_table[h], key_buffer, len) == 0) - return 0; - if (h == 0) - h = common_words_table_size; - } - } - int li = table[int(hc % header.table_size)]; - return li < 0 ? &minus_one : lists + li; -} - -static void merge(int *result, const int *s1, const int *s2) -{ - for (; *s1 >= 0; s1++) { - while (*s2 >= 0 && *s2 < *s1) - s2++; - if (*s2 == *s1) - *result++ = *s2; - } - *result++ = -1; -} - -const int *index_search_item::search(const char *ptr, int length, - int **temp_listp) -{ - const char *end = ptr + length; - if (*temp_listp) { - a_delete *temp_listp; - *temp_listp = 0; - } - const int *first_list = 0; - while (ptr < end && (first_list = search1(&ptr, end)) == 0) - ; - if (!first_list) - return 0; - if (*first_list < 0) - return first_list; - const int *second_list = 0; - while (ptr < end && (second_list = search1(&ptr, end)) == 0) - ; - if (!second_list) - return first_list; - if (*second_list < 0) - return second_list; - const int *p; - for (p = first_list; *p >= 0; p++) - ; - int len = p - first_list; - for (p = second_list; *p >= 0; p++) - ; - if (p - second_list < len) - len = p - second_list; - int *matches = new int[len + 1]; - merge(matches, first_list, second_list); - while (ptr < end) { - const int *list = search1(&ptr, end); - if (list != 0) { - if (*list < 0) { - a_delete matches; - return list; - } - merge(matches, matches, list); - if (*matches < 0) { - a_delete matches; - return &minus_one; - } - } - } - *temp_listp = matches; - return matches; -} - -void index_search_item::read_common_words_file() -{ - if (header.common <= 0) - return; - const char *common_words_file = munge_filename(strchr(pool, '\0') + 1); - errno = 0; - FILE *fp = fopen(common_words_file, "r"); - if (!fp) { - error("can't open `%1': %2", common_words_file, strerror(errno)); - return; - } - common_words_table_size = 2*header.common + 1; - while (!is_prime(common_words_table_size)) - common_words_table_size++; - common_words_table = new char *[common_words_table_size]; - for (int i = 0; i < common_words_table_size; i++) - common_words_table[i] = 0; - int count = 0; - int key_len = 0; - for (;;) { - int c = getc(fp); - while (c != EOF && !csalnum(c)) - c = getc(fp); - if (c == EOF) - break; - do { - if (key_len < header.truncate) - key_buffer[key_len++] = cmlower(c); - c = getc(fp); - } while (c != EOF && csalnum(c)); - if (key_len >= header.shortest) { - int h = hash(key_buffer, key_len) % common_words_table_size; - while (common_words_table[h]) { - if (h == 0) - h = common_words_table_size; - --h; - } - common_words_table[h] = new char[key_len + 1]; - memcpy(common_words_table[h], key_buffer, key_len); - common_words_table[h][key_len] = '\0'; - } - if (++count >= header.common) - break; - key_len = 0; - if (c == EOF) - break; - } - fclose(fp); -} - -void index_search_item::add_out_of_date_file(int fd, const char *filename, - int fid) -{ - search_item **pp; - for (pp = &out_of_date_files; *pp; pp = &(*pp)->next) - if ((*pp)->is_named(filename)) - return; - *pp = make_linear_search_item(fd, filename, fid); - warning("`%1' modified since `%2' created", filename, name); -} - -void index_search_item::check_files() -{ - const char *pool_end = pool + header.strings_size; - for (const char *ptr = strchr(ignore_fields, '\0') + 1; - ptr < pool_end; - ptr = strchr(ptr, '\0') + 1) { - const char *path = munge_filename(ptr); - struct stat sb; - if (stat(path, &sb) < 0) - error("can't stat `%1': %2", path, strerror(errno)); - else if (sb.st_mtime > mtime) { - int fd = open(path, O_RDONLY | O_BINARY); - if (fd < 0) - error("can't open `%1': %2", path, strerror(errno)); - else - add_out_of_date_file(fd, path, filename_id + (ptr - pool)); - } - } -} diff --git a/contrib/groff/src/libs/libbib/linear.cc b/contrib/groff/src/libs/libbib/linear.cc deleted file mode 100644 index 1dd902b..0000000 --- a/contrib/groff/src/libs/libbib/linear.cc +++ /dev/null @@ -1,503 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001 - 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 "lib.h" - -#include -#include -#include - -#include "posix.h" -#include "errarg.h" -#include "error.h" -#include "cset.h" -#include "cmap.h" -#include "nonposix.h" - -#include "refid.h" -#include "search.h" - -class file_buffer { - char *buffer; - char *bufend; -public: - file_buffer(); - ~file_buffer(); - int load(int fd, const char *filename); - const char *get_start() const; - const char *get_end() const; -}; - -typedef unsigned char uchar; - -static uchar map[256]; -static uchar inv_map[256][3]; - -struct map_init { - map_init(); -}; - -static map_init the_map_init; - -map_init::map_init() -{ - int i; - for (i = 0; i < 256; i++) - map[i] = csalnum(i) ? cmlower(i) : '\0'; - for (i = 0; i < 256; i++) { - if (cslower(i)) { - inv_map[i][0] = i; - inv_map[i][1] = cmupper(i); - inv_map[i][2] = '\0'; - } - else if (csdigit(i)) { - inv_map[i][0] = i; - inv_map[i][1] = 0; - } - else - inv_map[i][0] = '\0'; - } -} - - -class bmpattern { - char *pat; - int len; - int delta[256]; -public: - bmpattern(const char *pattern, int pattern_length); - ~bmpattern(); - const char *search(const char *p, const char *end) const; - int length() const; -}; - -bmpattern::bmpattern(const char *pattern, int pattern_length) -: len(pattern_length) -{ - pat = new char[len]; - int i; - for (i = 0; i < len; i++) - pat[i] = map[uchar(pattern[i])]; - for (i = 0; i < 256; i++) - delta[i] = len; - for (i = 0; i < len; i++) - for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++) - delta[*inv] = len - i - 1; -} - -const char *bmpattern::search(const char *buf, const char *end) const -{ - int buflen = end - buf; - if (len > buflen) - return 0; - const char *strend; - if (buflen > len*4) - strend = end - len*4; - else - strend = buf; - const char *k = buf + len - 1; - const int *del = delta; - const char *pattern = pat; - for (;;) { - while (k < strend) { - int t = del[uchar(*k)]; - if (!t) - break; - k += t; - k += del[uchar(*k)]; - k += del[uchar(*k)]; - } - while (k < end && del[uchar(*k)] != 0) - k++; - if (k == end) - break; - int j = len - 1; - const char *s = k; - for (;;) { - if (j == 0) - return s; - if (map[uchar(*--s)] != uchar(pattern[--j])) - break; - } - k++; - } - return 0; -} - -bmpattern::~bmpattern() -{ - a_delete pat; -} - -inline int bmpattern::length() const -{ - return len; -} - - -static const char *find_end(const char *bufend, const char *p); - -const char *linear_searcher::search_and_check(const bmpattern *key, - const char *buf, const char *bufend, const char **start) const -{ - assert(buf[-1] == '\n'); - assert(bufend[-1] == '\n'); - const char *ptr = buf; - for (;;) { - const char *found = key->search(ptr, bufend); - if (!found) - break; - if (check_match(buf, bufend, found, key->length(), &ptr, start)) - return found; - } - return 0; -} - -static const char *skip_field(const char *end, const char *p) -{ - for (;;) - if (*p++ == '\n') { - if (p == end || *p == '%') - break; - const char *q; - for (q = p; *q == ' ' || *q == '\t'; q++) - ; - if (*q == '\n') - break; - p = q + 1; - } - return p; -} - -static const char *find_end(const char *bufend, const char *p) -{ - for (;;) - if (*p++ == '\n') { - if (p == bufend) - break; - const char *q; - for (q = p; *q == ' ' || *q == '\t'; q++) - ; - if (*q == '\n') - break; - p = q + 1; - } - return p; -} - - -int linear_searcher::check_match(const char *buf, const char *bufend, - const char *match, int matchlen, - const char **cont, const char **start) const -{ - *cont = match + 1; - // The user is required to supply only the first truncate_len characters - // of the key. If truncate_len <= 0, he must supply all the key. - if ((truncate_len <= 0 || matchlen < truncate_len) - && map[uchar(match[matchlen])] != '\0') - return 0; - - // The character before the match must not be an alphanumeric - // character (unless the alphanumeric character follows one or two - // percent characters at the beginning of the line), nor must it be - // a percent character at the beginning of a line, nor a percent - // character following a percent character at the beginning of a - // line. - - switch (match - buf) { - case 0: - break; - case 1: - if (match[-1] == '%' || map[uchar(match[-1])] != '\0') - return 0; - break; - case 2: - if (map[uchar(match[-1])] != '\0' && match[-2] != '%') - return 0; - if (match[-1] == '%' - && (match[-2] == '\n' || match[-2] == '%')) - return 0; - break; - default: - if (map[uchar(match[-1])] != '\0' - && !(match[-2] == '%' - && (match[-3] == '\n' - || (match[-3] == '%' && match[-4] == '\n')))) - return 0; - if (match[-1] == '%' - && (match[-2] == '\n' - || (match[-2] == '%' && match[-3] == '\n'))) - return 0; - } - - const char *p = match; - int had_percent = 0; - for (;;) { - if (*p == '\n') { - if (!had_percent && p[1] == '%') { - if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) { - *cont = skip_field(bufend, match + matchlen); - return 0; - } - if (!start) - break; - had_percent = 1; - } - if (p <= buf) { - if (start) - *start = p + 1; - return 1; - } - const char *q; - for (q = p - 1; *q == ' ' || *q == '\t'; q--) - ; - if (*q == '\n') { - if (start) - *start = p + 1; - break; - } - p = q; - } - p--; - } - return 1; -} - -file_buffer::file_buffer() -: buffer(0), bufend(0) -{ -} - -file_buffer::~file_buffer() -{ - a_delete buffer; -} - -const char *file_buffer::get_start() const -{ - return buffer ? buffer + 4 : 0; -} - -const char *file_buffer::get_end() const -{ - return bufend; -} - -int file_buffer::load(int fd, const char *filename) -{ - struct stat sb; - if (fstat(fd, &sb) < 0) - error("can't fstat `%1': %2", filename, strerror(errno)); - else if (!S_ISREG(sb.st_mode)) - error("`%1' is not a regular file", filename); - else { - // We need one character extra at the beginning for an additional newline - // used as a sentinel. We get 4 instead so that the read buffer will be - // word-aligned. This seems to make the read slightly faster. We also - // need one character at the end also for an additional newline used as a - // sentinel. - int size = int(sb.st_size); - buffer = new char[size + 4 + 1]; - int nread = read(fd, buffer + 4, size); - if (nread < 0) - error("error reading `%1': %2", filename, strerror(errno)); - else if (nread != size) - error("size of `%1' decreased", filename); - else { - char c; - nread = read(fd, &c, 1); - if (nread != 0) - error("size of `%1' increased", filename); - else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0) - error("database `%1' is a binary file", filename); - else { - close(fd); - buffer[3] = '\n'; - int sidx = 4, didx = 4; - for ( ; sidx < size + 4; sidx++, didx++) - { - if (buffer[sidx] == '\r') - { - if (buffer[++sidx] != '\n') - buffer[didx++] = '\r'; - else - size--; - } - if (sidx != didx) - buffer[didx] = buffer[sidx]; - } - bufend = buffer + 4 + size; - if (bufend[-1] != '\n') - *bufend++ = '\n'; - return 1; - } - } - a_delete buffer; - buffer = 0; - } - close(fd); - return 0; -} - -linear_searcher::linear_searcher(const char *query, int query_len, - const char *ign, int trunc) -: ignore_fields(ign), truncate_len(trunc), keys(0), nkeys(0) -{ - const char *query_end = query + query_len; - int nk = 0; - const char *p; - for (p = query; p < query_end; p++) - if (map[uchar(*p)] != '\0' - && (p[1] == '\0' || map[uchar(p[1])] == '\0')) - nk++; - if (nk == 0) - return; - keys = new bmpattern*[nk]; - p = query; - for (;;) { - while (p < query_end && map[uchar(*p)] == '\0') - p++; - if (p == query_end) - break; - const char *start = p; - while (p < query_end && map[uchar(*p)] != '\0') - p++; - keys[nkeys++] = new bmpattern(start, p - start); - } - assert(nkeys <= nk); - if (nkeys == 0) { - a_delete keys; - keys = 0; - } -} - -linear_searcher::~linear_searcher() -{ - for (int i = 0; i < nkeys; i++) - delete keys[i]; - a_delete keys; -} - -int linear_searcher::search(const char *buffer, const char *bufend, - const char **startp, int *lengthp) const -{ - assert(bufend - buffer > 0); - assert(buffer[-1] == '\n'); - assert(bufend[-1] == '\n'); - if (nkeys == 0) - return 0; - for (;;) { - const char *refstart; - const char *found = search_and_check(keys[0], buffer, bufend, &refstart); - if (!found) - break; - const char *refend = find_end(bufend, found + keys[0]->length()); - int i; - for (i = 1; i < nkeys; i++) - if (!search_and_check(keys[i], refstart, refend)) - break; - if (i >= nkeys) { - *startp = refstart; - *lengthp = refend - refstart; - return 1; - } - buffer = refend; - } - return 0; -} - -class linear_search_item : public search_item { - file_buffer fbuf; -public: - linear_search_item(const char *filename, int fid); - ~linear_search_item(); - int load(int fd); - search_item_iterator *make_search_item_iterator(const char *); - friend class linear_search_item_iterator; -}; - -class linear_search_item_iterator : public search_item_iterator { - linear_search_item *lsi; - int pos; -public: - linear_search_item_iterator(linear_search_item *, const char *query); - ~linear_search_item_iterator(); - int next(const linear_searcher &, const char **ptr, int *lenp, - reference_id *ridp); -}; - -search_item *make_linear_search_item(int fd, const char *filename, int fid) -{ - linear_search_item *item = new linear_search_item(filename, fid); - if (!item->load(fd)) { - delete item; - return 0; - } - else - return item; -} - -linear_search_item::linear_search_item(const char *filename, int fid) -: search_item(filename, fid) -{ -} - -linear_search_item::~linear_search_item() -{ -} - -int linear_search_item::load(int fd) -{ - return fbuf.load(fd, name); -} - -search_item_iterator *linear_search_item::make_search_item_iterator( - const char *query) -{ - return new linear_search_item_iterator(this, query); -} - -linear_search_item_iterator::linear_search_item_iterator( - linear_search_item *p, const char *) -: lsi(p), pos(0) -{ -} - -linear_search_item_iterator::~linear_search_item_iterator() -{ -} - -int linear_search_item_iterator::next(const linear_searcher &searcher, - const char **startp, int *lengthp, - reference_id *ridp) -{ - const char *bufstart = lsi->fbuf.get_start(); - const char *bufend = lsi->fbuf.get_end(); - const char *ptr = bufstart + pos; - if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) { - pos = *startp + *lengthp - bufstart; - if (ridp) - *ridp = reference_id(lsi->filename_id, *startp - bufstart); - return 1; - } - else - return 0; -} diff --git a/contrib/groff/src/libs/libbib/search.cc b/contrib/groff/src/libs/libbib/search.cc deleted file mode 100644 index 2223fb6..0000000 --- a/contrib/groff/src/libs/libbib/search.cc +++ /dev/null @@ -1,133 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001 - 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 "lib.h" - -#include -#include -#include - -#include "posix.h" -#include "errarg.h" -#include "error.h" -#include "nonposix.h" - -#include "refid.h" -#include "search.h" - -int linear_truncate_len = 6; -const char *linear_ignore_fields = "XYZ"; - -search_list::search_list() -: list(0), niterators(0), next_fid(1) -{ -} - -search_list::~search_list() -{ - assert(niterators == 0); - while (list) { - search_item *tem = list->next; - delete list; - list = tem; - } -} - -void search_list::add_file(const char *filename, int silent) -{ - search_item *p = make_index_search_item(filename, next_fid); - if (!p) { - int fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) { - if (!silent) - error("can't open `%1': %2", filename, strerror(errno)); - } - else - p = make_linear_search_item(fd, filename, next_fid); - } - if (p) { - search_item **pp; - for (pp = &list; *pp; pp = &(*pp)->next) - ; - *pp = p; - next_fid = p->next_filename_id(); - } -} - -int search_list::nfiles() const -{ - int n = 0; - for (search_item *ptr = list; ptr; ptr = ptr->next) - n++; - return n; -} - -search_list_iterator::search_list_iterator(search_list *p, const char *q) -: list(p), ptr(p->list), iter(0), query(strsave(q)), - searcher(q, strlen(q), linear_ignore_fields, linear_truncate_len) -{ - list->niterators += 1; -} - -search_list_iterator::~search_list_iterator() -{ - list->niterators -= 1; - a_delete query; - delete iter; -} - -int search_list_iterator::next(const char **pp, int *lenp, reference_id *ridp) -{ - while (ptr) { - if (iter == 0) - iter = ptr->make_search_item_iterator(query); - if (iter->next(searcher, pp, lenp, ridp)) - return 1; - delete iter; - iter = 0; - ptr = ptr->next; - } - return 0; -} - -search_item::search_item(const char *nm, int fid) -: name(strsave(nm)), filename_id(fid), next(0) -{ -} - -search_item::~search_item() -{ - a_delete name; -} - -int search_item::is_named(const char *nm) const -{ - return strcmp(name, nm) == 0; -} - -int search_item::next_filename_id() const -{ - return filename_id + 1; -} - -search_item_iterator::~search_item_iterator() -{ -} diff --git a/contrib/groff/src/libs/libdriver/input.cc b/contrib/groff/src/libs/libdriver/input.cc deleted file mode 100644 index a02c139..0000000 --- a/contrib/groff/src/libs/libdriver/input.cc +++ /dev/null @@ -1,1814 +0,0 @@ -// -*- C++ -*- - -// /src/libs/libdriver/input.cc - -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 - Free Software Foundation, Inc. - - Written by James Clark (jjc@jclark.com) - Major rewrite 2001 by Bernd Warken (bwarken@mayn.de) - - Last update: 12 Apr 2002 - - This file is part of groff, the GNU roff text processing system. - - 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. -*/ - -/* Description - - This file implements the parser for the intermediate groff output, - see groff_out(5), and does the printout for the given device. - - All parsed information is processed within the function do_file() by - using the global object `pr' of class `printer'. So a device - postprocessor just needs to fill in the methods for the class - `printer' without having to worry about the syntax of the - intermediate output format. Consequently, the programming of groff - postprocessors is similar to the development of device-drivers. - - The prototyping for this file is done in driver.h (and error.h). - - Postprocessor programs must deallocate the global variables `pr' and - `device' using `delete', and `current_filename' using - `free((char *))'. -*/ - -/* Changes of the 2001 rewrite of this file. - - The interface to the outside and the handling of the global - variables was not changed, but internally many necessary changes - were performed. - - The main aim for this rewrite is to provide a first step towards - making groff fully compatible with classical troff without pain. - - Bugs fixed - - Unknown subcommands of `D' and `x' are now ignored like in the - classical case, but a warning is issued. This was also - implemented for the other commands. - - A warning is emitted if `x stop' is missing. - - `DC' and `DE' commands didn't position to the right end after - drawing (now they do), see discussion below. - - So far, `x stop' was ignored. Now it terminates the processing - of the current intermediate output file like the classical troff. - - The command `c' didn't check correctly on white-space. - - The environment stack wasn't suitable for the color extensions - (replaced by a class). - - The old groff parser could only handle a prologue with the first - 3 lines having a fixed structure, while classical troff specified - the sequence of the first 3 commands without further - restrictions. Now the parser is smart about additional - white space, comments, and empty lines in the prologue. - - The old parser allowed space characters only as syntactical - separators, while classical troff had tab characters as well. - Now any sequence of tabs and/or spaces is a syntactical - separator between commands and/or arguments. - - Range checks for numbers implemented. - - New and improved features - - The color commands `m' and `DF' are added. - - The old color command `Df' is now converted and delegated to `DFg'. - - The command `F' is implemented as `use intended file name'. It - checks whether its argument agrees with the file name used so far, - otherwise a warning is issued. Then the new name is remembered - and used for the following error messages. - - For the positioning after drawing commands, an alternative, easier - scheme is provided, but not yet activated; it can be chosen by - undefining the preprocessor macro STUPID_DRAWING_POSITIONING. - It extends the rule of the classical troff output language in a - logical way instead of the rather strange actual positioning. - For details, see the discussion below. - - For the `D' commands that only set the environment, the calling of - pr->send_draw() was removed because this doesn't make sense for - the `DF' commands; the (changed) environment is sent with the - next command anyway. - - Error handling was clearly separated into warnings and fatal. - - The error behavior on additional arguments for `D' and `x' - commands with a fixed number of arguments was changed from being - ignored (former groff) to issue a warning and ignore (now), see - skip_line_x(). No fatal was chosen because both string and - integer arguments can occur. - - The gtroff program issues a trailing dummy integer argument for - some drawing commands with an odd number of arguments to make the - number of arguments even, e.g. the DC and Dt commands; this is - honored now. - - All D commands with a variable number of args expect an even - number of trailing integer arguments, so fatal on error was - implemented. - - Disable environment stack and the commands `{' and `}' by making - them conditional on macro USE_ENV_STACK; actually, this is - undefined by default. There isn't any known application for these - features. - - Cosmetics - - Nested `switch' commands are avoided by using more functions. - Dangerous 'fall-through's avoided. - - Commands and functions are sorted alphabetically (where possible). - - Dynamic arrays/buffers are now implemented as container classes. - - Some functions had an ugly return structure; this has been - streamlined by using classes. - - Use standard C math functions for number handling, so getting rid - of differences to '0'. - - The macro `IntArg' has been created for an easier transition - to guaranteed 32 bits integers (`int' is enough for GNU, while - ANSI only guarantees `long int' to have a length of 32 bits). - - The many usages of type `int' are differentiated by using `Char', - `bool', and `IntArg' where appropriate. - - To ease the calls of the local utility functions, the parser - variables `current_file', `npages', and `current_env' - (formerly env) were made global to the file (formerly they were - local to the do_file() function) - - Various comments were added. - - TODO - - Get rid of the stupid drawing positioning. - - Can the `Dt' command be completely handled by setting environment - within do_file() instead of sending to pr? - - Integer arguments must be >= 32 bits, use conditional #define. - - Add scaling facility for classical device independence and - non-groff devices. Classical troff output had a quasi device - independence by scaling the intermediate output to the resolution - of the postprocessor device if different from the one specified - with `x T', groff have not. So implement full quasi device - indepedence, including the mapping of the strange classical - devices to the postprocessor device (seems to be reasonably - easy). - - The external, global pointer variables are not optimally handled. - - `pr' isn't used outside besides initialization and deletion. - So it could be replaced by a static local variable. For - example, a wrapper class `Postprocessor' for class `printer' with - internal make_printer() and automatic clean-up would make sense. - - The global variables `current_filename' and `current_lineno' are - only used for error reporting. So implement a static class - `Error' (`::' calls). - - The global `device' is the name used during the formatting - process; there should be a new variable for the device name used - during the postprocessing. - - Implement the B-spline drawing `D~' for all graphical devices. - - Make `environment' a class with an overflow check for its members - and a delete method to get rid of delete_current_env(). - - Implement the `EnvStack' to use `new' instead of `malloc'. - - The class definitions of this document could go into a new file. - - The comments in this section should go to a `Changelog' or some - `README' file in this directory. -*/ - -/* - Discussion of the positioning by drawing commands - - There was some confusion about the positioning of the graphical - pointer at the printout after having executed a `D' command. - The classical troff manual of Osanna & Kernighan specified, - - `The position after a graphical object has been drawn is - at its end; for circles and ellipses, the "end" is at the - right side.' - - From this, it follows that - - all open figures (args, splines, and lines) should position at their - final point. - - all circles and ellipses should position at their right-most point - (as if 2 halves had been drawn). - - all closed figures apart from circles and ellipses shouldn't change - the position because they return to their origin. - - all setting commands should not change position because they do not - draw any graphical object. - - In the case of the open figures, this means that the horizontal - displacement is the sum of all odd arguments and the vertical offset - the sum of all even arguments, called the alternate arguments sum - displacement in the following. - - Unfortunately, groff did not implement this simple rule. The former - documentation in groff_out(5) differed from the source code, and - neither of them is compatible with the classical rule. - - The former groff_out(5) specified to use the alternative arguments - sum displacement for calculating the drawing positioning of - non-classical commands, including the `Dt' command (setting-only) - and closed polygons. Applying this to the new groff color commands - will lead to disaster. For their arguments can take large values (> - 65000). On low resolution devices, the displacement of such large - values will corrupt the display or kill the printer. So the - nonsense specification has come to a natural end anyway. - - The groff source code, however, had no positioning for the - setting-only commands (esp. `Dt'), the right-end positioning for - outlined circles and ellipses, and the alternative argument sum - displacement for all other commands (including filled circles and - ellipses). - - The reason why no one seems to have suffered from this mayhem so - far is that the graphical objects are usually generated by - preprocessors like pic that do not depend on the automatic - positioning. When using the low level `\D' escape sequences or `D' - output commands, the strange positionings can be circumvented by - absolute positionings or by tricks like `\Z'. - - So doing an exorcism on the strange, incompatible displacements might - not harm any existing documents, but will make the usage of the - graphical escape sequences and commands natural. - - That's why the rewrite of this file returned to the reasonable, - classical specification with its clear end-of-drawing rule that is - suitable for all cases. But a macro STUPID_DRAWING_POSITIONING is - provided for testing the funny former behavior. - - The new rule implies the following behavior. - - Setting commands (`Dt', `Df', `DF') and polygons (`Dp' and `DP') - do not change position now. - - Filled circles and ellipses (`DC' and `DE') position at their - most right point (outlined ones `Dc' and `De' did this anyway). - - As before, all open graphical objects position to their final - drawing point (alternate sum of the command arguments). - -*/ - -#ifndef STUPID_DRAWING_POSITIONING -// uncomment next line if all non-classical D commands shall position -// to the strange alternate sum of args displacement -#define STUPID_DRAWING_POSITIONING -#endif - -// Decide whether the commands `{' and `}' for different environments -// should be used. -#undef USE_ENV_STACK - -#include "driver.h" -#include "device.h" - -#include -#include -#include -#include - - -/********************************************************************** - local types - **********************************************************************/ - -// integer type used in the fields of struct environment (see printer.h) -typedef int EnvInt; - -// integer arguments of groff_out commands, must be >= 32 bits -typedef int IntArg; - -// color components of groff_out color commands, must be >= 32 bits -typedef unsigned int ColorArg; - -// Array for IntArg values. -class IntArray { - size_t num_allocated; - size_t num_stored; - IntArg *data; -public: - IntArray(void); - IntArray(const size_t); - ~IntArray(void); - const IntArg operator[](const size_t i) const - { - if (i >= num_stored || i < 0) - fatal("index out of range"); - return (const IntArg) data[i]; - } - void append(IntArg); - const IntArg * const - get_data(void) const { return (const IntArg * const) data; } - const size_t len(void) const { return num_stored; } -}; - -// Characters read from the input queue. -class Char { - int data; -public: - Char(void) : data('\0') {} - Char(const int c) : data(c) {} - bool operator==(char c) const { return (data == c) ? true : false; } - bool operator==(int c) const { return (data == c) ? true : false; } - bool operator==(const Char c) const - { return (data == c.data) ? true : false; } - bool operator!=(char c) const { return !(*this == c); } - bool operator!=(int c) const { return !(*this == c); } - bool operator!=(const Char c) const { return !(*this == c); } - operator int() const { return (int) data; } - operator unsigned char() const { return (unsigned char) data; } - operator char() const { return (char) data; } -}; - -// Buffer for string arguments (Char, not char). -class StringBuf { - size_t num_allocated; - size_t num_stored; - Char *data; // not terminated by '\0' -public: - StringBuf(void); // allocate without storing - ~StringBuf(void); - void append(const Char); // append character to `data' - char *make_string(void); // return new copy of `data' with '\0' - bool is_empty(void) { // true if none stored - return (num_stored > 0) ? false : true; - } - void reset(void); // set `num_stored' to 0 -}; - -#ifdef USE_ENV_STACK -class EnvStack { - environment **data; - size_t num_allocated; - size_t num_stored; -public: - EnvStack(void); - ~EnvStack(void); - environment *pop(void); - void push(environment *e); -}; -#endif // USE_ENV_STACK - - -/********************************************************************** - external variables - **********************************************************************/ - -// exported as extern by error.h (called from driver.h) -// needed for error messages (see ../libgroff/error.cc) -const char *current_filename = 0; // printable name of the current file -int current_lineno = 0; // current line number of printout - -// exported as extern by device.h; -const char *device = 0; // cancel former init with literal - -// from driver.h; pr is kept between several runs of do_file() -// extern printer *pr; - -// Note: -// -// We rely on an implementation of the `new' operator which aborts -// gracefully if it can't allocate memory (e.g. from libgroff/new.cc). - - -/********************************************************************** - static local variables - **********************************************************************/ - -FILE *current_file = 0; // current input stream for parser - -// npages: number of pages processed so far (including current page), -// _not_ the page number in the printout (can be set with `p'). -int npages = 0; - -const ColorArg -COLORARG_MAX = (ColorArg) 65536U; // == 0xFFFF + 1 == 0x10000 - -const IntArg -INTARG_MAX = (IntArg) 0x7FFFFFFF; // maximal signed 32 bits number - -// parser environment, created and deleted by each run of do_file() -environment *current_env = 0; - -#ifdef USE_ENV_STACK -const size_t -envp_size = sizeof(environment *); -#endif // USE_ENV_STACK - - -/********************************************************************** - function declarations - **********************************************************************/ - -// utility functions -ColorArg color_from_Df_command(IntArg); - // transform old color into new -void delete_current_env(void); // delete global var current_env -void fatal_command(char); // abort for invalid command -inline Char get_char(void); // read next character from input stream -ColorArg get_color_arg(void); // read in argument for new color cmds -IntArray *get_D_fixed_args(const size_t); - // read in fixed number of integer - // arguments -IntArray *get_D_fixed_args_odd_dummy(const size_t); - // read in a fixed number of integer - // arguments plus optional dummy -IntArray *get_D_variable_args(void); - // variable, even number of int args -char *get_extended_arg(void); // argument for `x X' (several lines) -IntArg get_integer_arg(void); // read in next integer argument -IntArray *get_possibly_integer_args(); - // 0 or more integer arguments -char *get_string_arg(void); // read in next string arg, ended by WS -inline bool is_space_or_tab(const Char); - // test on space/tab char -Char next_arg_begin(void); // skip white space on current line -Char next_command(void); // go to next command, evt. diff. line -inline bool odd(const int); // test if integer is odd -void position_to_end_of_args(const IntArray * const); - // positioning after drawing -void remember_filename(const char *); - // set global current_filename -void send_draw(const Char, const IntArray * const); - // call pr->draw -void skip_line(void); // unconditionally skip to next line -bool skip_line_checked(void); // skip line, false if args are left -void skip_line_fatal(void); // skip line, fatal if args are left -void skip_line_warn(void); // skip line, warn if args are left -void skip_line_D(void); // skip line in D commands -void skip_line_x(void); // skip line in x commands -void skip_to_end_of_line(void); // skip to the end of the current line -inline void unget_char(const Char); - // restore character onto input - -// parser subcommands -void parse_color_command(color *); - // color sub(sub)commands m and DF -void parse_D_command(void); // graphical subcommands -bool parse_x_command(void); // device controller subcommands - - -/********************************************************************** - class methods - **********************************************************************/ - -#ifdef USE_ENV_STACK -EnvStack::EnvStack(void) -{ - num_allocated = 4; - // allocate pointer to array of num_allocated pointers to environment - data = (environment **) malloc(envp_size * num_allocated); - if (data == 0) - fatal("could not allocate environment data"); - num_stored = 0; -} - -EnvStack::~EnvStack(void) -{ - for (size_t i = 0; i < num_stored; i++) - delete data[i]; - free(data); -} - -// return top element from stack and decrease stack pointer -// -// the calling function must take care of properly deleting the result -environment * -EnvStack::pop(void) -{ - num_stored--; - environment *result = data[num_stored]; - data[num_stored] = 0; - return result; -} - -// copy argument and push this onto the stack -void -EnvStack::push(environment *e) -{ - environment *e_copy = new environment; - if (num_stored >= num_allocated) { - environment **old_data = data; - num_allocated *= 2; - data = (environment **) malloc(envp_size * num_allocated); - if (data == 0) - fatal("could not allocate data"); - for (size_t i = 0; i < num_stored; i++) - data[i] = old_data[i]; - free(old_data); - } - e_copy->col = new color; - e_copy->fill = new color; - *e_copy->col = *e->col; - *e_copy->fill = *e->fill; - e_copy->fontno = e->fontno; - e_copy->height = e->height; - e_copy->hpos = e->hpos; - e_copy->size = e->size; - e_copy->slant = e->slant; - e_copy->vpos = e->vpos; - data[num_stored] = e_copy; - num_stored++; -} -#endif // USE_ENV_STACK - -IntArray::IntArray(void) -{ - num_allocated = 4; - data = new IntArg[num_allocated]; - num_stored = 0; -} - -IntArray::IntArray(const size_t n) -{ - if (n <= 0) - fatal("number of integers to be allocated must be > 0"); - num_allocated = n; - data = new IntArg[num_allocated]; - num_stored = 0; -} - -IntArray::~IntArray(void) -{ - a_delete data; -} - -void -IntArray::append(IntArg x) -{ - if (num_stored >= num_allocated) { - IntArg *old_data = data; - num_allocated *= 2; - data = new IntArg[num_allocated]; - for (size_t i = 0; i < num_stored; i++) - data[i] = old_data[i]; - a_delete old_data; - } - data[num_stored] = x; - num_stored++; -} - -StringBuf::StringBuf(void) -{ - num_stored = 0; - num_allocated = 128; - data = new Char[num_allocated]; -} - -StringBuf::~StringBuf(void) -{ - a_delete data; -} - -void -StringBuf::append(const Char c) -{ - if (num_stored >= num_allocated) { - Char *old_data = data; - num_allocated *= 2; - data = new Char[num_allocated]; - for (size_t i = 0; i < num_stored; i++) - data[i] = old_data[i]; - a_delete old_data; - } - data[num_stored] = c; - num_stored++; -} - -char * -StringBuf::make_string(void) -{ - char *result = new char[num_stored + 1]; - for (size_t i = 0; i < num_stored; i++) - result[i] = (char) data[i]; - result[num_stored] = '\0'; - return result; -} - -void -StringBuf::reset(void) -{ - num_stored = 0; -} - -/********************************************************************** - utility functions - **********************************************************************/ - -////////////////////////////////////////////////////////////////////// -/* color_from_Df_command: - Process the gray shade setting command Df. - - Transform Df style color into DF style color. - Df color: 0-1000, 0 is white - DF color: 0-65536, 0 is black - - The Df command is obsoleted by command DFg, but kept for - compatibility. - - XXX: Add proper handling for values < 0 or > 1000 as documented in - groff_out(5). -*/ -ColorArg -color_from_Df_command(IntArg Df_gray) -{ - if (Df_gray <= 0) - return COLORARG_MAX; - if (Df_gray >= 1000) - return 0; - return ColorArg((1000-Df_gray) * COLORARG_MAX / 1000); // scaling -} - -////////////////////////////////////////////////////////////////////// -/* delete_current_env(): - Delete global variable current_env and its pointer members. - - This should be a class method of environment. -*/ -void delete_current_env(void) -{ - delete current_env->col; - delete current_env->fill; - delete current_env; -} - -////////////////////////////////////////////////////////////////////// -/* fatal_command(): - Emit error message about invalid command and abort. -*/ -void -fatal_command(char command) -{ - fatal("`%1' command invalid before first `p' command", command); -} - -////////////////////////////////////////////////////////////////////// -/* get_char(): - Retrieve the next character from the input queue. - - Return: The retrieved character (incl. EOF), converted to Char. -*/ -inline Char -get_char(void) -{ - return (Char) getc(current_file); -} - -////////////////////////////////////////////////////////////////////// -/* get_color_arg(): - Retrieve an argument suitable for the color commands m and DF. - - Return: The retrieved color argument. -*/ -ColorArg -get_color_arg(void) -{ - IntArg x = get_integer_arg(); - if (x < 0 || x > (IntArg)COLORARG_MAX) { - error("color component argument out of range"); - x = 0; - } - return (ColorArg) x; -} - -////////////////////////////////////////////////////////////////////// -/* get_D_fixed_args(): - Get a fixed number of integer arguments for D commands. - - Fatal if wrong number of arguments. - Too many arguments on the line raise a warning. - A line skip is done. - - number: In-parameter, the number of arguments to be retrieved. - ignore: In-parameter, ignore next argument -- GNU troff always emits - pairs of parameters for `D' extensions added by groff. - Default is `false'. - - Return: New IntArray containing the arguments. -*/ -IntArray * -get_D_fixed_args(const size_t number) -{ - if (number <= 0) - fatal("requested number of arguments must be > 0"); - IntArray *args = new IntArray(number); - for (size_t i = 0; i < number; i++) - args->append(get_integer_arg()); - skip_line_D(); - return args; -} - -////////////////////////////////////////////////////////////////////// -/* get_D_fixed_args_odd_dummy(): - Get a fixed number of integer arguments for D commands and optionally - ignore a dummy integer argument if the requested number is odd. - - The gtroff program adds a dummy argument to some commands to get - an even number of arguments. - Error if the number of arguments differs from the scheme above. - A line skip is done. - - number: In-parameter, the number of arguments to be retrieved. - - Return: New IntArray containing the arguments. -*/ -IntArray * -get_D_fixed_args_odd_dummy(const size_t number) -{ - if (number <= 0) - fatal("requested number of arguments must be > 0"); - IntArray *args = new IntArray(number); - for (size_t i = 0; i < number; i++) - args->append(get_integer_arg()); - if (odd(number)) { - IntArray *a = get_possibly_integer_args(); - if (a->len() > 1) - error("too many arguments"); - delete a; - } - skip_line_D(); - return args; -} - -////////////////////////////////////////////////////////////////////// -/* get_D_variable_args(): - Get a variable even number of integer arguments for D commands. - - Get as many integer arguments as possible from the rest of the - current line. - - The arguments are separated by an arbitrary sequence of space or - tab characters. - - A comment, a newline, or EOF indicates the end of processing. - - Error on non-digit characters different from these. - - A final line skip is performed (except for EOF). - - Return: New IntArray of the retrieved arguments. -*/ -IntArray * -get_D_variable_args() -{ - IntArray *args = get_possibly_integer_args(); - size_t n = args->len(); - if (n <= 0) - error("no arguments found"); - if (odd(n)) - error("even number of arguments expected"); - skip_line_D(); - return args; -} - -////////////////////////////////////////////////////////////////////// -/* get_extended_arg(): - Retrieve extended arg for `x X' command. - - - Skip leading spaces and tabs, error on EOL or newline. - - Return everything before the next NL or EOF ('#' is not a comment); - as long as the following line starts with '+' this is returned - as well, with the '+' replaced by a newline. - - Final line skip is always performed. - - Return: Allocated (new) string of retrieved text argument. -*/ -char * -get_extended_arg(void) -{ - StringBuf buf = StringBuf(); - Char c = next_arg_begin(); - while ((int) c != EOF) { - if ((int) c == '\n') { - current_lineno++; - c = get_char(); - if ((int) c == '+') - buf.append((Char) '\n'); - else { - unget_char(c); // first character of next line - break; - } - } - else - buf.append(c); - c = get_char(); - } - return buf.make_string(); -} - -////////////////////////////////////////////////////////////////////// -/* get_integer_arg(): Retrieve integer argument. - - Skip leading spaces and tabs, collect an optional '-' and all - following decimal digits (at least one) up to the next non-digit, - which is restored onto the input queue. - - Fatal error on all other situations. - - Return: Retrieved integer. -*/ -IntArg -get_integer_arg(void) -{ - StringBuf buf = StringBuf(); - Char c = next_arg_begin(); - if ((int) c == '-') { - buf.append(c); - c = get_char(); - } - if (!isdigit((int) c)) - error("integer argument expected"); - while (isdigit((int) c)) { - buf.append(c); - c = get_char(); - } - // c is not a digit - unget_char(c); - char *s = buf.make_string(); - errno = 0; - long int number = strtol(s, 0, 10); - if (errno != 0 - || number > INTARG_MAX || number < -INTARG_MAX) { - error("integer argument too large"); - number = 0; - } - delete s; - return (IntArg) number; -} - -////////////////////////////////////////////////////////////////////// -/* get_possibly_integer_args(): - Parse the rest of the input line as a list of integer arguments. - - Get as many integer arguments as possible from the rest of the - current line, even none. - - The arguments are separated by an arbitrary sequence of space or - tab characters. - - A comment, a newline, or EOF indicates the end of processing. - - Error on non-digit characters different from these. - - No line skip is performed. - - Return: New IntArray of the retrieved arguments. -*/ -IntArray * -get_possibly_integer_args() -{ - bool done = false; - StringBuf buf = StringBuf(); - Char c = get_char(); - IntArray *args = new IntArray(); - while (!done) { - buf.reset(); - while (is_space_or_tab(c)) - c = get_char(); - if (c == '-') { - Char c1 = get_char(); - if (isdigit((int) c1)) { - buf.append(c); - c = c1; - } - else - unget_char(c1); - } - while (isdigit((int) c)) { - buf.append(c); - c = get_char(); - } - if (!buf.is_empty()) { - char *s = buf.make_string(); - errno = 0; - long int x = strtol(s, 0, 10); - if (errno - || x > INTARG_MAX || x < -INTARG_MAX) { - error("invalid integer argument, set to 0"); - x = 0; - } - args->append((IntArg) x); - delete s; - } - // Here, c is not a digit. - // Terminate on comment, end of line, or end of file, while - // space or tab indicate continuation; otherwise error. - switch((int) c) { - case '#': - skip_to_end_of_line(); - done = true; - break; - case '\n': - done = true; - unget_char(c); - break; - case EOF: - done = true; - break; - case ' ': - case '\t': - break; - default: - error("integer argument expected"); - break; - } - } - return args; -} - -////////////////////////////////////////////////////////////////////// -/* get_string_arg(): - Retrieve string arg. - - - Skip leading spaces and tabs; error on EOL or newline. - - Return all following characters before the next space, tab, - newline, or EOF character (in-word '#' is not a comment character). - - The terminating space, tab, newline, or EOF character is restored - onto the input queue, so no line skip. - - Return: Retrieved string as char *, allocated by 'new'. -*/ -char * -get_string_arg(void) -{ - StringBuf buf = StringBuf(); - Char c = next_arg_begin(); - while (!is_space_or_tab(c) - && c != Char('\n') && c != Char(EOF)) { - buf.append(c); - c = get_char(); - } - unget_char(c); // restore white space - return buf.make_string(); -} - -////////////////////////////////////////////////////////////////////// -/* is_space_or_tab(): - Test a character if it is a space or tab. - - c: In-parameter, character to be tested. - - Return: True, if c is a space or tab character, false otherwise. -*/ -inline bool -is_space_or_tab(const Char c) -{ - return (c == Char(' ') || c == Char('\t')) ? true : false; -} - -////////////////////////////////////////////////////////////////////// -/* next_arg_begin(): - Return first character of next argument. - - Skip space and tab characters; error on newline or EOF. - - Return: The first character different from these (including '#'). -*/ -Char -next_arg_begin(void) -{ - Char c; - while (1) { - c = get_char(); - switch ((int) c) { - case ' ': - case '\t': - break; - case '\n': - case EOF: - error("missing argument"); - break; - default: // first essential character - return c; - } - } -} - -////////////////////////////////////////////////////////////////////// -/* next_command(): - Find the first character of the next command. - - Skip spaces, tabs, comments (introduced by #), and newlines. - - Return: The first character different from these (including EOF). -*/ -Char -next_command(void) -{ - Char c; - while (1) { - c = get_char(); - switch ((int) c) { - case ' ': - case '\t': - break; - case '\n': - current_lineno++; - break; - case '#': // comment - skip_line(); - break; - default: // EOF or first essential character - return c; - } - } -} - -////////////////////////////////////////////////////////////////////// -/* odd(): - Test whether argument is an odd number. - - n: In-parameter, the integer to be tested. - - Return: True if odd, false otherwise. -*/ -inline bool -odd(const int n) -{ - return (n & 1 == 1) ? true : false; -} - -////////////////////////////////////////////////////////////////////// -/* position_to_end_of_args(): - Move graphical pointer to end of drawn figure. - - This is used by the D commands that draw open geometrical figures. - The algorithm simply sums up all horizontal displacements (arguments - with even number) for the horizontal component. Similarly, the - vertical component is the sum of the odd arguments. - - args: In-parameter, the arguments of a former drawing command. -*/ -void -position_to_end_of_args(const IntArray * const args) -{ - size_t i; - const size_t n = args->len(); - for (i = 0; i < n; i += 2) - current_env->hpos += (*args)[i]; - for (i = 1; i < n; i += 2) - current_env->vpos += (*args)[i]; -} - -////////////////////////////////////////////////////////////////////// -/* remember_filename(): - Set global variable current_filename. - - The actual filename is stored in current_filename. This is used by - the postprocessors, expecting the name "" for stdin. - - filename: In-out-parameter; is changed to the new value also. -*/ -void -remember_filename(const char *filename) -{ - char *fname; - if (strcmp(filename, "-") == 0) - fname = ""; - else - fname = (char *) filename; - size_t len = strlen(fname) + 1; - if (current_filename != 0) - free((char *)current_filename); - current_filename = (const char *) malloc(len); - if (current_filename == 0) - fatal("can't malloc space for filename"); - strncpy((char *)current_filename, (char *)fname, len); -} - -////////////////////////////////////////////////////////////////////// -/* send_draw(): - Call draw method of printer class. - - subcmd: Letter of actual D subcommand. - args: Array of integer arguments of actual D subcommand. -*/ -void -send_draw(const Char subcmd, const IntArray * const args) -{ - EnvInt n = (EnvInt) args->len(); - pr->draw((int) subcmd, (IntArg *) args->get_data(), n, current_env); -} - -////////////////////////////////////////////////////////////////////// -/* skip_line(): - Go to next line within the input queue. - - Skip the rest of the current line, including the newline character. - The global variable current_lineno is adjusted. - No errors are raised. -*/ -void -skip_line(void) -{ - Char c = get_char(); - while (1) { - if (c == '\n') { - current_lineno++; - break; - } - if (c == EOF) - break; - c = get_char(); - } -} - -////////////////////////////////////////////////////////////////////// -/* skip_line_checked (): - Check that there aren't any arguments left on the rest of the line, - then skip line. - - Spaces, tabs, and a comment are allowed before newline or EOF. - All other characters raise an error. -*/ -bool -skip_line_checked(void) -{ - bool ok = true; - Char c = get_char(); - while (is_space_or_tab(c)) - c = get_char(); - switch((int) c) { - case '#': // comment - skip_line(); - break; - case '\n': - current_lineno++; - break; - case EOF: - break; - default: - ok = false; - skip_line(); - break; - } - return ok; -} - -////////////////////////////////////////////////////////////////////// -/* skip_line_fatal (): - Fatal error if arguments left, otherwise skip line. - - Spaces, tabs, and a comment are allowed before newline or EOF. - All other characters trigger the error. -*/ -void -skip_line_fatal(void) -{ - bool ok = skip_line_checked(); - if (!ok) { - current_lineno--; - error("too many arguments"); - current_lineno++; - } -} - -////////////////////////////////////////////////////////////////////// -/* skip_line_warn (): - Skip line, but warn if arguments are left on actual line. - - Spaces, tabs, and a comment are allowed before newline or EOF. - All other characters raise a warning -*/ -void -skip_line_warn(void) -{ - bool ok = skip_line_checked(); - if (!ok) { - current_lineno--; - warning("too many arguments on current line"); - current_lineno++; - } -} - -////////////////////////////////////////////////////////////////////// -/* skip_line_D (): - Skip line in `D' commands. - - Decide whether in case of an additional argument a fatal error is - raised (the documented classical behavior), only a warning is - issued, or the line is just skipped (former groff behavior). - Actually decided for the warning. -*/ -void -skip_line_D(void) -{ - skip_line_warn(); - // or: skip_line_fatal(); - // or: skip_line(); -} - -////////////////////////////////////////////////////////////////////// -/* skip_line_x (): - Skip line in `x' commands. - - Decide whether in case of an additional argument a fatal error is - raised (the documented classical behavior), only a warning is - issued, or the line is just skipped (former groff behavior). - Actually decided for the warning. -*/ -void -skip_line_x(void) -{ - skip_line_warn(); - // or: skip_line_fatal(); - // or: skip_line(); -} - -////////////////////////////////////////////////////////////////////// -/* skip_to_end_of_line(): - Go to the end of the current line. - - Skip the rest of the current line, excluding the newline character. - The global variable current_lineno is not changed. - No errors are raised. -*/ -void -skip_to_end_of_line(void) -{ - Char c = get_char(); - while (1) { - if (c == '\n') { - unget_char(c); - return; - } - if (c == EOF) - return; - c = get_char(); - } -} - -////////////////////////////////////////////////////////////////////// -/* unget_char(c): - Restore character c onto input queue. - - Write a character back onto the input stream. - EOF is gracefully handled. - - c: In-parameter; character to be pushed onto the input queue. -*/ -inline void -unget_char(const Char c) -{ - if (c != EOF) { - int ch = (int) c; - if (ungetc(ch, current_file) == EOF) - fatal("could not unget character"); - } -} - - -/********************************************************************** - parser subcommands - **********************************************************************/ - -////////////////////////////////////////////////////////////////////// -/* parse_color_command: - Process the commands m and DF, but not Df. - - col: In-out-parameter; the color object to be set, must have - been initialized before. -*/ -void -parse_color_command(color *col) -{ - ColorArg gray = 0; - ColorArg red = 0, green = 0, blue = 0; - ColorArg cyan = 0, magenta = 0, yellow = 0, black = 0; - Char subcmd = next_arg_begin(); - switch((int) subcmd) { - case 'c': // DFc or mc: CMY - cyan = get_color_arg(); - magenta = get_color_arg(); - yellow = get_color_arg(); - col->set_cmy(cyan, magenta, yellow); - break; - case 'd': // DFd or md: set default color - col->set_default(); - break; - case 'g': // DFg or mg: gray - gray = get_color_arg(); - col->set_gray(gray); - break; - case 'k': // DFk or mk: CMYK - cyan = get_color_arg(); - magenta = get_color_arg(); - yellow = get_color_arg(); - black = get_color_arg(); - col->set_cmyk(cyan, magenta, yellow, black); - break; - case 'r': // DFr or mr: RGB - red = get_color_arg(); - green = get_color_arg(); - blue = get_color_arg(); - col->set_rgb(red, green, blue); - break; - default: - error("invalid color scheme `%1'", (int) subcmd); - break; - } // end of color subcommands -} - -////////////////////////////////////////////////////////////////////// -/* parse_D_command(): - Parse the subcommands of graphical command D. - - This is the part of the do_file() parser that scans the graphical - subcommands. - - Error on lacking or wrong arguments. - - Warning on too many arguments. - - Line is always skipped. -*/ -void -parse_D_command() -{ - Char subcmd = next_arg_begin(); - switch((int) subcmd) { - case '~': // D~: draw B-spline - // actually, this isn't available for some postprocessors - // fall through - default: // unknown options are passed to device - { - IntArray *args = get_D_variable_args(); - send_draw(subcmd, args); - position_to_end_of_args(args); - delete args; - break; - } - case 'a': // Da: draw arc - { - IntArray *args = get_D_fixed_args(4); - send_draw(subcmd, args); - position_to_end_of_args(args); - delete args; - break; - } - case 'c': // Dc: draw circle line - { - IntArray *args = get_D_fixed_args(1); - send_draw(subcmd, args); - // move to right end - current_env->hpos += (*args)[0]; - delete args; - break; - } - case 'C': // DC: draw solid circle - { - IntArray *args = get_D_fixed_args_odd_dummy(1); - send_draw(subcmd, args); - // move to right end - current_env->hpos += (*args)[0]; - delete args; - break; - } - case 'e': // De: draw ellipse line - case 'E': // DE: draw solid ellipse - { - IntArray *args = get_D_fixed_args(2); - send_draw(subcmd, args); - // move to right end - current_env->hpos += (*args)[0]; - delete args; - break; - } - case 'f': // Df: set fill gray; obsoleted by DFg - { - IntArg arg = get_integer_arg(); - if ((arg >= 0) && (arg <= 1000)) { - // convert arg and treat it like DFg - ColorArg gray = color_from_Df_command(arg); - current_env->fill->set_gray(gray); - } - else { - // set fill color to the same value as the current outline color - delete current_env->fill; - current_env->fill = new color(current_env->col); - } - pr->change_fill_color(current_env); - // skip unused `vertical' component (\D'...' always emits pairs) - (void) get_integer_arg(); - // no positioning - skip_line_x(); - break; - } - case 'F': // DF: set fill color, several formats - parse_color_command(current_env->fill); - pr->change_fill_color(current_env); - // no positioning (setting-only command) - skip_line_x(); - break; - case 'l': // Dl: draw line - { - IntArray *args = get_D_fixed_args(2); - send_draw(subcmd, args); - position_to_end_of_args(args); - delete args; - break; - } - case 'p': // Dp: draw closed polygon line - case 'P': // DP: draw solid closed polygon - { - IntArray *args = get_D_variable_args(); - send_draw(subcmd, args); -# ifdef STUPID_DRAWING_POSITIONING - // final args positioning - position_to_end_of_args(args); -# endif - delete args; - break; - } - case 't': // Dt: set line thickness - { - IntArray *args = get_D_fixed_args_odd_dummy(1); - send_draw(subcmd, args); -# ifdef STUPID_DRAWING_POSITIONING - // final args positioning - position_to_end_of_args(args); -# endif - // no positioning? - delete args; - break; - } - } // end of D subcommands -} - -////////////////////////////////////////////////////////////////////// -/* parse_x_command(): - Parse subcommands of the device control command x. - - This is the part of the do_file() parser that scans the device - controlling commands. - - Error on duplicate prologue commands. - - Error on wrong or lacking arguments. - - Warning on too many arguments. - - Line is always skipped. - - Globals: - - current_env: is set by many subcommands. - - npages: page counting variable - - Return: boolean in the meaning of `stopped' - - true if parsing should be stopped (`x stop'). - - false if parsing should continue. -*/ -bool -parse_x_command(void) -{ - bool stopped = false; - char *subcmd_str = get_string_arg(); - char subcmd = subcmd_str[0]; - switch (subcmd) { - case 'f': // x font: mount font - { - IntArg n = get_integer_arg(); - char *name = get_string_arg(); - pr->load_font(n, name); - delete name; - skip_line_x(); - break; - } - case 'F': // x Filename: set filename for errors - { - char *str_arg = get_string_arg(); - if (str_arg == 0) - warning("empty argument for `x F' command"); - else { - remember_filename(str_arg); - delete str_arg; - } - break; - } - case 'H': // x Height: set character height - current_env->height = get_integer_arg(); - if (current_env->height == current_env->size) - current_env->height = 0; - skip_line_x(); - break; - case 'i': // x init: initialize device - error("duplicate `x init' command"); - skip_line_x(); - break; - case 'p': // x pause: pause device - skip_line_x(); - break; - case 'r': // x res: set resolution - error("duplicate `x res' command"); - skip_line_x(); - break; - case 's': // x stop: stop device - stopped = true; - skip_line_x(); - break; - case 'S': // x Slant: set slant - current_env->slant = get_integer_arg(); - skip_line_x(); - break; - case 't': // x trailer: generate trailer info - skip_line_x(); - break; - case 'T': // x Typesetter: set typesetter - error("duplicate `x T' command"); - skip_line(); - break; - case 'u': // x underline: from .cu - { - char *str_arg = get_string_arg(); - pr->special(str_arg, current_env, 'u'); - delete str_arg; - skip_line_x(); - break; - } - case 'X': // x X: send uninterpretedly to device - { - char *str_arg = get_extended_arg(); // includes line skip - if (npages <= 0) - error("`x X' command invalid before first `p' command"); - else - pr->special(str_arg, current_env); - delete str_arg; - break; - } - default: // ignore unknown x commands, but warn - warning("unknown command `x %1'", subcmd); - skip_line(); - } - delete subcmd_str; - return stopped; -} - - -/********************************************************************** - exported part (by driver.h) - **********************************************************************/ - -//////////////////////////////////////////////////////////////////////// -/* do_file(): - Parse and postprocess groff intermediate output. - - filename: "-" for standard input, normal file name otherwise -*/ -void -do_file(const char *filename) -{ - Char command; - bool stopped = false; // terminating condition - -#ifdef USE_ENV_STACK - EnvStack env_stack = EnvStack(); -#endif // USE_ENV_STACK - - // setup of global variables - npages = 0; - current_lineno = 1; - // `pr' is initialized after the prologue. - // `device' is set by the 1st prologue command. - - if (filename[0] == '-' && filename[1] == '\0') - current_file = stdin; - else { - errno = 0; - current_file = fopen(filename, "r"); - if (errno != 0 || current_file == 0) { - error("can't open file `%1'", filename); - return; - } - } - remember_filename(filename); - - if (current_env != 0) - delete_current_env(); - current_env = new environment; - current_env->col = new color; - current_env->fill = new color; - current_env->fontno = -1; - current_env->height = 0; - current_env->hpos = -1; - current_env->slant = 0; - current_env->size = 0; - current_env->vpos = -1; - - // parsing of prologue (first 3 commands) - { - char *str_arg; - IntArg int_arg; - - // 1st command `x T' - command = next_command(); - if ((int) command == EOF) - return; - if ((int) command != 'x') - fatal("the first command must be `x T'"); - str_arg = get_string_arg(); - if (str_arg[0] != 'T') - fatal("the first command must be `x T'"); - delete str_arg; - char *tmp_dev = get_string_arg(); - if (pr == 0) { // note: `pr' initialized after prologue - device = tmp_dev; - if (!font::load_desc()) - fatal("couldn't load DESC file, can't continue"); - } - else { - if (device == 0 || strcmp(device, tmp_dev) != 0) - fatal("all files must use the same device"); - delete tmp_dev; - } - skip_line_x(); // ignore further arguments - current_env->size = 10 * font::sizescale; - - // 2nd command `x res' - command = next_command(); - if ((int) command != 'x') - fatal("the second command must be `x res'"); - str_arg = get_string_arg(); - if (str_arg[0] != 'r') - fatal("the second command must be `x res'"); - delete str_arg; - int_arg = get_integer_arg(); - EnvInt font_res = font::res; - if (int_arg != font_res) - fatal("resolution does not match"); - int_arg = get_integer_arg(); - if (int_arg != font::hor) - fatal("minimum horizontal motion does not match"); - int_arg = get_integer_arg(); - if (int_arg != font::vert) - fatal("minimum vertical motion does not match"); - skip_line_x(); // ignore further arguments - - // 3rd command `x init' - command = next_command(); - if (command != 'x') - fatal("the third command must be `x init'"); - str_arg = get_string_arg(); - if (str_arg[0] != 'i') - fatal("the third command must be `x init'"); - delete str_arg; - skip_line_x(); - } - - // parsing of body - if (pr == 0) - pr = make_printer(); - while (!stopped) { - command = next_command(); - if (command == EOF) - break; - // spaces, tabs, comments, and newlines are skipped here - switch ((int) command) { - case '#': // #: comment, ignore up to end of line - skip_line(); - break; -#ifdef USE_ENV_STACK - case '{': // {: start a new environment (a copy) - env_stack.push(current_env); - break; - case '}': // }: pop previous env from stack - delete_current_env(); - current_env = env_stack.pop(); - break; -#endif // USE_ENV_STACK - case '0': // ddc: obsolete jump and print command - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { // expect 2 digits and a character - char s[3]; - Char c = next_arg_begin(); - if (npages <= 0) - fatal_command(command); - if (!isdigit((int) c)) { - error("digit expected"); - c = 0; - } - s[0] = (char) command; - s[1] = (char) c; - s[2] = '\0'; - errno = 0; - long int x = strtol(s, 0, 10); - if (errno != 0) - error("couldn't convert 2 digits"); - EnvInt hor_pos = (EnvInt) x; - current_env->hpos += hor_pos; - c = next_arg_begin(); - if ((int) c == '\n' || (int) c == EOF) - error("character argument expected"); - else - pr->set_ascii_char((unsigned char) c, current_env); - break; - } - case 'c': // c: print ascii char without moving - { - if (npages <= 0) - fatal_command(command); - Char c = next_arg_begin(); - if (c == '\n' || c == EOF) - error("missing argument to `c' command"); - else - pr->set_ascii_char((unsigned char) c, current_env); - break; - } - case 'C': // C: print named special character - { - if (npages <= 0) - fatal_command(command); - char *str_arg = get_string_arg(); - pr->set_special_char(str_arg, current_env); - delete str_arg; - break; - } - case 'D': // drawing commands - if (npages <= 0) - fatal_command(command); - parse_D_command(); - break; - case 'f': // f: set font to number - current_env->fontno = get_integer_arg(); - break; - case 'F': // F: obsolete, replaced by `x F' - { - char *str_arg = get_string_arg(); - remember_filename(str_arg); - delete str_arg; - break; - } - case 'h': // h: relative horizontal move - current_env->hpos += (EnvInt) get_integer_arg(); - break; - case 'H': // H: absolute horizontal positioning - current_env->hpos = (EnvInt) get_integer_arg(); - break; - case 'm': // m: glyph color - parse_color_command(current_env->col); - pr->change_color(current_env); - break; - case 'n': // n: print end of line - // ignore two arguments (historically) - if (npages <= 0) - fatal_command(command); - pr->end_of_line(); - (void) get_integer_arg(); - (void) get_integer_arg(); - break; - case 'N': // N: print char with given int code - if (npages <= 0) - fatal_command(command); - pr->set_numbered_char(get_integer_arg(), current_env); - break; - case 'p': // p: start new page with given number - if (npages > 0) - pr->end_page(current_env->vpos); - npages++; // increment # of processed pages - pr->begin_page(get_integer_arg()); - current_env->vpos = 0; - break; - case 's': // s: set point size - current_env->size = get_integer_arg(); - if (current_env->height == current_env->size) - current_env->height = 0; - break; - case 't': // t: print a text word - { - char c; - if (npages <= 0) - fatal_command(command); - char *str_arg = get_string_arg(); - size_t i = 0; - while ((c = str_arg[i++]) != '\0') { - EnvInt w; - pr->set_ascii_char((unsigned char) c, current_env, &w); - current_env->hpos += w; - } - delete str_arg; - break; - } - case 'u': // u: print spaced word - { - char c; - if (npages <= 0) - fatal_command(command); - EnvInt kern = (EnvInt) get_integer_arg(); - char *str_arg = get_string_arg(); - size_t i = 0; - while ((c = str_arg[i++]) != '\0') { - EnvInt w; - pr->set_ascii_char((unsigned char) c, current_env, &w); - current_env->hpos += w + kern; - } - delete str_arg; - break; - } - case 'v': // v: relative vertical move - current_env->vpos += (EnvInt) get_integer_arg(); - break; - case 'V': // V: absolute vertical positioning - current_env->vpos = (EnvInt) get_integer_arg(); - break; - case 'w': // w: inform about paddable space - break; - case 'x': // device controlling commands - stopped = parse_x_command(); - break; - default: - warning("unrecognized command `%1'", (unsigned char) command); - skip_line(); - break; - } // end of switch - } // end of while - - // end of file reached - if (npages > 0) - pr->end_page(current_env->vpos); - fclose(current_file); - // If `stopped' is not `true' here then there wasn't any `x stop'. - if (!stopped) - warning("no final `x stop' command"); - delete_current_env(); -} diff --git a/contrib/groff/src/libs/libdriver/printer.cc b/contrib/groff/src/libs/libdriver/printer.cc deleted file mode 100644 index c97e2ce..0000000 --- a/contrib/groff/src/libs/libdriver/printer.cc +++ /dev/null @@ -1,216 +0,0 @@ -// -*- C++ -*- - -// /src/libs/libdriver/printer.cc - -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 - Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - - Last update: 12 Apr 2002 - - 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_list(0), font_table(0), nfonts(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 *, char) -{ -} - -void printer::draw(int, int *, int, const environment *) -{ -} - -void printer::change_color(const environment *) -{ -} - -void printer::change_fill_color(const environment *) -{ -} - -void printer::set_ascii_char(unsigned char c, const environment *env, - int *widthp) -{ - char buf[2]; - int w; - font *f; - - buf[0] = c; - buf[1] = '\0'; - - int i = set_char_and_width(buf, env, &w, &f); - set_char(i, f, env, w, 0); - if (widthp) { - *widthp = w; - } -} - -void printer::set_special_char(const char *nm, const environment *env, - int *widthp) -{ - font *f; - int w; - int i = set_char_and_width(nm, env, &w, &f); - if (i != -1) { - set_char(i, f, env, w, nm); - if (widthp) - *widthp = w; - } -} - -int printer::set_char_and_width(const char *nm, const environment *env, - int *widthp, font **f) -{ - int i = font::name_to_index(nm); - int fn = env->fontno; - if (fn < 0 || fn >= nfonts) { - error("bad font position `%1'", fn); - return(-1); - } - *f = font_table[fn]; - if (*f == 0) { - error("no font mounted at `%1'", fn); - return(-1); - } - 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(-1); - } - int w = (*f)->get_width(i, env->size); - if (widthp) - *widthp = w; - return( i ); -} - -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, 0); -} - -font *printer::get_font_from_index(int fontno) -{ - if ((fontno >= 0) && (fontno < nfonts)) - return(font_table[fontno]); - else - return(0); -} diff --git a/contrib/groff/src/libs/libgroff/assert.cc b/contrib/groff/src/libs/libgroff/assert.cc deleted file mode 100644 index 89742e3..0000000 --- a/contrib/groff/src/libs/libgroff/assert.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* 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 -#include -#include "assert.h" - -extern const char *program_name; - -void assertion_failed(int lineno, const char *filename) -{ - if (program_name != 0) - fprintf(stderr, "%s: ", program_name); - fprintf(stderr, "Failed assertion at line %d, file `%s'.\n", - lineno, filename); - fflush(stderr); - abort(); -} diff --git a/contrib/groff/src/libs/libgroff/change_lf.cc b/contrib/groff/src/libs/libgroff/change_lf.cc deleted file mode 100644 index 2e44af1..0000000 --- a/contrib/groff/src/libs/libgroff/change_lf.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* 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 - -extern char *strsave(const char *); - -extern const char *current_filename; -extern int current_lineno; - -void change_filename(const char *f) -{ - if (current_filename != 0 && strcmp(current_filename, f) == 0) - return; - current_filename = strsave(f); -} - -void change_lineno(int ln) -{ - current_lineno = ln; -} diff --git a/contrib/groff/src/libs/libgroff/color.cc b/contrib/groff/src/libs/libgroff/color.cc deleted file mode 100644 index 68e604c..0000000 --- a/contrib/groff/src/libs/libgroff/color.cc +++ /dev/null @@ -1,363 +0,0 @@ -// -*- C++ -*- - -/* /src/libs/libgroff/color.cc - -Last update: 10 Apr 2002 - -Copyright (C) 2001, 2002 Free Software Foundation, Inc. - Written by Gaius Mulley - -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 "color.h" -#include "cset.h" -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include -#include -#include -#include "errarg.h" -#include "error.h" - -static inline unsigned int -min(const unsigned int a, const unsigned int b) -{ - if (a < b) - return a; - else - return b; -} - -color::color(const color * const c) -{ - scheme = c->scheme; - components[0] = c->components[0]; - components[1] = c->components[1]; - components[2] = c->components[2]; - components[3] = c->components[3]; -} - -int color::operator==(const color & c) const -{ - if (scheme != c.scheme) - return 0; - switch (scheme) { - case DEFAULT: - break; - case RGB: - if (Red != c.Red || Green != c.Green || Blue != c.Blue) - return 0; - break; - case CMYK: - if (Cyan != c.Cyan || Magenta != c.Magenta - || Yellow != c.Yellow || Black != c.Black) - return 0; - break; - case GRAY: - if (Gray != c.Gray) - return 0; - break; - case CMY: - if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow) - return 0; - break; - } - return 1; -} - -int color::operator!=(const color & c) const -{ - return !(*this == c); -} - -color_scheme color::get_components(unsigned int *c) const -{ -#if 0 - if (sizeof (c) < sizeof (unsigned int) * 4) - fatal("argument is not big enough to store 4 color components"); -#endif - c[0] = components[0]; - c[1] = components[1]; - c[2] = components[2]; - c[3] = components[3]; - return scheme; -} - -void color::set_default() -{ - scheme = DEFAULT; -} - -// (0, 0, 0) is black - -void color::set_rgb(const unsigned int r, const unsigned int g, - const unsigned int b) -{ - scheme = RGB; - Red = min(MAX_COLOR_VAL, r); - Green = min(MAX_COLOR_VAL, g); - Blue = min(MAX_COLOR_VAL, b); -} - -// (0, 0, 0) is white - -void color::set_cmy(const unsigned int c, const unsigned int m, - const unsigned int y) -{ - scheme = CMY; - Cyan = min(MAX_COLOR_VAL, c); - Magenta = min(MAX_COLOR_VAL, m); - Yellow = min(MAX_COLOR_VAL, y); -} - -// (0, 0, 0, 0) is white - -void color::set_cmyk(const unsigned int c, const unsigned int m, - const unsigned int y, const unsigned int k) -{ - scheme = CMYK; - Cyan = min(MAX_COLOR_VAL, c); - Magenta = min(MAX_COLOR_VAL, m); - Yellow = min(MAX_COLOR_VAL, y); - Black = min(MAX_COLOR_VAL, k); -} - -// (0) is black - -void color::set_gray(const unsigned int g) -{ - scheme = GRAY; - Gray = min(MAX_COLOR_VAL, g); -} - -/* - * atoh - computes the decimal value of a hexadecimal number string. - * `length' characters of `s' are read. Returns 1 if successful. - */ - -static int atoh(unsigned int *result, - const char * const s, const size_t length) -{ - size_t i = 0; - unsigned int val = 0; - while ((i < length) && csxdigit(s[i])) { - if (csdigit(s[i])) - val = val*0x10 + (s[i]-'0'); - else if (csupper(s[i])) - val = val*0x10 + (s[i]-'A') + 10; - else - val = val*0x10 + (s[i]-'a') + 10; - i++; - } - if (i != length) - return 0; - *result = val; - return 1; -} - -/* - * read_encoding - set color from a hexadecimal color string. - * - * Use color scheme `cs' to parse `n' color components from string `s'. - * Returns 1 if successful. - */ - -int color::read_encoding(const color_scheme cs, const char * const s, - const size_t n) -{ - size_t hex_length = 2; - scheme = cs; - char *p = (char *) s; - p++; - if (*p == '#') { - hex_length = 4; - p++; - } - for (size_t i = 0; i < n; i++) { - if (!atoh(&(components[i]), p, hex_length)) - return 0; - if (hex_length == 2) - components[i] *= 0x101; // scale up -- 0xff should become 0xffff - p += hex_length; - } - return 1; -} - -int color::read_rgb(const char * const s) -{ - return read_encoding(RGB, s, 3); -} - -int color::read_cmy(const char * const s) -{ - return read_encoding(CMY, s, 3); -} - -int color::read_cmyk(const char * const s) -{ - return read_encoding(CMYK, s, 4); -} - -int color::read_gray(const char * const s) -{ - return read_encoding(GRAY, s, 1); -} - -void -color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b) const -{ - switch (scheme) { - case RGB: - *r = Red; - *g = Green; - *b = Blue; - break; - case CMY: - *r = MAX_COLOR_VAL - Cyan; - *g = MAX_COLOR_VAL - Magenta; - *b = MAX_COLOR_VAL - Yellow; - break; - case CMYK: - *r = MAX_COLOR_VAL - - min(MAX_COLOR_VAL, - Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); - *g = MAX_COLOR_VAL - - min(MAX_COLOR_VAL, - Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); - *b = MAX_COLOR_VAL - - min(MAX_COLOR_VAL, - Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); - break; - case GRAY: - *r = *g = *b = Gray; - break; - default: - assert(0); - break; - } -} - -void -color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y) const -{ - switch (scheme) { - case RGB: - *c = MAX_COLOR_VAL - Red; - *m = MAX_COLOR_VAL - Green; - *y = MAX_COLOR_VAL - Blue; - break; - case CMY: - *c = Cyan; - *m = Magenta; - *y = Yellow; - break; - case CMYK: - *c = min(MAX_COLOR_VAL, - Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); - *m = min(MAX_COLOR_VAL, - Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); - *y = min(MAX_COLOR_VAL, - Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black); - break; - case GRAY: - *c = *m = *y = MAX_COLOR_VAL - Gray; - break; - default: - assert(0); - break; - } -} - -void color::get_cmyk(unsigned int *c, unsigned int *m, - unsigned int *y, unsigned int *k) const -{ - switch (scheme) { - case RGB: - *k = min(MAX_COLOR_VAL - Red, - min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue)); - if (MAX_COLOR_VAL == *k) { - *c = MAX_COLOR_VAL; - *m = MAX_COLOR_VAL; - *y = MAX_COLOR_VAL; - } - else { - *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k)) - / (MAX_COLOR_VAL - *k); - *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k)) - / (MAX_COLOR_VAL - *k); - *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k)) - / (MAX_COLOR_VAL - *k); - } - break; - case CMY: - *k = min(Cyan, min(Magenta, Yellow)); - if (MAX_COLOR_VAL == *k) { - *c = MAX_COLOR_VAL; - *m = MAX_COLOR_VAL; - *y = MAX_COLOR_VAL; - } - else { - *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k); - *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k); - *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k); - } - break; - case CMYK: - *c = Cyan; - *m = Magenta; - *y = Yellow; - *k = Black; - break; - case GRAY: - *c = *m = *y = 0; - *k = MAX_COLOR_VAL - Gray; - break; - default: - assert(0); - break; - } -} - -// we use `0.222r + 0.707g + 0.071b' (this is the ITU standard) -// as an approximation for gray - -void color::get_gray(unsigned int *g) const -{ - switch (scheme) { - case RGB: - *g = (222*Red + 707*Green + 71*Blue) / 1000; - break; - case CMY: - *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000; - break; - case CMYK: - *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000) - * (MAX_COLOR_VAL - Black); - break; - case GRAY: - *g = Gray; - break; - default: - assert(0); - break; - } -} - -color default_color; diff --git a/contrib/groff/src/libs/libgroff/device.cc b/contrib/groff/src/libs/libgroff/device.cc deleted file mode 100644 index 7efbfef..0000000 --- a/contrib/groff/src/libs/libgroff/device.cc +++ /dev/null @@ -1,36 +0,0 @@ -// -*- 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 -#include "device.h" -#include "defs.h" - -const char *device = DEVICE; - -struct device_init { - device_init(); -} _device_init; - -device_init::device_init() -{ - char *tem = getenv("GROFF_TYPESETTER"); - if (tem) - device = tem; -} diff --git a/contrib/groff/src/libs/libgroff/errarg.cc b/contrib/groff/src/libs/libgroff/errarg.cc deleted file mode 100644 index 2ddc0cc..0000000 --- a/contrib/groff/src/libs/libgroff/errarg.cc +++ /dev/null @@ -1,128 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002 - 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 -#include "assert.h" -#include "errarg.h" - -errarg::errarg(const char *p) : type(STRING) -{ - s = p ? p : "(null)"; -} - -errarg::errarg() : type(EMPTY) -{ -} - -errarg::errarg(int nn) : type(INTEGER) -{ - n = nn; -} - -errarg::errarg(unsigned int uu) : type(UNSIGNED_INTEGER) -{ - u = uu; -} - -errarg::errarg(char cc) : type(CHAR) -{ - c = cc; -} - -errarg::errarg(unsigned char cc) : type(CHAR) -{ - c = cc; -} - -errarg::errarg(double dd) : type(DOUBLE) -{ - d = dd; -} - -int errarg::empty() const -{ - return type == EMPTY; -} - -extern "C" { - const char *i_to_a(int); - const char *ui_to_a(unsigned int); -} - -void errarg::print() const -{ - switch (type) { - case INTEGER: - fputs(i_to_a(n), stderr); - break; - case UNSIGNED_INTEGER: - fputs(ui_to_a(u), stderr); - break; - case CHAR: - putc(c, stderr); - break; - case STRING: - fputs(s, stderr); - break; - case DOUBLE: - fprintf(stderr, "%g", d); - break; - case EMPTY: - break; - } -} - -errarg empty_errarg; - -void errprint(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - assert(format != 0); - char c; - while ((c = *format++) != '\0') { - if (c == '%') { - c = *format++; - switch(c) { - case '%': - fputc('%', stderr); - break; - case '1': - assert(!arg1.empty()); - arg1.print(); - break; - case '2': - assert(!arg2.empty()); - arg2.print(); - break; - case '3': - assert(!arg3.empty()); - arg3.print(); - break; - default: - assert(0); - } - } - else - putc(c, stderr); - } -} diff --git a/contrib/groff/src/libs/libgroff/error.cc b/contrib/groff/src/libs/libgroff/error.cc deleted file mode 100644 index 53fd629..0000000 --- a/contrib/groff/src/libs/libgroff/error.cc +++ /dev/null @@ -1,137 +0,0 @@ -// -*- 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 -#include -#include -#include "errarg.h" -#include "error.h" - -extern void fatal_error_exit(); - -enum error_type { WARNING, ERROR, FATAL }; - -static void do_error_with_file_and_line(const char *filename, int lineno, - error_type type, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - int need_space = 0; - if (program_name) { - fprintf(stderr, "%s:", program_name); - need_space = 1; - } - if (lineno >= 0 && filename != 0) { - if (strcmp(filename, "-") == 0) - filename = ""; - fprintf(stderr, "%s:%d:", filename, lineno); - need_space = 1; - } - switch (type) { - case FATAL: - fputs("fatal error:", stderr); - need_space = 1; - break; - case ERROR: - break; - case WARNING: - fputs("warning:", stderr); - need_space = 1; - break; - } - if (need_space) - fputc(' ', stderr); - errprint(format, arg1, arg2, arg3); - fputc('\n', stderr); - fflush(stderr); - if (type == FATAL) - fatal_error_exit(); -} - - -static void do_error(error_type type, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error_with_file_and_line(current_filename, current_lineno, - type, format, arg1, arg2, arg3); -} - - -void error(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error(ERROR, format, arg1, arg2, arg3); -} - -void warning(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error(WARNING, format, arg1, arg2, arg3); -} - -void fatal(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error(FATAL, format, arg1, arg2, arg3); -} - -void error_with_file_and_line(const char *filename, - int lineno, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error_with_file_and_line(filename, lineno, - ERROR, format, arg1, arg2, arg3); -} - -void warning_with_file_and_line(const char *filename, - int lineno, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error_with_file_and_line(filename, lineno, - WARNING, format, arg1, arg2, arg3); -} - -void fatal_with_file_and_line(const char *filename, - int lineno, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error_with_file_and_line(filename, lineno, - FATAL, format, arg1, arg2, arg3); -} diff --git a/contrib/groff/src/libs/libgroff/fatal.cc b/contrib/groff/src/libs/libgroff/fatal.cc deleted file mode 100644 index 42560dc..0000000 --- a/contrib/groff/src/libs/libgroff/fatal.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* 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 - -#define FATAL_ERROR_EXIT_CODE 3 - -void fatal_error_exit() -{ - exit(FATAL_ERROR_EXIT_CODE); -} diff --git a/contrib/groff/src/libs/libgroff/filename.cc b/contrib/groff/src/libs/libgroff/filename.cc deleted file mode 100644 index 1cbaa93..0000000 --- a/contrib/groff/src/libs/libgroff/filename.cc +++ /dev/null @@ -1 +0,0 @@ -const char *current_filename = 0; diff --git a/contrib/groff/src/libs/libgroff/font.cc b/contrib/groff/src/libs/libgroff/font.cc deleted file mode 100644 index 69e46e1..0000000 --- a/contrib/groff/src/libs/libgroff/font.cc +++ /dev/null @@ -1,1035 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "lib.h" - -#include -#include -#include -#include -#include "errarg.h" -#include "error.h" -#include "cset.h" -#include "font.h" -#include "paper.h" - -const char *const WS = " \t\n\r"; - -struct font_char_metric { - char type; - int code; - int width; - int height; - int depth; - int pre_math_space; - int italic_correction; - int subscript_correction; - char *special_device_coding; -}; - -struct font_kern_list { - int i1; - int i2; - int amount; - font_kern_list *next; - - font_kern_list(int, int, int, font_kern_list * = 0); -}; - -struct font_widths_cache { - font_widths_cache *next; - int point_size; - int *width; - - font_widths_cache(int, int, font_widths_cache * = 0); - ~font_widths_cache(); -}; - -/* text_file */ - -struct text_file { - FILE *fp; - char *path; - int lineno; - int size; - int skip_comments; - char *buf; - text_file(FILE *fp, char *p); - ~text_file(); - int next(); - void error(const char *format, - const errarg &arg1 = empty_errarg, - const errarg &arg2 = empty_errarg, - const errarg &arg3 = empty_errarg); -}; - -text_file::text_file(FILE *p, char *s) -: fp(p), path(s), lineno(0), size(0), skip_comments(1), buf(0) -{ -} - -text_file::~text_file() -{ - a_delete buf; - a_delete path; - if (fp) - fclose(fp); -} - -int text_file::next() -{ - if (fp == 0) - return 0; - if (buf == 0) { - buf = new char[128]; - size = 128; - } - for (;;) { - int i = 0; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - if (invalid_input_char(c)) - error("invalid input character code `%1'", int(c)); - else { - if (i + 1 >= size) { - char *old_buf = buf; - buf = new char[size*2]; - memcpy(buf, old_buf, size); - a_delete old_buf; - size *= 2; - } - buf[i++] = c; - if (c == '\n') - break; - } - } - if (i == 0) - break; - buf[i] = '\0'; - lineno++; - char *ptr = buf; - while (csspace(*ptr)) - ptr++; - if (*ptr != 0 && (!skip_comments || *ptr != '#')) - return 1; - } - return 0; -} - -void text_file::error(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - error_with_file_and_line(path, lineno, format, arg1, arg2, arg3); -} - - -/* font functions */ - -font::font(const char *s) -: ligatures(0), kern_hash_table(0), space_width(0), ch_index(0), nindices(0), - ch(0), ch_used(0), ch_size(0), special(0), widths_cache(0) -{ - name = new char[strlen(s) + 1]; - strcpy(name, s); - internalname = 0; - slant = 0.0; - // load(); // for testing -} - -font::~font() -{ - for (int i = 0; i < ch_used; i++) - if (ch[i].special_device_coding) - a_delete ch[i].special_device_coding; - a_delete ch; - a_delete ch_index; - if (kern_hash_table) { - for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) { - font_kern_list *kerns = kern_hash_table[i]; - while (kerns) { - font_kern_list *tem = kerns; - kerns = kerns->next; - delete tem; - } - } - a_delete kern_hash_table; - } - a_delete name; - a_delete internalname; - while (widths_cache) { - font_widths_cache *tem = widths_cache; - widths_cache = widths_cache->next; - delete tem; - } -} - -static int scale_round(int n, int x, int y) -{ - assert(x >= 0 && y > 0); - int y2 = y/2; - if (x == 0) - return 0; - if (n >= 0) { - if (n <= (INT_MAX - y2)/x) - return (n*x + y2)/y; - return int(n*double(x)/double(y) + .5); - } - else { - if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x) - return (n*x - y2)/y; - return int(n*double(x)/double(y) - .5); - } -} - -inline int font::scale(int w, int sz) -{ - return sz == unitwidth ? w : scale_round(w, sz, unitwidth); -} - -int font::unit_scale(double *value, char unit) -{ - // we scale everything to inch - double divisor = 0; - switch (unit) { - case 'i': - divisor = 1; - break; - case 'p': - divisor = 72; - break; - case 'P': - divisor = 6; - break; - case 'c': - divisor = 2.54; - break; - default: - assert(0); - break; - } - if (divisor) { - *value /= divisor; - return 1; - } - return 0; -} - -int font::get_skew(int c, int point_size, int sl) -{ - int h = get_height(c, point_size); - return int(h*tan((slant+sl)*PI/180.0) + .5); -} - -int font::contains(int c) -{ - return c >= 0 && c < nindices && ch_index[c] >= 0; -} - -int font::is_special() -{ - return special; -} - -font_widths_cache::font_widths_cache(int ps, int ch_size, - font_widths_cache *p) -: next(p), point_size(ps) -{ - width = new int[ch_size]; - for (int i = 0; i < ch_size; i++) - width[i] = -1; -} - -font_widths_cache::~font_widths_cache() -{ - a_delete width; -} - -int font::get_width(int c, int point_size) -{ - assert(c >= 0 && c < nindices); - int i = ch_index[c]; - assert(i >= 0); - - if (point_size == unitwidth) - return ch[i].width; - - if (!widths_cache) - widths_cache = new font_widths_cache(point_size, ch_size); - else if (widths_cache->point_size != point_size) { - font_widths_cache **p; - for (p = &widths_cache; *p; p = &(*p)->next) - if ((*p)->point_size == point_size) - break; - if (*p) { - font_widths_cache *tem = *p; - *p = (*p)->next; - tem->next = widths_cache; - widths_cache = tem; - } - else - widths_cache = new font_widths_cache(point_size, ch_size, widths_cache); - } - int &w = widths_cache->width[i]; - if (w < 0) - w = scale(ch[i].width, point_size); - return w; -} - -int font::get_height(int c, int point_size) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return scale(ch[ch_index[c]].height, point_size); -} - -int font::get_depth(int c, int point_size) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return scale(ch[ch_index[c]].depth, point_size); -} - -int font::get_italic_correction(int c, int point_size) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return scale(ch[ch_index[c]].italic_correction, point_size); -} - -int font::get_left_italic_correction(int c, int point_size) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return scale(ch[ch_index[c]].pre_math_space, point_size); -} - -int font::get_subscript_correction(int c, int point_size) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return scale(ch[ch_index[c]].subscript_correction, point_size); -} - -int font::get_space_width(int point_size) -{ - return scale(space_width, point_size); -} - -font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p) -: i1(c1), i2(c2), amount(n), next(p) -{ -} - -inline int font::hash_kern(int i1, int i2) -{ - int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE; - return n < 0 ? -n : n; -} - -void font::add_kern(int i1, int i2, int amount) -{ - if (!kern_hash_table) { - kern_hash_table = new font_kern_list *[KERN_HASH_TABLE_SIZE]; - for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) - kern_hash_table[i] = 0; - } - font_kern_list **p = kern_hash_table + hash_kern(i1, i2); - *p = new font_kern_list(i1, i2, amount, *p); -} - -int font::get_kern(int i1, int i2, int point_size) -{ - if (kern_hash_table) { - for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next) - if (i1 == p->i1 && i2 == p->i2) - return scale(p->amount, point_size); - } - return 0; -} - -int font::has_ligature(int mask) -{ - return mask & ligatures; -} - -int font::get_character_type(int c) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return ch[ch_index[c]].type; -} - -int font::get_code(int c) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return ch[ch_index[c]].code; -} - -const char *font::get_name() -{ - return name; -} - -const char *font::get_internal_name() -{ - return internalname; -} - -const char *font::get_special_device_encoding(int c) -{ - assert(c >= 0 && c < nindices && ch_index[c] >= 0); - return( ch[ch_index[c]].special_device_coding ); -} - -void font::alloc_ch_index(int index) -{ - if (nindices == 0) { - nindices = 128; - if (index >= nindices) - nindices = index + 10; - ch_index = new short[nindices]; - for (int i = 0; i < nindices; i++) - ch_index[i] = -1; - } - else { - int old_nindices = nindices; - nindices *= 2; - if (index >= nindices) - nindices = index + 10; - short *old_ch_index = ch_index; - ch_index = new short[nindices]; - memcpy(ch_index, old_ch_index, sizeof(short)*old_nindices); - for (int i = old_nindices; i < nindices; i++) - ch_index[i] = -1; - a_delete old_ch_index; - } -} - -void font::extend_ch() -{ - if (ch == 0) - ch = new font_char_metric[ch_size = 16]; - else { - int old_ch_size = ch_size; - ch_size *= 2; - font_char_metric *old_ch = ch; - ch = new font_char_metric[ch_size]; - memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric)); - a_delete old_ch; - } -} - -void font::compact() -{ - int i; - for (i = nindices - 1; i >= 0; i--) - if (ch_index[i] >= 0) - break; - i++; - if (i < nindices) { - short *old_ch_index = ch_index; - ch_index = new short[i]; - memcpy(ch_index, old_ch_index, i*sizeof(short)); - a_delete old_ch_index; - nindices = i; - } - if (ch_used < ch_size) { - font_char_metric *old_ch = ch; - ch = new font_char_metric[ch_used]; - memcpy(ch, old_ch, ch_used*sizeof(font_char_metric)); - a_delete old_ch; - ch_size = ch_used; - } -} - -void font::add_entry(int index, const font_char_metric &metric) -{ - assert(index >= 0); - if (index >= nindices) - alloc_ch_index(index); - assert(index < nindices); - if (ch_used + 1 >= ch_size) - extend_ch(); - assert(ch_used + 1 < ch_size); - ch_index[index] = ch_used; - ch[ch_used++] = metric; -} - -void font::copy_entry(int new_index, int old_index) -{ - assert(new_index >= 0 && old_index >= 0 && old_index < nindices); - if (new_index >= nindices) - alloc_ch_index(new_index); - ch_index[new_index] = ch_index[old_index]; -} - -font *font::load_font(const char *s, int *not_found) -{ - font *f = new font(s); - if (!f->load(not_found)) { - delete f; - return 0; - } - return f; -} - -static char *trim_arg(char *p) -{ - if (!p) - return 0; - while (csspace(*p)) - p++; - char *q = strchr(p, '\0'); - while (q > p && csspace(q[-1])) - q--; - *q = '\0'; - return p; -} - -int font::scan_papersize(const char *p, - const char **size, double *length, double *width) -{ - double l, w; - char lu[2], wu[2]; - const char *pp = p; - int test_file = 1; - char line[255]; -again: - if (csdigit(*pp)) { - if (sscanf(pp, "%lf%1[ipPc],%lf%1[ipPc]", &l, lu, &w, wu) == 4 - && l > 0 && w > 0 - && unit_scale(&l, lu[0]) && unit_scale(&w, wu[0])) { - if (length) - *length = l; - if (width) - *width = w; - if (size) - *size = "custom"; - return 1; - } - } - else { - int i; - for (i = 0; i < NUM_PAPERSIZES; i++) - if (strcasecmp(papersizes[i].name, pp) == 0) { - if (length) - *length = papersizes[i].length; - if (width) - *width = papersizes[i].width; - if (size) - *size = papersizes[i].name; - return 1; - } - if (test_file) { - FILE *f = fopen(p, "r"); - if (f) { - fgets(line, 254, f); - fclose(f); - test_file = 0; - char *linep = strchr(line, '\0'); - // skip final newline, if any - if (*(--linep) == '\n') - *linep = '\0'; - pp = line; - goto again; - } - } - } - return 0; -} - -// If the font can't be found, then if not_found is non-NULL, it will be set -// to 1 otherwise a message will be printed. - -int font::load(int *not_found) -{ - char *path; - FILE *fp; - if ((fp = open_file(name, &path)) == NULL) { - if (not_found) - *not_found = 1; - else - error("can't find font file `%1'", name); - return 0; - } - text_file t(fp, path); - t.skip_comments = 1; - char *p; - for (;;) { - if (!t.next()) { - t.error("missing charset command"); - return 0; - } - p = strtok(t.buf, WS); - if (strcmp(p, "name") == 0) { - } - else if (strcmp(p, "spacewidth") == 0) { - p = strtok(0, WS); - int n; - if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) { - t.error("bad argument for spacewidth command"); - return 0; - } - space_width = n; - } - else if (strcmp(p, "slant") == 0) { - p = strtok(0, WS); - double n; - if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) { - t.error("bad argument for slant command", p); - return 0; - } - slant = n; - } - else if (strcmp(p, "ligatures") == 0) { - for (;;) { - p = strtok(0, WS); - if (p == 0 || strcmp(p, "0") == 0) - break; - if (strcmp(p, "ff") == 0) - ligatures |= LIG_ff; - else if (strcmp(p, "fi") == 0) - ligatures |= LIG_fi; - else if (strcmp(p, "fl") == 0) - ligatures |= LIG_fl; - else if (strcmp(p, "ffi") == 0) - ligatures |= LIG_ffi; - else if (strcmp(p, "ffl") == 0) - ligatures |= LIG_ffl; - else { - t.error("unrecognised ligature `%1'", p); - return 0; - } - } - } - else if (strcmp(p, "internalname") == 0) { - p = strtok(0, WS); - if (!p) { - t.error("`internalname command requires argument"); - return 0; - } - internalname = new char[strlen(p) + 1]; - strcpy(internalname, p); - } - else if (strcmp(p, "special") == 0) { - special = 1; - } - else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) { - char *command = p; - p = strtok(0, "\n"); - handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno); - } - else - break; - } - char *command = p; - int had_charset = 0; - t.skip_comments = 0; - while (command) { - if (strcmp(command, "kernpairs") == 0) { - for (;;) { - if (!t.next()) { - command = 0; - break; - } - char *c1 = strtok(t.buf, WS); - if (c1 == 0) - continue; - char *c2 = strtok(0, WS); - if (c2 == 0) { - command = c1; - break; - } - p = strtok(0, WS); - if (p == 0) { - t.error("missing kern amount"); - return 0; - } - int n; - if (sscanf(p, "%d", &n) != 1) { - t.error("bad kern amount `%1'", p); - return 0; - } - int i1 = name_to_index(c1); - if (i1 < 0) { - t.error("invalid character `%1'", c1); - return 0; - } - int i2 = name_to_index(c2); - if (i2 < 0) { - t.error("invalid character `%1'", c2); - return 0; - } - add_kern(i1, i2, n); - } - } - else if (strcmp(command, "charset") == 0) { - had_charset = 1; - int last_index = -1; - for (;;) { - if (!t.next()) { - command = 0; - break; - } - char *nm = strtok(t.buf, WS); - if (nm == 0) - continue; // I dont think this should happen - p = strtok(0, WS); - if (p == 0) { - command = nm; - break; - } - if (p[0] == '"') { - if (last_index == -1) { - t.error("first charset entry is duplicate"); - return 0; - } - if (strcmp(nm, "---") == 0) { - t.error("unnamed character cannot be duplicate"); - return 0; - } - int index = name_to_index(nm); - if (index < 0) { - t.error("invalid character `%1'", nm); - return 0; - } - copy_entry(index, last_index); - } - else { - font_char_metric metric; - metric.height = 0; - metric.depth = 0; - metric.pre_math_space = 0; - metric.italic_correction = 0; - metric.subscript_correction = 0; - int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d", - &metric.width, &metric.height, &metric.depth, - &metric.italic_correction, - &metric.pre_math_space, - &metric.subscript_correction); - if (nparms < 1) { - t.error("bad width for `%1'", nm); - return 0; - } - p = strtok(0, WS); - if (p == 0) { - t.error("missing character type for `%1'", nm); - return 0; - } - int type; - if (sscanf(p, "%d", &type) != 1) { - t.error("bad character type for `%1'", nm); - return 0; - } - if (type < 0 || type > 255) { - t.error("character code `%1' out of range", type); - return 0; - } - metric.type = type; - p = strtok(0, WS); - if (p == 0) { - t.error("missing code for `%1'", nm); - return 0; - } - char *ptr; - metric.code = (int)strtol(p, &ptr, 0); - if (metric.code == 0 && ptr == p) { - t.error("bad code `%1' for character `%2'", p, nm); - return 0; - } - p = strtok(0, WS); - if ((p == NULL) || (strcmp(p, "--") == 0)) { - metric.special_device_coding = NULL; - } - else { - char *name = new char[strlen(p) + 1]; - strcpy(name, p); - metric.special_device_coding = name; - } - if (strcmp(nm, "---") == 0) { - last_index = number_to_index(metric.code); - add_entry(last_index, metric); - } - else { - last_index = name_to_index(nm); - if (last_index < 0) { - t.error("invalid character `%1'", nm); - return 0; - } - add_entry(last_index, metric); - copy_entry(number_to_index(metric.code), last_index); - } - } - } - if (last_index == -1) { - t.error("I didn't seem to find any characters"); - return 0; - } - } - else { - t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command); - return 0; - } - } - if (!had_charset) { - t.error("missing charset command"); - return 0; - } - if (space_width == 0) - space_width = scale_round(unitwidth, res, 72*3*sizescale); - compact(); - return 1; -} - -static struct { - const char *command; - int *ptr; -} table[] = { - { "res", &font::res }, - { "hor", &font::hor }, - { "vert", &font::vert }, - { "unitwidth", &font::unitwidth }, - { "paperwidth", &font::paperwidth }, - { "paperlength", &font::paperlength }, - { "spare1", &font::biggestfont }, - { "biggestfont", &font::biggestfont }, - { "spare2", &font::spare2 }, - { "sizescale", &font::sizescale } - }; - -int font::load_desc() -{ - int nfonts = 0; - FILE *fp; - char *path; - if ((fp = open_file("DESC", &path)) == 0) { - error("can't find `DESC' file"); - return 0; - } - text_file t(fp, path); - t.skip_comments = 1; - res = 0; - while (t.next()) { - char *p = strtok(t.buf, WS); - int found = 0; - unsigned int idx; - for (idx = 0; !found && idx < sizeof(table)/sizeof(table[0]); idx++) - if (strcmp(table[idx].command, p) == 0) - found = 1; - if (found) { - char *q = strtok(0, WS); - if (!q) { - t.error("missing value for command `%1'", p); - return 0; - } - //int *ptr = &(this->*(table[idx-1].ptr)); - int *ptr = table[idx-1].ptr; - if (sscanf(q, "%d", ptr) != 1) { - t.error("bad number `%1'", q); - return 0; - } - } - else if (strcmp("family", p) == 0) { - p = strtok(0, WS); - if (!p) { - t.error("family command requires an argument"); - return 0; - } - char *tem = new char[strlen(p)+1]; - strcpy(tem, p); - family = tem; - } - else if (strcmp("fonts", p) == 0) { - p = strtok(0, WS); - if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) { - t.error("bad number of fonts `%1'", p); - return 0; - } - font_name_table = (const char **)new char *[nfonts+1]; - for (int i = 0; i < nfonts; i++) { - p = strtok(0, WS); - while (p == 0) { - if (!t.next()) { - t.error("end of file while reading list of fonts"); - return 0; - } - p = strtok(t.buf, WS); - } - char *temp = new char[strlen(p)+1]; - strcpy(temp, p); - font_name_table[i] = temp; - } - p = strtok(0, WS); - if (p != 0) { - t.error("font count does not match number of fonts"); - return 0; - } - font_name_table[nfonts] = 0; - } - else if (strcmp("papersize", p) == 0) { - p = strtok(0, WS); - if (!p) { - t.error("papersize command requires an argument"); - return 0; - } - int found_paper = 0; - while (p) { - double unscaled_paperwidth, unscaled_paperlength; - if (scan_papersize(p, &papersize, &unscaled_paperlength, - &unscaled_paperwidth)) { - paperwidth = int(unscaled_paperwidth * res + 0.5); - paperlength = int(unscaled_paperlength * res + 0.5); - found_paper = 1; - break; - } - p = strtok(0, WS); - } - if (!found_paper) { - t.error("bad paper size"); - return 0; - } - } - else if (strcmp("pass_filenames", p) == 0) - pass_filenames = 1; - else if (strcmp("sizes", p) == 0) { - int n = 16; - sizes = new int[n]; - int i = 0; - for (;;) { - p = strtok(0, WS); - while (p == 0) { - if (!t.next()) { - t.error("list of sizes must be terminated by `0'"); - return 0; - } - p = strtok(t.buf, WS); - } - int lower, upper; - switch (sscanf(p, "%d-%d", &lower, &upper)) { - case 1: - upper = lower; - // fall through - case 2: - if (lower <= upper && lower >= 0) - break; - // fall through - default: - t.error("bad size range `%1'", p); - return 0; - } - if (i + 2 > n) { - int *old_sizes = sizes; - sizes = new int[n*2]; - memcpy(sizes, old_sizes, n*sizeof(int)); - n *= 2; - a_delete old_sizes; - } - sizes[i++] = lower; - if (lower == 0) - break; - sizes[i++] = upper; - } - if (i == 1) { - t.error("must have some sizes"); - return 0; - } - } - else if (strcmp("styles", p) == 0) { - int style_table_size = 5; - style_table = (const char **)new char *[style_table_size]; - int j; - for (j = 0; j < style_table_size; j++) - style_table[j] = 0; - int i = 0; - for (;;) { - p = strtok(0, WS); - if (p == 0) - break; - // leave room for terminating 0 - if (i + 1 >= style_table_size) { - const char **old_style_table = style_table; - style_table_size *= 2; - style_table = (const char **)new char*[style_table_size]; - for (j = 0; j < i; j++) - style_table[j] = old_style_table[j]; - for (; j < style_table_size; j++) - style_table[j] = 0; - a_delete old_style_table; - } - char *tem = new char[strlen(p) + 1]; - strcpy(tem, p); - style_table[i++] = tem; - } - } - else if (strcmp("tcommand", p) == 0) - tcommand = 1; - else if (strcmp("use_charnames_in_special", p) == 0) - use_charnames_in_special = 1; - else if (strcmp("charset", p) == 0) - break; - else if (unknown_desc_command_handler) { - char *command = p; - p = strtok(0, "\n"); - (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno); - } - } - if (res == 0) { - t.error("missing `res' command"); - return 0; - } - if (unitwidth == 0) { - t.error("missing `unitwidth' command"); - return 0; - } - if (font_name_table == 0) { - t.error("missing `fonts' command"); - return 0; - } - if (sizes == 0) { - t.error("missing `sizes' command"); - return 0; - } - if (sizescale < 1) { - t.error("bad `sizescale' value"); - return 0; - } - if (hor < 1) { - t.error("bad `hor' value"); - return 0; - } - if (vert < 1) { - t.error("bad `vert' value"); - return 0; - } - return 1; -} - -void font::handle_unknown_font_command(const char *, const char *, - const char *, int) -{ -} - -FONT_COMMAND_HANDLER -font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func) -{ - FONT_COMMAND_HANDLER prev = unknown_desc_command_handler; - unknown_desc_command_handler = func; - return prev; -} - diff --git a/contrib/groff/src/libs/libgroff/fontfile.cc b/contrib/groff/src/libs/libgroff/fontfile.cc deleted file mode 100644 index 8502d12..0000000 --- a/contrib/groff/src/libs/libgroff/fontfile.cc +++ /dev/null @@ -1,67 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "lib.h" - -#include -#include -#include -#include "font.h" -#include "searchpath.h" -#include "device.h" -#include "defs.h" - -const char *const FONT_ENV_VAR = "GROFF_FONT_PATH"; - -static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0); - -int font::res = 0; -int font::hor = 1; -int font::vert = 1; -int font::unitwidth = 0; -int font::paperwidth = 0; -int font::paperlength = 0; -const char *font::papersize = 0; -int font::biggestfont = 0; -int font::spare2 = 0; -int font::sizescale = 1; -int font::tcommand = 0; -int font::pass_filenames = 0; -int font::use_charnames_in_special = 0; -const char **font::font_name_table = 0; -int *font::sizes = 0; -const char *font::family = 0; -const char **font::style_table = 0; -FONT_COMMAND_HANDLER font::unknown_desc_command_handler = 0; - -void font::command_line_font_dir(const char *dir) -{ - font_path.command_line_dir(dir); -} - -FILE *font::open_file(const char *name, char **pathp) -{ - char *filename = new char[strlen(name) + strlen(device) + 5]; - sprintf(filename, "dev%s/%s", device, name); - FILE *fp = font_path.open_file(filename, pathp); - a_delete filename; - return fp; -} diff --git a/contrib/groff/src/libs/libgroff/geometry.cc b/contrib/groff/src/libs/libgroff/geometry.cc deleted file mode 100644 index 58a94a4..0000000 --- a/contrib/groff/src/libs/libgroff/geometry.cc +++ /dev/null @@ -1,286 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - Free Software Foundation, Inc. - Written by Gaius Mulley - using adjust_arc_center() from printer.cc, written by James Clark. - -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 -#include - -#undef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -#undef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - - -// 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 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 - - -/* - * check_output_arc_limits - works out the smallest box that will encompass - * an arc defined by an origin (x, y) and two - * vectors (p0, p1) and (p2, p3). - * (x1, y1) -> start of arc - * (x1, y1) + (xv1, yv1) -> center of circle - * (x1, y1) + (xv1, yv1) + (xv2, yv2) -> end of arc - * - * Works out in which quadrant the arc starts and - * stops, and from this it determines the x, y - * max/min limits. The arc is drawn clockwise. - * - * [I'm sure there is a better way to do this, but - * I don't know how. Please can someone let me - * know or "improve" this function.] - */ - -void check_output_arc_limits(int x1, int y1, - int xv1, int yv1, - int xv2, int yv2, - double c0, double c1, - int *minx, int *maxx, - int *miny, int *maxy) -{ - int radius = (int)sqrt(c0*c0 + c1*c1); - int x2 = x1 + xv1 + xv2; // end of arc is (x2, y2) - int y2 = y1 + yv1 + yv2; - - // firstly lets use the `circle' limitation - *minx = x1 + xv1 - radius; - *maxx = x1 + xv1 + radius; - *miny = y1 + yv1 - radius; - *maxy = y1 + yv1 + radius; - - /* now to see which min/max can be reduced and increased for the limits of - * the arc - * - * Q2 | Q1 - * -----+----- - * Q3 | Q4 - * - * - * NB. (x1+xv1, y1+yv1) is at the origin - * - * below we ask a nested question - * (i) from which quadrant does the first vector start? - * (ii) into which quadrant does the second vector go? - * from the 16 possible answers we determine the limits of the arc - */ - if (xv1 > 0 && yv1 > 0) { - // first vector in Q3 - if (xv2 >= 0 && yv2 >= 0 ) { - // second in Q1 - *maxx = x2; - *miny = y1; - } - else if (xv2 < 0 && yv2 >= 0) { - // second in Q2 - *maxx = x2; - *miny = y1; - } - else if (xv2 >= 0 && yv2 < 0) { - // second in Q4 - *miny = MIN(y1, y2); - } - else if (xv2 < 0 && yv2 < 0) { - // second in Q3 - if (x1 >= x2) { - *minx = x2; - *maxx = x1; - *miny = MIN(y1, y2); - *maxy = MAX(y1, y2); - } - else { - // xv2, yv2 could all be zero? - } - } - } - else if (xv1 > 0 && yv1 < 0) { - // first vector in Q2 - if (xv2 >= 0 && yv2 >= 0) { - // second in Q1 - *maxx = MAX(x1, x2); - *minx = MIN(x1, x2); - *miny = y1; - } - else if (xv2 < 0 && yv2 >= 0) { - // second in Q2 - if (x1 < x2) { - *maxx = x2; - *minx = x1; - *miny = MIN(y1, y2); - *maxy = MAX(y1, y2); - } - else { - // otherwise almost full circle anyway - } - } - else if (xv2 >= 0 && yv2 < 0) { - // second in Q4 - *miny = y2; - *minx = x1; - } - else if (xv2 < 0 && yv2 < 0) { - // second in Q3 - *minx = MIN(x1, x2); - } - } - else if (xv1 <= 0 && yv1 <= 0) { - // first vector in Q1 - if (xv2 >= 0 && yv2 >= 0) { - // second in Q1 - if (x1 < x2) { - *minx = x1; - *maxx = x2; - *miny = MIN(y1, y2); - *maxy = MAX(y1, y2); - } - else { - // nearly full circle - } - } - else if (xv2 < 0 && yv2 >= 0) { - // second in Q2 - *maxy = MAX(y1, y2); - } - else if (xv2 >= 0 && yv2 < 0) { - // second in Q4 - *miny = MIN(y1, y2); - *maxy = MAX(y1, y2); - *minx = MIN(x1, x2); - } - else if (xv2 < 0 && yv2 < 0) { - // second in Q3 - *minx = x2; - *maxy = y1; - } - } - else if (xv1 <= 0 && yv1 > 0) { - // first vector in Q4 - if (xv2 >= 0 && yv2 >= 0) { - // second in Q1 - *maxx = MAX(x1, x2); - } - else if (xv2 < 0 && yv2 >= 0) { - // second in Q2 - *maxy = MAX(y1, y2); - *maxx = MAX(x1, x2); - } - else if (xv2 >= 0 && yv2 < 0) { - // second in Q4 - if (x1 >= x2) { - *miny = MIN(y1, y2); - *maxy = MAX(y1, y2); - *minx = MIN(x1, x2); - *maxx = MAX(x2, x2); - } - else { - // nearly full circle - } - } - else if (xv2 < 0 && yv2 < 0) { - // second in Q3 - *maxy = MAX(y1, y2); - *minx = MIN(x1, x2); - *maxx = MAX(x1, x2); - } - } - - // this should *never* happen but if it does it means a case above is wrong - // this code is only present for safety sake - if (*maxx < *minx) { - fprintf(stderr, "assert failed *minx > *maxx\n"); - fflush(stderr); - *maxx = *minx; - } - if (*maxy < *miny) { - fprintf(stderr, "assert failed *miny > *maxy\n"); - fflush(stderr); - *maxy = *miny; - } -} diff --git a/contrib/groff/src/libs/libgroff/htmlhint.cc b/contrib/groff/src/libs/libgroff/htmlhint.cc deleted file mode 100644 index 3015767..0000000 --- a/contrib/groff/src/libs/libgroff/htmlhint.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. - Written by Gaius Mulley (gaius@glam.ac.uk) - -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 "lib.h" - -#include -#include - -#include "nonposix.h" -#include "stringclass.h" -#include "html-strings.h" - -/* - * This file contains a very simple set of routines which might - * be shared by preprocessors. It allows a preprocessor to indicate - * when an inline image should be created. - * This string is intercepted by pre-grohtml and substituted for - * the image name and suppression escapes. - * - * pre-html runs troff twice, once with -Thtml and once with -Tps. - * troff -Thtml device driver emits a tag - * and the postscript device driver works out the min/max limits - * of the graphic region. These region limits are read by pre-html - * and an image is generated via troff -Tps -> gs -> png - */ - -/* - * html_begin_suppress - emit a start of image tag which will be seen - * by pre-html. - */ -void html_begin_suppress() -{ - put_string(HTML_IMAGE_INLINE_BEGIN, stdout); -} - -/* - * html_end_suppress - emit an end of image tag which will be seen - * by pre-html. - */ -void html_end_suppress() -{ - put_string(HTML_IMAGE_INLINE_END, stdout); -} diff --git a/contrib/groff/src/libs/libgroff/lf.cc b/contrib/groff/src/libs/libgroff/lf.cc deleted file mode 100644 index 34272c7..0000000 --- a/contrib/groff/src/libs/libgroff/lf.cc +++ /dev/null @@ -1,62 +0,0 @@ -// -*- 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 -#include -#include "cset.h" -#include "stringclass.h" - -extern void change_filename(const char *); -extern void change_lineno(int); - -int interpret_lf_args(const char *p) -{ - while (*p == ' ') - p++; - if (!csdigit(*p)) - return 0; - int ln = 0; - do { - ln *= 10; - ln += *p++ - '0'; - } while (csdigit(*p)); - if (*p != ' ' && *p != '\n' && *p != '\0') - return 0; - while (*p == ' ') - p++; - if (*p == '\0' || *p == '\n') { - change_lineno(ln); - return 1; - } - const char *q; - for (q = p; - *q != '\0' && *q != ' ' && *q != '\n' && *q != '\\'; - q++) - ; - string tem(p, q - p); - while (*q == ' ') - q++; - if (*q != '\n' && *q != '\0') - return 0; - tem += '\0'; - change_filename(tem.contents()); - change_lineno(ln); - return 1; -} diff --git a/contrib/groff/src/libs/libgroff/lineno.cc b/contrib/groff/src/libs/libgroff/lineno.cc deleted file mode 100644 index f7138db..0000000 --- a/contrib/groff/src/libs/libgroff/lineno.cc +++ /dev/null @@ -1 +0,0 @@ -int current_lineno = 0; diff --git a/contrib/groff/src/libs/libgroff/macropath.cc b/contrib/groff/src/libs/libgroff/macropath.cc deleted file mode 100644 index 03c04cb..0000000 --- a/contrib/groff/src/libs/libgroff/macropath.cc +++ /dev/null @@ -1,30 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000 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 "lib.h" -#include "searchpath.h" -#include "macropath.h" -#include "defs.h" - -#define MACROPATH_ENVVAR "GROFF_TMAC_PATH" - -search_path macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 1); -search_path safer_macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 0); -search_path config_macro_path(MACROPATH_ENVVAR, MACROPATH, 0, 0); diff --git a/contrib/groff/src/libs/libgroff/maxfilename.cc b/contrib/groff/src/libs/libgroff/maxfilename.cc deleted file mode 100644 index 341cf92..0000000 --- a/contrib/groff/src/libs/libgroff/maxfilename.cc +++ /dev/null @@ -1,69 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1992, 2001 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. */ - -/* file_name_max(dir) does the same as pathconf(dir, _PC_NAME_MAX) */ - -#include "lib.h" - -#include - -#ifdef HAVE_UNISTD_H -#include -#endif /* HAVE_UNISTD_H */ - -#ifdef _POSIX_VERSION - -size_t file_name_max(const char *fname) -{ - return pathconf(fname, _PC_NAME_MAX); -} - -#else /* not _POSIX_VERSION */ - -#ifdef HAVE_LIMITS_H -#include -#endif /* HAVE_LIMITS_H */ - -#ifdef HAVE_DIRENT_H -#include -#else /* not HAVE_DIRENT_H */ -#ifdef HAVE_SYS_DIR_H -#include -#endif /* HAVE_SYS_DIR_H */ -#endif /* not HAVE_DIRENT_H */ - -#ifndef NAME_MAX -#ifdef MAXNAMLEN -#define NAME_MAX MAXNAMLEN -#else /* !MAXNAMLEN */ -#ifdef MAXNAMELEN -#define NAME_MAX MAXNAMELEN -#else /* !MAXNAMELEN */ -#define NAME_MAX 14 -#endif /* !MAXNAMELEN */ -#endif /* !MAXNAMLEN */ -#endif /* !NAME_MAX */ - -size_t file_name_max(const char *) -{ - return NAME_MAX; -} - -#endif /* not _POSIX_VERSION */ diff --git a/contrib/groff/src/libs/libgroff/mksdir.cc b/contrib/groff/src/libs/libgroff/mksdir.cc deleted file mode 100644 index bf4d300..0000000 --- a/contrib/groff/src/libs/libgroff/mksdir.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. - Written by Werner Lemberg (wl@gnu.org) - -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. */ - - -/* This file is heavily based on the file mkstemp.c which is part of the - fileutils package. */ - - -extern int gen_tempname(char *, int = 0); - -/* Generate a unique temporary directory name from TEMPLATE. - The last six characters of TEMPLATE must be "XXXXXX"; - they are replaced with a string that makes the filename unique. - Then open the directory and return a fd. */ -int mksdir(char *tmpl) -{ - return gen_tempname(tmpl, 1); -} diff --git a/contrib/groff/src/libs/libgroff/mkstemp.cc b/contrib/groff/src/libs/libgroff/mkstemp.cc deleted file mode 100644 index cd2717c..0000000 --- a/contrib/groff/src/libs/libgroff/mkstemp.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. - Written by Werner Lemberg (wl@gnu.org) - -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. */ - - -/* This file is heavily based on the file mkstemp.c which is part of the - fileutils package. */ - - -extern int gen_tempname(char *, int); - -/* Generate a unique temporary file name from TEMPLATE. - The last six characters of TEMPLATE must be "XXXXXX"; - they are replaced with a string that makes the filename unique. - Then open the file and return a fd. */ -int mkstemp(char *tmpl) -{ - return gen_tempname(tmpl, 0); -} diff --git a/contrib/groff/src/libs/libgroff/nametoindex.cc b/contrib/groff/src/libs/libgroff/nametoindex.cc deleted file mode 100644 index 7c94b25..0000000 --- a/contrib/groff/src/libs/libgroff/nametoindex.cc +++ /dev/null @@ -1,117 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "lib.h" - -#include -#include -#include -#include "errarg.h" -#include "error.h" -#include "font.h" -#include "ptable.h" - -declare_ptable(int) -implement_ptable(int) - -class character_indexer { -public: - character_indexer(); - ~character_indexer(); - int ascii_char_index(unsigned char); - int named_char_index(const char *); - int numbered_char_index(int); -private: - enum { NSMALL = 256 }; - int next_index; - int ascii_index[256]; - int small_number_index[NSMALL]; - PTABLE(int) table; -}; - -character_indexer::character_indexer() -: next_index(0) -{ - int i; - for (i = 0; i < 256; i++) - ascii_index[i] = -1; - for (i = 0; i < NSMALL; i++) - small_number_index[i] = -1; -} - -character_indexer::~character_indexer() -{ -} - -int character_indexer::ascii_char_index(unsigned char c) -{ - if (ascii_index[c] < 0) - ascii_index[c] = next_index++; - return ascii_index[c]; -} - -int character_indexer::numbered_char_index(int n) -{ - if (n >= 0 && n < NSMALL) { - if (small_number_index[n] < 0) - small_number_index[n] = next_index++; - return small_number_index[n]; - } - // Not the most efficient possible implementation. - char buf[INT_DIGITS + 3]; - buf[0] = ' '; - strcpy(buf + 1, i_to_a(n)); - return named_char_index(buf); -} - -int character_indexer::named_char_index(const char *s) -{ - int *np = table.lookup(s); - if (!np) { - np = new int; - *np = next_index++; - table.define(s, np); - } - return *np; -} - -static character_indexer indexer; - -int font::number_to_index(int n) -{ - return indexer.numbered_char_index(n); -} - -int font::name_to_index(const char *s) -{ - assert(s != 0 && s[0] != '\0' && s[0] != ' '); - if (s[1] == '\0') - return indexer.ascii_char_index(s[0]); - /* char128 and \200 are synonyms */ - if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') { - char *res; - long n = strtol(s + 4, &res, 10); - if (res != s + 4 && *res == '\0' && n >= 0 && n < 256) - return indexer.ascii_char_index((unsigned char)n); - } - return indexer.named_char_index(s); -} - diff --git a/contrib/groff/src/libs/libgroff/new.cc b/contrib/groff/src/libs/libgroff/new.cc deleted file mode 100644 index 4975149..0000000 --- a/contrib/groff/src/libs/libgroff/new.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright (C) 1989, 1990, 1991, 1992, 2001 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 "lib.h" - -#include -#include - -#include "posix.h" -#include "nonposix.h" - -extern const char *program_name; - -static void ewrite(const char *s) -{ - write(2, s, strlen(s)); -} - -void *operator new(size_t size) -{ - // Avoid relying on the behaviour of malloc(0). - if (size == 0) - size++; -#ifdef COOKIE_BUG - char *p = (char *)malloc(unsigned(size + 8)); -#else /* not COOKIE_BUG */ - char *p = (char *)malloc(unsigned(size)); -#endif /* not COOKIE_BUG */ - if (p == 0) { - if (program_name) { - ewrite(program_name); - ewrite(": "); - } - ewrite("out of memory\n"); - _exit(-1); - } -#ifdef COOKIE_BUG - ((unsigned *)p)[1] = 0; - return p + 8; -#else /* not COOKIE_BUG */ - return p; -#endif /* not COOKIE_BUG */ -} - -#ifdef COOKIE_BUG - -void operator delete(void *p) -{ - if (p) - free((void *)((char *)p - 8)); -} - -#endif /* COOKIE_BUG */ diff --git a/contrib/groff/src/libs/libgroff/paper.cc b/contrib/groff/src/libs/libgroff/paper.cc deleted file mode 100644 index d79733e..0000000 --- a/contrib/groff/src/libs/libgroff/paper.cc +++ /dev/null @@ -1,84 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2002 - Free Software Foundation, Inc. - Written by Werner Lemberg (wl@gnu.org) - -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 "lib.h" -#include "paper.h" - -paper papersizes[NUM_PAPERSIZES]; - -// length and width in mm -static void add_iso_paper(char series, int offset, - int start_length, int start_width) -{ - int length = start_length; - int width = start_width; - for (int i = 0; i < 8; i++) - { - char *p = new char[3]; - p[0] = series; - p[1] = '0' + i; - p[2] = '\0'; - papersizes[offset + i].name = p; - // convert mm to inch - papersizes[offset + i].length = (double)length / 25.4; - papersizes[offset + i].width = (double)width / 25.4; - // after division by two, values must be rounded down to the next - // integer (as specified by ISO) - int tmp = width; - width = length; - length = tmp / 2; - } -} - -// length and width in inch -static void add_american_paper(const char *name, int index, - double length, double width ) -{ - char *p = new char[strlen(name) + 1]; - strcpy(p, name); - papersizes[index].name = p; - papersizes[index].length = length; - papersizes[index].width = width; -} - -int papersize_init::initialised = 0; - -papersize_init::papersize_init() -{ - if (initialised) - return; - initialised = 1; - add_iso_paper('a', 0, 1189, 841); - add_iso_paper('b', 8, 1414, 1000); - add_iso_paper('c', 16, 1297, 917); - add_iso_paper('d', 24, 1090, 771); - add_american_paper("letter", 32, 11, 8.5); - add_american_paper("legal", 33, 14, 8.5); - add_american_paper("tabloid", 34, 17, 11); - add_american_paper("ledger", 35, 11, 17); - add_american_paper("statement", 36, 8.5, 5.5); - add_american_paper("executive", 37, 10, 7.5); - // the next three entries are for grolj4 - add_american_paper("com10", 38, 9.5, 4.125); - add_american_paper("monarch", 39, 7.5, 3.875); - // this is an ISO format, but it easier to use add_american_paper - add_american_paper("dl", 40, 220/25.4, 110/25.4); -} diff --git a/contrib/groff/src/libs/libgroff/prime.cc b/contrib/groff/src/libs/libgroff/prime.cc deleted file mode 100644 index f0b1ead..0000000 --- a/contrib/groff/src/libs/libgroff/prime.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include - -int is_prime(unsigned n) -{ - if (n <= 3) - return 1; - if (!(n & 1)) - return 0; - if (n % 3 == 0) - return 0; - unsigned lim = unsigned(sqrt((double)n)); - unsigned d = 5; - for (;;) { - if (d > lim) - break; - if (n % d == 0) - return 0; - d += 2; - if (d > lim) - break; - if (n % d == 0) - return 0; - d += 4; - } - return 1; -} diff --git a/contrib/groff/src/libs/libgroff/progname.cc b/contrib/groff/src/libs/libgroff/progname.cc deleted file mode 100644 index a70e341..0000000 --- a/contrib/groff/src/libs/libgroff/progname.cc +++ /dev/null @@ -1 +0,0 @@ -const char *program_name = 0; diff --git a/contrib/groff/src/libs/libgroff/ptable.cc b/contrib/groff/src/libs/libgroff/ptable.cc deleted file mode 100644 index 76735c2..0000000 --- a/contrib/groff/src/libs/libgroff/ptable.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* 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 "ptable.h" -#include "errarg.h" -#include "error.h" - -unsigned long hash_string(const char *s) -{ - assert(s != 0); - unsigned long h = 0, g; - while (*s != 0) { - h <<= 4; - h += *s++; - if ((g = h & 0xf0000000) != 0) { - h ^= g >> 24; - h ^= g; - } - } - return h; -} - -static const unsigned table_sizes[] = { -101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, -80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009, -16000057, 32000011, 64000031, 128000003, 0 -}; - -unsigned next_ptable_size(unsigned n) -{ - const unsigned *p; - for (p = table_sizes; *p <= n; p++) - if (*p == 0) - fatal("cannot expand table"); - return *p; -} diff --git a/contrib/groff/src/libs/libgroff/searchpath.cc b/contrib/groff/src/libs/libgroff/searchpath.cc deleted file mode 100644 index 1f8b233..0000000 --- a/contrib/groff/src/libs/libgroff/searchpath.cc +++ /dev/null @@ -1,132 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001 - 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 "lib.h" - -#include -#include - -#include "searchpath.h" -#include "nonposix.h" - -search_path::search_path(const char *envvar, const char *standard, - int add_home, int add_current) -{ - char *home = 0; - if (add_home) - home = getenv("HOME"); - char *e = 0; - if (envvar) - e = getenv(envvar); - dirs = new char[((e && *e) ? strlen(e) + 1 : 0) - + (add_current ? 1 + 1 : 0) - + ((home && *home) ? strlen(home) + 1 : 0) - + ((standard && *standard) ? strlen(standard) : 0) - + 1]; - *dirs = '\0'; - if (e && *e) { - strcat(dirs, e); - strcat(dirs, PATH_SEP); - } - if (add_current) { - strcat(dirs, "."); - strcat(dirs, PATH_SEP); - } - if (home && *home) { - strcat(dirs, home); - strcat(dirs, PATH_SEP); - } - if (standard && *standard) - strcat(dirs, standard); - init_len = strlen(dirs); -} - -search_path::~search_path() -{ - // dirs is always allocated - a_delete dirs; -} - -void search_path::command_line_dir(const char *s) -{ - char *old = dirs; - unsigned old_len = strlen(old); - unsigned slen = strlen(s); - dirs = new char[old_len + 1 + slen + 1]; - memcpy(dirs, old, old_len - init_len); - char *p = dirs; - p += old_len - init_len; - if (init_len == 0) - *p++ = PATH_SEP[0]; - memcpy(p, s, slen); - p += slen; - if (init_len > 0) { - *p++ = PATH_SEP[0]; - memcpy(p, old + old_len - init_len, init_len); - p += init_len; - } - *p++ = '\0'; - a_delete old; -} - -FILE *search_path::open_file(const char *name, char **pathp) -{ - assert(name != 0); - if (IS_ABSOLUTE(name) || *dirs == '\0') { - FILE *fp = fopen(name, "r"); - if (fp) { - if (pathp) - *pathp = strsave(name); - return fp; - } - else - return 0; - } - unsigned namelen = strlen(name); - char *p = dirs; - for (;;) { - char *end = strchr(p, PATH_SEP[0]); - if (!end) - end = strchr(p, '\0'); - int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; - char *path = new char[(end - p) + need_slash + namelen + 1]; - memcpy(path, p, end - p); - if (need_slash) - path[end - p] = '/'; - strcpy(path + (end - p) + need_slash, name); -#if 0 - fprintf(stderr, "trying `%s'\n", path); -#endif - FILE *fp = fopen(path, "r"); - if (fp) { - if (pathp) - *pathp = path; - else - a_delete path; - return fp; - } - a_delete path; - if (*end == '\0') - break; - p = end + 1; - } - return 0; -} diff --git a/contrib/groff/src/libs/libgroff/string.cc b/contrib/groff/src/libs/libgroff/string.cc deleted file mode 100644 index 2ef547e..0000000 --- a/contrib/groff/src/libs/libgroff/string.cc +++ /dev/null @@ -1,341 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 - 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 "lib.h" - -#include "stringclass.h" - -static char *salloc(int len, int *sizep); -static void sfree(char *ptr, int size); -static char *sfree_alloc(char *ptr, int size, int len, int *sizep); -static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep); - -static char *salloc(int len, int *sizep) -{ - if (len == 0) { - *sizep = 0; - return 0; - } - else - return new char[*sizep = len*2]; -} - -static void sfree(char *ptr, int) -{ - a_delete ptr; -} - -static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep) -{ - if (oldsz >= len) { - *sizep = oldsz; - return ptr; - } - a_delete ptr; - if (len == 0) { - *sizep = 0; - return 0; - } - else - return new char[*sizep = len*2]; -} - -static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep) -{ - if (oldsz >= newlen) { - *sizep = oldsz; - return ptr; - } - if (newlen == 0) { - a_delete ptr; - *sizep = 0; - return 0; - } - else { - char *p = new char[*sizep = newlen*2]; - if (oldlen < newlen && oldlen != 0) - memcpy(p, ptr, oldlen); - a_delete ptr; - return p; - } -} - -string::string() : ptr(0), len(0), sz(0) -{ -} - -string::string(const char *p, int n) : len(n) -{ - assert(n >= 0); - ptr = salloc(n, &sz); - if (n != 0) - memcpy(ptr, p, n); -} - -string::string(const char *p) -{ - if (p == 0) { - len = 0; - ptr = 0; - sz = 0; - } - else { - len = strlen(p); - ptr = salloc(len, &sz); - memcpy(ptr, p, len); - } -} - -string::string(char c) : len(1) -{ - ptr = salloc(1, &sz); - *ptr = c; -} - -string::string(const string &s) : len(s.len) -{ - ptr = salloc(len, &sz); - if (len != 0) - memcpy(ptr, s.ptr, len); -} - -string::~string() -{ - sfree(ptr, sz); -} - -string &string::operator=(const string &s) -{ - ptr = sfree_alloc(ptr, sz, s.len, &sz); - len = s.len; - if (len != 0) - memcpy(ptr, s.ptr, len); - return *this; -} - -string &string::operator=(const char *p) -{ - if (p == 0) { - sfree(ptr, len); - len = 0; - ptr = 0; - sz = 0; - } - else { - int slen = strlen(p); - ptr = sfree_alloc(ptr, sz, slen, &sz); - len = slen; - memcpy(ptr, p, len); - } - return *this; -} - -string &string::operator=(char c) -{ - ptr = sfree_alloc(ptr, sz, 1, &sz); - len = 1; - *ptr = c; - return *this; -} - -void string::move(string &s) -{ - sfree(ptr, sz); - ptr = s.ptr; - len = s.len; - sz = s.sz; - s.ptr = 0; - s.len = 0; - s.sz = 0; -} - -void string::grow1() -{ - ptr = srealloc(ptr, sz, len, len + 1, &sz); -} - -string &string::operator+=(const char *p) -{ - if (p != 0) { - int n = strlen(p); - int newlen = len + n; - if (newlen > sz) - ptr = srealloc(ptr, sz, len, newlen, &sz); - memcpy(ptr + len, p, n); - len = newlen; - } - return *this; -} - -string &string::operator+=(const string &s) -{ - if (s.len != 0) { - int newlen = len + s.len; - if (newlen > sz) - ptr = srealloc(ptr, sz, len, newlen, &sz); - memcpy(ptr + len, s.ptr, s.len); - len = newlen; - } - return *this; -} - -void string::append(const char *p, int n) -{ - if (n > 0) { - int newlen = len + n; - if (newlen > sz) - ptr = srealloc(ptr, sz, len, newlen, &sz); - memcpy(ptr + len, p, n); - len = newlen; - } -} - -string::string(const char *s1, int n1, const char *s2, int n2) -{ - assert(n1 >= 0 && n2 >= 0); - len = n1 + n2; - if (len == 0) { - sz = 0; - ptr = 0; - } - else { - ptr = salloc(len, &sz); - if (n1 == 0) - memcpy(ptr, s2, n2); - else { - memcpy(ptr, s1, n1); - if (n2 != 0) - memcpy(ptr + n1, s2, n2); - } - } -} - -int operator<=(const string &s1, const string &s2) -{ - return (s1.len <= s2.len - ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 - : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); -} - -int operator<(const string &s1, const string &s2) -{ - return (s1.len < s2.len - ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 - : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); -} - -int operator>=(const string &s1, const string &s2) -{ - return (s1.len >= s2.len - ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 - : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); -} - -int operator>(const string &s1, const string &s2) -{ - return (s1.len > s2.len - ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 - : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); -} - -void string::set_length(int i) -{ - assert(i >= 0); - if (i > sz) - ptr = srealloc(ptr, sz, len, i, &sz); - len = i; -} - -void string::clear() -{ - len = 0; -} - -int string::search(char c) const -{ - char *p = ptr ? (char *)memchr(ptr, c, len) : NULL; - return p ? p - ptr : -1; -} - -// we silently strip nuls - -char *string::extract() const -{ - char *p = ptr; - int n = len; - int nnuls = 0; - int i; - for (i = 0; i < n; i++) - if (p[i] == '\0') - nnuls++; - char *q = new char[n + 1 - nnuls]; - char *r = q; - for (i = 0; i < n; i++) - if (p[i] != '\0') - *r++ = p[i]; - *r = '\0'; - return q; -} - -void string::remove_spaces() -{ - int l = len - 1; - while (l >= 0 && ptr[l] == ' ') - l--; - char *p = ptr; - if (l > 0) - while (*p == ' ') { - p++; - l--; - } - if (len - 1 != l) { - if (l >= 0) { - len = l + 1; - char *tmp = new char[len]; - memcpy(tmp, p, len); - a_delete ptr; - ptr = tmp; - } - else { - len = 0; - if (ptr) { - a_delete ptr; - ptr = 0; - } - } - } -} - -void put_string(const string &s, FILE *fp) -{ - int len = s.length(); - const char *ptr = s.contents(); - for (int i = 0; i < len; i++) - putc(ptr[i], fp); -} - -string as_string(int i) -{ - static char buf[INT_DIGITS + 2]; - sprintf(buf, "%d", i); - return string(buf); -} - diff --git a/contrib/groff/src/libs/libgroff/strsave.cc b/contrib/groff/src/libs/libgroff/strsave.cc deleted file mode 100644 index dfd2b6f..0000000 --- a/contrib/groff/src/libs/libgroff/strsave.cc +++ /dev/null @@ -1,31 +0,0 @@ -// -*- 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 - -char *strsave(const char *s) -{ - if (s == 0) - return 0; - char *p = new char[strlen(s) + 1]; - strcpy(p, s); - return p; -} - diff --git a/contrib/groff/src/libs/libgroff/tmpfile.cc b/contrib/groff/src/libs/libgroff/tmpfile.cc deleted file mode 100644 index 41b7f06..0000000 --- a/contrib/groff/src/libs/libgroff/tmpfile.cc +++ /dev/null @@ -1,172 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001 - 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 "lib.h" - -#include -#include - -#include "posix.h" -#include "errarg.h" -#include "error.h" -#include "nonposix.h" - -// If this is set, create temporary files there -#define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR" -// otherwise if this is set, create temporary files there -#define TMPDIR_ENVVAR "TMPDIR" -// otherwise if P_tmpdir is defined, create temporary files there -#ifdef P_tmpdir -# define DEFAULT_TMPDIR P_tmpdir -#else -// otherwise create temporary files here. -# define DEFAULT_TMPDIR "/tmp" -#endif -// Use this as the prefix for temporary filenames. -#define TMPFILE_PREFIX_SHORT "" -#define TMPFILE_PREFIX_LONG "groff" - -char *tmpfile_prefix; -size_t tmpfile_prefix_len; -int use_short_postfix = 0; - -struct temp_init { - temp_init(); - ~temp_init(); -} _temp_init; - -temp_init::temp_init() -{ - const char *tem = getenv(GROFF_TMPDIR_ENVVAR); - if (!tem) { - tem = getenv(TMPDIR_ENVVAR); - if (!tem) - tem = DEFAULT_TMPDIR; - } - size_t tem_len = strlen(tem); - const char *tem_end = tem + tem_len - 1; - int need_slash = strchr(DIR_SEPS, *tem_end) == NULL ? 1 : 0; - char *tem2 = new char[tem_len + need_slash + 1]; - strcpy(tem2, tem); - if (need_slash) - strcat(tem2, "/"); - const char *tem3 = TMPFILE_PREFIX_LONG; - if (file_name_max(tem2) <= 14) { - tem3 = TMPFILE_PREFIX_SHORT; - use_short_postfix = 1; - } - tmpfile_prefix_len = tem_len + need_slash + strlen(tem3); - tmpfile_prefix = new char[tmpfile_prefix_len + 1]; - strcpy(tmpfile_prefix, tem2); - strcat(tmpfile_prefix, tem3); - a_delete tem2; -} - -temp_init::~temp_init() -{ - a_delete tmpfile_prefix; -} - -/* - * Generate a temporary name template with a postfix - * immediately after the TMPFILE_PREFIX. - * It uses the groff preferences for a temporary directory. - * Note that no file name is either created or opened, - * only the *template* is returned. - */ - -char *xtmptemplate(const char *postfix_long, const char *postfix_short) -{ - const char *postfix = use_short_postfix ? postfix_short : postfix_long; - int postlen = 0; - if (postfix) - postlen = strlen(postfix); - char *templ = new char[tmpfile_prefix_len + postlen + 6 + 1]; - strcpy(templ, tmpfile_prefix); - if (postlen > 0) - strcat(templ, postfix); - strcat(templ, "XXXXXX"); - return templ; -} - -// The trick with unlinking the temporary file while it is still in -// use is not portable, it will fail on MS-DOS and most MS-Windows -// filesystems. So it cannot be used on non-Posix systems. -// Instead, we maintain a list of files to be deleted on exit. -// This should be portable to all platforms. - -struct xtmpfile_list { - char *fname; - xtmpfile_list *next; - xtmpfile_list(char *fn) : fname(fn), next(0) {} -}; - -xtmpfile_list *xtmpfiles_to_delete = 0; - -struct xtmpfile_list_init { - ~xtmpfile_list_init(); -} _xtmpfile_list_init; - -xtmpfile_list_init::~xtmpfile_list_init() -{ - xtmpfile_list *x = xtmpfiles_to_delete; - while (x != 0) { - if (unlink(x->fname) < 0) - error("cannot unlink `%1': %2", x->fname, strerror(errno)); - xtmpfile_list *tmp = x; - x = x->next; - a_delete tmp->fname; - delete tmp; - } -} - -static void add_tmp_file(const char *name) -{ - char *s = new char[strlen(name)+1]; - strcpy(s, name); - xtmpfile_list *x = new xtmpfile_list(s); - x->next = xtmpfiles_to_delete; - xtmpfiles_to_delete = x; -} - -// Open a temporary file and with fatal error on failure. - -FILE *xtmpfile(char **namep, - const char *postfix_long, const char *postfix_short, - int do_unlink) -{ - char *templ = xtmptemplate(postfix_long, postfix_short); - errno = 0; - int fd = mkstemp(templ); - if (fd < 0) - fatal("cannot create temporary file: %1", strerror(errno)); - errno = 0; - FILE *fp = fdopen(fd, FOPEN_RWB); // many callers of xtmpfile use binary I/O - if (!fp) - fatal("fdopen: %1", strerror(errno)); - if (do_unlink) - add_tmp_file(templ); - if (namep) - *namep = templ; - else - a_delete templ; - return fp; -} diff --git a/contrib/groff/src/libs/libgroff/tmpname.cc b/contrib/groff/src/libs/libgroff/tmpname.cc deleted file mode 100644 index 213b0ee..0000000 --- a/contrib/groff/src/libs/libgroff/tmpname.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. - Written by Werner Lemberg (wl@gnu.org) - -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. */ - - -/* This file is heavily based on the function __gen_tempname() in the - file tempname.c which is part of the fileutils package. */ - - -#include "lib.h" - -#include -#include -#include -#include - -#include "posix.h" -#include "nonposix.h" - -#ifndef TMP_MAX -# define TMP_MAX 238328 -#endif - -#if HAVE_SYS_TIME_H -# include -#endif - -#ifdef HAVE_GETTIMEOFDAY -#ifdef NEED_DECLARATION_GETTIMEOFDAY -extern "C" { - int gettimeofday(struct timeval *, void *); -} -#endif -#endif - -#if HAVE_STDINT_H -# include -#endif - -/* Use the widest available unsigned type if uint64_t is not - available. The algorithm below extracts a number less than 62**6 - (approximately 2**35.725) from uint64_t, so ancient hosts where - uintmax_t is only 32 bits lose about 3.725 bits of randomness, - which is better than not having mkstemp at all. */ -#if !defined UINT64_MAX && !defined uint64_t -# define uint64_t uintmax_t -#endif - -/* These are the characters used in temporary filenames. */ -static const char letters[] = -"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - -int gen_tempname(char *tmpl, int dir) -{ - static uint64_t value; - - size_t len = strlen(tmpl); - if (len < 6 || strcmp(&tmpl[len - 6], "XXXXXX")) - return -1; /* EINVAL */ - - /* This is where the Xs start. */ - char *XXXXXX = &tmpl[len - 6]; - - /* Get some more or less random data. */ -#if HAVE_GETTIMEOFDAY - timeval tv; - gettimeofday(&tv, NULL); - uint64_t random_time_bits = ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec; -#else - uint64_t random_time_bits = time(NULL); -#endif - value += random_time_bits ^ getpid(); - - for (int count = 0; count < TMP_MAX; value += 7777, ++count) { - uint64_t v = value; - - /* Fill in the random bits. */ - XXXXXX[0] = letters[v % 62]; - v /= 62; - XXXXXX[1] = letters[v % 62]; - v /= 62; - XXXXXX[2] = letters[v % 62]; - v /= 62; - XXXXXX[3] = letters[v % 62]; - v /= 62; - XXXXXX[4] = letters[v % 62]; - v /= 62; - XXXXXX[5] = letters[v % 62]; - - int fd = dir ? mkdir(tmpl, S_IRUSR | S_IWUSR | S_IXUSR) - : open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); - - if (fd >= 0) - return fd; - else if (errno != EEXIST) - return -1; - } - - /* We got out of the loop because we ran out of combinations to try. */ - return -1; /* EEXIST */ -} diff --git a/contrib/groff/src/preproc/eqn/box.cc b/contrib/groff/src/preproc/eqn/box.cc deleted file mode 100644 index 41d8dff..0000000 --- a/contrib/groff/src/preproc/eqn/box.cc +++ /dev/null @@ -1,611 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h" -#include "pbox.h" - -const char *current_roman_font; - -char *gfont = 0; -char *grfont = 0; -char *gbfont = 0; -int gsize = 0; - -int script_size_reduction = -1; // negative means reduce by a percentage - -int positive_space = -1; -int negative_space = -1; - -int minimum_size = 5; - -int fat_offset = 4; -int body_height = 85; -int body_depth = 35; - -int over_hang = 0; -int accent_width = 31; -int delimiter_factor = 900; -int delimiter_shortfall = 50; - -int null_delimiter_space = 12; -int script_space = 5; -int thin_space = 17; -int medium_space = 22; -int thick_space = 28; - -int num1 = 70; -int num2 = 40; -// we don't use num3, because we don't have \atop -int denom1 = 70; -int denom2 = 36; -int axis_height = 26; // in 100ths of an em -int sup1 = 42; -int sup2 = 37; -int sup3 = 28; -int default_rule_thickness = 4; -int sub1 = 20; -int sub2 = 23; -int sup_drop = 38; -int sub_drop = 5; -int x_height = 45; -int big_op_spacing1 = 11; -int big_op_spacing2 = 17; -int big_op_spacing3 = 20; -int big_op_spacing4 = 60; -int big_op_spacing5 = 10; - -// These are for piles and matrices. - -int baseline_sep = 140; // = num1 + denom1 -int shift_down = 26; // = axis_height -int column_sep = 100; // = em space -int matrix_side_sep = 17; // = thin space - -int nroff = 0; // should we grok ndefine or tdefine? - -struct { - const char *name; - int *ptr; -} param_table[] = { - { "fat_offset", &fat_offset }, - { "over_hang", &over_hang }, - { "accent_width", &accent_width }, - { "delimiter_factor", &delimiter_factor }, - { "delimiter_shortfall", &delimiter_shortfall }, - { "null_delimiter_space", &null_delimiter_space }, - { "script_space", &script_space }, - { "thin_space", &thin_space }, - { "medium_space", &medium_space }, - { "thick_space", &thick_space }, - { "num1", &num1 }, - { "num2", &num2 }, - { "denom1", &denom1 }, - { "denom2", &denom2 }, - { "axis_height", &axis_height }, - { "sup1", ¹ }, - { "sup2", ² }, - { "sup3", ³ }, - { "default_rule_thickness", &default_rule_thickness }, - { "sub1", &sub1 }, - { "sub2", &sub2 }, - { "sup_drop", &sup_drop }, - { "sub_drop", &sub_drop }, - { "x_height", &x_height }, - { "big_op_spacing1", &big_op_spacing1 }, - { "big_op_spacing2", &big_op_spacing2 }, - { "big_op_spacing3", &big_op_spacing3 }, - { "big_op_spacing4", &big_op_spacing4 }, - { "big_op_spacing5", &big_op_spacing5 }, - { "minimum_size", &minimum_size }, - { "baseline_sep", &baseline_sep }, - { "shift_down", &shift_down }, - { "column_sep", &column_sep }, - { "matrix_side_sep", &matrix_side_sep }, - { "draw_lines", &draw_flag }, - { "body_height", &body_height }, - { "body_depth", &body_depth }, - { "nroff", &nroff }, - { 0, 0 } -}; - -void set_param(const char *name, int value) -{ - for (int i = 0; param_table[i].name != 0; i++) - if (strcmp(param_table[i].name, name) == 0) { - *param_table[i].ptr = value; - return; - } - error("unrecognised parameter `%1'", name); -} - -int script_style(int style) -{ - return style > SCRIPT_STYLE ? style - 2 : style; -} - -int cramped_style(int style) -{ - return (style & 1) ? style - 1 : style; -} - -void set_space(int n) -{ - if (n < 0) - negative_space = -n; - else - positive_space = n; -} - -// Return 0 if the specified size is bad. -// The caller is responsible for giving the error message. - -int set_gsize(const char *s) -{ - const char *p = (*s == '+' || *s == '-') ? s + 1 : s; - char *end; - long n = strtol(p, &end, 10); - if (n <= 0 || *end != '\0' || n > INT_MAX) - return 0; - if (p > s) { - if (!gsize) - gsize = 10; - if (*s == '+') { - if (gsize > INT_MAX - n) - return 0; - gsize += int(n); - } - else { - if (gsize - n <= 0) - return 0; - gsize -= int(n); - } - } - else - gsize = int(n); - return 1; -} - -void set_script_reduction(int n) -{ - script_size_reduction = n; -} - -const char *get_gfont() -{ - return gfont ? gfont : "I"; -} - -const char *get_grfont() -{ - return grfont ? grfont : "R"; -} - -const char *get_gbfont() -{ - return gbfont ? gbfont : "B"; -} - -void set_gfont(const char *s) -{ - a_delete gfont; - gfont = strsave(s); -} - -void set_grfont(const char *s) -{ - a_delete grfont; - grfont = strsave(s); -} - -void set_gbfont(const char *s) -{ - a_delete gbfont; - gbfont = strsave(s); -} - -// this must be precisely 2 characters in length -#define COMPATIBLE_REG "0C" - -void start_string() -{ - printf(".nr " COMPATIBLE_REG " \\n(.C\n"); - printf(".cp 0\n"); - printf(".ds " LINE_STRING "\n"); -} - -void output_string() -{ - printf("\\*(" LINE_STRING "\n"); -} - -void restore_compatibility() -{ - printf(".cp \\n(" COMPATIBLE_REG "\n"); -} - -void do_text(const char *s) -{ - printf(".eo\n"); - printf(".as " LINE_STRING " \"%s\n", s); - printf(".ec\n"); -} - -void set_minimum_size(int n) -{ - minimum_size = n; -} - -void set_script_size() -{ - if (minimum_size < 0) - minimum_size = 0; - if (script_size_reduction >= 0) - printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size); - else - printf(".ps (u;\\n[.ps]*7+5/10>?%d)\n", minimum_size); -} - -int box::next_uid = 0; - -box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++) -{ -} - -box::~box() -{ -} - -void box::top_level() -{ - // debug_print(); - // putc('\n', stderr); - box *b = this; - printf(".nr " SAVED_FONT_REG " \\n[.f]\n"); - printf(".ft\n"); - printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n"); - printf(".ft %s\n", get_gfont()); - printf(".nr " SAVED_SIZE_REG " \\n[.ps]\n"); - if (gsize > 0) { - char buf[INT_DIGITS + 1]; - sprintf(buf, "%d", gsize); - b = new size_box(strsave(buf), b); - } - current_roman_font = get_grfont(); - // This catches tabs used within \Z (which aren't allowed). - b->check_tabs(0); - int r = b->compute_metrics(DISPLAY_STYLE); - printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n"); - printf(".ft \\n[" SAVED_FONT_REG "]\n"); - printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r); - if (r == FOUND_MARK) { - printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n"); - printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid); - } - else if (r == FOUND_LINEUP) - printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n[" - SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n"); - else - assert(r == FOUND_NOTHING); - // The problem here is that the argument to \f is read in copy mode, - // so we cannot use \E there; so we hide it in a string instead. - // Another problem is that if we use \R directly, then the space will - // prevent it working in a macro argument. - printf(".ds " SAVE_FONT_STRING " " - "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'" - "\\fP" - "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'" - "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.ps]'" - "\\s0" - "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.ps]'" - "\n" - ".ds " RESTORE_FONT_STRING " " - "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]" - "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]" - "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'" - "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'" - "\n"); - printf(".as1 " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]"); - printf("\\f[%s]", get_gfont()); - printf("\\s'\\En[" SAVED_SIZE_REG "]u'"); - current_roman_font = get_grfont(); - b->output(); - printf("\\E*[" RESTORE_FONT_STRING "]\n"); - if (r == FOUND_LINEUP) - printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n[" - MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n[" - WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n", - b->uid); - b->extra_space(); - if (!inline_flag) - printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n[" - DEPTH_FORMAT "]u-%dM>?0)\n", - b->uid, body_height, b->uid, body_depth); - delete b; - next_uid = 0; -} - -// gpic defines this register so as to make geqn not produce `\x's -#define EQN_NO_EXTRA_SPACE_REG "0x" - -void box::extra_space() -{ - printf(".if !r" EQN_NO_EXTRA_SPACE_REG " " - ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n"); - if (positive_space >= 0 || negative_space >= 0) { - if (positive_space > 0) - printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " - ".as1 " LINE_STRING " \\x'-%dM'\n", positive_space); - if (negative_space > 0) - printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " - ".as1 " LINE_STRING " \\x'%dM'\n", negative_space); - positive_space = negative_space = -1; - } - else { - printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " - ".if \\n[" HEIGHT_FORMAT "]>%dM .as1 " LINE_STRING - " \\x'-(\\n[" HEIGHT_FORMAT - "]u-%dM)'\n", - uid, body_height, uid, body_height); - printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " - ".if \\n[" DEPTH_FORMAT "]>%dM .as1 " LINE_STRING - " \\x'\\n[" DEPTH_FORMAT - "]u-%dM'\n", - uid, body_depth, uid, body_depth); - } -} - -int box::compute_metrics(int) -{ - printf(".nr " WIDTH_FORMAT " 0\n", uid); - printf(".nr " HEIGHT_FORMAT " 0\n", uid); - printf(".nr " DEPTH_FORMAT " 0\n", uid); - return FOUND_NOTHING; -} - -void box::compute_subscript_kern() -{ - printf(".nr " SUB_KERN_FORMAT " 0\n", uid); -} - -void box::compute_skew() -{ - printf(".nr " SKEW_FORMAT " 0\n", uid); -} - -void box::output() -{ -} - -void box::check_tabs(int) -{ -} - -int box::is_char() -{ - return 0; -} - -int box::left_is_italic() -{ - return 0; -} - -int box::right_is_italic() -{ - return 0; -} - -void box::hint(unsigned) -{ -} - -void box::handle_char_type(int, int) -{ -} - - -box_list::box_list(box *pp) -{ - p = new box*[10]; - for (int i = 0; i < 10; i++) - p[i] = 0; - maxlen = 10; - len = 1; - p[0] = pp; -} - -void box_list::append(box *pp) -{ - if (len + 1 > maxlen) { - box **oldp = p; - maxlen *= 2; - p = new box*[maxlen]; - memcpy(p, oldp, sizeof(box*)*len); - a_delete oldp; - } - p[len++] = pp; -} - -box_list::~box_list() -{ - for (int i = 0; i < len; i++) - delete p[i]; - a_delete p; -} - -void box_list::list_check_tabs(int level) -{ - for (int i = 0; i < len; i++) - p[i]->check_tabs(level); -} - - -pointer_box::pointer_box(box *pp) : p(pp) -{ - spacing_type = p->spacing_type; -} - -pointer_box::~pointer_box() -{ - delete p; -} - -int pointer_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - return r; -} - -void pointer_box::compute_subscript_kern() -{ - p->compute_subscript_kern(); - printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid); -} - -void pointer_box::compute_skew() -{ - p->compute_skew(); - printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n", - uid, p->uid); -} - -void pointer_box::check_tabs(int level) -{ - p->check_tabs(level); -} - -int simple_box::compute_metrics(int) -{ - printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid); - output(); - printf(DELIMITER_CHAR "\n"); - printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid); - printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid); - printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid); - printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid); - return FOUND_NOTHING; -} - -void simple_box::compute_subscript_kern() -{ - // do nothing, we already computed it in do_metrics -} - -void simple_box::compute_skew() -{ - // do nothing, we already computed it in do_metrics -} - -int box::is_simple() -{ - return 0; -} - -int simple_box::is_simple() -{ - return 1; -} - -quoted_text_box::quoted_text_box(char *s) : text(s) -{ -} - -quoted_text_box::~quoted_text_box() -{ - a_delete text; -} - -void quoted_text_box::output() -{ - if (text) - fputs(text, stdout); -} - -tab_box::tab_box() : disabled(0) -{ -} - -// We treat a tab_box as having width 0 for width computations. - -void tab_box::output() -{ - if (!disabled) - printf("\\t"); -} - -void tab_box::check_tabs(int level) -{ - if (level > 0) { - error("tabs allowed only at outermost level"); - disabled = 1; - } -} - -space_box::space_box() -{ - spacing_type = SUPPRESS_TYPE; -} - -void space_box::output() -{ - printf("\\h'%dM'", thick_space); -} - -half_space_box::half_space_box() -{ - spacing_type = SUPPRESS_TYPE; -} - -void half_space_box::output() -{ - printf("\\h'%dM'", thin_space); -} - -void box_list::list_debug_print(const char *sep) -{ - p[0]->debug_print(); - for (int i = 1; i < len; i++) { - fprintf(stderr, "%s", sep); - p[i]->debug_print(); - } -} - -void quoted_text_box::debug_print() -{ - fprintf(stderr, "\"%s\"", (text ? text : "")); -} - -void half_space_box::debug_print() -{ - fprintf(stderr, "^"); -} - -void space_box::debug_print() -{ - fprintf(stderr, "~"); -} - -void tab_box::debug_print() -{ - fprintf(stderr, ""); -} diff --git a/contrib/groff/src/preproc/eqn/delim.cc b/contrib/groff/src/preproc/eqn/delim.cc deleted file mode 100644 index 29deded..0000000 --- a/contrib/groff/src/preproc/eqn/delim.cc +++ /dev/null @@ -1,381 +0,0 @@ -// -*- 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 "eqn.h" -#include "pbox.h" - -enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 }; - -// Small must be none-zero and must exist in each device. -// Small will be put in the roman font, others are assumed to be -// on the special font (so no font change will be necessary.) - -struct delimiter { - const char *name; - int flags; - const char *small; - const char *chain_format; - const char *ext; - const char *top; - const char *mid; - const char *bot; -} delim_table[] = { - { - "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]", - "\\[parenleftex]", - "\\[parenlefttp]", - 0, - "\\[parenleftbt]", - }, - { - ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]", - "\\[parenrightex]", - "\\[parenrighttp]", - 0, - "\\[parenrightbt]", - }, - { - "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]", - "\\[bracketleftex]", - "\\[bracketlefttp]", - 0, - "\\[bracketleftbt]", - }, - { - "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]", - "\\[bracketrightex]", - "\\[bracketrighttp]", - 0, - "\\[bracketrightbt]", - }, - { - "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]", - "\\[braceleftex]", - "\\[bracelefttp]", - "\\[braceleftmid]", - "\\[braceleftbt]", - }, - { - "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]", - "\\[bracerightex]", - "\\[bracerighttp]", - "\\[bracerightmid]", - "\\[bracerightbt]", - }, - { - "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]", - "\\[barex]", - }, - { - "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]", - "\\[bracketleftex]", - 0, - 0, - "\\[bracketleftbt]", - }, - { - "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]", - "\\[bracketrightex]", - 0, - 0, - "\\[bracketrightbt]", - }, - { - "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]", - "\\[bracketleftex]", - "\\[bracketlefttp]", - }, - { - "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]", - "\\[bracketrightex]", - "\\[bracketrighttp]", - }, - { - "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]", - "\\[bardblex]", - }, - { - "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]", - }, - { - ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]", - }, - { - "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]", - "\\[arrowvertex]", - "\\[arrowverttp]", - }, - { - "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]", - "\\[arrowvertex]", - 0, - 0, - "\\[arrowvertbt]", - }, - { - "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]", - "\\[arrowvertex]", - "\\[arrowverttp]", - 0, - "\\[arrowvertbt]", - }, -}; - -const int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0])); - -class delim_box : public box { -private: - char *left; - char *right; - box *p; -public: - delim_box(char *, box *, char *); - ~delim_box(); - int compute_metrics(int); - void output(); - void check_tabs(int); - void debug_print(); -}; - -box *make_delim_box(char *l, box *pp, char *r) -{ - if (l != 0 && *l == '\0') { - a_delete l; - l = 0; - } - if (r != 0 && *r == '\0') { - a_delete r; - r = 0; - } - return new delim_box(l, pp, r); -} - -delim_box::delim_box(char *l, box *pp, char *r) -: left(l), right(r), p(pp) -{ -} - -delim_box::~delim_box() -{ - a_delete left; - a_delete right; - delete p; -} - -static void build_extensible(const char *ext, const char *top, const char *mid, - const char *bot) -{ - assert(ext != 0); - printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", - ext); - printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n"); - printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n"); - if (top) { - printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" - ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", - top); - printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n"); - printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n"); - } - if (mid) { - printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" - ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", - mid); - printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n"); - printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n"); - } - if (bot) { - printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" - ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", - bot); - printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n"); - printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n"); - } - printf(".nr " TOTAL_HEIGHT_REG " 0"); - if (top) - printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]"); - if (bot) - printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]"); - if (mid) - printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]"); - printf("\n"); - // determine how many extensible characters we need - printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]"); - if (mid) - printf("/2"); - printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n[" - EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n"); - - printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n[" - EXT_DEPTH_REG "]*\\n[" TEMP_REG "]"); - if (mid) - printf("*2"); - printf(")\n"); - printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR - "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n", - axis_height); - if (top) - printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'" - "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR - "\\v'\\n[" TOP_DEPTH_REG "]u'\n", - top); - - // this macro appends $2 copies of $3 to string $1 - printf(".de " REPEAT_APPEND_STRING_MACRO "\n" - ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n" - "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n" - ".\\}\n" - "..\n"); - - printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] " - "\\v'\\n[" EXT_HEIGHT_REG "]u'" - "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR - "\\v'\\n[" EXT_DEPTH_REG "]u'\n", - ext); - - if (mid) { - printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'" - "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR - "\\v'\\n[" MID_DEPTH_REG "]u'\n", - mid); - printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING - " \\n[" TEMP_REG "] " - "\\v'\\n[" EXT_HEIGHT_REG "]u'" - "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR - "\\v'\\n[" EXT_DEPTH_REG "]u'\n", - ext); - } - if (bot) - printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'" - "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR - "\\v'\\n[" BOT_DEPTH_REG "]u'\n", - bot); - printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n"); -} - -static void define_extensible_string(char *delim, int uid, - left_or_right_t left_or_right) -{ - printf(".ds " DELIM_STRING "\n"); - delimiter *d = delim_table; - int delim_len = strlen(delim); - int i; - for (i = 0; i < DELIM_TABLE_SIZE; i++, d++) - if (strncmp(delim, d->name, delim_len) == 0 - && (left_or_right & d->flags) != 0) - break; - if (i >= DELIM_TABLE_SIZE) { - error("there is no `%1' delimiter", delim); - printf(".nr " DELIM_WIDTH_REG " 0\n"); - return; - } - - printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n" - ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR - "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n" - ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n" - ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] " - "\\{", - current_roman_font, d->small, axis_height, - current_roman_font, d->small); - - char buf[256]; - sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]"); - printf(".nr " INDEX_REG " 0\n" - ".de " TEMP_MACRO "\n" - ".ie c%s \\{\\\n" - ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n" - ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR - "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n" - ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n" - ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] " - "\\{.nr " INDEX_REG " +1\n" - "." TEMP_MACRO "\n" - ".\\}\\}\n" - ".el .nr " INDEX_REG " 0-1\n" - "..\n" - "." TEMP_MACRO "\n", - buf, buf, axis_height, buf); - if (d->ext) { - printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext); - build_extensible(d->ext, d->top, d->mid, d->bot); - printf(".\\}\\}\n"); - } - printf(".\\}\n"); - printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n"); - printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" - ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n", - uid, uid, axis_height); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" - ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n", - uid, uid, axis_height); -} - -int delim_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM" - ">?(\\n[" DEPTH_FORMAT "]+%dM)\n", - p->uid, axis_height, p->uid, axis_height); - printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500" - ">?(\\n[" DELTA_REG "]*2-%dM)\n", - delimiter_factor, delimiter_shortfall); - if (left) { - define_extensible_string(left, uid, LEFT_DELIM); - printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n", - uid); - if (r) - printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n"); - } - if (right) { - define_extensible_string(right, uid, RIGHT_DELIM); - printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n", - uid); - } - return r; -} - -void delim_box::output() -{ - if (left) - printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid); - p->output(); - if (right) - printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid); -} - -void delim_box::check_tabs(int level) -{ - p->check_tabs(level); -} - -void delim_box::debug_print() -{ - fprintf(stderr, "left \"%s\" { ", left ? left : ""); - p->debug_print(); - fprintf(stderr, " }"); - if (right) - fprintf(stderr, " right \"%s\"", right); -} - diff --git a/contrib/groff/src/preproc/eqn/lex.cc b/contrib/groff/src/preproc/eqn/lex.cc deleted file mode 100644 index 4e62f86..0000000 --- a/contrib/groff/src/preproc/eqn/lex.cc +++ /dev/null @@ -1,1166 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "eqn.h" -#include "eqn_tab.h" -#include "stringclass.h" -#include "ptable.h" - -struct definition { - char is_macro; - char is_simple; - union { - int tok; - char *contents; - }; - definition(); - ~definition(); -}; - -definition::definition() : is_macro(1), is_simple(0) -{ - contents = 0; -} - -definition::~definition() -{ - if (is_macro) - a_delete contents; -} - -declare_ptable(definition) -implement_ptable(definition) - -PTABLE(definition) macro_table; - -static struct { - const char *name; - int token; -} token_table[] = { - { "over", OVER }, - { "smallover", SMALLOVER }, - { "sqrt", SQRT }, - { "sub", SUB }, - { "sup", SUP }, - { "lpile", LPILE }, - { "rpile", RPILE }, - { "cpile", CPILE }, - { "pile", PILE }, - { "left", LEFT }, - { "right", RIGHT }, - { "to", TO }, - { "from", FROM }, - { "size", SIZE }, - { "font", FONT }, - { "roman", ROMAN }, - { "bold", BOLD }, - { "italic", ITALIC }, - { "fat", FAT }, - { "bar", BAR }, - { "under", UNDER }, - { "accent", ACCENT }, - { "uaccent", UACCENT }, - { "above", ABOVE }, - { "fwd", FWD }, - { "back", BACK }, - { "down", DOWN }, - { "up", UP }, - { "matrix", MATRIX }, - { "col", COL }, - { "lcol", LCOL }, - { "rcol", RCOL }, - { "ccol", CCOL }, - { "mark", MARK }, - { "lineup", LINEUP }, - { "space", SPACE }, - { "gfont", GFONT }, - { "gsize", GSIZE }, - { "define", DEFINE }, - { "sdefine", SDEFINE }, - { "ndefine", NDEFINE }, - { "tdefine", TDEFINE }, - { "undef", UNDEF }, - { "ifdef", IFDEF }, - { "include", INCLUDE }, - { "copy", INCLUDE }, - { "delim", DELIM }, - { "chartype", CHARTYPE }, - { "type", TYPE }, - { "vcenter", VCENTER }, - { "set", SET }, - { "opprime", PRIME }, - { "grfont", GRFONT }, - { "gbfont", GBFONT }, - { "split", SPLIT }, - { "nosplit", NOSPLIT }, - { "special", SPECIAL }, -}; - -static struct { - const char *name; - const char *def; -} def_table[] = { - { "ALPHA", "\\(*A" }, - { "BETA", "\\(*B" }, - { "CHI", "\\(*X" }, - { "DELTA", "\\(*D" }, - { "EPSILON", "\\(*E" }, - { "ETA", "\\(*Y" }, - { "GAMMA", "\\(*G" }, - { "IOTA", "\\(*I" }, - { "KAPPA", "\\(*K" }, - { "LAMBDA", "\\(*L" }, - { "MU", "\\(*M" }, - { "NU", "\\(*N" }, - { "OMEGA", "\\(*W" }, - { "OMICRON", "\\(*O" }, - { "PHI", "\\(*F" }, - { "PI", "\\(*P" }, - { "PSI", "\\(*Q" }, - { "RHO", "\\(*R" }, - { "SIGMA", "\\(*S" }, - { "TAU", "\\(*T" }, - { "THETA", "\\(*H" }, - { "UPSILON", "\\(*U" }, - { "XI", "\\(*C" }, - { "ZETA", "\\(*Z" }, - { "Alpha", "\\(*A" }, - { "Beta", "\\(*B" }, - { "Chi", "\\(*X" }, - { "Delta", "\\(*D" }, - { "Epsilon", "\\(*E" }, - { "Eta", "\\(*Y" }, - { "Gamma", "\\(*G" }, - { "Iota", "\\(*I" }, - { "Kappa", "\\(*K" }, - { "Lambda", "\\(*L" }, - { "Mu", "\\(*M" }, - { "Nu", "\\(*N" }, - { "Omega", "\\(*W" }, - { "Omicron", "\\(*O" }, - { "Phi", "\\(*F" }, - { "Pi", "\\(*P" }, - { "Psi", "\\(*Q" }, - { "Rho", "\\(*R" }, - { "Sigma", "\\(*S" }, - { "Tau", "\\(*T" }, - { "Theta", "\\(*H" }, - { "Upsilon", "\\(*U" }, - { "Xi", "\\(*C" }, - { "Zeta", "\\(*Z" }, - { "alpha", "\\(*a" }, - { "beta", "\\(*b" }, - { "chi", "\\(*x" }, - { "delta", "\\(*d" }, - { "epsilon", "\\(*e" }, - { "eta", "\\(*y" }, - { "gamma", "\\(*g" }, - { "iota", "\\(*i" }, - { "kappa", "\\(*k" }, - { "lambda", "\\(*l" }, - { "mu", "\\(*m" }, - { "nu", "\\(*n" }, - { "omega", "\\(*w" }, - { "omicron", "\\(*o" }, - { "phi", "\\(*f" }, - { "pi", "\\(*p" }, - { "psi", "\\(*q" }, - { "rho", "\\(*r" }, - { "sigma", "\\(*s" }, - { "tau", "\\(*t" }, - { "theta", "\\(*h" }, - { "upsilon", "\\(*u" }, - { "xi", "\\(*c" }, - { "zeta", "\\(*z" }, - { "max", "{type \"operator\" roman \"max\"}" }, - { "min", "{type \"operator\" roman \"min\"}" }, - { "lim", "{type \"operator\" roman \"lim\"}" }, - { "sin", "{type \"operator\" roman \"sin\"}" }, - { "cos", "{type \"operator\" roman \"cos\"}" }, - { "tan", "{type \"operator\" roman \"tan\"}" }, - { "sinh", "{type \"operator\" roman \"sinh\"}" }, - { "cosh", "{type \"operator\" roman \"cosh\"}" }, - { "tanh", "{type \"operator\" roman \"tanh\"}" }, - { "arc", "{type \"operator\" roman \"arc\"}" }, - { "log", "{type \"operator\" roman \"log\"}" }, - { "ln", "{type \"operator\" roman \"ln\"}" }, - { "exp", "{type \"operator\" roman \"exp\"}" }, - { "Re", "{type \"operator\" roman \"Re\"}" }, - { "Im", "{type \"operator\" roman \"Im\"}" }, - { "det", "{type \"operator\" roman \"det\"}" }, - { "and", "{roman \"and\"}" }, - { "if", "{roman \"if\"}" }, - { "for", "{roman \"for\"}" }, - { "sum", "{type \"operator\" vcenter size +5 \\(*S}" }, - { "prod", "{type \"operator\" vcenter size +5 \\(*P}" }, - { "int", "{type \"operator\" vcenter size +8 \\(is}" }, - { "union", "{type \"operator\" vcenter size +5 \\(cu}" }, - { "inter", "{type \"operator\" vcenter size +5 \\(ca}" }, - { "times", "type \"binary\" \\(mu" }, - { "ldots", "type \"inner\" { . . . }" }, - { "inf", "\\(if" }, - { "partial", "\\(pd" }, - { "nothing", "\"\"" }, - { "half", "{1 smallover 2}" }, - { "hat_def", "roman \"^\"" }, - { "hat", "accent { hat_def }" }, - { "dot_def", "back 15 \"\\v'-52M'.\\v'52M'\"" }, - { "dot", "accent { dot_def }" }, - { "dotdot_def", "back 25 \"\\v'-52M'..\\v'52M'\"" }, - { "dotdot", "accent { dotdot_def }" }, - { "tilde_def", "\"~\"" }, - { "tilde", "accent { tilde_def }" }, - { "utilde_def", "\"\\v'75M'~\\v'-75M'\"" }, - { "utilde", "uaccent { utilde_def }" }, - { "vec_def", "up 52 size -5 \\(->" }, - { "vec", "accent { vec_def }" }, - { "dyad_def", "up 52 size -5 {\\(<- back 60 \\(->}" }, - { "dyad", "accent { dyad_def }" }, - { "==", "type \"relation\" \\(==" }, - { "!=", "type \"relation\" \\(!=" }, - { "+-", "type \"binary\" \\(+-" }, - { "->", "type \"relation\" \\(->" }, - { "<-", "type \"relation\" \\(<-" }, - { "<<", "{ < back 20 < }" }, - { ">>", "{ > back 20 > }" }, - { "...", "type \"inner\" vcenter { . . . }" }, - { "prime", "'" }, - { "approx", "type \"relation\" \"\\(~=\"" }, - { "grad", "\\(gr" }, - { "del", "\\(gr" }, - { "cdot", "type \"binary\" vcenter ." }, - { "dollar", "$" }, -}; - -void init_table(const char *device) -{ - unsigned int i; - for (i = 0; i < sizeof(token_table)/sizeof(token_table[0]); i++) { - definition *def = new definition; - def->is_macro = 0; - def->tok = token_table[i].token; - macro_table.define(token_table[i].name, def); - } - for (i = 0; i < sizeof(def_table)/sizeof(def_table[0]); i++) { - definition *def = new definition; - def->is_macro = 1; - def->contents = strsave(def_table[i].def); - def->is_simple = 1; - macro_table.define(def_table[i].name, def); - } - definition *def = new definition; - def->is_macro = 1; - def->contents = strsave("1"); - macro_table.define(device, def); -} - -class input { - input *next; -public: - input(input *p); - virtual ~input(); - virtual int get() = 0; - virtual int peek() = 0; - virtual int get_location(char **, int *); - - friend int get_char(); - friend int peek_char(); - friend int get_location(char **, int *); - friend void init_lex(const char *str, const char *filename, int lineno); -}; - -class file_input : public input { - FILE *fp; - char *filename; - int lineno; - string line; - const char *ptr; - int read_line(); -public: - file_input(FILE *, const char *, input *); - ~file_input(); - int get(); - int peek(); - int get_location(char **, int *); -}; - - -class macro_input : public input { - char *s; - char *p; -public: - macro_input(const char *, input *); - ~macro_input(); - int get(); - int peek(); -}; - -class top_input : public macro_input { - char *filename; - int lineno; - public: - top_input(const char *, const char *, int, input *); - ~top_input(); - int get(); - int get_location(char **, int *); -}; - -class argument_macro_input: public input { - char *s; - char *p; - char *ap; - int argc; - char *argv[9]; -public: - argument_macro_input(const char *, int, char **, input *); - ~argument_macro_input(); - int get(); - int peek(); -}; - -input::input(input *x) : next(x) -{ -} - -input::~input() -{ -} - -int input::get_location(char **, int *) -{ - return 0; -} - -file_input::file_input(FILE *f, const char *fn, input *p) -: input(p), lineno(0), ptr("") -{ - fp = f; - filename = strsave(fn); -} - -file_input::~file_input() -{ - a_delete filename; - fclose(fp); -} - -int file_input::read_line() -{ - for (;;) { - line.clear(); - lineno++; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - else if (invalid_input_char(c)) - lex_error("invalid input character code %1", c); - else { - line += char(c); - if (c == '\n') - break; - } - } - if (line.length() == 0) - return 0; - if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'E' - && (line[2] == 'Q' || line[2] == 'N') - && (line.length() == 3 || line[3] == ' ' || line[3] == '\n' - || compatible_flag))) { - line += '\0'; - ptr = line.contents(); - return 1; - } - } -} - -int file_input::get() -{ - if (*ptr != '\0' || read_line()) - return *ptr++ & 0377; - else - return EOF; -} - -int file_input::peek() -{ - if (*ptr != '\0' || read_line()) - return *ptr; - else - return EOF; -} - -int file_input::get_location(char **fnp, int *lnp) -{ - *fnp = filename; - *lnp = lineno; - return 1; -} - -macro_input::macro_input(const char *str, input *x) : input(x) -{ - p = s = strsave(str); -} - -macro_input::~macro_input() -{ - a_delete s; -} - -int macro_input::get() -{ - if (p == 0 || *p == '\0') - return EOF; - else - return *p++ & 0377; -} - -int macro_input::peek() -{ - if (p == 0 || *p == '\0') - return EOF; - else - return *p & 0377; -} - -top_input::top_input(const char *str, const char *fn, int ln, input *x) -: macro_input(str, x), lineno(ln) -{ - filename = strsave(fn); -} - -top_input::~top_input() -{ - a_delete filename; -} - -int top_input::get() -{ - int c = macro_input::get(); - if (c == '\n') - lineno++; - return c; -} - -int top_input::get_location(char **fnp, int *lnp) -{ - *fnp = filename; - *lnp = lineno; - return 1; -} - -// Character representing $1. Must be invalid input character. -#define ARG1 14 - -argument_macro_input::argument_macro_input(const char *body, int ac, - char **av, input *x) -: input(x), ap(0), argc(ac) -{ - int i; - for (i = 0; i < argc; i++) - argv[i] = av[i]; - p = s = strsave(body); - int j = 0; - for (i = 0; s[i] != '\0'; i++) - if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') { - if (s[i+1] != '0') - s[j++] = ARG1 + s[++i] - '1'; - } - else - s[j++] = s[i]; - s[j] = '\0'; -} - - -argument_macro_input::~argument_macro_input() -{ - for (int i = 0; i < argc; i++) - a_delete argv[i]; - a_delete s; -} - -int argument_macro_input::get() -{ - if (ap) { - if (*ap != '\0') - return *ap++ & 0377; - ap = 0; - } - if (p == 0) - return EOF; - while (*p >= ARG1 && *p <= ARG1 + 8) { - int i = *p++ - ARG1; - if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { - ap = argv[i]; - return *ap++ & 0377; - } - } - if (*p == '\0') - return EOF; - return *p++ & 0377; -} - -int argument_macro_input::peek() -{ - if (ap) { - if (*ap != '\0') - return *ap & 0377; - ap = 0; - } - if (p == 0) - return EOF; - while (*p >= ARG1 && *p <= ARG1 + 8) { - int i = *p++ - ARG1; - if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { - ap = argv[i]; - return *ap & 0377; - } - } - if (*p == '\0') - return EOF; - return *p & 0377; -} - -static input *current_input = 0; - -/* we insert a newline between input from different levels */ - -int get_char() -{ - if (current_input == 0) - return EOF; - else { - int c = current_input->get(); - if (c != EOF) - return c; - else { - input *tem = current_input; - current_input = current_input->next; - delete tem; - return '\n'; - } - } -} - -int peek_char() -{ - if (current_input == 0) - return EOF; - else { - int c = current_input->peek(); - if (c != EOF) - return c; - else - return '\n'; - } -} - -int get_location(char **fnp, int *lnp) -{ - for (input *p = current_input; p; p = p->next) - if (p->get_location(fnp, lnp)) - return 1; - return 0; -} - -string token_buffer; -const int NCONTEXT = 4; -string context_ring[NCONTEXT]; -int context_index = 0; - -void flush_context() -{ - for (int i = 0; i < NCONTEXT; i++) - context_ring[i] = ""; - context_index = 0; -} - -void show_context() -{ - int i = context_index; - fputs(" context is\n\t", stderr); - for (;;) { - int j = (i + 1) % NCONTEXT; - if (j == context_index) { - fputs(">>> ", stderr); - put_string(context_ring[i], stderr); - fputs(" <<<", stderr); - break; - } - else if (context_ring[i].length() > 0) { - put_string(context_ring[i], stderr); - putc(' ', stderr); - } - i = j; - } - putc('\n', stderr); -} - -void add_context(const string &s) -{ - context_ring[context_index] = s; - context_index = (context_index + 1) % NCONTEXT; -} - -void add_context(char c) -{ - context_ring[context_index] = c; - context_index = (context_index + 1) % NCONTEXT; -} - -void add_quoted_context(const string &s) -{ - string &r = context_ring[context_index]; - r = '"'; - for (int i = 0; i < s.length(); i++) - if (s[i] == '"') - r += "\\\""; - else - r += s[i]; - r += '"'; - context_index = (context_index + 1) % NCONTEXT; -} - -void init_lex(const char *str, const char *filename, int lineno) -{ - while (current_input != 0) { - input *tem = current_input; - current_input = current_input->next; - delete tem; - } - current_input = new top_input(str, filename, lineno, 0); - flush_context(); -} - - -void get_delimited_text() -{ - char *filename; - int lineno; - int got_location = get_location(&filename, &lineno); - int start = get_char(); - while (start == ' ' || start == '\t' || start == '\n') - start = get_char(); - token_buffer.clear(); - if (start == EOF) { - if (got_location) - error_with_file_and_line(filename, lineno, - "end of input while defining macro"); - else - error("end of input while defining macro"); - return; - } - for (;;) { - int c = get_char(); - if (c == EOF) { - if (got_location) - error_with_file_and_line(filename, lineno, - "end of input while defining macro"); - else - error("end of input while defining macro"); - add_context(start + token_buffer); - return; - } - if (c == start) - break; - token_buffer += char(c); - } - add_context(start + token_buffer + start); -} - -void interpolate_macro_with_args(const char *body) -{ - char *argv[9]; - int argc = 0; - int i; - for (i = 0; i < 9; i++) - argv[i] = 0; - int level = 0; - int c; - do { - token_buffer.clear(); - for (;;) { - c = get_char(); - if (c == EOF) { - lex_error("end of input while scanning macro arguments"); - break; - } - if (level == 0 && (c == ',' || c == ')')) { - if (token_buffer.length() > 0) { - token_buffer += '\0'; - argv[argc] = strsave(token_buffer.contents()); - } - // for `foo()', argc = 0 - if (argc > 0 || c != ')' || i > 0) - argc++; - break; - } - token_buffer += char(c); - if (c == '(') - level++; - else if (c == ')') - level--; - } - } while (c != ')' && c != EOF); - current_input = new argument_macro_input(body, argc, argv, current_input); -} - -/* If lookup flag is non-zero the token will be looked up to see -if it is macro. If it's 1, it will looked up to see if it's a token. -*/ - -int get_token(int lookup_flag = 0) -{ - for (;;) { - int c = get_char(); - while (c == ' ' || c == '\n') - c = get_char(); - switch (c) { - case EOF: - { - add_context("end of input"); - } - return 0; - case '"': - { - int quoted = 0; - token_buffer.clear(); - for (;;) { - c = get_char(); - if (c == EOF) { - lex_error("missing \""); - break; - } - else if (c == '\n') { - lex_error("newline before end of quoted text"); - break; - } - else if (c == '"') { - if (!quoted) - break; - token_buffer[token_buffer.length() - 1] = '"'; - quoted = 0; - } - else { - token_buffer += c; - quoted = quoted ? 0 : c == '\\'; - } - } - } - add_quoted_context(token_buffer); - return QUOTED_TEXT; - case '{': - case '}': - case '^': - case '~': - case '\t': - add_context(c); - return c; - default: - { - int break_flag = 0; - int quoted = 0; - token_buffer.clear(); - if (c == '\\') - quoted = 1; - else - token_buffer += c; - int done = 0; - while (!done) { - c = peek_char(); - if (!quoted && lookup_flag != 0 && c == '(') { - token_buffer += '\0'; - definition *def = macro_table.lookup(token_buffer.contents()); - if (def && def->is_macro && !def->is_simple) { - (void)get_char(); // skip initial '(' - interpolate_macro_with_args(def->contents); - break_flag = 1; - break; - } - token_buffer.set_length(token_buffer.length() - 1); - } - if (quoted) { - quoted = 0; - switch (c) { - case EOF: - lex_error("`\\' ignored at end of equation"); - done = 1; - break; - case '\n': - lex_error("`\\' ignored because followed by newline"); - done = 1; - break; - case '\t': - lex_error("`\\' ignored because followed by tab"); - done = 1; - break; - case '"': - (void)get_char(); - token_buffer += '"'; - break; - default: - (void)get_char(); - token_buffer += '\\'; - token_buffer += c; - break; - } - } - else { - switch (c) { - case EOF: - case '{': - case '}': - case '^': - case '~': - case '"': - case ' ': - case '\t': - case '\n': - done = 1; - break; - case '\\': - (void)get_char(); - quoted = 1; - break; - default: - (void)get_char(); - token_buffer += char(c); - break; - } - } - } - if (break_flag || token_buffer.length() == 0) - break; - if (lookup_flag != 0) { - token_buffer += '\0'; - definition *def = macro_table.lookup(token_buffer.contents()); - token_buffer.set_length(token_buffer.length() - 1); - if (def) { - if (def->is_macro) { - current_input = new macro_input(def->contents, current_input); - break; - } - else if (lookup_flag == 1) { - add_context(token_buffer); - return def->tok; - } - } - } - add_context(token_buffer); - return TEXT; - } - } - } -} - -void do_include() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad filename for include"); - return; - } - token_buffer += '\0'; - const char *filename = token_buffer.contents(); - errno = 0; - FILE *fp = fopen(filename, "r"); - if (fp == 0) { - lex_error("can't open included file `%1'", filename); - return; - } - current_input = new file_input(fp, filename, current_input); -} - -void ignore_definition() -{ - int t = get_token(); - if (t != TEXT) { - lex_error("bad definition"); - return; - } - get_delimited_text(); -} - -void do_definition(int is_simple) -{ - int t = get_token(); - if (t != TEXT) { - lex_error("bad definition"); - return; - } - token_buffer += '\0'; - const char *name = token_buffer.contents(); - definition *def = macro_table.lookup(name); - if (def == 0) { - def = new definition; - macro_table.define(name, def); - } - else if (def->is_macro) { - a_delete def->contents; - } - get_delimited_text(); - token_buffer += '\0'; - def->is_macro = 1; - def->contents = strsave(token_buffer.contents()); - def->is_simple = is_simple; -} - -void do_undef() -{ - int t = get_token(); - if (t != TEXT) { - lex_error("bad undef command"); - return; - } - token_buffer += '\0'; - macro_table.define(token_buffer.contents(), 0); -} - -void do_gsize() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad argument to gsize command"); - return; - } - token_buffer += '\0'; - if (!set_gsize(token_buffer.contents())) - lex_error("invalid size `%1'", token_buffer.contents()); -} - -void do_gfont() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad argument to gfont command"); - return; - } - token_buffer += '\0'; - set_gfont(token_buffer.contents()); -} - -void do_grfont() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad argument to grfont command"); - return; - } - token_buffer += '\0'; - set_grfont(token_buffer.contents()); -} - -void do_gbfont() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad argument to gbfont command"); - return; - } - token_buffer += '\0'; - set_gbfont(token_buffer.contents()); -} - -void do_space() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad argument to space command"); - return; - } - token_buffer += '\0'; - char *ptr; - long n = strtol(token_buffer.contents(), &ptr, 10); - if (n == 0 && ptr == token_buffer.contents()) - lex_error("bad argument `%1' to space command", token_buffer.contents()); - else - set_space(int(n)); -} - -void do_ifdef() -{ - int t = get_token(); - if (t != TEXT) { - lex_error("bad ifdef"); - return; - } - token_buffer += '\0'; - definition *def = macro_table.lookup(token_buffer.contents()); - int result = def && def->is_macro && !def->is_simple; - get_delimited_text(); - if (result) { - token_buffer += '\0'; - current_input = new macro_input(token_buffer.contents(), current_input); - } -} - -void do_delim() -{ - int c = get_char(); - while (c == ' ' || c == '\n') - c = get_char(); - int d; - if (c == EOF || (d = get_char()) == EOF) - lex_error("end of file while reading argument to `delim'"); - else { - if (c == 'o' && d == 'f' && peek_char() == 'f') { - (void)get_char(); - start_delim = end_delim = '\0'; - } - else { - start_delim = c; - end_delim = d; - } - } -} - -void do_chartype() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad chartype"); - return; - } - token_buffer += '\0'; - string type = token_buffer; - t = get_token(); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad chartype"); - return; - } - token_buffer += '\0'; - set_char_type(type.contents(), strsave(token_buffer.contents())); -} - -void do_set() -{ - int t = get_token(2); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad set"); - return; - } - token_buffer += '\0'; - string param = token_buffer; - t = get_token(); - if (t != TEXT && t != QUOTED_TEXT) { - lex_error("bad set"); - return; - } - token_buffer += '\0'; - int n; - if (sscanf(&token_buffer[0], "%d", &n) != 1) { - lex_error("bad number `%1'", token_buffer.contents()); - return; - } - set_param(param.contents(), n); -} - -int yylex() -{ - for (;;) { - int tk = get_token(1); - switch(tk) { - case UNDEF: - do_undef(); - break; - case SDEFINE: - do_definition(1); - break; - case DEFINE: - do_definition(0); - break; - case TDEFINE: - if (!nroff) - do_definition(0); - else - ignore_definition(); - break; - case NDEFINE: - if (nroff) - do_definition(0); - else - ignore_definition(); - break; - case GSIZE: - do_gsize(); - break; - case GFONT: - do_gfont(); - break; - case GRFONT: - do_grfont(); - break; - case GBFONT: - do_gbfont(); - break; - case SPACE: - do_space(); - break; - case INCLUDE: - do_include(); - break; - case IFDEF: - do_ifdef(); - break; - case DELIM: - do_delim(); - break; - case CHARTYPE: - do_chartype(); - break; - case SET: - do_set(); - break; - case QUOTED_TEXT: - case TEXT: - token_buffer += '\0'; - yylval.str = strsave(token_buffer.contents()); - // fall through - default: - return tk; - } - } -} - -void lex_error(const char *message, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - char *filename; - int lineno; - if (!get_location(&filename, &lineno)) - error(message, arg1, arg2, arg3); - else - error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); -} - -void yyerror(const char *s) -{ - char *filename; - int lineno; - if (!get_location(&filename, &lineno)) - error(s); - else - error_with_file_and_line(filename, lineno, s); - show_context(); -} - diff --git a/contrib/groff/src/preproc/eqn/limit.cc b/contrib/groff/src/preproc/eqn/limit.cc deleted file mode 100644 index c8b5587..0000000 --- a/contrib/groff/src/preproc/eqn/limit.cc +++ /dev/null @@ -1,195 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h" -#include "pbox.h" - -class limit_box : public box { -private: - box *p; - box *from; - box *to; -public: - limit_box(box *, box *, box *); - ~limit_box(); - int compute_metrics(int); - void output(); - void debug_print(); - void check_tabs(int); -}; - -box *make_limit_box(box *pp, box *qq, box *rr) -{ - return new limit_box(pp, qq, rr); -} - -limit_box::limit_box(box *pp, box *qq, box *rr) -: p(pp), from(qq), to(rr) -{ - spacing_type = p->spacing_type; -} - -limit_box::~limit_box() -{ - delete p; - delete from; - delete to; -} - -int limit_box::compute_metrics(int style) -{ - printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid); - if (!(style <= SCRIPT_STYLE && one_size_reduction_flag)) - set_script_size(); - printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid); - int res = 0; - int mark_uid = -1; - if (from != 0) { - res = from->compute_metrics(cramped_style(script_style(style))); - if (res) - mark_uid = from->uid; - } - if (to != 0) { - int r = to->compute_metrics(script_style(style)); - if (res && r) - error("multiple marks and lineups"); - else { - mark_uid = to->uid; - res = r; - } - } - printf(".ps \\n[" SIZE_FORMAT "]u\n", uid); - int r = p->compute_metrics(style); - p->compute_subscript_kern(); - if (res && r) - error("multiple marks and lineups"); - else { - mark_uid = p->uid; - res = r; - } - printf(".nr " LEFT_WIDTH_FORMAT " " - "0\\n[" WIDTH_FORMAT "]", - uid, p->uid); - if (from != 0) - printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", - p->uid, from->uid); - if (to != 0) - printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", - p->uid, to->uid); - printf("/2\n"); - printf(".nr " WIDTH_FORMAT " " - "0\\n[" WIDTH_FORMAT "]", - uid, p->uid); - if (from != 0) - printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", - p->uid, from->uid); - if (to != 0) - printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])", - p->uid, to->uid); - printf("/2+\\n[" LEFT_WIDTH_FORMAT "]\n", uid); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid); - if (to != 0) - printf(">?\\n[" WIDTH_FORMAT "]", to->uid); - if (from != 0) - printf(">?\\n[" WIDTH_FORMAT "]", from->uid); - printf("\n"); - if (res) - printf(".nr " MARK_REG " +(\\n[" LEFT_WIDTH_FORMAT "]" - "-(\\n[" WIDTH_FORMAT "]/2))\n", - uid, mark_uid); - if (to != 0) { - printf(".nr " SUP_RAISE_FORMAT " %dM+\\n[" DEPTH_FORMAT - "]>?%dM+\\n[" HEIGHT_FORMAT "]\n", - uid, big_op_spacing1, to->uid, big_op_spacing3, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" - HEIGHT_FORMAT "]+%dM\n", - uid, uid, to->uid, big_op_spacing5); - } - else - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - if (from != 0) { - printf(".nr " SUB_LOWER_FORMAT " %dM+\\n[" HEIGHT_FORMAT - "]>?%dM+\\n[" DEPTH_FORMAT "]\n", - uid, big_op_spacing2, from->uid, big_op_spacing4, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n[" - DEPTH_FORMAT "]+%dM\n", - uid, uid, from->uid, big_op_spacing5); - } - else - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - return res; -} - -void limit_box::output() -{ - printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid); - if (to != 0) { - printf("\\Z" DELIMITER_CHAR); - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u" - "+(-\\n[" WIDTH_FORMAT "]u+\\n[" SUB_KERN_FORMAT "]u/2u)'", - uid, to->uid, p->uid); - to->output(); - printf(DELIMITER_CHAR); - } - if (from != 0) { - printf("\\Z" DELIMITER_CHAR); - printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid); - printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u" - "+(-\\n[" SUB_KERN_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'", - uid, p->uid, from->uid); - from->output(); - printf(DELIMITER_CHAR); - } - printf("\\s[\\n[" SIZE_FORMAT "]u]", uid); - printf("\\Z" DELIMITER_CHAR); - printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u" - "-(\\n[" WIDTH_FORMAT "]u/2u)'", - uid, p->uid); - p->output(); - printf(DELIMITER_CHAR); - printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); -} - -void limit_box::debug_print() -{ - fprintf(stderr, "{ "); - p->debug_print(); - fprintf(stderr, " }"); - if (from) { - fprintf(stderr, " from { "); - from->debug_print(); - fprintf(stderr, " }"); - } - if (to) { - fprintf(stderr, " to { "); - to->debug_print(); - fprintf(stderr, " }"); - } -} - -void limit_box::check_tabs(int level) -{ - if (to) - to->check_tabs(level + 1); - if (from) - from->check_tabs(level + 1); - p->check_tabs(level + 1); -} diff --git a/contrib/groff/src/preproc/eqn/list.cc b/contrib/groff/src/preproc/eqn/list.cc deleted file mode 100644 index 1118fa1..0000000 --- a/contrib/groff/src/preproc/eqn/list.cc +++ /dev/null @@ -1,237 +0,0 @@ -// -*- 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 "eqn.h" -#include "pbox.h" - -list_box *box::to_list_box() -{ - return 0; -} - -list_box *list_box::to_list_box() -{ - return this; -} - -void list_box::append(box *pp) -{ - list_box *q = pp->to_list_box(); - if (q == 0) - list.append(pp); - else { - for (int i = 0; i < q->list.len; i++) { - list.append(q->list.p[i]); - q->list.p[i] = 0; - } - q->list.len = 0; - delete q; - } -} - -list_box::list_box(box *pp) : list(pp), sty(-1) -{ - list_box *q = pp->to_list_box(); - if (q != 0) { - // flatten it - list.p[0] = q->list.p[0]; - for (int i = 1; i < q->list.len; i++) { - list.append(q->list.p[i]); - q->list.p[i] = 0; - } - q->list.len = 0; - delete q; - } -} - -static int compute_spacing(int is_script, int left, int right) -{ - if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE) - return 0; - if (left == PUNCTUATION_TYPE) - return is_script ? 0 : thin_space; - if (left == OPENING_TYPE || right == CLOSING_TYPE) - return 0; - if (right == BINARY_TYPE || left == BINARY_TYPE) - return is_script ? 0 : medium_space; - if (right == RELATION_TYPE) { - if (left == RELATION_TYPE) - return 0; - else - return is_script ? 0 : thick_space; - } - if (left == RELATION_TYPE) - return is_script ? 0 : thick_space; - if (right == OPERATOR_TYPE) - return thin_space; - if (left == INNER_TYPE || right == INNER_TYPE) - return is_script ? 0 : thin_space; - if (left == OPERATOR_TYPE && right == ORDINARY_TYPE) - return thin_space; - return 0; -} - -int list_box::compute_metrics(int style) -{ - sty = style; - int i; - for (i = 0; i < list.len; i++) { - int t = list.p[i]->spacing_type; - // 5 - if (t == BINARY_TYPE) { - int prevt; - if (i == 0 - || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE - || prevt == OPERATOR_TYPE - || prevt == RELATION_TYPE - || prevt == OPENING_TYPE - || prevt == PUNCTUATION_TYPE) - list.p[i]->spacing_type = ORDINARY_TYPE; - } - // 7 - else if ((t == RELATION_TYPE || t == CLOSING_TYPE - || t == PUNCTUATION_TYPE) - && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE) - list.p[i-1]->spacing_type = ORDINARY_TYPE; - } - for (i = 0; i < list.len; i++) { - unsigned flags = 0; - if (i - 1 >= 0 && list.p[i - 1]->right_is_italic()) - flags |= HINT_PREV_IS_ITALIC; - if (i + 1 < list.len && list.p[i + 1]->left_is_italic()) - flags |= HINT_NEXT_IS_ITALIC; - if (flags) - list.p[i]->hint(flags); - } - is_script = (style <= SCRIPT_STYLE); - int total_spacing = 0; - for (i = 1; i < list.len; i++) - total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type, - list.p[i]->spacing_type); - int res = 0; - for (i = 0; i < list.len; i++) - if (!list.p[i]->is_simple()) { - int r = list.p[i]->compute_metrics(style); - if (r) { - if (res) - error("multiple marks and lineups"); - else { - compute_sublist_width(i); - printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n"); - res = r; - } - } - } - printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing); - for (i = 0; i < list.len; i++) - if (!list.p[i]->is_simple()) - printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid); - printf("\n"); - printf(".nr " HEIGHT_FORMAT " 0", uid); - for (i = 0; i < list.len; i++) - if (!list.p[i]->is_simple()) - printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid); - printf("\n"); - printf(".nr " DEPTH_FORMAT " 0", uid); - for (i = 0; i < list.len; i++) - if (!list.p[i]->is_simple()) - printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid); - printf("\n"); - int have_simple = 0; - for (i = 0; i < list.len && !have_simple; i++) - have_simple = list.p[i]->is_simple(); - if (have_simple) { - printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid); - for (i = 0; i < list.len; i++) - if (list.p[i]->is_simple()) - list.p[i]->output(); - printf(DELIMITER_CHAR "\n"); - printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n", - uid, uid); - printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n", - uid, uid); - } - return res; -} - -void list_box::compute_sublist_width(int n) -{ - int total_spacing = 0; - int i; - for (i = 1; i < n + 1 && i < list.len; i++) - total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type, - list.p[i]->spacing_type); - printf(".nr " TEMP_REG " %dM", total_spacing); - for (i = 0; i < n; i++) - if (!list.p[i]->is_simple()) - printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid); - int have_simple = 0; - for (i = 0; i < n && !have_simple; i++) - have_simple = list.p[i]->is_simple(); - if (have_simple) { - printf("+\\w" DELIMITER_CHAR); - for (i = 0; i < n; i++) - if (list.p[i]->is_simple()) - list.p[i]->output(); - printf(DELIMITER_CHAR); - } - printf("\n"); -} - -void list_box::compute_subscript_kern() -{ - // We can only call compute_subscript_kern if we have called - // compute_metrics first. - if (list.p[list.len-1]->is_simple()) - list.p[list.len-1]->compute_metrics(sty); - list.p[list.len-1]->compute_subscript_kern(); - printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", - uid, list.p[list.len-1]->uid); -} - -void list_box::output() -{ - for (int i = 0; i < list.len; i++) { - if (i > 0) { - int n = compute_spacing(is_script, - list.p[i-1]->spacing_type, - list.p[i]->spacing_type); - if (n > 0) - printf("\\h'%dM'", n); - } - list.p[i]->output(); - } -} - -void list_box::handle_char_type(int st, int ft) -{ - for (int i = 0; i < list.len; i++) - list.p[i]->handle_char_type(st, ft); -} - -void list_box::debug_print() -{ - list.list_debug_print(" "); -} - -void list_box::check_tabs(int level) -{ - list.list_check_tabs(level); -} diff --git a/contrib/groff/src/preproc/eqn/main.cc b/contrib/groff/src/preproc/eqn/main.cc deleted file mode 100644 index dabac5f..0000000 --- a/contrib/groff/src/preproc/eqn/main.cc +++ /dev/null @@ -1,395 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "eqn.h" -#include "stringclass.h" -#include "device.h" -#include "searchpath.h" -#include "macropath.h" -#include "htmlhint.h" -#include "pbox.h" -#include "ctype.h" - -#define STARTUP_FILE "eqnrc" - -extern int yyparse(); -extern "C" const char *Version_string; - -static char *delim_search (char *, int); -static int inline_equation (FILE *, string &, string &); - -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 html = 0; - - -int read_line(FILE *fp, string *p) -{ - p->clear(); - int c = -1; - while ((c = getc(fp)) != EOF) { - if (!invalid_input_char(c)) - *p += char(c); - else - error("invalid input character code `%1'", c); - if (c == '\n') - break; - } - current_lineno++; - return p->length() > 0; -} - -void do_file(FILE *fp, const char *filename) -{ - string linebuf; - string str; - printf(".lf 1 %s\n", filename); - current_filename = filename; - current_lineno = 0; - while (read_line(fp, &linebuf)) { - 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(); - restore_compatibility(); - if (non_empty_flag) { - printf(".lf %d\n", current_lineno - 1); - output_string(); - } - printf(".lf %d\n", current_lineno); - put_string(linebuf, stdout); - } - else if (start_delim != '\0' && linebuf.search(start_delim) >= 0 - && inline_equation(fp, linebuf, str)) - ; - else - put_string(linebuf, stdout); - } - current_filename = 0; - current_lineno = 0; -} - -// Handle an inline equation. Return 1 if it was an inline equation, -// otherwise. -static int inline_equation(FILE *fp, string &linebuf, string &str) -{ - linebuf += '\0'; - char *ptr = &linebuf[0]; - char *start = delim_search(ptr, start_delim); - if (!start) { - // It wasn't a delimiter after all. - linebuf.set_length(linebuf.length() - 1); // strip the '\0' - return 0; - } - start_string(); - inline_flag = 1; - for (;;) { - 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("unterminated `%1' at line %2, looking for `%3'", - start_delim, start_lineno, end_delim); - linebuf += '\0'; - ptr = &linebuf[0]; - } - str += '\0'; - if (html) { - printf(".as1 %s ", LINE_STRING); - html_begin_suppress(); - printf("\n"); - } - init_lex(str.contents(), current_filename, start_lineno); - yyparse(); - if (html) { - printf(".as1 %s ", LINE_STRING); - html_end_suppress(); - printf("\n"); - } - start = delim_search(ptr, start_delim); - if (start == 0) { - char *nl = strchr(ptr, '\n'); - if (nl != 0) - *nl = '\0'; - do_text(ptr); - break; - } - } - restore_compatibility(); - printf(".lf %d\n", current_lineno); - output_string(); - printf(".lf %d\n", current_lineno + 1); - return 1; -} - -/* Search for delim. Skip over number register and string names etc. */ - -static char *delim_search(char *ptr, int delim) -{ - while (*ptr) { - if (*ptr == delim) - return ptr; - if (*ptr++ == '\\') { - switch (*ptr) { - case 'n': - case '*': - case 'f': - case 'g': - case 'k': - switch (*++ptr) { - case '\0': - case '\\': - break; - case '(': - if (*++ptr != '\\' && *ptr != '\0' - && *++ptr != '\\' && *ptr != '\0') - ptr++; - break; - case '[': - while (*++ptr != '\0') - if (*ptr == ']') { - ptr++; - break; - } - break; - default: - ptr++; - break; - } - break; - case '\\': - case '\0': - break; - default: - ptr++; - break; - } - } - } - return 0; -} - -void usage(FILE *stream) -{ - fprintf(stream, - "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n", - program_name); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int opt; - int load_startup_file = 1; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "DCRvd:f:p:s:m:T:M:rN", long_options, - NULL)) - != EOF) - switch (opt) { - case 'C': - compatible_flag = 1; - break; - case 'R': // don't load eqnrc - load_startup_file = 0; - break; - case 'M': - config_macro_path.command_line_dir(optarg); - break; - case 'v': - { - printf("GNU eqn (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'd': - if (optarg[0] == '\0' || optarg[1] == '\0') - error("-d requires two character argument"); - else if (invalid_input_char(optarg[0])) - error("bad delimiter `%1'", optarg[0]); - else if (invalid_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; - if (strcmp(device, "ps:html") == 0) { - device = "ps"; - html = 1; - } - break; - case 's': - if (!set_gsize(optarg)) - error("invalid 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': - warning("-D option is obsolete: use `set draw_lines 1' instead"); - draw_flag = 1; - break; - case 'N': - no_newline_in_delim_flag = 1; - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - init_table(device); - init_char_table(); - printf(".if !'\\*(.T'%s' " - ".if !'\\*(.T'html' " // the html device uses `-Tps' to render - // equations as images - ".tm warning: %s should have been given a `-T\\*(.T' option\n", - device, program_name); - printf(".if '\\*(.T'html' " - ".if !'%s'ps' " - ".tm warning: %s should have been given a `-Tps' option\n", - device, program_name); - printf(".if '\\*(.T'html' " - ".if !'%s'ps' " - ".tm warning: (it is advisable to invoke groff via: groff -Thtml -e)\n", - device); - if (load_startup_file) { - char *path; - FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path); - if (fp) { - do_file(fp, path); - fclose(fp); - a_delete path; - } - } - if (optind >= argc) - do_file(stdin, "-"); - else - for (int i = optind; i < argc; i++) - if (strcmp(argv[i], "-") == 0) - do_file(stdin, "-"); - else { - errno = 0; - FILE *fp = fopen(argv[i], "r"); - if (!fp) - fatal("can't open `%1': %2", argv[i], strerror(errno)); - else { - do_file(fp, argv[i]); - fclose(fp); - } - } - if (ferror(stdout) || fflush(stdout) < 0) - fatal("output error"); - return 0; -} diff --git a/contrib/groff/src/preproc/eqn/mark.cc b/contrib/groff/src/preproc/eqn/mark.cc deleted file mode 100644 index 99d1b75..0000000 --- a/contrib/groff/src/preproc/eqn/mark.cc +++ /dev/null @@ -1,121 +0,0 @@ -// -*- 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 "eqn.h" -#include "pbox.h" - -class mark_box : public pointer_box { -public: - mark_box(box *); - int compute_metrics(int); - void output(); - void debug_print(); -}; - -// we push down marks so that they don't interfere with spacing - -box *make_mark_box(box *p) -{ - list_box *b = p->to_list_box(); - if (b != 0) { - b->list.p[0] = make_mark_box(b->list.p[0]); - return b; - } - else - return new mark_box(p); -} - -mark_box::mark_box(box *pp) : pointer_box(pp) -{ -} - -void mark_box::output() -{ - p->output(); -} - -int mark_box::compute_metrics(int style) -{ - int res = p->compute_metrics(style); - if (res) - error("multiple marks and lineups"); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - printf(".nr " MARK_REG " 0\n"); - return FOUND_MARK; -} - -void mark_box::debug_print() -{ - fprintf(stderr, "mark { "); - p->debug_print(); - fprintf(stderr, " }"); -} - - -class lineup_box : public pointer_box { -public: - lineup_box(box *); - void output(); - int compute_metrics(int style); - void debug_print(); -}; - -// we push down lineups so that they don't interfere with spacing - -box *make_lineup_box(box *p) -{ - list_box *b = p->to_list_box(); - if (b != 0) { - b->list.p[0] = make_lineup_box(b->list.p[0]); - return b; - } - else - return new lineup_box(p); -} - -lineup_box::lineup_box(box *pp) : pointer_box(pp) -{ -} - -void lineup_box::output() -{ - p->output(); -} - -int lineup_box::compute_metrics(int style) -{ - int res = p->compute_metrics(style); - if (res) - error("multiple marks and lineups"); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - printf(".nr " MARK_REG " 0\n"); - return FOUND_LINEUP; -} - -void lineup_box::debug_print() -{ - fprintf(stderr, "lineup { "); - p->debug_print(); - fprintf(stderr, " }"); -} diff --git a/contrib/groff/src/preproc/eqn/other.cc b/contrib/groff/src/preproc/eqn/other.cc deleted file mode 100644 index c052f52..0000000 --- a/contrib/groff/src/preproc/eqn/other.cc +++ /dev/null @@ -1,601 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h" -#include "pbox.h" - -class accent_box : public pointer_box { -private: - box *ab; -public: - accent_box(box *, box *); - ~accent_box(); - int compute_metrics(int); - void output(); - void debug_print(); - void check_tabs(int); -}; - -box *make_accent_box(box *p, box *q) -{ - return new accent_box(p, q); -} - -accent_box::accent_box(box *pp, box *qq) : pointer_box(pp), ab(qq) -{ -} - -accent_box::~accent_box() -{ - delete ab; -} - -#if 0 -int accent_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - p->compute_skew(); - ab->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n", - uid, p->uid, x_height); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n[" - SUP_RAISE_FORMAT "]\n", - uid, ab->uid, uid); - return r; -} - -void accent_box::output() -{ - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n[" - SKEW_FORMAT "]u'", - p->uid, ab->uid, p->uid); - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - ab->output(); - printf("\\h'-\\n[" WIDTH_FORMAT "]u'", ab->uid); - printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); - printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n[" - SKEW_FORMAT "]u)'", - p->uid, ab->uid, p->uid); - p->output(); -} -#endif - -/* This version copes with the possibility of an accent's being wider -than its accentee. LEFT_WIDTH_FORMAT gives the distance from the -left edge of the resulting box to the middle of the accentee's box.*/ - -int accent_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - p->compute_skew(); - ab->compute_metrics(style); - printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" - ">?(\\n[" WIDTH_FORMAT "]/2-\\n[" SKEW_FORMAT "])\n", - uid, p->uid, ab->uid, p->uid); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" - ">?(\\n[" WIDTH_FORMAT "]/2+\\n[" SKEW_FORMAT "])" - "+\\n[" LEFT_WIDTH_FORMAT "]\n", - uid, p->uid, ab->uid, p->uid, uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n", - uid, p->uid, x_height); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n[" - SUP_RAISE_FORMAT "]\n", - uid, ab->uid, uid); - if (r) - printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]" - "-(\\n[" WIDTH_FORMAT "]/2)'\n", - uid, p->uid); - return r; -} - -void accent_box::output() -{ - printf("\\Z" DELIMITER_CHAR); - printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u+\\n[" SKEW_FORMAT "]u" - "-(\\n[" WIDTH_FORMAT "]u/2u)'", - uid, p->uid, ab->uid); - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - ab->output(); - printf(DELIMITER_CHAR); - printf("\\Z" DELIMITER_CHAR); - printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'", - uid, p->uid); - p->output(); - printf(DELIMITER_CHAR); - printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); -} - -void accent_box::check_tabs(int level) -{ - ab->check_tabs(level + 1); - p->check_tabs(level + 1); -} - -void accent_box::debug_print() -{ - fprintf(stderr, "{ "); - p->debug_print(); - fprintf(stderr, " } accent { "); - ab->debug_print(); - fprintf(stderr, " }"); -} - -class overline_char_box : public simple_box { -public: - overline_char_box(); - void output(); - void debug_print(); -}; - -overline_char_box::overline_char_box() -{ -} - -void overline_char_box::output() -{ - printf("\\v'-%dM/2u-%dM'", 7*default_rule_thickness, x_height); - printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"), - accent_width); - printf("\\v'%dM/2u+%dM'", 7*default_rule_thickness, x_height); -} - -void overline_char_box::debug_print() -{ - fprintf(stderr, ""); -} - -class overline_box : public pointer_box { -public: - overline_box(box *); - int compute_metrics(int); - void output(); - void debug_print(); -}; - -box *make_overline_box(box *p) -{ - if (p->is_char()) - return new accent_box(p, new overline_char_box); - else - return new overline_box(p); -} - -overline_box::overline_box(box *pp) : pointer_box(pp) -{ -} - -int overline_box::compute_metrics(int style) -{ - int r = p->compute_metrics(cramped_style(style)); - // 9 - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+%dM\n", - uid, p->uid, default_rule_thickness*5); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - return r; -} - -void overline_box::output() -{ - // 9 - printf("\\Z" DELIMITER_CHAR); - printf("\\v'-\\n[" HEIGHT_FORMAT "]u-(%dM/2u)'", - p->uid, 7*default_rule_thickness); - if (draw_flag) - printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid); - else - printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid); - printf(DELIMITER_CHAR); - p->output(); -} - -void overline_box::debug_print() -{ - fprintf(stderr, "{ "); - p->debug_print(); - fprintf(stderr, " } bar"); -} - -class uaccent_box : public pointer_box { - box *ab; -public: - uaccent_box(box *, box *); - ~uaccent_box(); - int compute_metrics(int); - void output(); - void compute_subscript_kern(); - void check_tabs(int); - void debug_print(); -}; - -box *make_uaccent_box(box *p, box *q) -{ - return new uaccent_box(p, q); -} - -uaccent_box::uaccent_box(box *pp, box *qq) -: pointer_box(pp), ab(qq) -{ -} - -uaccent_box::~uaccent_box() -{ - delete ab; -} - -int uaccent_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - ab->compute_metrics(style); - printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" - ">?(\\n[" WIDTH_FORMAT "]/2)\n", - uid, p->uid, ab->uid); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2" - ">?(\\n[" WIDTH_FORMAT "]/2)" - "+\\n[" LEFT_WIDTH_FORMAT "]\n", - uid, p->uid, ab->uid, uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" - "+\\n[" DEPTH_FORMAT "]\n", - uid, p->uid, ab->uid); - if (r) - printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]" - "-(\\n[" WIDTH_FORMAT "]/2)'\n", - uid, p->uid); - return r; -} - -void uaccent_box::output() -{ - printf("\\Z" DELIMITER_CHAR); - printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'", - uid, ab->uid); - printf("\\v'\\n[" DEPTH_FORMAT "]u'", p->uid); - ab->output(); - printf(DELIMITER_CHAR); - printf("\\Z" DELIMITER_CHAR); - printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'", - uid, p->uid); - p->output(); - printf(DELIMITER_CHAR); - printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); -} - -void uaccent_box::check_tabs(int level) -{ - ab->check_tabs(level + 1); - p->check_tabs(level + 1); -} - -void uaccent_box::compute_subscript_kern() -{ - box::compute_subscript_kern(); // want 0 subscript kern -} - -void uaccent_box::debug_print() -{ - fprintf(stderr, "{ "); - p->debug_print(); - fprintf(stderr, " } uaccent { "); - ab->debug_print(); - fprintf(stderr, " }"); -} - -class underline_char_box : public simple_box { -public: - underline_char_box(); - void output(); - void debug_print(); -}; - -underline_char_box::underline_char_box() -{ -} - -void underline_char_box::output() -{ - printf("\\v'%dM/2u'", 7*default_rule_thickness); - printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"), - accent_width); - printf("\\v'-%dM/2u'", 7*default_rule_thickness); -} - -void underline_char_box::debug_print() -{ - fprintf(stderr, ""); -} - - -class underline_box : public pointer_box { -public: - underline_box(box *); - int compute_metrics(int); - void output(); - void compute_subscript_kern(); - void debug_print(); -}; - -box *make_underline_box(box *p) -{ - if (p->is_char()) - return new uaccent_box(p, new underline_char_box); - else - return new underline_box(p); -} - -underline_box::underline_box(box *pp) : pointer_box(pp) -{ -} - -int underline_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - // 10 - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n", - uid, p->uid, default_rule_thickness*5); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - return r; -} - -void underline_box::output() -{ - // 10 - printf("\\Z" DELIMITER_CHAR); - printf("\\v'\\n[" DEPTH_FORMAT "]u+(%dM/2u)'", - p->uid, 7*default_rule_thickness); - if (draw_flag) - printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid); - else - printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid); - printf(DELIMITER_CHAR); - p->output(); -} - -// we want an underline box to have 0 subscript kern - -void underline_box::compute_subscript_kern() -{ - box::compute_subscript_kern(); -} - -void underline_box::debug_print() -{ - fprintf(stderr, "{ "); - p->debug_print(); - fprintf(stderr, " } under"); -} - -size_box::size_box(char *s, box *pp) : pointer_box(pp), size(s) -{ -} - -int size_box::compute_metrics(int style) -{ - printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid); - printf(".ps %s\n", size); - printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid); - int r = p->compute_metrics(style); - printf(".ps \\n[" SIZE_FORMAT "]u\n", uid); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - return r; -} - -void size_box::output() -{ - printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid); - p->output(); - printf("\\s[\\n[" SIZE_FORMAT "]u]", uid); -} - -size_box::~size_box() -{ - a_delete size; -} - -void size_box::debug_print() -{ - fprintf(stderr, "size %s { ", size); - p->debug_print(); - fprintf(stderr, " }"); -} - - -font_box::font_box(char *s, box *pp) : pointer_box(pp), f(s) -{ -} - -font_box::~font_box() -{ - a_delete f; -} - -int font_box::compute_metrics(int style) -{ - const char *old_roman_font = current_roman_font; - current_roman_font = f; - printf(".nr " FONT_FORMAT " \\n[.f]\n", uid); - printf(".ft %s\n", f); - int r = p->compute_metrics(style); - current_roman_font = old_roman_font; - printf(".ft \\n[" FONT_FORMAT "]\n", uid); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - return r; -} - -void font_box::output() -{ - printf("\\f[%s]", f); - const char *old_roman_font = current_roman_font; - current_roman_font = f; - p->output(); - current_roman_font = old_roman_font; - printf("\\f[\\n[" FONT_FORMAT "]]", uid); -} - -void font_box::debug_print() -{ - fprintf(stderr, "font %s { ", f); - p->debug_print(); - fprintf(stderr, " }"); -} - -fat_box::fat_box(box *pp) : pointer_box(pp) -{ -} - -int fat_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n", - uid, p->uid, fat_offset); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - return r; -} - -void fat_box::output() -{ - p->output(); - printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p->uid); - printf("\\h'%dM'", fat_offset); - p->output(); -} - - -void fat_box::debug_print() -{ - fprintf(stderr, "fat { "); - p->debug_print(); - fprintf(stderr, " }"); -} - - -vmotion_box::vmotion_box(int i, box *pp) : pointer_box(pp), n(i) -{ -} - -int vmotion_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - if (n > 0) { - printf(".nr " HEIGHT_FORMAT " %dM+\\n[" HEIGHT_FORMAT "]\n", - uid, n, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - } - else { - printf(".nr " DEPTH_FORMAT " %dM+\\n[" DEPTH_FORMAT "]>?0\n", - uid, -n, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", - uid, p->uid); - } - return r; -} - -void vmotion_box::output() -{ - printf("\\v'%dM'", -n); - p->output(); - printf("\\v'%dM'", n); -} - -void vmotion_box::debug_print() -{ - if (n >= 0) - fprintf(stderr, "up %d { ", n); - else - fprintf(stderr, "down %d { ", -n); - p->debug_print(); - fprintf(stderr, " }"); -} - -hmotion_box::hmotion_box(int i, box *pp) : pointer_box(pp), n(i) -{ -} - -int hmotion_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n", - uid, p->uid, n); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); - if (r) - printf(".nr " MARK_REG " +%dM\n", n); - return r; -} - -void hmotion_box::output() -{ - printf("\\h'%dM'", n); - p->output(); -} - -void hmotion_box::debug_print() -{ - if (n >= 0) - fprintf(stderr, "fwd %d { ", n); - else - fprintf(stderr, "back %d { ", -n); - p->debug_print(); - fprintf(stderr, " }"); -} - -vcenter_box::vcenter_box(box *pp) : pointer_box(pp) -{ -} - -int vcenter_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); - printf(".nr " SUP_RAISE_FORMAT " \\n[" DEPTH_FORMAT "]-\\n[" - HEIGHT_FORMAT "]/2+%dM\n", - uid, p->uid, p->uid, axis_height); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n[" - SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]-\\n[" - SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid); - - return r; -} - -void vcenter_box::output() -{ - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - p->output(); - printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); -} - -void vcenter_box::debug_print() -{ - fprintf(stderr, "vcenter { "); - p->debug_print(); - fprintf(stderr, " }"); -} - diff --git a/contrib/groff/src/preproc/eqn/over.cc b/contrib/groff/src/preproc/eqn/over.cc deleted file mode 100644 index 279efc8..0000000 --- a/contrib/groff/src/preproc/eqn/over.cc +++ /dev/null @@ -1,197 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 - 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 "eqn.h" -#include "pbox.h" - -class over_box : public box { -private: - int reduce_size; - box *num; - box *den; -public: - over_box(int small, box *, box *); - ~over_box(); - void debug_print(); - int compute_metrics(int); - void output(); - void check_tabs(int); -}; - -box *make_over_box(box *pp, box *qq) -{ - return new over_box(0, pp, qq); -} - -box *make_small_over_box(box *pp, box *qq) -{ - return new over_box(1, pp, qq); -} - -over_box::over_box(int is_small, box *pp, box *qq) -: reduce_size(is_small), num(pp), den(qq) -{ - spacing_type = INNER_TYPE; -} - -over_box::~over_box() -{ - delete num; - delete den; -} - -int over_box::compute_metrics(int style) -{ - if (reduce_size) { - style = script_style(style); - printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid); - set_script_size(); - printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid); - } - int mark_uid = 0; - int res = num->compute_metrics(style); - if (res) - mark_uid = num->uid; - int r = den->compute_metrics(cramped_style(style)); - if (r && res) - error("multiple marks and lineups"); - else { - mark_uid = den->uid; - res = r; - } - if (reduce_size) - printf(".ps \\n[" SIZE_FORMAT "]u\n", uid); - printf(".nr " WIDTH_FORMAT " (\\n[" WIDTH_FORMAT "]>?\\n[" WIDTH_FORMAT "]", - uid, num->uid, den->uid); - // allow for \(ru being wider than both the numerator and denominator - if (!draw_flag) - fputs(">?\\w" DELIMITER_CHAR "\\(ru" DELIMITER_CHAR, stdout); - printf(")+%dM\n", null_delimiter_space*2 + over_hang*2); - // 15b - printf(".nr " SUP_RAISE_FORMAT " %dM\n", - uid, (reduce_size ? num2 : num1)); - printf(".nr " SUB_LOWER_FORMAT " %dM\n", - uid, (reduce_size ? denom2 : denom1)); - - // 15d - printf(".nr " SUP_RAISE_FORMAT " +(\\n[" DEPTH_FORMAT - "]-\\n[" SUP_RAISE_FORMAT "]+%dM+(%dM/2)+%dM)>?0\n", - uid, num->uid, uid, axis_height, default_rule_thickness, - default_rule_thickness*(reduce_size ? 1 : 3)); - printf(".nr " SUB_LOWER_FORMAT " +(\\n[" HEIGHT_FORMAT - "]-\\n[" SUB_LOWER_FORMAT "]-%dM+(%dM/2)+%dM)>?0\n", - uid, den->uid, uid, axis_height, default_rule_thickness, - default_rule_thickness*(reduce_size ? 1 : 3)); - - - printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" - HEIGHT_FORMAT "]\n", - uid, uid, num->uid); - printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n[" - DEPTH_FORMAT "]\n", - uid, uid, den->uid); - if (res) - printf(".nr " MARK_REG " +(\\n[" WIDTH_FORMAT "]-\\n[" - WIDTH_FORMAT "]/2)\n", uid, mark_uid); - return res; -} - -#define USE_Z - -void over_box::output() -{ - if (reduce_size) - printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid); -#ifdef USE_Z - printf("\\Z" DELIMITER_CHAR); -#endif - // move up to the numerator baseline - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - // move across so that it's centered - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", - uid, num->uid); - - // print the numerator - num->output(); - -#ifdef USE_Z - printf(DELIMITER_CHAR); -#else - // back again - printf("\\h'-\\n[" WIDTH_FORMAT "]u'", num->uid); - printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'", - uid, num->uid); - // down again - printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); -#endif -#ifdef USE_Z - printf("\\Z" DELIMITER_CHAR); -#endif - // move down to the denominator baseline - printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid); - - // move across so that it's centered - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", - uid, den->uid); - - // print the the denominator - den->output(); - -#ifdef USE_Z - printf(DELIMITER_CHAR); -#else - // back again - printf("\\h'-\\n[" WIDTH_FORMAT "]u'", den->uid); - printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'", - uid, den->uid); - // up again - printf("\\v'-\\n[" SUB_LOWER_FORMAT "]u'", uid); -#endif - if (reduce_size) - printf("\\s[\\n[" SIZE_FORMAT "]u]", uid); - // draw the line - printf("\\h'%dM'", null_delimiter_space); - printf("\\v'-%dM'", axis_height); - fputs(draw_flag ? "\\D'l" : "\\l'", stdout); - printf("\\n[" WIDTH_FORMAT "]u-%dM", - uid, 2*null_delimiter_space); - fputs(draw_flag ? " 0'" : "\\&\\(ru'", stdout); - printf("\\v'%dM'", axis_height); - printf("\\h'%dM'", null_delimiter_space); -} - -void over_box::debug_print() -{ - fprintf(stderr, "{ "); - num->debug_print(); - if (reduce_size) - fprintf(stderr, " } smallover { "); - else - fprintf(stderr, " } over { "); - den->debug_print(); - fprintf(stderr, " }"); -} - -void over_box::check_tabs(int level) -{ - num->check_tabs(level + 1); - den->check_tabs(level + 1); -} diff --git a/contrib/groff/src/preproc/eqn/pile.cc b/contrib/groff/src/preproc/eqn/pile.cc deleted file mode 100644 index 0df5241..0000000 --- a/contrib/groff/src/preproc/eqn/pile.cc +++ /dev/null @@ -1,293 +0,0 @@ -// -*- 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. */ -// piles and matrices - -#include "eqn.h" -#include "pbox.h" - -// SUP_RAISE_FORMAT gives the first baseline -// BASELINE_SEP_FORMAT gives the separation between baselines - -int pile_box::compute_metrics(int style) -{ - int i; - for (i = 0; i < col.len; i++) - col.p[i]->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0", uid); - for (i = 0; i < col.len; i++) - printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid); - printf("\n"); - printf(".nr " BASELINE_SEP_FORMAT " %dM", - uid, baseline_sep+col.space); - for (i = 1; i < col.len; i++) - printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", - col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5); - // round it so that it's a multiple of the vertical resolution - printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); - - printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" - "+%dM\n", - uid, uid, col.len-1, axis_height - shift_down); - printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" - HEIGHT_FORMAT "]\n", - uid, uid, col.p[0]->uid); - printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n[" - DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n", - uid, uid, col.len-1, col.p[col.len-1]->uid, uid); - return FOUND_NOTHING; -} - -void pile_box::output() -{ - int i; - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - for (i = 0; i < col.len; i++) { - switch (col.align) { - case LEFT_ALIGN: - break; - case CENTER_ALIGN: - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", - uid, col.p[i]->uid); - break; - case RIGHT_ALIGN: - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", - uid, col.p[i]->uid); - break; - default: - assert(0); - } - col.p[i]->output(); - printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid); - switch (col.align) { - case LEFT_ALIGN: - break; - case CENTER_ALIGN: - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", - col.p[i]->uid, uid); - break; - case RIGHT_ALIGN: - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", - col.p[i]->uid, uid); - break; - default: - assert(0); - } - if (i != col.len - 1) - printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); - } - printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); - printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid); - printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); -} - -pile_box::pile_box(box *pp) : col(pp) -{ -} - -void pile_box::check_tabs(int level) -{ - col.list_check_tabs(level); -} - -void pile_box::debug_print() -{ - col.debug_print("pile"); -} - -int matrix_box::compute_metrics(int style) -{ - int i, j; - int maxlen = 0; - int space = 0; - for (i = 0; i < len; i++) { - for (j = 0; j < p[i]->len; j++) - p[i]->p[j]->compute_metrics(style); - if (p[i]->len > maxlen) - maxlen = p[i]->len; - if (p[i]->space > space) - space = p[i]->space; - } - for (i = 0; i < len; i++) { - printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i); - for (j = 0; j < p[i]->len; j++) - printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid); - printf("\n"); - } - printf(".nr " WIDTH_FORMAT " %dM", - uid, column_sep*(len-1)+2*matrix_side_sep); - for (i = 0; i < len; i++) - printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i); - printf("\n"); - printf(".nr " BASELINE_SEP_FORMAT " %dM", - uid, baseline_sep+space); - for (i = 0; i < len; i++) - for (j = 1; j < p[i]->len; j++) - printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", - p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5); - // round it so that it's a multiple of the vertical resolution - printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); - printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" - "+%dM\n", - uid, uid, maxlen-1, axis_height - shift_down); - printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0", - uid, uid); - for (i = 0; i < len; i++) - printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid); - printf(")>?0\n"); - printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n[" - SUP_RAISE_FORMAT "]+(0", - uid, uid, maxlen-1, uid); - for (i = 0; i < len; i++) - if (p[i]->len == maxlen) - printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[maxlen-1]->uid); - printf(")>?0\n"); - return FOUND_NOTHING; -} - -void matrix_box::output() -{ - printf("\\h'%dM'", matrix_side_sep); - for (int i = 0; i < len; i++) { - int j; - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - for (j = 0; j < p[i]->len; j++) { - switch (p[i]->align) { - case LEFT_ALIGN: - break; - case CENTER_ALIGN: - printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", - uid, i, p[i]->p[j]->uid); - break; - case RIGHT_ALIGN: - printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", - uid, i, p[i]->p[j]->uid); - break; - default: - assert(0); - } - p[i]->p[j]->output(); - printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid); - switch (p[i]->align) { - case LEFT_ALIGN: - break; - case CENTER_ALIGN: - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'", - p[i]->p[j]->uid, uid, i); - break; - case RIGHT_ALIGN: - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'", - p[i]->p[j]->uid, uid, i); - break; - default: - assert(0); - } - if (j != p[i]->len - 1) - printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); - } - printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); - printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid); - printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i); - if (i != len - 1) - printf("\\h'%dM'", column_sep); - } - printf("\\h'%dM'", matrix_side_sep); -} - -matrix_box::matrix_box(column *pp) -{ - p = new column*[10]; - for (int i = 0; i < 10; i++) - p[i] = 0; - maxlen = 10; - len = 1; - p[0] = pp; -} - -matrix_box::~matrix_box() -{ - for (int i = 0; i < len; i++) - delete p[i]; - a_delete p; -} - -void matrix_box::append(column *pp) -{ - if (len + 1 > maxlen) { - column **oldp = p; - maxlen *= 2; - p = new column*[maxlen]; - memcpy(p, oldp, sizeof(column*)*len); - a_delete oldp; - } - p[len++] = pp; -} - -void matrix_box::check_tabs(int level) -{ - for (int i = 0; i < len; i++) - p[i]->list_check_tabs(level); -} - -void matrix_box::debug_print() -{ - fprintf(stderr, "matrix { "); - p[0]->debug_print("col"); - for (int i = 1; i < len; i++) { - fprintf(stderr, " "); - p[i]->debug_print("col"); - } - fprintf(stderr, " }"); -} - -column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0) -{ -} - -void column::set_alignment(alignment a) -{ - align = a; -} - -void column::set_space(int n) -{ - space = n; -} - -void column::debug_print(const char *s) -{ - char c = '\0'; // shut up -Wall - switch (align) { - case LEFT_ALIGN: - c = 'l'; - break; - case RIGHT_ALIGN: - c = 'r'; - break; - case CENTER_ALIGN: - c = 'c'; - break; - default: - assert(0); - } - fprintf(stderr, "%c%s %d { ", c, s, space); - list_debug_print(" above "); - fprintf(stderr, " }"); -} - diff --git a/contrib/groff/src/preproc/eqn/script.cc b/contrib/groff/src/preproc/eqn/script.cc deleted file mode 100644 index 62a05b4..0000000 --- a/contrib/groff/src/preproc/eqn/script.cc +++ /dev/null @@ -1,221 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h" -#include "pbox.h" - -class script_box : public pointer_box { -private: - box *sub; - box *sup; -public: - script_box(box *, box *, box *); - ~script_box(); - int compute_metrics(int); - void output(); - void debug_print(); - int left_is_italic(); - void hint(unsigned); - void check_tabs(int); -}; - -/* The idea is that the script should attach to the rightmost box -of a list. For example, given `2x sup 3', the superscript should -attach to `x' rather than `2x'. */ - -box *make_script_box(box *nuc, box *sub, box *sup) -{ - list_box *b = nuc->to_list_box(); - if (b != 0) { - b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1], - sub, - sup); - return b; - } - else - return new script_box(nuc, sub, sup); -} - -script_box::script_box(box *pp, box *qq, box *rr) -: pointer_box(pp), sub(qq), sup(rr) -{ -} - -script_box::~script_box() -{ - delete sub; - delete sup; -} - -int script_box::left_is_italic() -{ - return p->left_is_italic(); -} - -int script_box::compute_metrics(int style) -{ - int res = p->compute_metrics(style); - p->compute_subscript_kern(); - printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid); - if (!(style <= SCRIPT_STYLE && one_size_reduction_flag)) - set_script_size(); - printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid); - if (sub != 0) - sub->compute_metrics(cramped_style(script_style(style))); - if (sup != 0) - sup->compute_metrics(script_style(style)); - // 18a - if (p->is_char()) { - printf(".nr " SUP_RAISE_FORMAT " 0\n", uid); - printf(".nr " SUB_LOWER_FORMAT " 0\n", uid); - } - else { - printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n", - uid, p->uid, sup_drop); - printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n", - uid, p->uid, sub_drop); - } - printf(".ps \\n[" SIZE_FORMAT "]u\n", uid); - if (sup == 0) { - assert(sub != 0); - // 18b - printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n[" - HEIGHT_FORMAT "]-(%dM*4/5))\n", - uid, uid, sub1, sub->uid, x_height); - } - else { - // sup != 0 - // 18c - int p; - if (style == DISPLAY_STYLE) - p = sup1; - else if (style & 1) // not cramped - p = sup2; - else - p = sup3; - printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT - "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n", - uid, uid, p, sup->uid, x_height); - // 18d - if (sub != 0) { - printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n", - uid, uid, sub2); - // 18e - printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n[" - SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n[" - SUB_LOWER_FORMAT "]+(4*%dM)\n", - sup->uid, uid, sub->uid, uid, default_rule_thickness); - printf(".if \\n[" TEMP_REG "] \\{"); - printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid); - printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT - "]+\\n[" DEPTH_FORMAT "]>?0\n", - x_height, uid, sup->uid); - printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid); - printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid); - printf(".\\}\n"); - } - } - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid); - if (sub != 0 && sup != 0) - printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n[" - WIDTH_FORMAT "])+%dM)>?0\n", - sub->uid, p->uid, sup->uid, script_space); - else if (sub != 0) - printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n", - sub->uid, p->uid, script_space); - else if (sup != 0) - printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space); - else - printf("\n"); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]", - uid, p->uid); - if (sup != 0) - printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])", - uid, sup->uid); - if (sub != 0) - printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])", - uid, sub->uid); - printf("\n"); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]", - uid, p->uid); - if (sub != 0) - printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])", - uid, sub->uid); - if (sup != 0) - printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])", - uid, sup->uid); - printf("\n"); - return res; -} - -void script_box::output() -{ - p->output(); - if (sup != 0) { - printf("\\Z" DELIMITER_CHAR); - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid); - sup->output(); - printf("\\s[\\n[" SIZE_FORMAT "]u]", uid); - printf(DELIMITER_CHAR); - } - if (sub != 0) { - printf("\\Z" DELIMITER_CHAR); - printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid); - printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid); - printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid); - sub->output(); - printf("\\s[\\n[" SIZE_FORMAT "]u]", uid); - printf(DELIMITER_CHAR); - } - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", - uid, p->uid); -} - -void script_box::hint(unsigned flags) -{ - p->hint(flags & ~HINT_NEXT_IS_ITALIC); -} - -void script_box::debug_print() -{ - fprintf(stderr, "{ "); - p->debug_print(); - fprintf(stderr, " }"); - if (sub) { - fprintf(stderr, " sub { "); - sub->debug_print(); - fprintf(stderr, " }"); - } - if (sup) { - fprintf(stderr, " sup { "); - sup->debug_print(); - fprintf(stderr, " }"); - } -} - -void script_box::check_tabs(int level) -{ - if (sup) - sup->check_tabs(level + 1); - if (sub) - sub->check_tabs(level + 1); - p->check_tabs(level); -} diff --git a/contrib/groff/src/preproc/eqn/special.cc b/contrib/groff/src/preproc/eqn/special.cc deleted file mode 100644 index 310261a..0000000 --- a/contrib/groff/src/preproc/eqn/special.cc +++ /dev/null @@ -1,115 +0,0 @@ -// -*- 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 "eqn.h" -#include "pbox.h" - -#define STRING_FORMAT PREFIX "str%d" - -#define SPECIAL_STRING "0s" -#define SPECIAL_WIDTH_REG "0w" -#define SPECIAL_HEIGHT_REG "0h" -#define SPECIAL_DEPTH_REG "0d" -#define SPECIAL_SUB_KERN_REG "0skern" -#define SPECIAL_SKEW_REG "0skew" - -/* -For example: - -.de Cl -.ds 0s \Z'\\*[0s]'\v'\\n(0du'\D'l \\n(0wu -\\n(0hu-\\n(0du'\v'\\n(0hu' -.. -.EQ -define cancel 'special Cl' -.EN -*/ - - -class special_box : public pointer_box { - char *macro_name; -public: - special_box(char *, box *); - ~special_box(); - int compute_metrics(int); - void compute_subscript_kern(); - void compute_skew(); - void output(); - void debug_print(); -}; - -box *make_special_box(char *s, box *p) -{ - return new special_box(s, p); -} - -special_box::special_box(char *s, box *pp) : pointer_box(pp), macro_name(s) -{ -} - -special_box::~special_box() -{ - a_delete macro_name; -} - -int special_box::compute_metrics(int style) -{ - int r = p->compute_metrics(style); - p->compute_subscript_kern(); - p->compute_skew(); - printf(".ds " SPECIAL_STRING " \""); - p->output(); - printf("\n"); - printf(".nr " SPECIAL_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", p->uid); - printf(".nr " SPECIAL_HEIGHT_REG " \\n[" HEIGHT_FORMAT "]\n", p->uid); - printf(".nr " SPECIAL_DEPTH_REG " \\n[" DEPTH_FORMAT "]\n", p->uid); - printf(".nr " SPECIAL_SUB_KERN_REG " \\n[" SUB_KERN_FORMAT "]\n", p->uid); - printf(".nr " SPECIAL_SKEW_REG " 0\\n[" SKEW_FORMAT "]\n", p->uid); - printf(".%s\n", macro_name); - printf(".rn " SPECIAL_STRING " " STRING_FORMAT "\n", uid); - printf(".nr " WIDTH_FORMAT " 0\\n[" SPECIAL_WIDTH_REG "]\n", uid); - printf(".nr " HEIGHT_FORMAT " 0>?\\n[" SPECIAL_HEIGHT_REG "]\n", uid); - printf(".nr " DEPTH_FORMAT " 0>?\\n[" SPECIAL_DEPTH_REG "]\n", uid); - printf(".nr " SUB_KERN_FORMAT " 0>?\\n[" SPECIAL_SUB_KERN_REG "]\n", uid); - printf(".nr " SKEW_FORMAT " 0\\n[" SPECIAL_SKEW_REG "]\n", uid); - // User will have to change MARK_REG if appropriate. - return r; -} - -void special_box::compute_subscript_kern() -{ - // Already computed in compute_metrics(), so do nothing. -} - -void special_box::compute_skew() -{ - // Already computed in compute_metrics(), so do nothing. -} - -void special_box::output() -{ - printf("\\*[" STRING_FORMAT "]", uid); -} - -void special_box::debug_print() -{ - fprintf(stderr, "special %s { ", macro_name); - p->debug_print(); - fprintf(stderr, " }"); -} diff --git a/contrib/groff/src/preproc/eqn/sqrt.cc b/contrib/groff/src/preproc/eqn/sqrt.cc deleted file mode 100644 index bffa4f2..0000000 --- a/contrib/groff/src/preproc/eqn/sqrt.cc +++ /dev/null @@ -1,179 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "eqn.h" -#include "pbox.h" - - -class sqrt_box : public pointer_box { -public: - sqrt_box(box *); - int compute_metrics(int style); - void output(); - void debug_print(); - void check_tabs(int); -}; - -box *make_sqrt_box(box *pp) -{ - return new sqrt_box(pp); -} - -sqrt_box::sqrt_box(box *pp) : pointer_box(pp) -{ -} - -#define SQRT_CHAR "\\(sr" -#define RADICAL_EXTENSION_CHAR "\\[radicalex]" - -#define SQRT_CHAIN "\\[sr\\\\n[" INDEX_REG "]]" -#define BAR_CHAIN "\\[radicalex\\\\n[" INDEX_REG "]]" - -int sqrt_box::compute_metrics(int style) -{ - // 11 - int r = p->compute_metrics(cramped_style(style)); - printf(".nr " TEMP_REG " \\n[" HEIGHT_FORMAT "]+\\n[" DEPTH_FORMAT - "]+%dM+(%dM/4)\n", - p->uid, p->uid, default_rule_thickness, - (style > SCRIPT_STYLE ? x_height : default_rule_thickness)); - printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid); - printf(".ds " SQRT_STRING_FORMAT " " SQRT_CHAR "\n", uid); - printf(".ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n"); - printf(".nr " SQRT_WIDTH_FORMAT - " 0\\w" DELIMITER_CHAR SQRT_CHAR DELIMITER_CHAR "\n", - uid); - printf(".if \\n[rst]-\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{", - default_rule_thickness); - - printf(".nr " INDEX_REG " 0\n" - ".de " TEMP_MACRO "\n" - ".ie c" SQRT_CHAIN " \\{" - ".ds " SQRT_STRING_FORMAT " " SQRT_CHAIN "\n" - ".ie c" BAR_CHAIN " .ds " BAR_STRING " " BAR_CHAIN "\n" - ".el .ds " BAR_STRING " " RADICAL_EXTENSION_CHAR "\n" - ".nr " SQRT_WIDTH_FORMAT - " 0\\w" DELIMITER_CHAR SQRT_CHAIN DELIMITER_CHAR "\n" - ".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "] \\{" - ".nr " INDEX_REG " +1\n" - "." TEMP_MACRO "\n" - ".\\}\\}\n" - ".el .nr " INDEX_REG " 0-1\n" - "..\n" - "." TEMP_MACRO "\n", - uid, uid, default_rule_thickness); - - printf(".if \\n[" INDEX_REG "]<0 \\{"); - - // Determine the maximum point size - printf(".ps 1000\n"); - printf(".nr " MAX_SIZE_REG " \\n[.ps]\n"); - printf(".ps \\n[" SIZE_FORMAT "]u\n", uid); - // We define a macro that will increase the current point size - // until we get a radical sign that's tall enough or we reach - // the maximum point size. - printf(".de " TEMP_MACRO "\n" - ".nr " SQRT_WIDTH_FORMAT - " 0\\w" DELIMITER_CHAR "\\*[" SQRT_STRING_FORMAT "]" DELIMITER_CHAR "\n" - ".if \\\\n[rst]-\\\\n[rsb]-%dM<\\n[" TEMP_REG "]" - "&(\\\\n[.ps]<\\n[" MAX_SIZE_REG "]) \\{" - ".ps +1\n" - "." TEMP_MACRO "\n" - ".\\}\n" - "..\n" - "." TEMP_MACRO "\n", - uid, uid, default_rule_thickness); - - printf(".\\}\\}\n"); - - printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid); - // set TEMP_REG to the amount by which the radical sign is too big - printf(".nr " TEMP_REG " \\n[rst]-\\n[rsb]-%dM-\\n[" TEMP_REG "]\n", - default_rule_thickness); - // If TEMP_REG is negative, the bottom of the radical sign should - // be -TEMP_REG above the bottom of p. If it's positive, the bottom - // of the radical sign should be TEMP_REG/2 below the bottom of p. - // This calculates the amount by which the baseline of the radical - // should be raised. - printf(".nr " SUP_RAISE_FORMAT " (-\\n[" TEMP_REG "]>?(-\\n[" TEMP_REG "]/2))" - "-\\n[rsb]-\\n[" DEPTH_FORMAT "]\n", uid, p->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" - ">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n", - uid, p->uid, uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" - ">?(-\\n[" SUP_RAISE_FORMAT "]-\\n[rsb])\n", - uid, p->uid, uid); - // Do this last, so we don't lose height and depth information on - // the radical sign. - // Remember that the width of the bar might be greater than the width of p. - - printf(".nr " TEMP_REG " " - "\\n[" WIDTH_FORMAT "]" - ">?\\w" DELIMITER_CHAR "\\*[" BAR_STRING "]" DELIMITER_CHAR "\n", - p->uid); - printf(".as " SQRT_STRING_FORMAT " " - "\\l'\\n[" TEMP_REG "]u\\&\\*[" BAR_STRING "]'\n", - uid); - printf(".nr " WIDTH_FORMAT " \\n[" TEMP_REG "]" - "+\\n[" SQRT_WIDTH_FORMAT "]\n", - uid, uid); - - if (r) - printf(".nr " MARK_REG " +\\n[" SQRT_WIDTH_FORMAT "]\n", uid); - // the top of the bar might be higher than the top of the radical sign - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" - ">?(\\n[" SUP_RAISE_FORMAT "]+\\n[rst])\n", - uid, p->uid, uid); - // put a bit of extra space above the bar - printf(".nr " HEIGHT_FORMAT " +%dM\n", uid, default_rule_thickness); - printf(".ps \\n[" SIZE_FORMAT "]u\n", uid); - return r; -} - -void sqrt_box::output() -{ - printf("\\Z" DELIMITER_CHAR); - printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid); - printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); - printf("\\*[" SQRT_STRING_FORMAT "]", uid); - printf("\\s[\\n[" SIZE_FORMAT "]u]", uid); - printf(DELIMITER_CHAR); - - printf("\\Z" DELIMITER_CHAR); - printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u" - "+\\n[" SQRT_WIDTH_FORMAT "]u/2u'", - uid, p->uid, uid); - p->output(); - printf(DELIMITER_CHAR); - - printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); -} - -void sqrt_box::debug_print() -{ - fprintf(stderr, "sqrt { "); - p->debug_print(); - fprintf(stderr, " }"); -} - -void sqrt_box::check_tabs(int level) -{ - p->check_tabs(level + 1); -} diff --git a/contrib/groff/src/preproc/eqn/text.cc b/contrib/groff/src/preproc/eqn/text.cc deleted file mode 100644 index b0f1700..0000000 --- a/contrib/groff/src/preproc/eqn/text.cc +++ /dev/null @@ -1,528 +0,0 @@ -// -*- 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 "eqn.h" -#include "pbox.h" -#include "ptable.h" - -class char_box : public simple_box { - unsigned char c; - char next_is_italic; - char prev_is_italic; -public: - char_box(unsigned char); - void debug_print(); - void output(); - int is_char(); - int left_is_italic(); - int right_is_italic(); - void hint(unsigned); - void handle_char_type(int, int); -}; - -class special_char_box : public simple_box { - char *s; -public: - special_char_box(const char *); - ~special_char_box(); - void output(); - void debug_print(); - int is_char(); - void handle_char_type(int, int); -}; - -const char *spacing_type_table[] = { - "ordinary", - "operator", - "binary", - "relation", - "opening", - "closing", - "punctuation", - "inner", - "suppress", - 0, -}; - -const int DIGIT_TYPE = 0; -const int LETTER_TYPE = 1; - -const char *font_type_table[] = { - "digit", - "letter", - 0, -}; - -struct char_info { - int spacing_type; - int font_type; - char_info(); -}; - -char_info::char_info() -: spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE) -{ -} - -static char_info char_table[256]; - -declare_ptable(char_info) -implement_ptable(char_info) - -PTABLE(char_info) special_char_table; - -static int get_special_char_spacing_type(const char *ch) -{ - char_info *p = special_char_table.lookup(ch); - return p ? p->spacing_type : ORDINARY_TYPE; -} - -static int get_special_char_font_type(const char *ch) -{ - char_info *p = special_char_table.lookup(ch); - return p ? p->font_type : DIGIT_TYPE; -} - -static void set_special_char_type(const char *ch, int st, int ft) -{ - char_info *p = special_char_table.lookup(ch); - if (!p) { - p = new char_info; - special_char_table.define(ch, p); - } - if (st >= 0) - p->spacing_type = st; - if (ft >= 0) - p->font_type = ft; -} - -void init_char_table() -{ - set_special_char_type("pl", 2, -1); // binary - set_special_char_type("mi", 2, -1); - set_special_char_type("eq", 3, -1); // relation - set_special_char_type("<=", 3, -1); - set_special_char_type(">=", 3, -1); - char_table['}'].spacing_type = 5; // closing - char_table[')'].spacing_type = 5; - char_table[']'].spacing_type = 5; - char_table['{'].spacing_type = 4; // opening - char_table['('].spacing_type = 4; - char_table['['].spacing_type = 4; - char_table[','].spacing_type = 6; // punctuation - char_table[';'].spacing_type = 6; - char_table[':'].spacing_type = 6; - char_table['.'].spacing_type = 6; - char_table['>'].spacing_type = 3; - char_table['<'].spacing_type = 3; - char_table['*'].spacing_type = 2; // binary - for (int i = 0; i < 256; i++) - if (csalpha(i)) - char_table[i].font_type = LETTER_TYPE; -} - -static int lookup_spacing_type(const char *type) -{ - for (int i = 0; spacing_type_table[i] != 0; i++) - if (strcmp(spacing_type_table[i], type) == 0) - return i; - return -1; -} - -static int lookup_font_type(const char *type) -{ - for (int i = 0; font_type_table[i] != 0; i++) - if (strcmp(font_type_table[i], type) == 0) - return i; - return -1; -} - -void box::set_spacing_type(char *type) -{ - int t = lookup_spacing_type(type); - if (t < 0) - error("unrecognised type `%1'", type); - else - spacing_type = t; - a_delete type; -} - -char_box::char_box(unsigned char cc) -: c(cc), next_is_italic(0), prev_is_italic(0) -{ - spacing_type = char_table[c].spacing_type; -} - -void char_box::hint(unsigned flags) -{ - if (flags & HINT_PREV_IS_ITALIC) - prev_is_italic = 1; - if (flags & HINT_NEXT_IS_ITALIC) - next_is_italic = 1; -} - -void char_box::output() -{ - int font_type = char_table[c].font_type; - if (font_type != LETTER_TYPE) - printf("\\f[%s]", current_roman_font); - if (!prev_is_italic) - fputs("\\,", stdout); - if (c == '\\') - fputs("\\e", stdout); - else - putchar(c); - if (!next_is_italic) - fputs("\\/", stdout); - else - fputs("\\&", stdout); // suppress ligaturing and kerning - if (font_type != LETTER_TYPE) - fputs("\\fP", stdout); -} - -int char_box::left_is_italic() -{ - int font_type = char_table[c].font_type; - return font_type == LETTER_TYPE; -} - -int char_box::right_is_italic() -{ - int font_type = char_table[c].font_type; - return font_type == LETTER_TYPE; -} - -int char_box::is_char() -{ - return 1; -} - -void char_box::debug_print() -{ - if (c == '\\') { - putc('\\', stderr); - putc('\\', stderr); - } - else - putc(c, stderr); -} - -special_char_box::special_char_box(const char *t) -{ - s = strsave(t); - spacing_type = get_special_char_spacing_type(s); -} - -special_char_box::~special_char_box() -{ - a_delete s; -} - -void special_char_box::output() -{ - int font_type = get_special_char_font_type(s); - if (font_type != LETTER_TYPE) - printf("\\f[%s]", current_roman_font); - printf("\\,\\[%s]\\/", s); - if (font_type != LETTER_TYPE) - printf("\\fP"); -} - -int special_char_box::is_char() -{ - return 1; -} - -void special_char_box::debug_print() -{ - fprintf(stderr, "\\[%s]", s); -} - - -void char_box::handle_char_type(int st, int ft) -{ - if (st >= 0) - char_table[c].spacing_type = st; - if (ft >= 0) - char_table[c].font_type = ft; -} - -void special_char_box::handle_char_type(int st, int ft) -{ - set_special_char_type(s, st, ft); -} - -void set_char_type(const char *type, char *ch) -{ - assert(ch != 0); - int st = lookup_spacing_type(type); - int ft = lookup_font_type(type); - if (st < 0 && ft < 0) { - error("bad character type `%1'", type); - a_delete ch; - return; - } - box *b = split_text(ch); - b->handle_char_type(st, ft); - delete b; -} - -/* We give primes special treatment so that in ``x' sub 2'', the ``2'' -will be tucked under the prime */ - -class prime_box : public pointer_box { - box *pb; -public: - prime_box(box *); - ~prime_box(); - int compute_metrics(int style); - void output(); - void compute_subscript_kern(); - void debug_print(); - void handle_char_type(int, int); -}; - -box *make_prime_box(box *pp) -{ - return new prime_box(pp); -} - -prime_box::prime_box(box *pp) : pointer_box(pp) -{ - pb = new special_char_box("fm"); -} - -prime_box::~prime_box() -{ - delete pb; -} - -int prime_box::compute_metrics(int style) -{ - int res = p->compute_metrics(style); - pb->compute_metrics(style); - printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]" - "+\\n[" WIDTH_FORMAT "]\n", - uid, p->uid, pb->uid); - printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" - ">?\\n[" HEIGHT_FORMAT "]\n", - uid, p->uid, pb->uid); - printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" - ">?\\n[" DEPTH_FORMAT "]\n", - uid, p->uid, pb->uid); - return res; -} - -void prime_box::compute_subscript_kern() -{ - p->compute_subscript_kern(); - printf(".nr " SUB_KERN_FORMAT " 0\\n[" WIDTH_FORMAT "]" - "+\\n[" SUB_KERN_FORMAT "]>?0\n", - uid, pb->uid, p->uid); -} - -void prime_box::output() -{ - p->output(); - pb->output(); -} - -void prime_box::handle_char_type(int st, int ft) -{ - p->handle_char_type(st, ft); - pb->handle_char_type(st, ft); -} - -void prime_box::debug_print() -{ - p->debug_print(); - putc('\'', stderr); -} - -box *split_text(char *text) -{ - list_box *lb = 0; - box *fb = 0; - char *s = text; - while (*s != '\0') { - char c = *s++; - box *b = 0; - switch (c) { - case '+': - b = new special_char_box("pl"); - break; - case '-': - b = new special_char_box("mi"); - break; - case '=': - b = new special_char_box("eq"); - break; - case '\'': - b = new special_char_box("fm"); - break; - case '<': - if (*s == '=') { - b = new special_char_box("<="); - s++; - break; - } - goto normal_char; - case '>': - if (*s == '=') { - b = new special_char_box(">="); - s++; - break; - } - goto normal_char; - case '\\': - if (*s == '\0') { - lex_error("bad escape"); - break; - } - c = *s++; - switch (c) { - case '(': - { - char buf[3]; - if (*s != '\0') { - buf[0] = *s++; - if (*s != '\0') { - buf[1] = *s++; - buf[2] = '\0'; - b = new special_char_box(buf); - } - else { - lex_error("bad escape"); - } - } - else { - lex_error("bad escape"); - } - } - break; - case '[': - { - char *ch = s; - while (*s != ']' && *s != '\0') - s++; - if (*s == '\0') - lex_error("bad escape"); - else { - *s++ = '\0'; - b = new special_char_box(ch); - } - } - break; - case 'f': - case 'g': - case 'k': - case 'n': - case '*': - { - char *escape_start = s - 2; - switch (*s) { - case '(': - if (*++s != '\0') - ++s; - break; - case '[': - for (++s; *s != '\0' && *s != ']'; s++) - ; - break; - } - if (*s == '\0') - lex_error("bad escape"); - else { - ++s; - char *buf = new char[s - escape_start + 1]; - memcpy(buf, escape_start, s - escape_start); - buf[s - escape_start] = '\0'; - b = new quoted_text_box(buf); - } - } - break; - case '-': - case '_': - { - char buf[2]; - buf[0] = c; - buf[1] = '\0'; - b = new special_char_box(buf); - } - break; - case '`': - b = new special_char_box("ga"); - break; - case '\'': - b = new special_char_box("aa"); - break; - case 'e': - case '\\': - b = new char_box('\\'); - break; - case '^': - case '|': - case '0': - { - char buf[3]; - buf[0] = '\\'; - buf[1] = c; - buf[2] = '\0'; - b = new quoted_text_box(strsave(buf)); - break; - } - default: - lex_error("unquoted escape"); - b = new quoted_text_box(strsave(s - 2)); - s = strchr(s, '\0'); - break; - } - break; - default: - normal_char: - b = new char_box(c); - break; - } - while (*s == '\'') { - if (b == 0) - b = new quoted_text_box(0); - b = new prime_box(b); - s++; - } - if (b != 0) { - if (lb != 0) - lb->append(b); - else if (fb != 0) { - lb = new list_box(fb); - lb->append(b); - } - else - fb = b; - } - } - delete text; - if (lb != 0) - return lb; - else if (fb != 0) - return fb; - else - return new quoted_text_box(0); -} - diff --git a/contrib/groff/src/preproc/grn/hdb.cc b/contrib/groff/src/preproc/grn/hdb.cc deleted file mode 100644 index 648a535..0000000 --- a/contrib/groff/src/preproc/grn/hdb.cc +++ /dev/null @@ -1,339 +0,0 @@ -/* Last non-groff version: hdb.c 1.8 (Berkeley) 84/10/20 - * - * Copyright -C- 1982 Barry S. Roitblat - * - * This file contains database routines for the hard copy programs of the - * gremlin picture editor. - */ - -#include "gprint.h" -#include -#include -#include - -#include "errarg.h" -#include "error.h" - -#define MAXSTRING 128 -#define MAXSTRING_S "127" - -/* imports from main.cc */ - -extern int linenum; /* current line number in input file */ -extern char gremlinfile[]; /* name of file currently reading */ -extern int SUNFILE; /* TRUE if SUN gremlin file */ -extern void savebounds(float x, float y); - -/* imports from hpoint.cc */ - -extern POINT *PTInit(); -extern POINT *PTMakePoint(float x, float y, POINT ** pplist); - - -int DBGetType(register char *s); - - -/* - * This routine returns a pointer to an initialized database element which - * would be the only element in an empty list. - */ -ELT * -DBInit() -{ - return ((ELT *) NULL); -} /* end DBInit */ - - -/* - * This routine creates a new element with the specified attributes and - * links it into database. - */ -ELT * -DBCreateElt(int type, - POINT * pointlist, - int brush, - int size, - char *text, - ELT **db) -{ - register ELT *temp; - - temp = (ELT *) malloc(sizeof(ELT)); - temp->nextelt = *db; - temp->type = type; - temp->ptlist = pointlist; - temp->brushf = brush; - temp->size = size; - temp->textpt = text; - *db = temp; - return (temp); -} /* end CreateElt */ - - -/* - * This routine reads the specified file into a database and returns a - * pointer to that database. - */ -ELT * -DBRead(register FILE *file) -{ - register int i; - register int done; /* flag for input exhausted */ - register float nx; /* x holder so x is not set before orienting */ - int type; /* element type */ - ELT *elist; /* pointer to the file's elements */ - POINT *plist; /* pointer for reading in points */ - char string[MAXSTRING], *txt; - float x, y; /* x and y are read in point coords */ - int len, brush, size; - int lastpoint; - - SUNFILE = FALSE; - elist = DBInit(); - (void) fscanf(file, "%" MAXSTRING_S "s%*[^\n]\n", string); - if (strcmp(string, "gremlinfile")) { - if (strcmp(string, "sungremlinfile")) { - error("`%1' is not a gremlin file", gremlinfile); - return (elist); - } - SUNFILE = TRUE; - } - - (void) fscanf(file, "%d%f%f\n", &size, &x, &y); - /* ignore orientation and file positioning point */ - - done = FALSE; - while (!done) { - /* if (fscanf(file,"%" MAXSTRING_S "s\n", string) == EOF) */ - /* I changed the scanf format because the element */ - /* can have two words (e.g. CURVE SPLINE) */ - if (fscanf(file, "\n%" MAXSTRING_S "[^\n]%*[^\n]\n", string) == EOF) { - error("`%1', error in file format", gremlinfile); - return (elist); - } - - type = DBGetType(string); /* interpret element type */ - if (type < 0) { /* no more data */ - done = TRUE; - (void) fclose(file); - } else { -#ifdef UW_FASTSCAN - (void) xscanf(file, &x, &y); /* always one point */ -#else - (void) fscanf(file, "%f%f\n", &x, &y); /* always one point */ -#endif /* UW_FASTSCAN */ - plist = PTInit(); /* NULL point list */ - - /* - * Files created on the SUN have point lists terminated by a line - * containing only an asterik ('*'). Files created on the AED have - * point lists terminated by the coordinate pair (-1.00 -1.00). - */ - if (TEXT(type)) { /* read only first point for TEXT elements */ - nx = xorn(x, y); - y = yorn(x, y); - (void) PTMakePoint(nx, y, &plist); - savebounds(nx, y); - -#ifdef UW_FASTSCAN - while (xscanf(file, &x, &y)); -#else - lastpoint = FALSE; - do { - fgets(string, MAXSTRING, file); - if (string[0] == '*') { /* SUN gremlin file */ - lastpoint = TRUE; - } else { - (void) sscanf(string, "%f%f", &x, &y); - if ((x == -1.00 && y == -1.00) && (!SUNFILE)) - lastpoint = TRUE; - } - } while (!lastpoint); -#endif /* UW_FASTSCAN */ - } else { /* not TEXT element */ -#ifdef UW_FASTSCAN - do { - nx = xorn(x, y); - y = yorn(x, y); - (void) PTMakePoint(nx, y, &plist); - savebounds(nx, y); - } while (xscanf(file, &x, &y)); -#else - lastpoint = FALSE; - while (!lastpoint) { - nx = xorn(x, y); - y = yorn(x, y); - (void) PTMakePoint(nx, y, &plist); - savebounds(nx, y); - - fgets(string, MAXSTRING, file); - if (string[0] == '*') { /* SUN gremlin file */ - lastpoint = TRUE; - } else { - (void) sscanf(string, "%f%f", &x, &y); - if ((x == -1.00 && y == -1.00) && (!SUNFILE)) - lastpoint = TRUE; - } - } -#endif /* UW_FASTSCAN */ - } - (void) fscanf(file, "%d%d\n", &brush, &size); - (void) fscanf(file, "%d", &len); /* text length */ - (void) getc(file); /* eat blank */ - txt = (char *) malloc((unsigned) len + 1); - for (i = 0; i < len; ++i) { /* read text */ - txt[i] = getc(file); - } - txt[len] = '\0'; - (void) DBCreateElt(type, plist, brush, size, txt, &elist); - } /* end else */ - } /* end while not done */ ; - return (elist); -} /* end DBRead */ - - -/* - * Interpret element type in string s. - * Old file format consisted of integer element types. - * New file format has literal names for element types. - */ -int -DBGetType(register char *s) -{ - if (isdigit(s[0]) || (s[0] == '-')) /* old element format or EOF */ - return (atoi(s)); - - switch (s[0]) { - case 'P': - return (POLYGON); - case 'V': - return (VECTOR); - case 'A': - return (ARC); - case 'C': - if (s[1] == 'U') { - if (s[5] == '\n') - return (CURVE); - switch (s[7]) { - case 'S': - return(BSPLINE); - case 'E': - fprintf(stderr, - "Warning: Bezier Curves will be printed as B-Splines\n"); - return(BSPLINE); - default: - return(CURVE); - } - } - switch (s[4]) { - case 'L': - return (CENTLEFT); - case 'C': - return (CENTCENT); - case 'R': - return (CENTRIGHT); - default: - fatal("unknown element type"); - } - case 'B': - switch (s[3]) { - case 'L': - return (BOTLEFT); - case 'C': - return (BOTCENT); - case 'R': - return (BOTRIGHT); - default: - fatal("unknown element type"); - } - case 'T': - switch (s[3]) { - case 'L': - return (TOPLEFT); - case 'C': - return (TOPCENT); - case 'R': - return (TOPRIGHT); - default: - fatal("unknown element type"); - } - default: - fatal("unknown element type"); - } - - return 0; /* never reached */ -} - -#ifdef UW_FASTSCAN -/* - * Optimization hack added by solomon@crys.wisc.edu, 12/2/86. - * A huge fraction of the time was spent reading floating point numbers from - * the input file, but the numbers always have the format 'ddd.dd'. Thus - * the following special-purpose version of fscanf. - * - * xscanf(f,xp,yp) does roughly what fscanf(f,"%f%f",xp,yp) does except: - * -the next piece of input must be of the form - * * *'.'* * *'.'* - * -xscanf eats the character following the second number - * -xscanf returns 0 for "end-of-data" indication, 1 otherwise, where - * end-of-data is signalled by a '*' [in which case the rest of the - * line is gobbled], or by '-1.00 -1.00' [but only if !SUNFILE]. - */ -int -xscanf(FILE *f, - float *xp, - float *yp) -{ - register int c, i, j, m, frac; - int iscale = 1, jscale = 1; /* x = i/scale, y=j/jscale */ - - while ((c = getc(f)) == ' '); - if (c == '*') { - while ((c = getc(f)) != '\n'); - return 0; - } - i = m = frac = 0; - while (isdigit(c) || c == '.' || c == '-') { - if (c == '-') { - m++; - c = getc(f); - continue; - } - if (c == '.') - frac = 1; - else { - if (frac) - iscale *= 10; - i = 10 * i + c - '0'; - } - c = getc(f); - } - if (m) - i = -i; - *xp = (double) i / (double) iscale; - - while ((c = getc(f)) == ' '); - j = m = frac = 0; - while (isdigit(c) || c == '.' || c == '-') { - if (c == '-') { - m++; - c = getc(f); - continue; - } - if (c == '.') - frac = 1; - else { - if (frac) - jscale *= 10; - j = 10 * j + c - '0'; - } - c = getc(f); - } - if (m) - j = -j; - *yp = (double) j / (double) jscale; - return (SUNFILE || i != -iscale || j != -jscale); -} -#endif /* UW_FASTSCAN */ - -/* EOF */ diff --git a/contrib/groff/src/preproc/grn/hgraph.cc b/contrib/groff/src/preproc/grn/hgraph.cc deleted file mode 100644 index d307faa..0000000 --- a/contrib/groff/src/preproc/grn/hgraph.cc +++ /dev/null @@ -1,1055 +0,0 @@ -/* Last non-groff version: hgraph.c 1.14 (Berkeley) 84/11/27 - * - * This file contains the graphics routines for converting gremlin pictures - * to troff input. - */ - -#include "lib.h" - -#include "gprint.h" - -#ifdef NEED_DECLARATION_HYPOT -extern "C" { - double hypot(double, double); -} -#endif /* NEED_DECLARATION_HYPOT */ - -#define MAXVECT 40 -#define MAXPOINTS 200 -#define LINELENGTH 1 -#define PointsPerInterval 64 -#define pi 3.14159265358979324 -#define twopi (2.0 * pi) -#define len(a, b) hypot((double)(b.x-a.x), (double)(b.y-a.y)) - - -extern int dotshifter; /* for the length of dotted curves */ - -extern int style[]; /* line and character styles */ -extern double thick[]; -extern char *tfont[]; -extern int tsize[]; -extern int stipple_index[]; /* stipple font index for stipples 0 - 16 */ -extern char *stipple; /* stipple type (cf or ug) */ - - -extern double troffscale; /* imports from main.c */ -extern double linethickness; -extern int linmod; -extern int lastx; -extern int lasty; -extern int lastyline; -extern int ytop; -extern int ybottom; -extern int xleft; -extern int xright; -extern enum { - OUTLINE, FILL, BOTH -} polyfill; - -extern double adj1; -extern double adj2; -extern double adj3; -extern double adj4; -extern int res; - -void HGSetFont(int font, int size); -void HGPutText(int justify, POINT pnt, register char *string); -void HGSetBrush(int mode); -void tmove2(int px, int py); -void doarc(POINT cp, POINT sp, int angle); -void tmove(POINT * ptr); -void cr(); -void drawwig(POINT * ptr, int type); -void HGtline(int x1, int y1); -void dx(double x); -void dy(double y); -void HGArc(register int cx, register int cy, int px, int py, int angle); -void picurve(register int *x, register int *y, int npts); -void HGCurve(int *x, int *y, int numpoints); -void Paramaterize(int x[], int y[], float h[], int n); -void PeriodicSpline(float h[], int z[], - float dz[], float d2z[], float d3z[], - int npoints); -void NaturalEndSpline(float h[], int z[], - float dz[], float d2z[], float d3z[], - int npoints); - - - -/*----------------------------------------------------------------------------* - | Routine: HGPrintElt (element_pointer, baseline) - | - | Results: Examines a picture element and calls the appropriate - | routine(s) to print them according to their type. After the - | picture is drawn, current position is (lastx, lasty). - *----------------------------------------------------------------------------*/ - -void -HGPrintElt(ELT *element, - int baseline) -{ - register POINT *p1; - register POINT *p2; - register int length; - register int graylevel; - - if (!DBNullelt(element) && !Nullpoint((p1 = element->ptlist))) { - /* p1 always has first point */ - if (TEXT(element->type)) { - HGSetFont(element->brushf, element->size); - switch (element->size) { - case 1: - p1->y += adj1; - break; - case 2: - p1->y += adj2; - break; - case 3: - p1->y += adj3; - break; - case 4: - p1->y += adj4; - break; - default: - break; - } - HGPutText(element->type, *p1, element->textpt); - } else { - if (element->brushf) /* if there is a brush, the */ - HGSetBrush(element->brushf); /* graphics need it set */ - - switch (element->type) { - - case ARC: - p2 = PTNextPoint(p1); - tmove(p2); - doarc(*p1, *p2, element->size); - cr(); - break; - - case CURVE: - length = 0; /* keep track of line length */ - drawwig(p1, CURVE); - cr(); - break; - - case BSPLINE: - length = 0; /* keep track of line length */ - drawwig(p1, BSPLINE); - cr(); - break; - - case VECTOR: - length = 0; /* keep track of line length so */ - tmove(p1); /* single lines don't get long */ - while (!Nullpoint((p1 = PTNextPoint(p1)))) { - HGtline((int) (p1->x * troffscale), - (int) (p1->y * troffscale)); - if (length++ > LINELENGTH) { - length = 0; - printf("\\\n"); - } - } /* end while */ - cr(); - break; - - case POLYGON: - { - /* brushf = style of outline; size = color of fill: - * on first pass (polyfill=FILL), do the interior using 'P' - * unless size=0 - * on second pass (polyfill=OUTLINE), do the outline using a series - * of vectors. It might make more sense to use \D'p ...', - * but there is no uniform way to specify a 'fill character' - * that prints as 'no fill' on all output devices (and - * stipple fonts). - * If polyfill=BOTH, just use the \D'p ...' command. - */ - float firstx = p1->x; - float firsty = p1->y; - - length = 0; /* keep track of line length so */ - /* single lines don't get long */ - - if (polyfill == FILL || polyfill == BOTH) { - /* do the interior */ - char command = (polyfill == BOTH && element->brushf) ? 'p' : 'P'; - - /* include outline, if there is one and */ - /* the -p flag was set */ - - /* switch based on what gremlin gives */ - switch (element->size) { - case 1: - graylevel = 1; - break; - case 3: - graylevel = 2; - break; - case 12: - graylevel = 3; - break; - case 14: - graylevel = 4; - break; - case 16: - graylevel = 5; - break; - case 19: - graylevel = 6; - break; - case 21: - graylevel = 7; - break; - case 23: - graylevel = 8; - break; - default: /* who's giving something else? */ - graylevel = NSTIPPLES; - break; - } - /* int graylevel = element->size; */ - - if (graylevel < 0) - break; - if (graylevel > NSTIPPLES) - graylevel = NSTIPPLES; - printf("\\h'-%du'\\D'f %du'", - stipple_index[graylevel], - stipple_index[graylevel]); - cr(); - tmove(p1); - printf("\\D'%c", command); - - while (!Nullpoint((PTNextPoint(p1)))) { - p1 = PTNextPoint(p1); - dx((double) p1->x); - dy((double) p1->y); - if (length++ > LINELENGTH) { - length = 0; - printf("\\\n"); - } - } /* end while */ - - /* close polygon if not done so by user */ - if ((firstx != p1->x) || (firsty != p1->y)) { - dx((double) firstx); - dy((double) firsty); - } - putchar('\''); - cr(); - break; - } - /* else polyfill == OUTLINE; only draw the outline */ - if (!(element->brushf)) - break; - length = 0; /* keep track of line length */ - tmove(p1); - - while (!Nullpoint((PTNextPoint(p1)))) { - p1 = PTNextPoint(p1); - HGtline((int) (p1->x * troffscale), - (int) (p1->y * troffscale)); - if (length++ > LINELENGTH) { - length = 0; - printf("\\\n"); - } - } /* end while */ - - /* close polygon if not done so by user */ - if ((firstx != p1->x) || (firsty != p1->y)) { - HGtline((int) (firstx * troffscale), - (int) (firsty * troffscale)); - } - cr(); - break; - } /* end case POLYGON */ - } /* end switch */ - } /* end else Text */ - } /* end if */ -} /* end PrintElt */ - - -/*----------------------------------------------------------------------------* - | Routine: HGPutText (justification, position_point, string) - | - | Results: Given the justification, a point to position with, and a - | string to put, HGPutText first sends the string into a - | diversion, moves to the positioning point, then outputs - | local vertical and horizontal motions as needed to justify - | the text. After all motions are done, the diversion is - | printed out. - *----------------------------------------------------------------------------*/ - -void -HGPutText(int justify, - POINT pnt, - register char *string) -{ - int savelasty = lasty; /* vertical motion for text is to be */ - /* ignored. Save current y here */ - - printf(".nr g8 \\n(.d\n"); /* save current vertical position. */ - printf(".ds g9 \""); /* define string containing the text. */ - while (*string) { /* put out the string */ - if (*string == '\\' && - *(string + 1) == '\\') { /* one character at a */ - printf("\\\\\\"); /* time replacing // */ - string++; /* by //// to prevent */ - } /* interpretation at */ - printf("%c", *(string++)); /* printout time */ - } - printf("\n"); - - tmove(&pnt); /* move to positioning point */ - - switch (justify) { - /* local vertical motions */ - /* (the numbers here are used to be somewhat compatible with gprint) */ - case CENTLEFT: - case CENTCENT: - case CENTRIGHT: - printf("\\v'0.85n'"); /* down half */ - break; - - case TOPLEFT: - case TOPCENT: - case TOPRIGHT: - printf("\\v'1.7n'"); /* down whole */ - } - - switch (justify) { - /* local horizontal motions */ - case BOTCENT: - case CENTCENT: - case TOPCENT: - printf("\\h'-\\w'\\*(g9'u/2u'"); /* back half */ - break; - - case BOTRIGHT: - case CENTRIGHT: - case TOPRIGHT: - printf("\\h'-\\w'\\*(g9'u'"); /* back whole */ - } - - printf("\\&\\*(g9\n"); /* now print the text. */ - printf(".sp |\\n(g8u\n"); /* restore vertical position */ - lasty = savelasty; /* vertical position restored to where it */ - lastx = xleft; /* was before text, also horizontal is at */ - /* left */ -} /* end HGPutText */ - - -/*----------------------------------------------------------------------------* - | Routine: doarc (center_point, start_point, angle) - | - | Results: Produces either drawarc command or a drawcircle command - | depending on the angle needed to draw through. - *----------------------------------------------------------------------------*/ - -void -doarc(POINT cp, - POINT sp, - int angle) -{ - if (angle) /* arc with angle */ - HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale), - (int) (sp.x * troffscale), (int) (sp.y * troffscale), angle); - else /* a full circle (angle == 0) */ - HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale), - (int) (sp.x * troffscale), (int) (sp.y * troffscale), 0); -} - - -/*----------------------------------------------------------------------------* - | Routine: HGSetFont (font_number, Point_size) - | - | Results: ALWAYS outputs a .ft and .ps directive to troff. This is - | done because someone may change stuff inside a text string. - | Changes thickness back to default thickness. Default - | thickness depends on font and pointsize. - *----------------------------------------------------------------------------*/ - -void -HGSetFont(int font, - int size) -{ - printf(".ft %s\n" - ".ps %d\n", tfont[font - 1], tsize[size - 1]); - linethickness = DEFTHICK; -} - - -/*----------------------------------------------------------------------------* - | Routine: HGSetBrush (line_mode) - | - | Results: Generates the troff commands to set up the line width and - | style of subsequent lines. Does nothing if no change is - | needed. - | - | Side Efct: Sets `linmode' and `linethicknes'. - *----------------------------------------------------------------------------*/ - -void -HGSetBrush(int mode) -{ - register int printed = 0; - - if (linmod != style[--mode]) { - /* Groff doesn't understand \Ds, so we take it out */ - /* printf ("\\D's %du'", linmod = style[mode]); */ - linmod = style[mode]; - printed = 1; - } - if (linethickness != thick[mode]) { - linethickness = thick[mode]; - printf("\\h'-%.2fp'\\D't %.2fp'", linethickness, linethickness); - printed = 1; - } - if (printed) - cr(); -} - - -/*----------------------------------------------------------------------------* - | Routine: dx (x_destination) - | - | Results: Scales and outputs a number for delta x (with a leading - | space) given `lastx' and x_destination. - | - | Side Efct: Resets `lastx' to x_destination. - *----------------------------------------------------------------------------*/ - -void -dx(double x) -{ - register int ix = (int) (x * troffscale); - - printf(" %du", ix - lastx); - lastx = ix; -} - - -/*----------------------------------------------------------------------------* - | Routine: dy (y_destination) - | - | Results: Scales and outputs a number for delta y (with a leading - | space) given `lastyline' and y_destination. - | - | Side Efct: Resets `lastyline' to y_destination. Since `line' vertical - | motions don't affect `page' ones, `lasty' isn't updated. - *----------------------------------------------------------------------------*/ - -void -dy(double y) -{ - register int iy = (int) (y * troffscale); - - printf(" %du", iy - lastyline); - lastyline = iy; -} - - -/*----------------------------------------------------------------------------* - | Routine: tmove2 (px, py) - | - | Results: Produces horizontal and vertical moves for troff given the - | pair of points to move to and knowing the current position. - | Also puts out a horizontal move to start the line. This is - | a variation without the .sp command. - *----------------------------------------------------------------------------*/ - -void -tmove2(int px, - int py) -{ - register int dx; - register int dy; - - if ((dy = py - lasty)) { - printf("\\v'%du'", dy); - } - lastyline = lasty = py; /* lasty is always set to current */ - if ((dx = px - lastx)) { - printf("\\h'%du'", dx); - lastx = px; - } -} - - -/*----------------------------------------------------------------------------* - | Routine: tmove (point_pointer) - | - | Results: Produces horizontal and vertical moves for troff given the - | pointer of a point to move to and knowing the current - | position. Also puts out a horizontal move to start the - | line. - *----------------------------------------------------------------------------*/ - -void -tmove(POINT * ptr) -{ - register int ix = (int) (ptr->x * troffscale); - register int iy = (int) (ptr->y * troffscale); - register int dx; - register int dy; - - if ((dy = iy - lasty)) { - printf(".sp %du\n", dy); - } - lastyline = lasty = iy; /* lasty is always set to current */ - if ((dx = ix - lastx)) { - printf("\\h'%du'", dx); - lastx = ix; - } -} - - -/*----------------------------------------------------------------------------* - | Routine: cr ( ) - | - | Results: Ends off an input line. `.sp -1' is also added to counteract - | the vertical move done at the end of text lines. - | - | Side Efct: Sets `lastx' to `xleft' for troff's return to left margin. - *----------------------------------------------------------------------------*/ - -void -cr() -{ - printf("\n.sp -1\n"); - lastx = xleft; -} - - -/*----------------------------------------------------------------------------* - | Routine: line ( ) - | - | Results: Draws a single solid line to (x,y). - *----------------------------------------------------------------------------*/ - -void -line(int px, - int py) -{ - printf("\\D'l"); - printf(" %du", px - lastx); - printf(" %du'", py - lastyline); - lastx = px; - lastyline = lasty = py; -} - - -/*---------------------------------------------------------------------------- - | Routine: drawwig (ptr, type) - | - | Results: The point sequence found in the structure pointed by ptr is - | placed in integer arrays for further manipulation by the - | existing routing. With the corresponding type parameter, - | either picurve or HGCurve are called. - *----------------------------------------------------------------------------*/ - -void -drawwig(POINT * ptr, - int type) -{ - register int npts; /* point list index */ - int x[MAXPOINTS], y[MAXPOINTS]; /* point list */ - - for (npts = 1; !Nullpoint(ptr); ptr = PTNextPoint(ptr), npts++) { - x[npts] = (int) (ptr->x * troffscale); - y[npts] = (int) (ptr->y * troffscale); - } - if (--npts) { - if (type == CURVE) /* Use the 2 different types of curves */ - HGCurve(&x[0], &y[0], npts); - else - picurve(&x[0], &y[0], npts); - } -} - - -/*---------------------------------------------------------------------------- - | Routine: HGArc (xcenter, ycenter, xstart, ystart, angle) - | - | Results: This routine plots an arc centered about (cx, cy) counter - | clockwise starting from the point (px, py) through `angle' - | degrees. If angle is 0, a full circle is drawn. It does so - | by creating a draw-path around the arc whose density of - | points depends on the size of the arc. - *----------------------------------------------------------------------------*/ - -void -HGArc(register int cx, - register int cy, - int px, - int py, - int angle) -{ - double xs, ys, resolution, fullcircle; - int m; - register int mask; - register int extent; - register int nx; - register int ny; - register int length; - register double epsilon; - - xs = px - cx; - ys = py - cy; - - length = 0; - - resolution = (1.0 + hypot(xs, ys) / res) * PointsPerInterval; - /* mask = (1 << (int) log10(resolution + 1.0)) - 1; */ - (void) frexp(resolution, &m); /* A bit more elegant than log10 */ - for (mask = 1; mask < m; mask = mask << 1); - mask -= 1; - - epsilon = 1.0 / resolution; - fullcircle = (2.0 * pi) * resolution; - if (angle == 0) - extent = (int) fullcircle; - else - extent = (int) (angle * fullcircle / 360.0); - - HGtline(px, py); - while (--extent >= 0) { - xs += epsilon * ys; - nx = cx + (int) (xs + 0.5); - ys -= epsilon * xs; - ny = cy + (int) (ys + 0.5); - if (!(extent & mask)) { - HGtline(nx, ny); /* put out a point on circle */ - if (length++ > LINELENGTH) { - length = 0; - printf("\\\n"); - } - } - } /* end for */ -} /* end HGArc */ - - -/*---------------------------------------------------------------------------- - | Routine: picurve (xpoints, ypoints, num_of_points) - | - | Results: Draws a curve delimited by (not through) the line segments - | traced by (xpoints, ypoints) point list. This is the `Pic' - | style curve. - *----------------------------------------------------------------------------*/ - -void -picurve(register int *x, - register int *y, - int npts) -{ - register int nseg; /* effective resolution for each curve */ - register int xp; /* current point (and temporary) */ - register int yp; - int pxp, pyp; /* previous point (to make lines from) */ - int i; /* inner curve segment traverser */ - int length = 0; - double w; /* position factor */ - double t1, t2, t3; /* calculation temps */ - - if (x[1] == x[npts] && y[1] == y[npts]) { - x[0] = x[npts - 1]; /* if the lines' ends meet, make */ - y[0] = y[npts - 1]; /* sure the curve meets */ - x[npts + 1] = x[2]; - y[npts + 1] = y[2]; - } else { /* otherwise, make the ends of the */ - x[0] = x[1]; /* curve touch the ending points of */ - y[0] = y[1]; /* the line segments */ - x[npts + 1] = x[npts]; - y[npts + 1] = y[npts]; - } - - pxp = (x[0] + x[1]) / 2; /* make the last point pointers */ - pyp = (y[0] + y[1]) / 2; /* point to the start of the 1st line */ - tmove2(pxp, pyp); - - for (; npts--; x++, y++) { /* traverse the line segments */ - xp = x[0] - x[1]; - yp = y[0] - y[1]; - nseg = (int) hypot((double) xp, (double) yp); - xp = x[1] - x[2]; - yp = y[1] - y[2]; - /* `nseg' is the number of line */ - /* segments that will be drawn for */ - /* each curve segment. */ - nseg = (int) ((double) (nseg + (int) hypot((double) xp, (double) yp)) / - res * PointsPerInterval); - - for (i = 1; i < nseg; i++) { - w = (double) i / (double) nseg; - t1 = w * w; - t3 = t1 + 1.0 - (w + w); - t2 = 2.0 - (t3 + t1); - xp = (((int) (t1 * x[2] + t2 * x[1] + t3 * x[0])) + 1) / 2; - yp = (((int) (t1 * y[2] + t2 * y[1] + t3 * y[0])) + 1) / 2; - - HGtline(xp, yp); - if (length++ > LINELENGTH) { - length = 0; - printf("\\\n"); - } - } - } -} - - -/*---------------------------------------------------------------------------- - | Routine: HGCurve(xpoints, ypoints, num_points) - | - | Results: This routine generates a smooth curve through a set of - | points. The method used is the parametric spline curve on - | unit knot mesh described in `Spline Curve Techniques' by - | Patrick Baudelaire, Robert Flegal, and Robert Sproull -- - | Xerox Parc. - *----------------------------------------------------------------------------*/ - -void -HGCurve(int *x, - int *y, - int numpoints) -{ - float h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS]; - float d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS]; - float t, t2, t3; - register int j; - register int k; - register int nx; - register int ny; - int lx, ly; - int length = 0; - - lx = x[1]; - ly = y[1]; - tmove2(lx, ly); - - /* - * Solve for derivatives of the curve at each point separately for x and y - * (parametric). - */ - Paramaterize(x, y, h, numpoints); - - /* closed curve */ - if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) { - PeriodicSpline(h, x, dx, d2x, d3x, numpoints); - PeriodicSpline(h, y, dy, d2y, d3y, numpoints); - } else { - NaturalEndSpline(h, x, dx, d2x, d3x, numpoints); - NaturalEndSpline(h, y, dy, d2y, d3y, numpoints); - } - - /* - * generate the curve using the above information and PointsPerInterval - * vectors between each specified knot. - */ - - for (j = 1; j < numpoints; ++j) { - if ((x[j] == x[j + 1]) && (y[j] == y[j + 1])) - continue; - for (k = 0; k <= PointsPerInterval; ++k) { - t = (float) k *h[j] / (float) PointsPerInterval; - t2 = t * t; - t3 = t * t * t; - nx = x[j] + (int) (t * dx[j] + t2 * d2x[j] / 2 + t3 * d3x[j] / 6); - ny = y[j] + (int) (t * dy[j] + t2 * d2y[j] / 2 + t3 * d3y[j] / 6); - HGtline(nx, ny); - if (length++ > LINELENGTH) { - length = 0; - printf("\\\n"); - } - } /* end for k */ - } /* end for j */ -} /* end HGCurve */ - - -/*---------------------------------------------------------------------------- - | Routine: Paramaterize (xpoints, ypoints, hparams, num_points) - | - | Results: This routine calculates parameteric values for use in - | calculating curves. The parametric values are returned - | in the array h. The values are an approximation of - | cumulative arc lengths of the curve (uses cord length). - | For additional information, see paper cited below. - *----------------------------------------------------------------------------*/ - -void -Paramaterize(int x[], - int y[], - float h[], - int n) -{ - register int dx; - register int dy; - register int i; - register int j; - float u[MAXPOINTS]; - - for (i = 1; i <= n; ++i) { - u[i] = 0; - for (j = 1; j < i; j++) { - dx = x[j + 1] - x[j]; - dy = y[j + 1] - y[j]; - /* Here was overflowing, so I changed it. */ - /* u[i] += sqrt ((double) (dx * dx + dy * dy)); */ - u[i] += hypot((double) dx, (double) dy); - } - } - for (i = 1; i < n; ++i) - h[i] = u[i + 1] - u[i]; -} /* end Paramaterize */ - - -/*---------------------------------------------------------------------------- - | Routine: PeriodicSpline (h, z, dz, d2z, d3z, npoints) - | - | Results: This routine solves for the cubic polynomial to fit a spline - | curve to the the points specified by the list of values. - | The Curve generated is periodic. The algorithms for this - | curve are from the `Spline Curve Techniques' paper cited - | above. - *----------------------------------------------------------------------------*/ - -void -PeriodicSpline(float h[], /* paramaterization */ - int z[], /* point list */ - float dz[], /* to return the 1st derivative */ - float d2z[], /* 2nd derivative */ - float d3z[], /* 3rd derivative */ - int npoints) /* number of valid points */ -{ - float d[MAXPOINTS]; - float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; - float c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS]; - int i; - - /* step 1 */ - for (i = 1; i < npoints; ++i) { - deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0; - } - h[0] = h[npoints - 1]; - deltaz[0] = deltaz[npoints - 1]; - - /* step 2 */ - for (i = 1; i < npoints - 1; ++i) { - d[i] = deltaz[i + 1] - deltaz[i]; - } - d[0] = deltaz[1] - deltaz[0]; - - /* step 3a */ - a[1] = 2 * (h[0] + h[1]); - b[1] = d[0]; - c[1] = h[0]; - for (i = 2; i < npoints - 1; ++i) { - a[i] = 2 * (h[i - 1] + h[i]) - - pow((double) h[i - 1], (double) 2.0) / a[i - 1]; - b[i] = d[i - 1] - h[i - 1] * b[i - 1] / a[i - 1]; - c[i] = -h[i - 1] * c[i - 1] / a[i - 1]; - } - - /* step 3b */ - r[npoints - 1] = 1; - s[npoints - 1] = 0; - for (i = npoints - 2; i > 0; --i) { - r[i] = -(h[i] * r[i + 1] + c[i]) / a[i]; - s[i] = (6 * b[i] - h[i] * s[i + 1]) / a[i]; - } - - /* step 4 */ - d2z[npoints - 1] = (6 * d[npoints - 2] - h[0] * s[1] - - h[npoints - 1] * s[npoints - 2]) - / (h[0] * r[1] + h[npoints - 1] * r[npoints - 2] - + 2 * (h[npoints - 2] + h[0])); - for (i = 1; i < npoints - 1; ++i) { - d2z[i] = r[i] * d2z[npoints - 1] + s[i]; - } - d2z[npoints] = d2z[1]; - - /* step 5 */ - for (i = 1; i < npoints; ++i) { - dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6; - d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0; - } -} /* end PeriodicSpline */ - - -/*---------------------------------------------------------------------------- - | Routine: NaturalEndSpline (h, z, dz, d2z, d3z, npoints) - | - | Results: This routine solves for the cubic polynomial to fit a spline - | curve the the points specified by the list of values. The - | alogrithms for this curve are from the `Spline Curve - | Techniques' paper cited above. - *----------------------------------------------------------------------------*/ - -void -NaturalEndSpline(float h[], /* parameterization */ - int z[], /* Point list */ - float dz[], /* to return the 1st derivative */ - float d2z[], /* 2nd derivative */ - float d3z[], /* 3rd derivative */ - int npoints) /* number of valid points */ -{ - float d[MAXPOINTS]; - float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS]; - int i; - - /* step 1 */ - for (i = 1; i < npoints; ++i) { - deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0; - } - deltaz[0] = deltaz[npoints - 1]; - - /* step 2 */ - for (i = 1; i < npoints - 1; ++i) { - d[i] = deltaz[i + 1] - deltaz[i]; - } - d[0] = deltaz[1] - deltaz[0]; - - /* step 3 */ - a[0] = 2 * (h[2] + h[1]); - b[0] = d[1]; - for (i = 1; i < npoints - 2; ++i) { - a[i] = 2 * (h[i + 1] + h[i + 2]) - - pow((double) h[i + 1], (double) 2.0) / a[i - 1]; - b[i] = d[i + 1] - h[i + 1] * b[i - 1] / a[i - 1]; - } - - /* step 4 */ - d2z[npoints] = d2z[1] = 0; - for (i = npoints - 1; i > 1; --i) { - d2z[i] = (6 * b[i - 2] - h[i] * d2z[i + 1]) / a[i - 2]; - } - - /* step 5 */ - for (i = 1; i < npoints; ++i) { - dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6; - d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0; - } -} /* end NaturalEndSpline */ - - -/*----------------------------------------------------------------------------* - | Routine: change (x_position, y_position, visible_flag) - | - | Results: As HGtline passes from the invisible to visible (or vice - | versa) portion of a line, change is called to either draw - | the line, or initialize the beginning of the next one. - | Change calls line to draw segments if visible_flag is set - | (which means we're leaving a visible area). - *----------------------------------------------------------------------------*/ - -void -change(register int x, - register int y, - register int vis) -{ - static int length = 0; - - if (vis) { /* leaving a visible area, draw it. */ - line(x, y); - if (length++ > LINELENGTH) { - length = 0; - printf("\\\n"); - } - } else { /* otherwise, we're entering one, remember */ - /* beginning */ - tmove2(x, y); - } -} - - -/*---------------------------------------------------------------------------- - | Routine: HGtline (xstart, ystart, xend, yend) - | - | Results: Draws a line from current position to (x1,y1) using line(x1, - | y1) to place individual segments of dotted or dashed lines. - *----------------------------------------------------------------------------*/ - -void -HGtline(int x1, - int y1) -{ - register int x0 = lastx; - register int y0 = lasty; - register int dx; - register int dy; - register int oldcoord; - register int res1; - register int visible; - register int res2; - register int xinc; - register int yinc; - register int dotcounter; - - if (linmod == SOLID) { - line(x1, y1); - return; - } - - /* for handling different resolutions */ - dotcounter = linmod << dotshifter; - - xinc = 1; - yinc = 1; - if ((dx = x1 - x0) < 0) { - xinc = -xinc; - dx = -dx; - } - if ((dy = y1 - y0) < 0) { - yinc = -yinc; - dy = -dy; - } - res1 = 0; - res2 = 0; - visible = 0; - if (dx >= dy) { - oldcoord = y0; - while (x0 != x1) { - if ((x0 & dotcounter) && !visible) { - change(x0, y0, 0); - visible = 1; - } else if (visible && !(x0 & dotcounter)) { - change(x0 - xinc, oldcoord, 1); - visible = 0; - } - if (res1 > res2) { - oldcoord = y0; - res2 += dx - res1; - res1 = 0; - y0 += yinc; - } - res1 += dy; - x0 += xinc; - } - } else { - oldcoord = x0; - while (y0 != y1) { - if ((y0 & dotcounter) && !visible) { - change(x0, y0, 0); - visible = 1; - } else if (visible && !(y0 & dotcounter)) { - change(oldcoord, y0 - yinc, 1); - visible = 0; - } - if (res1 > res2) { - oldcoord = x0; - res2 += dy - res1; - res1 = 0; - x0 += xinc; - } - res1 += dx; - y0 += yinc; - } - } - if (visible) - change(x1, y1, 1); - else - change(x1, y1, 0); -} - -/* EOF */ diff --git a/contrib/groff/src/preproc/grn/hpoint.cc b/contrib/groff/src/preproc/grn/hpoint.cc deleted file mode 100644 index f4e1ca8..0000000 --- a/contrib/groff/src/preproc/grn/hpoint.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* Last non-groff version: hpoint.c 1.1 84/10/08 */ - -/* - * This file contains routines for manipulating the point data structures - * for the gremlin picture editor. - */ - -#include -#include "gprint.h" - - -/* - * Return pointer to empty point list. - */ -POINT * -PTInit() -{ - return ((POINT *) NULL); -} - - -/* - * This routine creates a new point with coordinates x and y and links it - * into the pointlist. - */ -POINT * -PTMakePoint(float x, - float y, - POINT **pplist) -{ - register POINT *point; - - if (Nullpoint(point = *pplist)) { /* empty list */ - *pplist = (POINT *) malloc(sizeof(POINT)); - point = *pplist; - } else { - while (!Nullpoint(point->nextpt)) - point = point->nextpt; - point->nextpt = (POINT *) malloc(sizeof(POINT)); - point = point->nextpt; - } - - point->x = x; - point->y = y; - point->nextpt = PTInit(); - return (point); -} /* end PTMakePoint */ - -/* EOF */ diff --git a/contrib/groff/src/preproc/grn/main.cc b/contrib/groff/src/preproc/grn/main.cc deleted file mode 100644 index 9b09ea6..0000000 --- a/contrib/groff/src/preproc/grn/main.cc +++ /dev/null @@ -1,906 +0,0 @@ -/* Last non-groff version: main.cc 1.23 (Berkeley) 85/08/05 - * - * Adapted to GNU troff by Daniel Senderowicz 99/12/29. - * - * Further refinements by Werner Lemberg 00/02/20. - * - * - * This file contains the main and file system dependent routines for - * processing gremlin files into troff input. The program watches input go - * by to standard output, only interpreting things between .GS and .GE - * lines. Default values (font, size, scale, thickness) may be overridden - * with a `default' command and are further overridden by commands in the - * input. - * - * Inside the GS and GE, commands are accepted to reconfigure the picture. - * At most one command may reside on each line, and each command is followed - * by a parameter separated by white space. The commands are as follows, - * and may be abbreviated down to one character (with exception of `scale' - * and `stipple' down to "sc" and "st") and may be upper or lower case. - * - * default - Make all settings in the current - * .GS/.GE the global defaults. Height, - * width and file are NOT saved. - * 1, 2, 3, 4 - Set size 1, 2, 3, or 4 (followed by an - * integer point size). - * roman, italics, bold, special - Set gremlin's fonts to any other troff - * font (one or two characters). - * stipple, l - Use a stipple font for polygons. Arg - * is troff font name. No Default. Can - * use only one stipple font per picture. - * (See below for stipple font index.) - * scale, x - Scale is IN ADDITION to the global - * scale factor from the default. - * pointscale - Turn on scaling point sizes to match - * `scale' commands. (Optional operand - * `off' to turn it off.) - * narrow, medium, thick - Set widths of lines. - * file - Set the file name to read the gremlin - * picture from. If the file isn't in - * the current directory, the gremlin - * library is tried. - * width, height - These two commands override any - * scaling factor that is in effect, and - * forces the picture to fit into either - * the height or width specified, - * whichever makes the picture smaller. - * The operand for these two commands is - * a floating-point number in units of - * inches. - * l (integer ) - Set association between stipple - * and a stipple `character'. must - * be in the range 0 to NSTIPPLES (16) - * inclusive. The integer operand is an - * index in the stipple font selected. - * Valid cf (cifplot) indices are 1-32 - * (although 24 is not defined), valid ug - * (unigrafix) indices are 1-14, and - * valid gs (gray scale) indices are - * 0-16. Nonetheless, any number between - * 0 and 255 is accepted since new - * stipple fonts may be added. An - * integer operand is required. - * - * Troff number registers used: g1 through g9. g1 is the width of the - * picture, and g2 is the height. g3, and g4, save information, g8 and g9 - * are used for text processing and g5-g7 are reserved. - */ - - -#include "lib.h" - -#include -#include -#include "gprint.h" - -#include "device.h" -#include "font.h" -#include "searchpath.h" -#include "macropath.h" - -#include "errarg.h" -#include "error.h" -#include "defs.h" - -extern "C" const char *Version_string; - -/* database imports */ - -extern void HGPrintElt(ELT *element, int baseline); -extern ELT *DBInit(); -extern ELT *DBRead(register FILE *file); -extern POINT *PTInit(); -extern POINT *PTMakePoint(float x, float y, POINT **pplist); - - -#define SUN_SCALEFACTOR 0.70 - -/* #define DEFSTIPPLE "gs" */ -#define DEFSTIPPLE "cf" - -#define MAXINLINE 100 /* input line length */ - -#define SCREENtoINCH 0.02 /* scaling factor, screen to inches */ - -#define BIG 999999999999.0 /* unweildly large floating number */ - - -static char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99"; - -int res; /* the printer's resolution goes here */ - -int dotshifter; /* for the length of dotted curves */ - -double linethickness; /* brush styles */ -int linmod; -int lastx; /* point registers for printing elements */ -int lasty; -int lastyline; /* A line's vertical position is NOT the */ - /* same after that line is over, so for a */ - /* line of drawing commands, vertical */ - /* spacing is kept in lastyline */ - -/* These are the default fonts, sizes, line styles, */ -/* and thicknesses. They can be modified from a */ -/* `default' command and are reset each time the */ -/* start of a picture (.GS) is found. */ - -char *deffont[] = -{"R", "I", "B", "S"}; -int defsize[] = -{10, 16, 24, 36}; -/* #define BASE_THICKNESS 1.0 */ -#define BASE_THICKNESS 0.15 -double defthick[STYLES] = -{1 * BASE_THICKNESS, - 1 * BASE_THICKNESS, - 5 * BASE_THICKNESS, - 1 * BASE_THICKNESS, - 1 * BASE_THICKNESS, - 3 * BASE_THICKNESS}; - -/* int cf_stipple_index[NSTIPPLES + 1] = */ -/* {0, 1, 3, 12, 14, 16, 19, 21, 23}; */ -/* a logarithmic scale looks better than a linear one for the gray shades */ -/* */ -/* int other_stipple_index[NSTIPPLES + 1] = */ -/* {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; */ - -int cf_stipple_index[NSTIPPLES + 1] = -{0, 18, 32, 56, 100, 178, 316, 562, 1000}; /* only 1-8 used */ -int other_stipple_index[NSTIPPLES + 1] = -{0, 62, 125, 187, 250, 312, 375, 437, 500, - 562, 625, 687, 750, 812, 875, 937, 1000}; - -/* int *defstipple_index = other_stipple_index; */ -int *defstipple_index = cf_stipple_index; - -int style[STYLES] = -{DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID}; -double scale = 1.0; /* no scaling, default */ -int defpoint = 0; /* flag for pointsize scaling */ -char *defstipple = (char *) 0; -enum { - OUTLINE, FILL, BOTH -} polyfill; - -/* flag to controll filling of polygons */ - -double adj1 = 0.0; -double adj2 = 0.0; -double adj3 = 0.0; -double adj4 = 0.0; - -double thick[STYLES]; /* thicknesses set by defaults, then by */ - /* commands */ -char *tfont[FONTS]; /* fonts originally set to deffont values, */ - /* then */ -int tsize[SIZES]; /* optionally changed by commands inside */ - /* grn */ -int stipple_index[NSTIPPLES + 1]; /* stipple font file indices */ -char *stipple; - -double xscale; /* scaling factor from individual pictures */ -double troffscale; /* scaling factor at output time */ - -double width; /* user-request maximum width for picture */ - /* (in inches) */ -double height; /* user-request height */ -int pointscale; /* flag for pointsize scaling */ -int setdefault; /* flag for a .GS/.GE to remember all */ - /* settings */ -int sflag; /* -s flag: sort order (do polyfill first) */ - -double toppoint; /* remember the picture */ -double bottompoint; /* bounds in these variables */ -double leftpoint; -double rightpoint; - -int ytop; /* these are integer versions of the above */ -int ybottom; /* so not to convert each time they're used */ -int xleft; -int xright; - -int linenum = 0; /* line number of input file */ -char inputline[MAXINLINE]; /* spot to filter through the file */ -char *c1 = inputline; /* c1, c2, and c3 will be used to */ -char *c2 = inputline + 1; /* hunt for lines that begin with */ -char *c3 = inputline + 2; /* ".GS" by looking individually */ -char *c4 = inputline + 3; /* needed for compatibility mode */ -char GScommand[MAXINLINE]; /* put user's ".GS" command line here */ -char gremlinfile[MAXINLINE]; /* filename to use for a picture */ -int SUNFILE = FALSE; /* TRUE if SUN gremlin file */ -int compatibility_flag = FALSE; /* TRUE if in compatibility mode */ - - -void getres(); -char *doinput(FILE *fp); -void conv(register FILE *fp, int baseline); -void savestate(); -int has_polygon(register ELT *elist); -void interpret(char *line); - - -void -usage(FILE *stream) -{ - fprintf(stream, - "usage: %s [ -vCs ] [ -M dir ] [ -F dir ] [ -T dev ] [ file ]\n", - program_name); -} - - -/*----------------------------------------------------------------------------* - | Routine: main (argument_count, argument_pointer) - | - | Results: Parses the command line, accumulating input file names, then - | reads the inputs, passing it directly to output until a `.GS' - | line is read. Main then passes control to `conv' to do the - | gremlin file conversions. - *----------------------------------------------------------------------------*/ - -int -main(int argc, - char **argv) -{ - program_name = argv[0]; - register FILE *fp; - register int k; - register char c; - register int gfil = 0; - char *file[50]; - char *operand(int *argcp, char ***argvp); - - while (--argc) { - if (**++argv != '-') - file[gfil++] = *argv; - else - switch (c = (*argv)[1]) { - - case 0: - file[gfil++] = NULL; - break; - - case 'C': /* compatibility mode */ - compatibility_flag = TRUE; - break; - - case 'F': /* font path to find DESC */ - font::command_line_font_dir(operand(&argc, &argv)); - break; - - case 'T': /* final output typesetter name */ - device = operand(&argc, &argv); - break; - - case 'M': /* set library directory */ - macro_path.command_line_dir(operand(&argc, &argv)); - break; - - case 's': /* preserve order of elements */ - sflag = 1; - break; - - case '-': - if (strcmp(*argv,"--version")==0) { - case 'v': - printf("GNU grn (groff) version %s\n", Version_string); - exit(0); - break; - } - if (strcmp(*argv,"--help")==0) { - case '?': - usage(stdout); - exit(0); - break; - } - // fallthrough - default: - error("unknown switch: %1", c); - usage(stderr); - exit(1); - } - } - - getres(); /* set the resolution for an output device */ - - if (gfil == 0) { /* no filename, use standard input */ - file[0] = NULL; - gfil++; - } - - for (k = 0; k < gfil; k++) { - if (file[k] != NULL) { - if ((fp = fopen(file[k], "r")) == NULL) - fatal("can't open %1", file[k]); - } else - fp = stdin; - - while (doinput(fp) != NULL) { - if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') { - if (compatibility_flag || - *c4 == '\n' || *c4 == ' ' || *c4 == '\0') - conv(fp, linenum); - else - fputs(inputline, stdout); - } else - fputs(inputline, stdout); - } - } -} - - -/*----------------------------------------------------------------------------* - | Routine: char * operand (& argc, & argv) - | - | Results: Returns address of the operand given with a command-line - | option. It uses either `-Xoperand' or `-X operand', whichever - | is present. The program is terminated if no option is - | present. - | - | Side Efct: argc and argv are updated as necessary. - *----------------------------------------------------------------------------*/ - -char * -operand(int *argcp, - char ***argvp) -{ - if ((**argvp)[2]) - return (**argvp + 2); /* operand immediately follows */ - if ((--*argcp) <= 0) { /* no operand */ - error("command-line option operand missing."); - exit(8); - } - return (*(++(*argvp))); /* operand is next word */ -} - - -/*----------------------------------------------------------------------------* - | Routine: getres () - | - | Results: Sets `res' to the resolution of the output device. - *----------------------------------------------------------------------------*/ - -void -getres() -{ - int linepiece; - - if (!font::load_desc()) - fatal("sorry, I can't continue"); - - res = font::res; - - /* Correct the brush thicknesses based on res */ - /* if (res >= 256) { - defthick[0] = res >> 8; - defthick[1] = res >> 8; - defthick[2] = res >> 4; - defthick[3] = res >> 8; - defthick[4] = res >> 8; - defthick[5] = res >> 6; - } */ - - linepiece = res >> 9; - for (dotshifter = 0; linepiece; dotshifter++) - linepiece = linepiece >> 1; -} - - -/*----------------------------------------------------------------------------* - | Routine: char * doinput (file_pointer) - | - | Results: A line of input is read into `inputline'. - | - | Side Efct: "linenum" is incremented. - | - | Bugs: Lines longer than MAXINLINE are NOT checked, except for - | updating `linenum'. - *----------------------------------------------------------------------------*/ - -char * -doinput(FILE *fp) -{ - char *k; - - if ((k = fgets(inputline, MAXINLINE, fp)) == NULL) - return k; - if (strchr(inputline, '\n')) /* ++ only if it's a complete line */ - linenum++; - return (char *) !NULL; -} - - -/*----------------------------------------------------------------------------* - | Routine: initpic ( ) - | - | Results: Sets all parameters to the normal defaults, possibly - | overridden by a setdefault command. Initialize the picture - | variables, and output the startup commands to troff to begin - | the picture. - *----------------------------------------------------------------------------*/ - -void -initpic() -{ - register int i; - - for (i = 0; i < STYLES; i++) { /* line thickness defaults */ - thick[i] = defthick[i]; - } - for (i = 0; i < FONTS; i++) { /* font name defaults */ - tfont[i] = deffont[i]; - } - for (i = 0; i < SIZES; i++) { /* font size defaults */ - tsize[i] = defsize[i]; - } - for (i = 0; i <= NSTIPPLES; i++) { /* stipple font file default indices */ - stipple_index[i] = defstipple_index[i]; - } - stipple = defstipple; - - gremlinfile[0] = 0; /* filename is `null' */ - setdefault = 0; /* this is not the default settings (yet) */ - - toppoint = BIG; /* set the picture bounds out */ - bottompoint = -BIG; /* of range so they'll be set */ - leftpoint = BIG; /* by `savebounds' on input */ - rightpoint = -BIG; - - pointscale = defpoint; /* flag for scaling point sizes default */ - xscale = scale; /* default scale of individual pictures */ - width = 0.0; /* size specifications input by user */ - height = 0.0; - - linethickness = DEFTHICK; /* brush styles */ - linmod = DEFSTYLE; -} - - -/*----------------------------------------------------------------------------* - | Routine: conv (file_pointer, starting_line) - | - | Results: At this point, we just passed a `.GS' line in the input - | file. conv reads the input and calls `interpret' to process - | commands, gathering up information until a `.GE' line is - | found. It then calls `HGPrint' to do the translation of the - | gremlin file to troff commands. - *----------------------------------------------------------------------------*/ - -void -conv(register FILE *fp, - int baseline) -{ - register FILE *gfp = NULL; /* input file pointer */ - register int done = 0; /* flag to remember if finished */ - register ELT *e; /* current element pointer */ - ELT *PICTURE; /* whole picture data base pointer */ - double temp; /* temporary calculating area */ - /* POINT ptr; */ /* coordinates of a point to pass to `mov' */ - /* routine */ - int flyback; /* flag `want to end up at the top of the */ - /* picture?' */ - int compat; /* test character after .GE or .GF */ - - - initpic(); /* set defaults, ranges, etc. */ - strcpy(GScommand, inputline); /* save `.GS' line for later */ - - do { - done = (doinput(fp) == NULL); /* test for EOF */ - flyback = (*c3 == 'F'); /* and .GE or .GF */ - compat = (compatibility_flag || - *c4 == '\n' || *c4 == ' ' || *c4 == '\0'); - done |= (*c1 == '.' && *c2 == 'G' && (*c3 == 'E' || flyback) && - compat); - - if (done) { - if (setdefault) - savestate(); - - if (!gremlinfile[0]) { - if (!setdefault) - error("at line %1: no picture filename.\n", baseline); - return; - } - char *path; - gfp = macro_path.open_file(gremlinfile, &path); - if (!gfp) - return; - PICTURE = DBRead(gfp); /* read picture file */ - fclose(gfp); - a_delete path; - if (DBNullelt(PICTURE)) - return; /* If a request is made to make the */ - /* picture fit into a specific area, */ - /* set the scale to do that. */ - - if (stipple == (char *) NULL) /* if user forgot stipple */ - if (has_polygon(PICTURE)) /* and picture has a polygon */ - stipple = DEFSTIPPLE; /* then set the default */ - - if ((temp = bottompoint - toppoint) < 0.1) - temp = 0.1; - temp = (height != 0.0) ? height / (temp * SCREENtoINCH) : BIG; - if ((troffscale = rightpoint - leftpoint) < 0.1) - troffscale = 0.1; - troffscale = (width != 0.0) ? - width / (troffscale * SCREENtoINCH) : BIG; - if (temp == BIG && troffscale == BIG) - troffscale = xscale; - else { - if (temp < troffscale) - troffscale = temp; - } /* here, troffscale is the */ - /* picture's scaling factor */ - if (pointscale) { - register int i; /* do pointscaling here, when */ - /* scale is known, before output */ - for (i = 0; i < SIZES; i++) - tsize[i] = (int) (troffscale * (double) tsize[i] + 0.5); - } - - /* change to device units */ - troffscale *= SCREENtoINCH * res; /* from screen units */ - - ytop = (int) (toppoint * troffscale); /* calculate integer */ - ybottom = (int) (bottompoint * troffscale); /* versions of the */ - xleft = (int) (leftpoint * troffscale); /* picture limits */ - xright = (int) (rightpoint * troffscale); - - /* save stuff in number registers, */ - /* register g1 = picture width and */ - /* register g2 = picture height, */ - /* set vertical spacing, no fill, */ - /* and break (to make sure picture */ - /* starts on left), and put out the */ - /* user's `.GS' line. */ - printf(".br\n" - ".nr g1 %du\n" - ".nr g2 %du\n" - "%s" - ".nr g3 \\n(.f\n" - ".nr g4 \\n(.s\n" - "\\0\n" - ".sp -1\n", - xright - xleft, ybottom - ytop, GScommand); - - if (stipple) /* stipple requested for this picture */ - printf(".st %s\n", stipple); - lastx = xleft; /* note where we are (upper left */ - lastyline = lasty = ytop; /* corner of the picture) */ - - /* Just dump everything in the order it appears. - * - * If -s command-line option, traverse picture twice: First time, - * print only the interiors of filled polygons (as borderless - * polygons). Second time, print the outline as series of line - * segments. This way, postprocessors that overwrite rather than - * merge picture elements (such as Postscript) can still have text and - * graphics on a shaded background. - */ - /* if (sflag) */ - if (!sflag) { /* changing the default for filled polygons */ - e = PICTURE; - polyfill = FILL; - while (!DBNullelt(e)) { - printf(".mk\n"); - if (e->type == POLYGON) - HGPrintElt(e, baseline); - printf(".rt\n"); - lastx = xleft; - lastyline = lasty = ytop; - e = DBNextElt(e); - } - } - e = PICTURE; - - /* polyfill = !sflag ? BOTH : OUTLINE; */ - polyfill = sflag ? BOTH : OUTLINE; /* changing the default */ - while (!DBNullelt(e)) { - printf(".mk\n"); - HGPrintElt(e, baseline); - printf(".rt\n"); - lastx = xleft; - lastyline = lasty = ytop; - e = DBNextElt(e); - } - - /* decide where to end picture */ - - /* I changed everything here. I always use the combination .mk and */ - /* .rt so once finished I just space down the heigth of the picture */ - /* that is \n(g2u */ - if (flyback) { /* end picture at upper left */ - /* ptr.x = leftpoint; - ptr.y = toppoint; */ - } else { /* end picture at lower left */ - /* ptr.x = leftpoint; - ptr.y = bottompoint; */ - printf(".sp \\n(g2u\n"); - } - - /* tmove(&ptr); */ /* restore default line parameters */ - - /* restore everything to the way it was before the .GS, then put */ - /* out the `.GE' line from user */ - - /* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */ - /* groff doesn't understand the \Ds command */ - - printf("\\D't %du'\n", DEFTHICK); - if (flyback) /* make sure we end up at top of */ - printf(".sp -1\n"); /* picture if `flying back' */ - if (stipple) /* restore stipple to previous */ - printf(".st\n"); - printf(".br\n" - ".ft \\n(g3\n" - ".ps \\n(g4\n" - "%s", inputline); - } else - interpret(inputline); /* take commands from the input file */ - } while (!done); -} - - -/*----------------------------------------------------------------------------* - | Routine: savestate ( ) - | - | Results: all the current scaling / font size / font name / thickness - | / pointscale settings are saved to be the defaults. Scaled - | point sizes are NOT saved. The scaling is done each time a - | new picture is started. - | - | Side Efct: scale, and def* are modified. - *----------------------------------------------------------------------------*/ - -void -savestate() -{ - register int i; - - for (i = 0; i < STYLES; i++) /* line thickness defaults */ - defthick[i] = thick[i]; - for (i = 0; i < FONTS; i++) /* font name defaults */ - deffont[i] = tfont[i]; - for (i = 0; i < SIZES; i++) /* font size defaults */ - defsize[i] = tsize[i]; - for (i = 0; i <= NSTIPPLES; i++) /* stipple font file default indices */ - defstipple_index[i] = stipple_index[i]; - - defstipple = stipple; /* if stipple has been set, it's remembered */ - scale *= xscale; /* default scale of individual pictures */ - defpoint = pointscale; /* flag for scaling pointsizes from x factors */ -} - - -/*----------------------------------------------------------------------------* - | Routine: savebounds (x_coordinate, y_coordinate) - | - | Results: Keeps track of the maximum and minimum extent of a picture - | in the global variables: left-, right-, top- and - | bottompoint. `savebounds' assumes that the points have been - | oriented to the correct direction. No scaling has taken - | place, though. - *----------------------------------------------------------------------------*/ - -void -savebounds(float x, - float y) -{ - if (x < leftpoint) - leftpoint = x; - if (x > rightpoint) - rightpoint = x; - if (y < toppoint) - toppoint = y; - if (y > bottompoint) - bottompoint = y; -} - - -/*----------------------------------------------------------------------------* - | Routine: interpret (character_string) - | - | Results: Commands are taken from the input string and performed. - | Commands are separated by the endofline, and are of the - | format: - | string1 string2 - | - | where string1 is the command and string2 is the argument. - | - | Side Efct: Font and size strings, plus the gremlin file name and the - | width and height variables are set by this routine. - *----------------------------------------------------------------------------*/ - -void -interpret(char *line) -{ - char str1[MAXINLINE]; - char str2[MAXINLINE]; - register char *chr; - register int i; - double par; - - str2[0] = '\0'; - sscanf(line, "%80s%80s", &str1[0], &str2[0]); - for (chr = &str1[0]; *chr; chr++) /* convert command to */ - if (isupper(*chr)) - *chr = tolower(*chr); /* lower case */ - - switch (str1[0]) { - - case '1': - case '2': /* font sizes */ - case '3': - case '4': - i = atoi(str2); - if (i > 0 && i < 1000) - tsize[str1[0] - '1'] = i; - else - error("bad font size value at line %1", linenum); - break; - - case 'r': /* roman */ - if (str2[0] < '0') - goto nofont; - tfont[0] = (char *) malloc(strlen(str2) + 1); - strcpy(tfont[0], str2); - break; - - case 'i': /* italics */ - if (str2[0] < '0') - goto nofont; - tfont[1] = (char *) malloc(strlen(str2) + 1); - strcpy(tfont[1], str2); - break; - - case 'b': /* bold */ - if (str2[0] < '0') - goto nofont; - tfont[2] = (char *) malloc(strlen(str2) + 1); - strcpy(tfont[2], str2); - break; - - case 's': /* special */ - if (str1[1] == 'c') - goto scalecommand; /* or scale */ - - if (str2[0] < '0') { - nofont: - error("no fontname specified in line %1", linenum); - break; - } - if (str1[1] == 't') - goto stipplecommand; /* or stipple */ - - tfont[3] = (char *) malloc(strlen(str2) + 1); - strcpy(tfont[3], str2); - break; - - case 'l': /* l */ - if (isdigit(str1[1])) { /* set stipple index */ - int index = atoi(str1 + 1), val; - - if (index < 0 || index > NSTIPPLES) { - error("bad stipple number %1 at line %2", index, linenum); - break; - } - if (!defstipple_index) - defstipple_index = other_stipple_index; - val = atoi(str2); - if (val >= 0 && val < 256) - stipple_index[index] = val; - else - error("bad stipple index value at line %1", linenum); - break; - } - - stipplecommand: /* set stipple name */ - stipple = (char *) malloc(strlen(str2) + 1); - strcpy(stipple, str2); - /* if its a `known' font (currently only `cf'), set indicies */ - if (strcmp(stipple, "cf") == 0) - defstipple_index = cf_stipple_index; - else - defstipple_index = other_stipple_index; - for (i = 0; i <= NSTIPPLES; i++) - stipple_index[i] = defstipple_index[i]; - break; - - case 'a': /* text adjust */ - par = atof(str2); - switch (str1[1]) { - case '1': - adj1 = par; - break; - case '2': - adj2 = par; - break; - case '3': - adj3 = par; - break; - case '4': - adj4 = par; - break; - default: - error("bad adjust command at line %1", linenum); - break; - } - break; - - case 't': /* thick */ - thick[2] = defthick[0] * atof(str2); - break; - - case 'm': /* medium */ - thick[5] = defthick[0] * atof(str2); - break; - - case 'n': /* narrow */ - thick[0] = thick[1] = thick[3] = thick[4] = - defthick[0] * atof(str2); - break; - - case 'x': /* x */ - scalecommand: /* scale */ - par = atof(str2); - if (par > 0.0) - xscale *= par; - else - error("invalid scale value on line %1", linenum); - break; - - case 'f': /* file */ - strcpy(gremlinfile, str2); - break; - - case 'w': /* width */ - width = atof(str2); - if (width < 0.0) - width = -width; - break; - - case 'h': /* height */ - height = atof(str2); - if (height < 0.0) - height = -height; - break; - - case 'd': /* defaults */ - setdefault = 1; - break; - - case 'p': /* pointscale */ - if (strcmp("off", str2)) - pointscale = 1; - else - pointscale = 0; - break; - - default: - error("unknown command `%1' on line %2", str1, linenum); - exit(8); - break; - }; -} - - -/* - * return TRUE if picture contains a polygon - * otherwise FALSE - */ - -int -has_polygon(register ELT *elist) -{ - while (!DBNullelt(elist)) { - if (elist->type == POLYGON) - return (1); - elist = DBNextElt(elist); - } - - return (0); -} - -/* EOF */ diff --git a/contrib/groff/src/preproc/html/pre-html.cc b/contrib/groff/src/preproc/html/pre-html.cc deleted file mode 100644 index e7364dd..0000000 --- a/contrib/groff/src/preproc/html/pre-html.cc +++ /dev/null @@ -1,1525 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. - Written by Gaius Mulley (gaius@glam.ac.uk). - -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. */ - -#define PREHTMLC - -#include "lib.h" - -#include -#include -#include -#include -#include -#include "errarg.h" -#include "error.h" -#include "stringclass.h" -#include "posix.h" -#include "defs.h" -#include "searchpath.h" -#include "paper.h" -#include "font.h" - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef _POSIX_VERSION -#include -#define PID_T pid_t -#else /* not _POSIX_VERSION */ -#define PID_T int -#endif /* not _POSIX_VERSION */ - -#include - -#include "nonposix.h" - -extern "C" const char *Version_string; - -#include "pre-html.h" -#include "pushback.h" -#include "html-strings.h" - -#define DEFAULT_LINE_LENGTH 7 // inches wide -#define DEFAULT_IMAGE_RES 100 // number of pixels per inch resolution -#define IMAGE_BOARDER_PIXELS 0 -#define INLINE_LEADER_CHAR '\\' - -#define TRANSPARENT "-background white -transparent white" -#define MIN_ALPHA_BITS 0 -#define MAX_ALPHA_BITS 4 - -#define PAGE_TEMPLATE_SHORT "pg" -#define PAGE_TEMPLATE_LONG "-page-" -#define PS_TEMPLATE_SHORT "ps" -#define PS_TEMPLATE_LONG "-ps-" -#define REGION_TEMPLATE_SHORT "rg" -#define REGION_TEMPLATE_LONG "-regions-" - -#if 0 -# define DEBUGGING -#endif - -#if !defined(TRUE) -# define TRUE (1==1) -#endif -#if !defined(FALSE) -# define FALSE (1==0) -#endif - -typedef enum {CENTERED, LEFT, RIGHT, INLINE} IMAGE_ALIGNMENT; - -static int postscriptRes =-1; // postscript resolution, dots per inch -static int stdoutfd = 1; // output file descriptor - normally 1 but might move - // -1 means closed -static int copyofstdoutfd =-1; // a copy of stdout, so we can restore stdout when - // writing to post-html -static char *psFileName = NULL; // name of postscript file -static char *psPageName = NULL; // name of file containing postscript current page -static char *regionFileName = NULL; // name of file containing all image regions -static char *imagePageName = NULL; // name of bitmap image containing current page -static char *image_device = "pnmraw"; -static int image_res = DEFAULT_IMAGE_RES; -static int vertical_offset = 0; -static char *image_template = NULL; // image template filename -static char *macroset_template= NULL; // image template passed to troff by -D -static int troff_arg = 0; // troff arg index -static char *image_dir = NULL; // user specified image directory -static int textAlphaBits = MAX_ALPHA_BITS; -static int graphicAlphaBits = MAX_ALPHA_BITS; -static char *antiAlias = NULL; // antialias arguments we pass to gs. -static int show_progress = FALSE; // should we display page numbers as they are processed? -static int currentPageNo = -1; // current image page number -#if defined(DEBUGGING) -static int debug = FALSE; -static char *troffFileName = NULL; // output of pre-html output which is sent to troff -Tps -static char *htmlFileName = NULL; // output of pre-html output which is sent to troff -Thtml -#endif - -static char *linebuf = NULL; // for scanning devps/DESC -static int linebufsize = 0; - -const char *const FONT_ENV_VAR = "GROFF_FONT_PATH"; -static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0); - - -/* - * Images are generated via postscript, gs and the pnm utilities. - */ - -#define IMAGE_DEVICE "-Tps" - -/* - * prototypes - */ -static int do_file(const char *filename); - -/* - * sys_fatal - writes a fatal error message. - * Taken from src/roff/groff/pipeline.c. - */ - -void sys_fatal (const char *s) -{ - fatal("%1: %2", s, strerror(errno)); -} - -/* - * get_line - copies a line (w/o newline) from a file to the global line buffer - */ - -int get_line (FILE *f) -{ - if (f == 0) - return 0; - if (linebuf == 0) { - linebuf = new char[128]; - linebufsize = 128; - } - int i = 0; - // skip leading whitespace - for (;;) { - int c = getc(f); - if (c == EOF) - return 0; - if (c != ' ' && c != '\t') { - ungetc(c, f); - break; - } - } - for (;;) { - int c = getc(f); - if (c == EOF) - break; - if (i + 1 >= linebufsize) { - char *old_linebuf = linebuf; - linebuf = new char[linebufsize * 2]; - memcpy(linebuf, old_linebuf, linebufsize); - a_delete old_linebuf; - linebufsize *= 2; - } - linebuf[i++] = c; - if (c == '\n') { - i--; - break; - } - } - linebuf[i] = '\0'; - return 1; -} - -/* - * get_resolution - returns the postscript resolution from devps/DESC - */ - -static unsigned int get_resolution (void) -{ - char *pathp; - FILE *f; - unsigned int res; - f = font_path.open_file("devps/DESC", &pathp); - if (f == 0) - fatal("can't open devps/DESC"); - while (get_line(f)) { - int n = sscanf(linebuf, "res %u", &res); - if (n >= 1) { - fclose(f); - return res; - } - } - fatal("can't find `res' keyword in devps/DESC"); - return 0; -} - -/* - * html_system - a wrapper for system() - */ - -void html_system(const char *s, int redirect_stdout) -{ - // Redirect standard error to the null device. This is more - // portable than using "2> /dev/null", since it doesn't require a - // Unixy shell. - int save_stderr = dup(2); - int save_stdout = dup(1); - int fdnull = open(NULL_DEV, O_WRONLY|O_BINARY, 0666); - if (save_stderr > 2 && fdnull > 2) - dup2(fdnull, 2); - if (redirect_stdout && save_stdout > 1 && fdnull > 1) - dup2(fdnull, 1); - if (fdnull >= 0) - close(fdnull); - int status = system(s); - dup2(save_stderr, 2); - if (redirect_stdout) - dup2(save_stdout, 1); - if (status == -1) - fprintf(stderr, "Calling `%s' failed\n", s); - else if (status) - fprintf(stderr, "Calling `%s' returned status %d\n", s, status); - close(save_stderr); - close(save_stdout); -} - -/* - * make_message - taken from man printf(3), creates a string via malloc - * and places the result of the va args into string. - * Finally the new string is returned. - */ - -char * -make_message (const char *fmt, ...) -{ - /* Guess we need no more than 100 bytes. */ - int n, size = 100; - char *p; - char *np; - va_list ap; - if ((p = (char *)malloc (size)) == NULL) - return NULL; - while (1) { - /* Try to print in the allocated space. */ - va_start(ap, fmt); - n = vsnprintf (p, size, fmt, ap); - va_end(ap); - /* If that worked, return the string. */ - if (n > -1 && n < size) { - if (size > n+1) { - np = strsave(p); - free(p); - return np; - } - return p; - } - /* Else try again with more space. */ - if (n > -1) /* glibc 2.1 */ - size = n+1; /* precisely what is needed */ - else /* glibc 2.0 */ - size *= 2; /* twice the old size */ - if ((np = (char *)realloc (p, size)) == NULL) { - free(p); /* realloc failed, free old, p. */ - return NULL; - } - p = np; /* use realloc'ed, p */ - } -} - -/* - * the class and methods for retaining ascii text - */ - -struct char_block { - enum { SIZE = 256 }; - char buffer[SIZE]; - int used; - char_block *next; - - char_block(); -}; - -/* - * char_block - constructor, sets the, used, and, next, fields to zero. - */ - -char_block::char_block() -: used(0), next(0) -{ -} - -class char_buffer { -public: - char_buffer(); - ~char_buffer(); - int read_file(FILE *fp); - int do_html(int argc, char *argv[]); - int do_image(int argc, char *argv[]); - void write_file_html(void); - void write_file_troff(void); - void write_upto_newline (char_block **t, int *i, int is_html); - int can_see(char_block **t, int *i, char *string); - int skip_spaces(char_block **t, int *i); - void skip_until_newline(char_block **t, int *i); -private: - char_block *head; - char_block *tail; -}; - -/* - * char_buffer - constructor - */ - -char_buffer::char_buffer() -: head(0), tail(0) -{ -} - -/* - * char_buffer - deconstructor, throws aways the whole buffer list. - */ - -char_buffer::~char_buffer() -{ - while (head != NULL) { - char_block *temp = head; - head = head->next; - delete temp; - } -} - -/* - * read_file - read in a complete file, fp, placing the contents inside char_blocks. - */ - -int char_buffer::read_file (FILE *fp) -{ - int n; - - while (! feof(fp)) { - if (tail == NULL) { - tail = new char_block; - head = tail; - } else { - if (tail->used == char_block::SIZE) { - tail->next = new char_block; - tail = tail->next; - } - } - // at this point we have a tail which is ready for the next SIZE bytes of the file - - n = fread(tail->buffer, sizeof(char), char_block::SIZE-tail->used, fp); - if (n <= 0) { - // error - return( 0 ); - } else { - tail->used += n*sizeof(char); - } - } - return( 1 ); -} - -/* - * writeNbytes - writes n bytes to stdout. - */ - -static void writeNbytes (char *s, int l) -{ - int n=0; - int r; - - while (n0) && (image_dir[strlen(image_dir)-1] != '/')) { - image_dir = make_message("%s/", image_dir); - if (image_dir == NULL) - sys_fatal("make_message"); - } - - if (image_template == NULL) - macroset_template = make_message("%sgrohtml-%d", image_dir, (int)getpid()); - else - macroset_template = make_message("%s%s", image_dir, image_template); - - if (macroset_template == NULL) - sys_fatal("make_message"); - - image_template = (char *)malloc(strlen("-%d")+strlen(macroset_template)+1); - if (image_template == NULL) - sys_fatal("malloc"); - strcpy(image_template, macroset_template); - strcat(image_template, "-%d"); -} - -/* - * setupAntiAlias - sets up the antialias string, used when we call gs. - */ - -static void setupAntiAlias (void) -{ - if (textAlphaBits == 0 && graphicAlphaBits == 0) - antiAlias = make_message(" "); - else if (textAlphaBits == 0) - antiAlias = make_message("-dGraphicsAlphaBits=%d ", graphicAlphaBits); - else if (graphicAlphaBits == 0) - antiAlias = make_message("-dTextAlphaBits=%d ", textAlphaBits); - else - antiAlias = make_message("-dTextAlphaBits=%d -dGraphicsAlphaBits=%d ", - textAlphaBits, graphicAlphaBits); -} - -/* - * checkImageDir - checks to see whether the image directory is available. - */ - -static void checkImageDir (void) -{ - if ((image_dir != NULL) && (strcmp(image_dir, "") != 0)) - if (! ((mkdir(image_dir, 0777) == 0) || (errno == EEXIST))) { - error("cannot create directory `%1'", image_dir); - exit(1); - } -} - -/* - * write_end_image - ends the image. It writes out the image extents if we are using -Tps. - */ - -static void write_end_image (int is_html) -{ - /* - * if we are producing html then these - * emit image name and enable output - * else - * we are producing images - * in which case these generate image - * boundaries - */ - writeString("\\O[4]\\O[2]"); - if (is_html) - writeString("\\O[1]"); - else - writeString("\\O[0]"); -} - -/* - * write_start_image - writes the troff which will: - * - * (i) disable html output for the following image - * (ii) reset the max/min x/y registers during postscript - * rendering. - */ - -static void write_start_image (IMAGE_ALIGNMENT pos, int is_html) -{ - writeString("\\O[5"); - switch (pos) { - - case INLINE: - writeString("i"); - break; - case LEFT: - writeString("l"); - break; - case RIGHT: - writeString("r"); - break; - case CENTERED: - default: - writeString("c"); - break; - } - writeString(image_template); writeString(".png]"); - if (is_html) - writeString("\\O[0]\\O[3]"); - else - // reset min/max registers - writeString("\\O[1]\\O[3]"); -} - -/* - * write_upto_newline - writes the contents of the buffer until a newline is seen. - * It checks for HTML_IMAGE_INLINE_BEGIN and HTML_IMAGE_INLINE_END - * and if they are present it processes them. - */ - -void char_buffer::write_upto_newline (char_block **t, int *i, int is_html) -{ - int j=*i; - - if (*t) { - while ((j < (*t)->used) && ((*t)->buffer[j] != '\n') && - ((*t)->buffer[j] != INLINE_LEADER_CHAR)) { - j++; - } - if ((j < (*t)->used) && ((*t)->buffer[j] == '\n')) { - j++; - } - writeNbytes((*t)->buffer+(*i), j-(*i)); - if ((*t)->buffer[j] == INLINE_LEADER_CHAR) { - if (can_see(t, &j, HTML_IMAGE_INLINE_BEGIN)) - write_start_image(INLINE, is_html); - else if (can_see(t, &j, HTML_IMAGE_INLINE_END)) - write_end_image(is_html); - else { - if (j < (*t)->used) { - *i = j; - j++; - writeNbytes((*t)->buffer+(*i), j-(*i)); - } - } - } - if (j == (*t)->used) { - *i = 0; - if ((*t)->buffer[j-1] == '\n') { - *t = (*t)->next; - } else { - *t = (*t)->next; - write_upto_newline(t, i, is_html); - } - } else { - // newline was seen - *i = j; - } - } -} - -/* - * can_see - returns TRUE if we can see string in t->buffer[i] onwards - */ - -int char_buffer::can_see (char_block **t, int *i, char *string) -{ - int j = 0; - int l = strlen(string); - int k = *i; - char_block *s = *t; - - while (s) { - while ((kused) && (jbuffer[k] == string[j])) { - j++; - k++; - } - if (j == l) { - *i = k; - *t = s; - return( TRUE ); - } else if ((kused) && (s->buffer[k] != string[j])) { - return( FALSE ); - } - s = s->next; - k = 0; - } - return( FALSE ); -} - -/* - * skip_spaces - returns TRUE if we have not run out of data. - * It also consumes spaces. - */ - -int char_buffer::skip_spaces(char_block **t, int *i) -{ - char_block *s = *t; - int k = *i; - - while (s) { - while ((kused) && (isspace(s->buffer[k]))) { - k++; - } - if (k == s->used) { - k = 0; - s = s->next; - } else { - *i = k; - return( TRUE ); - } - } - return( FALSE ); -} - -/* - * skip_until_newline - skips all characters until a newline is seen. - * The newline is not consumed. - */ - -void char_buffer::skip_until_newline (char_block **t, int *i) -{ - int j=*i; - - if (*t) { - while ((j < (*t)->used) && ((*t)->buffer[j] != '\n')) { - j++; - } - if (j == (*t)->used) { - *i = 0; - *t = (*t)->next; - skip_until_newline(t, i); - } else { - // newline was seen - *i = j; - } - } -} - -/* - * write_file_troff - writes the buffer to stdout (troff). - */ - -void char_buffer::write_file_troff (void) -{ - char_block *t=head; - int i=0; - - if (t != NULL) { - do { - write_upto_newline(&t, &i, FALSE); - } while (t != NULL); - } - if (close(stdoutfd) < 0) - sys_fatal("close"); - - // now we grab fd=1 so that the next pipe cannot use fd=1 - if (stdoutfd == 1) { - if (dup(2) != stdoutfd) { - sys_fatal("dup failed to use fd=1"); - } - } -} - -/* - * the image class remembers the position of all images in the postscript file - * and assigns names for each image. - */ - -struct imageItem { - imageItem *next; - int X1; - int Y1; - int X2; - int Y2; - char *imageName; - int resolution; - int maxx; - int pageNo; - - imageItem (int x1, int y1, int x2, int y2, int page, int res, int max_width, char *name); - ~imageItem (); -}; - -/* - * imageItem - constructor - */ - -imageItem::imageItem (int x1, int y1, int x2, int y2, int page, int res, int max_width, char *name) -{ - X1 = x1; - Y1 = y1; - X2 = x2; - Y2 = y2; - pageNo = page; - resolution = res; - maxx = max_width; - imageName = name; - next = NULL; -} - -/* - * imageItem - deconstructor - */ - -imageItem::~imageItem () -{ -} - -/* - * imageList - class containing a list of imageItems. - */ - -class imageList { -private: - imageItem *head; - imageItem *tail; - int count; -public: - imageList(); - ~imageList(); - void add(int x1, int y1, int x2, int y2, int page, int res, int maxx, char *name); - void createImages (void); - int createPage (int pageno); - void createImage (imageItem *i); - int getMaxX (int pageno); -}; - -/* - * imageList - constructor. - */ - -imageList::imageList () - : head(0), tail(0), count(0) -{ -} - -/* - * imageList - deconstructor. - */ - -imageList::~imageList () -{ - while (head != NULL) { - imageItem *i = head; - head = head->next; - delete i; - } -} - -/* - * createPage - creates one image of, page pageno, from the postscript file. - */ - -int imageList::createPage (int pageno) -{ - char *s; - - if (currentPageNo == pageno) - return 0; - - if (currentPageNo >= 1) { - /* - * we need to unlink the files which change each time a new page is processed. - * The final unlink is done by xtmpfile when pre-grohtml exits. - */ - unlink(imagePageName); - unlink(psPageName); - } - - if (show_progress) { - fprintf(stderr, "[%d] ", pageno); - fflush(stderr); - } - -#if defined(DEBUGGING) - if (debug) - fprintf(stderr, "creating page %d\n", pageno); -#endif - - s = make_message("psselect -q -p%d %s %s\n", - pageno, psFileName, psPageName); - - if (s == NULL) - sys_fatal("make_message"); -#if defined(DEBUGGING) - if (debug) { - fwrite(s, sizeof(char), strlen(s), stderr); - fflush(stderr); - } -#endif - html_system(s, 1); - - s = make_message("echo showpage | " - "gs%s -q -dBATCH -dSAFER " - "-dDEVICEHEIGHTPOINTS=792 " - "-dDEVICEWIDTHPOINTS=%d -dFIXEDMEDIA=true " - "-sDEVICE=%s -r%d %s " - "-sOutputFile=%s %s -\n", - EXE_EXT, - (getMaxX(pageno) * image_res) / postscriptRes, - image_device, - image_res, - antiAlias, - imagePageName, - psPageName); - if (s == NULL) - sys_fatal("make_message"); -#if defined(DEBUGGING) - if (debug) { - fwrite(s, sizeof(char), strlen(s), stderr); - fflush(stderr); - } -#endif - html_system(s, 1); - a_delete s; - currentPageNo = pageno; - return 0; -} - -/* - * min - returns the minimum of two numbers. - */ - -int min (int x, int y) -{ - if (x < y) { - return( x ); - } else { - return( y ); - } -} - -/* - * max - returns the maximum of two numbers. - */ - -int max (int x, int y) -{ - if (x > y) { - return( x ); - } else { - return( y ); - } -} - -/* - * getMaxX - returns the largest right hand position for any image on, pageno - */ - -int imageList::getMaxX (int pageno) -{ - imageItem *h = head; - int x = postscriptRes * DEFAULT_LINE_LENGTH; - - while (h != NULL) { - if (h->pageNo == pageno) - x = max(h->X2, x); - h = h->next; - } - return x; -} - -/* - * createImage - generates a minimal png file from the set of page images. - */ - -void imageList::createImage (imageItem *i) -{ - if (i->X1 != -1) { - char *s; - int x1 = max(min(i->X1, i->X2)*image_res/postscriptRes-1*IMAGE_BOARDER_PIXELS, 0); - int y1 = max((image_res*vertical_offset/72)+min(i->Y1, i->Y2)*image_res/postscriptRes-IMAGE_BOARDER_PIXELS, 0); - int x2 = max(i->X1, i->X2)*image_res/postscriptRes+1*IMAGE_BOARDER_PIXELS; - int y2 = (image_res*vertical_offset/72)+(max(i->Y1, i->Y2)*image_res/postscriptRes)+1+IMAGE_BOARDER_PIXELS; - if (createPage(i->pageNo) == 0) { - s = make_message("pnmcut%s %d %d %d %d < %s | pnmcrop -quiet | pnmtopng%s %s > %s \n", - EXE_EXT, - x1, y1, x2-x1+1, y2-y1+1, - imagePageName, - EXE_EXT, - TRANSPARENT, - i->imageName); - if (s == NULL) - sys_fatal("make_message"); - -#if defined(DEBUGGING) - if (debug) { - fprintf(stderr, s); - fflush(stderr); - } -#endif - html_system(s, 0); - a_delete s; - } else { - fprintf(stderr, "failed to generate image of page %d\n", i->pageNo); - fflush(stderr); - } -#if defined(DEBUGGING) - } else { - if (debug) { - fprintf(stderr, "ignoring image as x1 coord is -1\n"); - fflush(stderr); - } -#endif - } -} - -/* - * add - an image description to the imageList. - */ - -void imageList::add (int x1, int y1, int x2, int y2, int page, int res, int maxx, char *name) -{ - imageItem *i = new imageItem(x1, y1, x2, y2, page, res, maxx, name); - - if (head == NULL) { - head = i; - tail = i; - } else { - tail->next = i; - tail = i; - } -} - -/* - * createImages - foreach image descriptor on the imageList, create the actual image. - */ - -void imageList::createImages (void) -{ - imageItem *h = head; - - while (h != NULL) { - createImage(h); - h = h->next; - } -} - -static imageList listOfImages; // list of images defined by the region file. - -/* - * write_file_html - writes the buffer to stdout (troff). - * It writes out the file replacing template image names with - * actual image names. - */ - -void char_buffer::write_file_html (void) -{ - char_block *t=head; - int i=0; - - if (t != NULL) { - do { - write_upto_newline(&t, &i, TRUE); - } while (t != NULL); - } - if (close(stdoutfd) < 0) - sys_fatal("close"); - - // now we grab fd=1 so that the next pipe cannot use fd=1 - if (stdoutfd == 1) { - if (dup(2) != stdoutfd) { - sys_fatal("dup failed to use fd=1"); - } - } -} - -/* - * generateImages - parses the region file and generates images - * from the postscript file. The region file - * contains the x1,y1 x2,y2 extents of each - * image. - */ - -static void generateImages (char *regionFileName) -{ - pushBackBuffer *f=new pushBackBuffer(regionFileName); - - while (f->putPB(f->getPB()) != eof) { - if (f->isString("grohtml-info:page")) { - int page = f->readInt(); - int x1 = f->readInt(); - int y1 = f->readInt(); - int x2 = f->readInt(); - int y2 = f->readInt(); - int maxx = f->readInt(); - char *name = f->readString(); - int res = postscriptRes; - listOfImages.add(x1, y1, x2, y2, page, res, maxx, name); - while ((f->putPB(f->getPB()) != '\n') && - (f->putPB(f->getPB()) != eof)) { - (void)f->getPB(); - } - if (f->putPB(f->getPB()) == '\n') { - (void)f->getPB(); - } - } else { - /* - * write any error messages out to the user - */ - fputc(f->getPB(), stderr); - } - } - - listOfImages.createImages(); - if (show_progress) { - fprintf(stderr, "done\n"); - fflush(stderr); - } - delete f; -} - -/* - * replaceFd - replace a file descriptor, was, with, willbe. - */ - -static void replaceFd (int was, int willbe) -{ - int dupres; - - if (was != willbe) { - if (close(was)<0) { - sys_fatal("close"); - } - dupres = dup(willbe); - if (dupres != was) { - sys_fatal("dup"); - fprintf(stderr, "trying to replace fd=%d with %d dup used %d\n", was, willbe, dupres); - if (willbe == 1) { - fprintf(stderr, "likely that stdout should be opened before %d\n", was); - } - exit(1); - } - if (close(willbe) < 0) { - sys_fatal("close"); - } - } -} - -/* - * waitForChild - waits for child, pid, to exit. - */ - -static void waitForChild (PID_T pid) -{ - PID_T waitpd; - int status; - - waitpd = WAIT(&status, pid, _WAIT_CHILD); - if (waitpd != pid) - sys_fatal("wait"); -} - -/* - * alterDeviceTo - if toImage is set then the arg list is altered to include - * IMAGE_DEVICE and we invoke groff rather than troff. - * else - * set -Thtml and groff - */ - -static void alterDeviceTo (int argc, char *argv[], int toImage) -{ - int i=0; - - if (toImage) { - while (i < argc) { - if (strcmp(argv[i], "-Thtml") == 0) { - argv[i] = IMAGE_DEVICE; - } - i++; - } - argv[troff_arg] = "groff"; /* rather than troff */ - } else { - while (i < argc) { - if (strcmp(argv[i], IMAGE_DEVICE) == 0) { - argv[i] = "-Thtml"; - } - i++; - } - argv[troff_arg] = "groff"; /* use groff -Z */ - } -} - -/* - * addZ - appends -Z onto the command list for groff. - */ - -char **addZ (int argc, char *argv[]) -{ - char **new_argv = (char **)malloc((argc+2)*sizeof(char *)); - int i=0; - - if (new_argv == NULL) - sys_fatal("malloc"); - - if (argc > 0) { - new_argv[i] = argv[i]; - i++; - } - new_argv[i] = "-Z"; - while (i)\n"); - fprintf(stream, " place all png files into image_directory\n"); -} - -/* - * scanArguments - scans for all arguments including -P-i, -P-o, -P-D and -P-I. It returns - * the argument index of the first non option. - */ - -int scanArguments (int argc, char **argv) -{ - const char *command_prefix = getenv("GROFF_COMMAND_PREFIX"); - if (!command_prefix) - command_prefix = PROG_PREFIX; - char *troff_name = new char[strlen(command_prefix) + strlen("troff") + 1]; - strcpy(troff_name, command_prefix); - strcat(troff_name, "troff"); - int c, i; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((c = getopt_long(argc, argv, "+a:g:o:i:I:D:F:vbdhlrnp", long_options, NULL)) - != EOF) - switch(c) { - case 'v': - printf("GNU pre-grohtml (groff) version %s\n", Version_string); - exit(0); - case 'a': - textAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)), MAX_ALPHA_BITS); - if (textAlphaBits == 3) { - error("cannot use 3 bits of antialiasing information"); - exit(1); - } - break; - case 'g': - graphicAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)), MAX_ALPHA_BITS); - if (graphicAlphaBits == 3) { - error("cannot use 3 bits of antialiasing information"); - exit(1); - } - break; - case 'b': - // handled by post-grohtml (set background color to white) - break; - case 'D': - image_dir = optarg; - break; - case 'I': - image_template = optarg; - break; - case 'i': - image_res = atoi(optarg); - break; - case 'F': - font_path.command_line_dir(optarg); - break; - case 'o': - vertical_offset = atoi(optarg); - break; - case 'p': - show_progress = TRUE; - break; - case 'd': -#if defined(DEBUGGING) - debug = TRUE; -#endif - break; - case 'h': - // handled by post-grohtml - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - break; - } - - i = optind; - while (i < argc) { - if (strcmp(argv[i], troff_name) == 0) - troff_arg = i; - else if (argv[i][0] != '-') - return i; - i++; - } - a_delete troff_name; - - return argc; -} - -/* - * makeTempFiles - name the temporary files - */ - -static int makeTempFiles (void) -{ -#if defined(DEBUGGING) - psFileName = "/tmp/prehtml-ps"; - regionFileName = "/tmp/prehtml-region"; - imagePageName = "/tmp/prehtml-page"; - psPageName = "/tmp/prehtml-psn"; - troffFileName = "/tmp/prehtml-troff"; - htmlFileName = "/tmp/prehtml-html"; -#else - FILE *f; - - /* psPageName contains a single page of postscript */ - f = xtmpfile(&psPageName, - PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT, - TRUE); - if (f == NULL) { - sys_fatal("xtmpfile"); - return -1; - } - fclose(f); - - /* imagePageName contains a bitmap image of the single postscript page */ - f = xtmpfile(&imagePageName, - PAGE_TEMPLATE_LONG, PAGE_TEMPLATE_SHORT, - TRUE); - if (f == NULL) { - sys_fatal("xtmpfile"); - return -1; - } - fclose(f); - - /* psFileName contains a postscript file of the complete document */ - f = xtmpfile(&psFileName, - PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT, - TRUE); - if (f == NULL) { - sys_fatal("xtmpfile"); - return -1; - } - fclose(f); - - /* regionFileName contains a list of the images and their boxed coordinates */ - f = xtmpfile(®ionFileName, - REGION_TEMPLATE_LONG, REGION_TEMPLATE_SHORT, - TRUE); - if (f == NULL) { - sys_fatal("xtmpfile"); - return -1; - } - fclose(f); - -#endif - return 0; -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - int i; - int found=0; - int ok=1; - - postscriptRes = get_resolution(); - i = scanArguments(argc, argv); - setupAntiAlias(); - checkImageDir(); - makeFileName(); - while (i < argc) { - if (argv[i][0] != '-') { - /* found source file */ - ok = do_file(argv[i]); - if (! ok) { - return( 0 ); - } - found = 1; - } - i++; - } - - copyofstdoutfd=dup(stdoutfd); - - if (! found) { - do_file("-"); - } - if (makeTempFiles()) - return 1; - ok = inputFile.do_image(argc, argv); - if (ok == 0) { - generateImages(regionFileName); - ok = inputFile.do_html(argc, argv); - } - return ok; -} - -static int do_file(const char *filename) -{ - FILE *fp; - - current_filename = filename; - if (strcmp(filename, "-") == 0) { - fp = stdin; - } else { - fp = fopen(filename, "r"); - if (fp == 0) { - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } - } - - if (inputFile.read_file(fp)) { - } - - if (fp != stdin) - fclose(fp); - current_filename = NULL; - return 1; -} diff --git a/contrib/groff/src/preproc/html/pushback.cc b/contrib/groff/src/preproc/html/pushback.cc deleted file mode 100644 index d18c5e2..0000000 --- a/contrib/groff/src/preproc/html/pushback.cc +++ /dev/null @@ -1,333 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. - Written by Gaius Mulley (gaius@glam.ac.uk). - -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 "lib.h" - -#include -#include -#include -#include -#include -#include "errarg.h" -#include "error.h" -#include "stringclass.h" -#include "posix.h" -#include "nonposix.h" - -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "pushback.h" -#include "pre-html.h" - -#if !defined(TRUE) -# define TRUE (1==1) -#endif - -#if !defined(FALSE) -# define FALSE (1==0) -#endif - -# define ERROR(X) (void)(fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \ - (fflush(stderr)) && localexit(1)) - - -#define MAXPUSHBACKSTACK 4096 /* maximum number of character that can be pushed back */ - - -/* - * constructor for pushBackBuffer - */ - -pushBackBuffer::pushBackBuffer (char *filename) -{ - charStack = (char *)malloc(MAXPUSHBACKSTACK); - if (charStack == 0) { - sys_fatal("malloc"); - } - stackPtr = 0; /* index to push back stack */ - debug = 0; - verbose = 0; - eofFound = FALSE; - lineNo = 1; - if (strcmp(filename, "") != 0) { - stdIn = dup(0); - close(0); - if (open(filename, O_RDONLY) != 0) { - sys_fatal("when trying to open file"); - } else { - fileName = filename; - } - } -} - -pushBackBuffer::~pushBackBuffer () -{ - int old; - - if (charStack != 0) { - free(charStack); - } - close(0); - /* restore stdin in file descriptor 0 */ - old = dup(stdIn); - close(stdIn); -} - -/* - * localexit - wraps exit with a return code to aid the ERROR macro. - */ - -int localexit (int i) -{ - exit(i); - return( 1 ); -} - -/* - * getPB - returns a character, possibly a pushed back character. - */ - -char pushBackBuffer::getPB (void) -{ - if (stackPtr>0) { - stackPtr--; - return( charStack[stackPtr] ); - } else { - char ch; - - if (read(0, &ch, 1) == 1) { - if (verbose) { - printf("%c", ch); - } - if (ch == '\n') { - lineNo++; - } - return( ch ); - } else { - eofFound = TRUE; - return( eof ); - } - } -} - -/* - * putPB - pushes a character onto the push back stack. - * The same character is returned. - */ - -char pushBackBuffer::putPB (char ch) -{ - if (stackPtr=0) { - if (putPB(s[i]) != s[i]) { - ERROR("assert failed"); - } - i--; - } - } - return( FALSE ); -} - -/* - * isDigit - returns TRUE if the character, ch, is a digit. - */ - -static int isDigit (char ch) -{ - return( ((ch>='0') && (ch<='9')) ); -} - -/* - * isHexDigit - returns TRUE if the character, ch, is a hex digit. - */ - -#if 0 -static int isHexDigit (char ch) -{ - return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) ); -} -#endif - -/* - * readInt - returns an integer from the input stream. - */ - -int pushBackBuffer::readInt (void) -{ - int c =0; - int i =0; - int s =1; - char ch=getPB(); - - while (isWhite(ch)) { - ch=getPB(); - } - // now read integer - - if (ch == '-') { - s = -1; - ch = getPB(); - } - while (isDigit(ch)) { - i *= 10; - if ((ch>='0') && (ch<='9')) { - i += (int)(ch-'0'); - } - ch = getPB(); - c++; - } - if (ch != putPB(ch)) { - ERROR("assert failed"); - } - return( i*s ); -} - -/* - * convertToFloat - converts integers, a and b into a.b - */ - -static float convertToFloat (int a, int b) -{ - int c=10; - float f; - - while (b>c) { - c *= 10; - } - f = ((float)a) + (((float)b)/((float)c)); - return( f ); -} - -/* - * readNumber - returns a float representing the word just read. - */ - -float pushBackBuffer::readNumber (void) -{ - int i; - char ch; - - i = readInt(); - if ((ch = getPB()) == '.') { - return convertToFloat(i, readInt()); - } - putPB(ch); - return (float)i; -} - -/* - * readString - reads a string terminated by white space - * and returns a malloced area of memory containing - * a copy of the characters. - */ - -char *pushBackBuffer::readString (void) -{ - char buffer[MAXPUSHBACKSTACK]; - char *string = 0; - int i=0; - char ch=getPB(); - - while (isWhite(ch)) { - ch=getPB(); - } - while ((i < MAXPUSHBACKSTACK) && (! isWhite(ch)) && (! eofFound)) { - buffer[i] = ch; - i++; - ch = getPB(); - } - if (i < MAXPUSHBACKSTACK) { - buffer[i] = (char)0; - string = (char *)malloc(strlen(buffer)+1); - strcpy(string, buffer); - } - return( string ); -} diff --git a/contrib/groff/src/preproc/pic/common.cc b/contrib/groff/src/preproc/pic/common.cc deleted file mode 100644 index 5075e93..0000000 --- a/contrib/groff/src/preproc/pic/common.cc +++ /dev/null @@ -1,496 +0,0 @@ -// -*- 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 "pic.h" -#include "common.h" - -// output a dashed circle as a series of arcs - -void common_output::dashed_circle(const position ¢, double rad, - const line_type <) -{ - assert(lt.type == line_type::dashed); - line_type slt = lt; - slt.type = line_type::solid; - double dash_angle = lt.dash_width/rad; - int ndashes; - double gap_angle; - if (dash_angle >= M_PI/4.0) { - if (dash_angle < M_PI/2.0) { - gap_angle = M_PI/2.0 - dash_angle; - ndashes = 4; - } - else if (dash_angle < M_PI) { - gap_angle = M_PI - dash_angle; - ndashes = 2; - } - else { - circle(cent, rad, slt, -1.0); - return; - } - } - else { - ndashes = 4*int(ceil(M_PI/(4.0*dash_angle))); - gap_angle = (M_PI*2.0)/ndashes - dash_angle; - } - for (int i = 0; i < ndashes; i++) { - double start_angle = i*(dash_angle+gap_angle) - dash_angle/2.0; - solid_arc(cent, rad, start_angle, start_angle + dash_angle, lt); - } -} - -// output a dotted circle as a series of dots - -void common_output::dotted_circle(const position ¢, double rad, - const line_type <) -{ - assert(lt.type == line_type::dotted); - double gap_angle = lt.dash_width/rad; - int ndots; - if (gap_angle >= M_PI/2.0) { - // always have at least 2 dots - gap_angle = M_PI; - ndots = 2; - } - else { - ndots = 4*int(M_PI/(2.0*gap_angle)); - gap_angle = (M_PI*2.0)/ndots; - } - double ang = 0.0; - for (int i = 0; i < ndots; i++, ang += gap_angle) - dot(cent + position(cos(ang), sin(ang))*rad, lt); -} - -// return non-zero iff we can compute a center - -int compute_arc_center(const position &start, const position ¢, - const position &end, position *result) -{ - // This finds the point along the vector from start to cent that - // is equidistant between start and end. - distance c = cent - start; - distance e = end - start; - double n = c*e; - if (n == 0.0) - return 0; - *result = start + c*((e*e)/(2.0*n)); - return 1; -} - -// output a dashed arc as a series of arcs - -void common_output::dashed_arc(const position &start, const position ¢, - const position &end, const line_type <) -{ - assert(lt.type == line_type::dashed); - position c; - if (!compute_arc_center(start, cent, end, &c)) { - line(start, &end, 1, lt); - return; - } - distance start_offset = start - c; - distance end_offset = end - c; - double start_angle = atan2(start_offset.y, start_offset.x); - double end_angle = atan2(end_offset.y, end_offset.x); - double rad = hypot(c - start); - double dash_angle = lt.dash_width/rad; - double total_angle = end_angle - start_angle; - while (total_angle < 0) - total_angle += M_PI + M_PI; - if (total_angle <= dash_angle*2.0) { - solid_arc(cent, rad, start_angle, end_angle, lt); - return; - } - int ndashes = int((total_angle - dash_angle)/(dash_angle*2.0) + .5); - double dash_and_gap_angle = (total_angle - dash_angle)/ndashes; - for (int i = 0; i <= ndashes; i++) - solid_arc(cent, rad, start_angle + i*dash_and_gap_angle, - start_angle + i*dash_and_gap_angle + dash_angle, lt); -} - -// output a dotted arc as a series of dots - -void common_output::dotted_arc(const position &start, const position ¢, - const position &end, const line_type <) -{ - assert(lt.type == line_type::dotted); - position c; - if (!compute_arc_center(start, cent, end, &c)) { - line(start, &end, 1, lt); - return; - } - distance start_offset = start - c; - distance end_offset = end - c; - double start_angle = atan2(start_offset.y, start_offset.x); - double total_angle = atan2(end_offset.y, end_offset.x) - start_angle; - while (total_angle < 0) - total_angle += M_PI + M_PI; - double rad = hypot(c - start); - int ndots = int(total_angle/(lt.dash_width/rad) + .5); - if (ndots == 0) - dot(start, lt); - else { - for (int i = 0; i <= ndots; i++) { - double a = start_angle + (total_angle*i)/ndots; - dot(cent + position(cos(a), sin(a))*rad, lt); - } - } -} - -void common_output::solid_arc(const position ¢, double rad, - double start_angle, double end_angle, - const line_type <) -{ - line_type slt = lt; - slt.type = line_type::solid; - arc(cent + position(cos(start_angle), sin(start_angle))*rad, - cent, - cent + position(cos(end_angle), sin(end_angle))*rad, - slt); -} - - -void common_output::rounded_box(const position ¢, const distance &dim, - double rad, const line_type <, double fill) -{ - if (fill >= 0.0) - filled_rounded_box(cent, dim, rad, fill); - switch (lt.type) { - case line_type::invisible: - break; - case line_type::dashed: - dashed_rounded_box(cent, dim, rad, lt); - break; - case line_type::dotted: - dotted_rounded_box(cent, dim, rad, lt); - break; - case line_type::solid: - solid_rounded_box(cent, dim, rad, lt); - break; - default: - assert(0); - } -} - - -void common_output::dashed_rounded_box(const position ¢, - const distance &dim, double rad, - const line_type <) -{ - line_type slt = lt; - slt.type = line_type::solid; - - double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad; - int n_hor_dashes = int(hor_length/(lt.dash_width*2.0) + .5); - double hor_gap_width = (n_hor_dashes != 0 - ? hor_length/n_hor_dashes - lt.dash_width - : 0.0); - - double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad; - int n_vert_dashes = int(vert_length/(lt.dash_width*2.0) + .5); - double vert_gap_width = (n_vert_dashes != 0 - ? vert_length/n_vert_dashes - lt.dash_width - : 0.0); - // Note that each corner arc has to be split into two for dashing, - // because one part is dashed using vert_gap_width, and the other - // using hor_gap_width. - double offset = lt.dash_width/2.0; - dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, - -M_PI/4.0, 0, slt, lt.dash_width, vert_gap_width, &offset); - dash_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad), - cent + position(dim.x/2.0, dim.y/2.0 - rad), - slt, lt.dash_width, vert_gap_width, &offset); - dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, - 0, M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset); - - offset = lt.dash_width/2.0; - dash_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, - M_PI/4.0, M_PI/2, slt, lt.dash_width, hor_gap_width, &offset); - dash_line(cent + position(dim.x/2.0 - rad, dim.y/2.0), - cent + position(-dim.x/2.0 + rad, dim.y/2.0), - slt, lt.dash_width, hor_gap_width, &offset); - dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, - M_PI/2, 3*M_PI/4.0, slt, lt.dash_width, hor_gap_width, &offset); - - offset = lt.dash_width/2.0; - dash_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, - 3.0*M_PI/4.0, M_PI, slt, lt.dash_width, vert_gap_width, &offset); - dash_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad), - cent + position(-dim.x/2.0, -dim.y/2.0 + rad), - slt, lt.dash_width, vert_gap_width, &offset); - dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, - M_PI, 5.0*M_PI/4.0, slt, lt.dash_width, vert_gap_width, &offset); - - offset = lt.dash_width/2.0; - dash_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, - 5*M_PI/4.0, 3*M_PI/2.0, slt, lt.dash_width, hor_gap_width, &offset); - dash_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0), - cent + position(dim.x/2.0 - rad, -dim.y/2.0), - slt, lt.dash_width, hor_gap_width, &offset); - dash_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, - 3*M_PI/2, 7*M_PI/4, slt, lt.dash_width, hor_gap_width, &offset); -} - -// Used by dashed_rounded_box. - -void common_output::dash_arc(const position ¢, double rad, - double start_angle, double end_angle, - const line_type <, - double dash_width, double gap_width, - double *offsetp) -{ - double length = (end_angle - start_angle)*rad; - double pos = 0.0; - for (;;) { - if (*offsetp >= dash_width) { - double rem = dash_width + gap_width - *offsetp; - if (pos + rem > length) { - *offsetp += length - pos; - break; - } - else { - pos += rem; - *offsetp = 0.0; - } - } - else { - double rem = dash_width - *offsetp; - if (pos + rem > length) { - solid_arc(cent, rad, start_angle + pos/rad, end_angle, lt); - *offsetp += length - pos; - break; - } - else { - solid_arc(cent, rad, start_angle + pos/rad, - start_angle + (pos + rem)/rad, lt); - pos += rem; - *offsetp = dash_width; - } - } - } -} - -// Used by dashed_rounded_box. - -void common_output::dash_line(const position &start, const position &end, - const line_type <, - double dash_width, double gap_width, - double *offsetp) -{ - distance dist = end - start; - double length = hypot(dist); - if (length == 0.0) - return; - double pos = 0.0; - for (;;) { - if (*offsetp >= dash_width) { - double rem = dash_width + gap_width - *offsetp; - if (pos + rem > length) { - *offsetp += length - pos; - break; - } - else { - pos += rem; - *offsetp = 0.0; - } - } - else { - double rem = dash_width - *offsetp; - if (pos + rem > length) { - line(start + dist*(pos/length), &end, 1, lt); - *offsetp += length - pos; - break; - } - else { - position p(start + dist*((pos + rem)/length)); - line(start + dist*(pos/length), &p, 1, lt); - pos += rem; - *offsetp = dash_width; - } - } - } -} - -void common_output::dotted_rounded_box(const position ¢, - const distance &dim, double rad, - const line_type <) -{ - line_type slt = lt; - slt.type = line_type::solid; - - double hor_length = dim.x + (M_PI/2.0 - 2.0)*rad; - int n_hor_dots = int(hor_length/lt.dash_width + .5); - double hor_gap_width = (n_hor_dots != 0 - ? hor_length/n_hor_dots - : lt.dash_width); - - double vert_length = dim.y + (M_PI/2.0 - 2.0)*rad; - int n_vert_dots = int(vert_length/lt.dash_width + .5); - double vert_gap_width = (n_vert_dots != 0 - ? vert_length/n_vert_dots - : lt.dash_width); - double epsilon = lt.dash_width/(rad*100.0); - - double offset = 0.0; - dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, - -M_PI/4.0, 0, slt, vert_gap_width, &offset); - dot_line(cent + position(dim.x/2.0, -dim.y/2.0 + rad), - cent + position(dim.x/2.0, dim.y/2.0 - rad), - slt, vert_gap_width, &offset); - dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, - 0, M_PI/4.0 - epsilon, slt, vert_gap_width, &offset); - - offset = 0.0; - dot_arc(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, - M_PI/4.0, M_PI/2, slt, hor_gap_width, &offset); - dot_line(cent + position(dim.x/2.0 - rad, dim.y/2.0), - cent + position(-dim.x/2.0 + rad, dim.y/2.0), - slt, hor_gap_width, &offset); - dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, - M_PI/2, 3*M_PI/4.0 - epsilon, slt, hor_gap_width, &offset); - - offset = 0.0; - dot_arc(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, - 3.0*M_PI/4.0, M_PI, slt, vert_gap_width, &offset); - dot_line(cent + position(-dim.x/2.0, dim.y/2.0 - rad), - cent + position(-dim.x/2.0, -dim.y/2.0 + rad), - slt, vert_gap_width, &offset); - dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, - M_PI, 5.0*M_PI/4.0 - epsilon, slt, vert_gap_width, &offset); - - offset = 0.0; - dot_arc(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, - 5*M_PI/4.0, 3*M_PI/2.0, slt, hor_gap_width, &offset); - dot_line(cent + position(-dim.x/2.0 + rad, -dim.y/2.0), - cent + position(dim.x/2.0 - rad, -dim.y/2.0), - slt, hor_gap_width, &offset); - dot_arc(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, - 3*M_PI/2, 7*M_PI/4 - epsilon, slt, hor_gap_width, &offset); -} - -// Used by dotted_rounded_box. - -void common_output::dot_arc(const position ¢, double rad, - double start_angle, double end_angle, - const line_type <, double gap_width, - double *offsetp) -{ - double length = (end_angle - start_angle)*rad; - double pos = 0.0; - for (;;) { - if (*offsetp == 0.0) { - double ang = start_angle + pos/rad; - dot(cent + position(cos(ang), sin(ang))*rad, lt); - } - double rem = gap_width - *offsetp; - if (pos + rem > length) { - *offsetp += length - pos; - break; - } - else { - pos += rem; - *offsetp = 0.0; - } - } -} - -// Used by dotted_rounded_box. - -void common_output::dot_line(const position &start, const position &end, - const line_type <, double gap_width, - double *offsetp) -{ - distance dist = end - start; - double length = hypot(dist); - if (length == 0.0) - return; - double pos = 0.0; - for (;;) { - if (*offsetp == 0.0) - dot(start + dist*(pos/length), lt); - double rem = gap_width - *offsetp; - if (pos + rem > length) { - *offsetp += length - pos; - break; - } - else { - pos += rem; - *offsetp = 0.0; - } - } -} - -void common_output::solid_rounded_box(const position ¢, - const distance &dim, double rad, - const line_type <) -{ - position tem = cent - dim/2.0; - arc(tem + position(0.0, rad), - tem + position(rad, rad), - tem + position(rad, 0.0), - lt); - tem = cent + position(-dim.x/2.0, dim.y/2.0); - arc(tem + position(rad, 0.0), - tem + position(rad, -rad), - tem + position(0.0, -rad), - lt); - tem = cent + dim/2.0; - arc(tem + position(0.0, -rad), - tem + position(-rad, -rad), - tem + position(-rad, 0.0), - lt); - tem = cent + position(dim.x/2.0, -dim.y/2.0); - arc(tem + position(-rad, 0.0), - tem + position(-rad, rad), - tem + position(0.0, rad), - lt); - position end; - end = cent + position(-dim.x/2.0, dim.y/2.0 - rad); - line(cent - dim/2.0 + position(0.0, rad), &end, 1, lt); - end = cent + position(dim.x/2.0 - rad, dim.y/2.0); - line(cent + position(-dim.x/2.0 + rad, dim.y/2.0), &end, 1, lt); - end = cent + position(dim.x/2.0, -dim.y/2.0 + rad); - line(cent + position(dim.x/2.0, dim.y/2.0 - rad), &end, 1, lt); - end = cent + position(-dim.x/2.0 + rad, -dim.y/2.0); - line(cent + position(dim.x/2.0 - rad, -dim.y/2.0), &end, 1, lt); -} - -void common_output::filled_rounded_box(const position ¢, - const distance &dim, double rad, - double fill) -{ - line_type ilt; - ilt.type = line_type::invisible; - circle(cent + position(dim.x/2.0 - rad, dim.y/2.0 - rad), rad, ilt, fill); - circle(cent + position(-dim.x/2.0 + rad, dim.y/2.0 - rad), rad, ilt, fill); - circle(cent + position(-dim.x/2.0 + rad, -dim.y/2.0 + rad), rad, ilt, fill); - circle(cent + position(dim.x/2.0 - rad, -dim.y/2.0 + rad), rad, ilt, fill); - position vec[4]; - vec[0] = cent + position(dim.x/2.0, dim.y/2.0 - rad); - vec[1] = cent + position(-dim.x/2.0, dim.y/2.0 - rad); - vec[2] = cent + position(-dim.x/2.0, -dim.y/2.0 + rad); - vec[3] = cent + position(dim.x/2.0, -dim.y/2.0 + rad); - polygon(vec, 4, ilt, fill); - vec[0] = cent + position(dim.x/2.0 - rad, dim.y/2.0); - vec[1] = cent + position(-dim.x/2.0 + rad, dim.y/2.0); - vec[2] = cent + position(-dim.x/2.0 + rad, -dim.y/2.0); - vec[3] = cent + position(dim.x/2.0 - rad, -dim.y/2.0); - polygon(vec, 4, ilt, fill); -} diff --git a/contrib/groff/src/preproc/pic/lex.cc b/contrib/groff/src/preproc/pic/lex.cc deleted file mode 100644 index 14a4cc3..0000000 --- a/contrib/groff/src/preproc/pic/lex.cc +++ /dev/null @@ -1,1992 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002 - 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 "pic.h" -#include "ptable.h" -#include "object.h" -#include "pic_tab.h" - -declare_ptable(char) -implement_ptable(char) - -PTABLE(char) macro_table; - -class macro_input : public input { - char *s; - char *p; -public: - macro_input(const char *); - ~macro_input(); - int get(); - int peek(); -}; - -class argument_macro_input : public input { - char *s; - char *p; - char *ap; - int argc; - char *argv[9]; -public: - argument_macro_input(const char *, int, char **); - ~argument_macro_input(); - int get(); - int peek(); -}; - -input::input() : next(0) -{ -} - -input::~input() -{ -} - -int input::get_location(const char **, int *) -{ - return 0; -} - -file_input::file_input(FILE *f, const char *fn) -: fp(f), filename(fn), lineno(0), ptr("") -{ -} - -file_input::~file_input() -{ - fclose(fp); -} - -int file_input::read_line() -{ - for (;;) { - line.clear(); - lineno++; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - else if (invalid_input_char(c)) - lex_error("invalid input character code %1", c); - else { - line += char(c); - if (c == '\n') - break; - } - } - if (line.length() == 0) - return 0; - if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P' - && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F') - && (line.length() == 3 || line[3] == ' ' || line[3] == '\n' - || compatible_flag))) { - line += '\0'; - ptr = line.contents(); - return 1; - } - } -} - -int file_input::get() -{ - if (*ptr != '\0' || read_line()) - return (unsigned char)*ptr++; - else - return EOF; -} - -int file_input::peek() -{ - if (*ptr != '\0' || read_line()) - return (unsigned char)*ptr; - else - return EOF; -} - -int file_input::get_location(const char **fnp, int *lnp) -{ - *fnp = filename; - *lnp = lineno; - return 1; -} - -macro_input::macro_input(const char *str) -{ - p = s = strsave(str); -} - -macro_input::~macro_input() -{ - a_delete s; -} - -int macro_input::get() -{ - if (p == 0 || *p == '\0') - return EOF; - else - return (unsigned char)*p++; -} - -int macro_input::peek() -{ - if (p == 0 || *p == '\0') - return EOF; - else - return (unsigned char)*p; -} - -// Character representing $1. Must be invalid input character. -#define ARG1 14 - -char *process_body(const char *body) -{ - char *s = strsave(body); - int j = 0; - for (int i = 0; s[i] != '\0'; i++) - if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') { - if (s[i+1] != '0') - s[j++] = ARG1 + s[++i] - '1'; - } - else - s[j++] = s[i]; - s[j] = '\0'; - return s; -} - - -argument_macro_input::argument_macro_input(const char *body, int ac, char **av) -: ap(0), argc(ac) -{ - for (int i = 0; i < argc; i++) - argv[i] = av[i]; - p = s = process_body(body); -} - - -argument_macro_input::~argument_macro_input() -{ - for (int i = 0; i < argc; i++) - a_delete argv[i]; - a_delete s; -} - -int argument_macro_input::get() -{ - if (ap) { - if (*ap != '\0') - return (unsigned char)*ap++; - ap = 0; - } - if (p == 0) - return EOF; - while (*p >= ARG1 && *p <= ARG1 + 8) { - int i = *p++ - ARG1; - if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { - ap = argv[i]; - return (unsigned char)*ap++; - } - } - if (*p == '\0') - return EOF; - return (unsigned char)*p++; -} - -int argument_macro_input::peek() -{ - if (ap) { - if (*ap != '\0') - return (unsigned char)*ap; - ap = 0; - } - if (p == 0) - return EOF; - while (*p >= ARG1 && *p <= ARG1 + 8) { - int i = *p++ - ARG1; - if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { - ap = argv[i]; - return (unsigned char)*ap; - } - } - if (*p == '\0') - return EOF; - return (unsigned char)*p; -} - -class input_stack { - static input *current_input; - static int bol_flag; -public: - static void push(input *); - static void clear(); - static int get_char(); - static int peek_char(); - static int get_location(const char **fnp, int *lnp); - static void push_back(unsigned char c, int was_bol = 0); - static int bol(); -}; - -input *input_stack::current_input = 0; -int input_stack::bol_flag = 0; - -inline int input_stack::bol() -{ - return bol_flag; -} - -void input_stack::clear() -{ - while (current_input != 0) { - input *tem = current_input; - current_input = current_input->next; - delete tem; - } - bol_flag = 1; -} - -void input_stack::push(input *in) -{ - in->next = current_input; - current_input = in; -} - -void lex_init(input *top) -{ - input_stack::clear(); - input_stack::push(top); -} - -void lex_cleanup() -{ - while (input_stack::get_char() != EOF) - ; -} - -int input_stack::get_char() -{ - while (current_input != 0) { - int c = current_input->get(); - if (c != EOF) { - bol_flag = c == '\n'; - return c; - } - // don't pop the top-level input off the stack - if (current_input->next == 0) - return EOF; - input *tem = current_input; - current_input = current_input->next; - delete tem; - } - return EOF; -} - -int input_stack::peek_char() -{ - while (current_input != 0) { - int c = current_input->peek(); - if (c != EOF) - return c; - if (current_input->next == 0) - return EOF; - input *tem = current_input; - current_input = current_input->next; - delete tem; - } - return EOF; -} - -class char_input : public input { - int c; -public: - char_input(int); - int get(); - int peek(); -}; - -char_input::char_input(int n) : c((unsigned char)n) -{ -} - -int char_input::get() -{ - int n = c; - c = EOF; - return n; -} - -int char_input::peek() -{ - return c; -} - -void input_stack::push_back(unsigned char c, int was_bol) -{ - push(new char_input(c)); - bol_flag = was_bol; -} - -int input_stack::get_location(const char **fnp, int *lnp) -{ - for (input *p = current_input; p; p = p->next) - if (p->get_location(fnp, lnp)) - return 1; - return 0; -} - -string context_buffer; - -string token_buffer; -double token_double; -int token_int; - -void interpolate_macro_with_args(const char *body) -{ - char *argv[9]; - int argc = 0; - int i; - for (i = 0; i < 9; i++) - argv[i] = 0; - int level = 0; - int c; - enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL; - do { - token_buffer.clear(); - for (;;) { - c = input_stack::get_char(); - if (c == EOF) { - lex_error("end of input while scanning macro arguments"); - break; - } - if (state == NORMAL && level == 0 && (c == ',' || c == ')')) { - if (token_buffer.length() > 0) { - token_buffer += '\0'; - argv[argc] = strsave(token_buffer.contents()); - } - // for `foo()', argc = 0 - if (argc > 0 || c != ')' || i > 0) - argc++; - break; - } - token_buffer += char(c); - switch (state) { - case NORMAL: - if (c == '"') - state = IN_STRING; - else if (c == '(') - level++; - else if (c == ')') - level--; - break; - case IN_STRING: - if (c == '"') - state = NORMAL; - else if (c == '\\') - state = IN_STRING_QUOTED; - break; - case IN_STRING_QUOTED: - state = IN_STRING; - break; - } - } - } while (c != ')' && c != EOF); - input_stack::push(new argument_macro_input(body, argc, argv)); -} - -static int docmp(const char *s1, int n1, const char *s2, int n2) -{ - if (n1 < n2) { - int r = memcmp(s1, s2, n1); - return r ? r : -1; - } - else if (n1 > n2) { - int r = memcmp(s1, s2, n2); - return r ? r : 1; - } - else - return memcmp(s1, s2, n1); -} - -int lookup_keyword(const char *str, int len) -{ - static struct keyword { - const char *name; - int token; - } table[] = { - { "Here", HERE }, - { "above", ABOVE }, - { "aligned", ALIGNED }, - { "and", AND }, - { "arc", ARC }, - { "arrow", ARROW }, - { "at", AT }, - { "atan2", ATAN2 }, - { "below", BELOW }, - { "between", BETWEEN }, - { "bottom", BOTTOM }, - { "box", BOX }, - { "by", BY }, - { "ccw", CCW }, - { "center", CENTER }, - { "chop", CHOP }, - { "circle", CIRCLE }, - { "color", COLORED }, - { "colored", COLORED }, - { "colour", COLORED }, - { "coloured", COLORED }, - { "command", COMMAND }, - { "copy", COPY }, - { "cos", COS }, - { "cw", CW }, - { "dashed", DASHED }, - { "define", DEFINE }, - { "diam", DIAMETER }, - { "diameter", DIAMETER }, - { "do", DO }, - { "dotted", DOTTED }, - { "down", DOWN }, - { "east", EAST }, - { "ellipse", ELLIPSE }, - { "else", ELSE }, - { "end", END }, - { "exp", EXP }, - { "fill", FILL }, - { "filled", FILL }, - { "for", FOR }, - { "from", FROM }, - { "height", HEIGHT }, - { "ht", HEIGHT }, - { "if", IF }, - { "int", INT }, - { "invis", INVISIBLE }, - { "invisible", INVISIBLE }, - { "last", LAST }, - { "left", LEFT }, - { "line", LINE }, - { "ljust", LJUST }, - { "log", LOG }, - { "lower", LOWER }, - { "max", K_MAX }, - { "min", K_MIN }, - { "move", MOVE }, - { "north", NORTH }, - { "of", OF }, - { "outline", OUTLINED }, - { "outlined", OUTLINED }, - { "plot", PLOT }, - { "print", PRINT }, - { "rad", RADIUS }, - { "radius", RADIUS }, - { "rand", RAND }, - { "reset", RESET }, - { "right", RIGHT }, - { "rjust", RJUST }, - { "same", SAME }, - { "sh", SH }, - { "shaded", SHADED }, - { "sin", SIN }, - { "solid", SOLID }, - { "south", SOUTH }, - { "spline", SPLINE }, - { "sprintf", SPRINTF }, - { "sqrt", SQRT }, - { "srand", SRAND }, - { "start", START }, - { "the", THE }, - { "then", THEN }, - { "thick", THICKNESS }, - { "thickness", THICKNESS }, - { "thru", THRU }, - { "to", TO }, - { "top", TOP }, - { "undef", UNDEF }, - { "until", UNTIL }, - { "up", UP }, - { "upper", UPPER }, - { "way", WAY }, - { "west", WEST }, - { "wid", WIDTH }, - { "width", WIDTH }, - { "with", WITH }, - }; - - const keyword *start = table; - const keyword *end = table + sizeof(table)/sizeof(table[0]); - while (start < end) { - // start <= target < end - const keyword *mid = start + (end - start)/2; - - int cmp = docmp(str, len, mid->name, strlen(mid->name)); - if (cmp == 0) - return mid->token; - if (cmp < 0) - end = mid; - else - start = mid + 1; - } - return 0; -} - -int get_token_after_dot(int c) -{ - // get_token deals with the case where c is a digit - switch (c) { - case 'h': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - context_buffer = ".ht"; - return DOT_HT; - } - else if (c == 'e') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'i') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'g') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'h') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - context_buffer = ".height"; - return DOT_HT; - } - input_stack::push_back('h'); - } - input_stack::push_back('g'); - } - input_stack::push_back('i'); - } - input_stack::push_back('e'); - } - input_stack::push_back('h'); - return '.'; - case 'x': - input_stack::get_char(); - context_buffer = ".x"; - return DOT_X; - case 'y': - input_stack::get_char(); - context_buffer = ".y"; - return DOT_Y; - case 'c': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'e') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'n') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'e') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'r') { - input_stack::get_char(); - context_buffer = ".center"; - return DOT_C; - } - input_stack::push_back('e'); - } - input_stack::push_back('t'); - } - input_stack::push_back('n'); - } - input_stack::push_back('e'); - } - context_buffer = ".c"; - return DOT_C; - case 'n': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'e') { - input_stack::get_char(); - context_buffer = ".ne"; - return DOT_NE; - } - else if (c == 'w') { - input_stack::get_char(); - context_buffer = ".nw"; - return DOT_NW; - } - else { - context_buffer = ".n"; - return DOT_N; - } - break; - case 'e': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'n') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'd') { - input_stack::get_char(); - context_buffer = ".end"; - return DOT_END; - } - input_stack::push_back('n'); - context_buffer = ".e"; - return DOT_E; - } - context_buffer = ".e"; - return DOT_E; - case 'w': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'i') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'd') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'h') { - input_stack::get_char(); - context_buffer = ".width"; - return DOT_WID; - } - input_stack::push_back('t'); - } - context_buffer = ".wid"; - return DOT_WID; - } - input_stack::push_back('i'); - } - context_buffer = ".w"; - return DOT_W; - case 's': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'e') { - input_stack::get_char(); - context_buffer = ".se"; - return DOT_SE; - } - else if (c == 'w') { - input_stack::get_char(); - context_buffer = ".sw"; - return DOT_SW; - } - else { - if (c == 't') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'a') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'r') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - context_buffer = ".start"; - return DOT_START; - } - input_stack::push_back('r'); - } - input_stack::push_back('a'); - } - input_stack::push_back('t'); - } - context_buffer = ".s"; - return DOT_S; - } - break; - case 't': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'o') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'p') { - input_stack::get_char(); - context_buffer = ".top"; - return DOT_N; - } - input_stack::push_back('o'); - } - context_buffer = ".t"; - return DOT_N; - case 'l': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'e') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'f') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - context_buffer = ".left"; - return DOT_W; - } - input_stack::push_back('f'); - } - input_stack::push_back('e'); - } - context_buffer = ".l"; - return DOT_W; - case 'r': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'a') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'd') { - input_stack::get_char(); - context_buffer = ".rad"; - return DOT_RAD; - } - input_stack::push_back('a'); - } - else if (c == 'i') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'g') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'h') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - context_buffer = ".right"; - return DOT_E; - } - input_stack::push_back('h'); - } - input_stack::push_back('g'); - } - input_stack::push_back('i'); - } - context_buffer = ".r"; - return DOT_E; - case 'b': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'o') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'o') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'm') { - input_stack::get_char(); - context_buffer = ".bottom"; - return DOT_S; - } - input_stack::push_back('o'); - } - input_stack::push_back('t'); - } - context_buffer = ".bot"; - return DOT_S; - } - input_stack::push_back('o'); - } - context_buffer = ".b"; - return DOT_S; - default: - context_buffer = '.'; - return '.'; - } -} - -int get_token(int lookup_flag) -{ - context_buffer.clear(); - for (;;) { - int n = 0; - int bol = input_stack::bol(); - int c = input_stack::get_char(); - if (bol && c == command_char) { - token_buffer.clear(); - token_buffer += c; - // the newline is not part of the token - for (;;) { - c = input_stack::peek_char(); - if (c == EOF || c == '\n') - break; - input_stack::get_char(); - token_buffer += char(c); - } - context_buffer = token_buffer; - return COMMAND_LINE; - } - switch (c) { - case EOF: - return EOF; - case ' ': - case '\t': - break; - case '\\': - { - int d = input_stack::peek_char(); - if (d != '\n') { - context_buffer = '\\'; - return '\\'; - } - input_stack::get_char(); - break; - } - case '#': - do { - c = input_stack::get_char(); - } while (c != '\n' && c != EOF); - if (c == '\n') - context_buffer = '\n'; - return c; - case '"': - context_buffer = '"'; - token_buffer.clear(); - for (;;) { - c = input_stack::get_char(); - if (c == '\\') { - context_buffer += '\\'; - c = input_stack::peek_char(); - if (c == '"') { - input_stack::get_char(); - token_buffer += '"'; - context_buffer += '"'; - } - else - token_buffer += '\\'; - } - else if (c == '\n') { - error("newline in string"); - break; - } - else if (c == EOF) { - error("missing `\"'"); - break; - } - else if (c == '"') { - context_buffer += '"'; - break; - } - else { - context_buffer += char(c); - token_buffer += char(c); - } - } - return TEXT; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - int overflow = 0; - n = 0; - for (;;) { - if (n > (INT_MAX - 9)/10) { - overflow = 1; - break; - } - n *= 10; - n += c - '0'; - context_buffer += char(c); - c = input_stack::peek_char(); - if (c == EOF || !csdigit(c)) - break; - c = input_stack::get_char(); - } - token_double = n; - if (overflow) { - for (;;) { - token_double *= 10.0; - token_double += c - '0'; - context_buffer += char(c); - c = input_stack::peek_char(); - if (c == EOF || !csdigit(c)) - break; - c = input_stack::get_char(); - } - // if somebody asks for 1000000000000th, we will silently - // give them INT_MAXth - double temp = token_double; // work around gas 1.34/sparc bug - if (token_double > INT_MAX) - n = INT_MAX; - else - n = int(temp); - } - } - switch (c) { - case 'i': - case 'I': - context_buffer += char(c); - input_stack::get_char(); - return NUMBER; - case '.': - { - context_buffer += '.'; - input_stack::get_char(); - got_dot: - double factor = 1.0; - for (;;) { - c = input_stack::peek_char(); - if (c == EOF || !csdigit(c)) - break; - input_stack::get_char(); - context_buffer += char(c); - factor /= 10.0; - if (c != '0') - token_double += factor*(c - '0'); - } - if (c != 'e' && c != 'E') { - if (c == 'i' || c == 'I') { - context_buffer += char(c); - input_stack::get_char(); - } - return NUMBER; - } - } - // fall through - case 'e': - case 'E': - { - int echar = c; - input_stack::get_char(); - c = input_stack::peek_char(); - int sign = '+'; - if (c == '+' || c == '-') { - sign = c; - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == EOF || !csdigit(c)) { - input_stack::push_back(sign); - input_stack::push_back(echar); - return NUMBER; - } - context_buffer += char(echar); - context_buffer += char(sign); - } - else { - if (c == EOF || !csdigit(c)) { - input_stack::push_back(echar); - return NUMBER; - } - context_buffer += char(echar); - } - input_stack::get_char(); - context_buffer += char(c); - n = c - '0'; - for (;;) { - c = input_stack::peek_char(); - if (c == EOF || !csdigit(c)) - break; - input_stack::get_char(); - context_buffer += char(c); - n = n*10 + (c - '0'); - } - if (sign == '-') - n = -n; - if (c == 'i' || c == 'I') { - context_buffer += char(c); - input_stack::get_char(); - } - token_double *= pow(10.0, n); - return NUMBER; - } - case 'n': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'd') { - input_stack::get_char(); - token_int = n; - context_buffer += "nd"; - return ORDINAL; - } - input_stack::push_back('n'); - return NUMBER; - case 'r': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'd') { - input_stack::get_char(); - token_int = n; - context_buffer += "rd"; - return ORDINAL; - } - input_stack::push_back('r'); - return NUMBER; - case 't': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'h') { - input_stack::get_char(); - token_int = n; - context_buffer += "th"; - return ORDINAL; - } - input_stack::push_back('t'); - return NUMBER; - case 's': - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - token_int = n; - context_buffer += "st"; - return ORDINAL; - } - input_stack::push_back('s'); - return NUMBER; - default: - return NUMBER; - } - break; - case '\'': - { - c = input_stack::peek_char(); - if (c == 't') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == 'h') { - input_stack::get_char(); - context_buffer = "'th"; - return TH; - } - else - input_stack::push_back('t'); - } - context_buffer = "'"; - return '\''; - } - case '.': - { - c = input_stack::peek_char(); - if (c != EOF && csdigit(c)) { - n = 0; - token_double = 0.0; - context_buffer = '.'; - goto got_dot; - } - return get_token_after_dot(c); - } - case '<': - c = input_stack::peek_char(); - if (c == '-') { - input_stack::get_char(); - c = input_stack::peek_char(); - if (c == '>') { - input_stack::get_char(); - context_buffer = "<->"; - return DOUBLE_ARROW_HEAD; - } - context_buffer = "<-"; - return LEFT_ARROW_HEAD; - } - else if (c == '=') { - input_stack::get_char(); - context_buffer = "<="; - return LESSEQUAL; - } - context_buffer = "<"; - return '<'; - case '-': - c = input_stack::peek_char(); - if (c == '>') { - input_stack::get_char(); - context_buffer = "->"; - return RIGHT_ARROW_HEAD; - } - context_buffer = "-"; - return '-'; - case '!': - c = input_stack::peek_char(); - if (c == '=') { - input_stack::get_char(); - context_buffer = "!="; - return NOTEQUAL; - } - context_buffer = "!"; - return '!'; - case '>': - c = input_stack::peek_char(); - if (c == '=') { - input_stack::get_char(); - context_buffer = ">="; - return GREATEREQUAL; - } - context_buffer = ">"; - return '>'; - case '=': - c = input_stack::peek_char(); - if (c == '=') { - input_stack::get_char(); - context_buffer = "=="; - return EQUALEQUAL; - } - context_buffer = "="; - return '='; - case '&': - c = input_stack::peek_char(); - if (c == '&') { - input_stack::get_char(); - context_buffer = "&&"; - return ANDAND; - } - context_buffer = "&"; - return '&'; - case '|': - c = input_stack::peek_char(); - if (c == '|') { - input_stack::get_char(); - context_buffer = "||"; - return OROR; - } - context_buffer = "|"; - return '|'; - default: - if (c != EOF && csalpha(c)) { - token_buffer.clear(); - token_buffer = c; - for (;;) { - c = input_stack::peek_char(); - if (c == EOF || (!csalnum(c) && c != '_')) - break; - input_stack::get_char(); - token_buffer += char(c); - } - int tok = lookup_keyword(token_buffer.contents(), - token_buffer.length()); - if (tok != 0) { - context_buffer = token_buffer; - return tok; - } - char *def = 0; - if (lookup_flag) { - token_buffer += '\0'; - def = macro_table.lookup(token_buffer.contents()); - token_buffer.set_length(token_buffer.length() - 1); - if (def) { - if (c == '(') { - input_stack::get_char(); - interpolate_macro_with_args(def); - } - else - input_stack::push(new macro_input(def)); - } - } - if (!def) { - context_buffer = token_buffer; - if (csupper(token_buffer[0])) - return LABEL; - else - return VARIABLE; - } - } - else { - context_buffer = char(c); - return (unsigned char)c; - } - break; - } - } -} - -int get_delimited() -{ - token_buffer.clear(); - int c = input_stack::get_char(); - while (c == ' ' || c == '\t' || c == '\n') - c = input_stack::get_char(); - if (c == EOF) { - lex_error("missing delimiter"); - return 0; - } - context_buffer = char(c); - int had_newline = 0; - int start = c; - int level = 0; - enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL; - for (;;) { - c = input_stack::get_char(); - if (c == EOF) { - lex_error("missing closing delimiter"); - return 0; - } - if (c == '\n') - had_newline = 1; - else if (!had_newline) - context_buffer += char(c); - switch (state) { - case NORMAL: - if (start == '{') { - if (c == '{') { - level++; - break; - } - if (c == '}') { - if (--level < 0) - state = DELIM_END; - break; - } - } - else { - if (c == start) { - state = DELIM_END; - break; - } - } - if (c == '"') - state = IN_STRING; - break; - case IN_STRING_QUOTED: - if (c == '\n') - state = NORMAL; - else - state = IN_STRING; - break; - case IN_STRING: - if (c == '"' || c == '\n') - state = NORMAL; - else if (c == '\\') - state = IN_STRING_QUOTED; - break; - case DELIM_END: - // This case it just to shut cfront 2.0 up. - default: - assert(0); - } - if (state == DELIM_END) - break; - token_buffer += c; - } - return 1; -} - -void do_define() -{ - int t = get_token(0); // do not expand what we are defining - if (t != VARIABLE && t != LABEL) { - lex_error("can only define variable or placename"); - return; - } - token_buffer += '\0'; - string nm = token_buffer; - const char *name = nm.contents(); - if (!get_delimited()) - return; - token_buffer += '\0'; - macro_table.define(name, strsave(token_buffer.contents())); -} - -void do_undef() -{ - int t = get_token(0); // do not expand what we are undefining - if (t != VARIABLE && t != LABEL) { - lex_error("can only define variable or placename"); - return; - } - token_buffer += '\0'; - macro_table.define(token_buffer.contents(), 0); -} - - -class for_input : public input { - char *var; - char *body; - double to; - int by_is_multiplicative; - double by; - const char *p; - int done_newline; -public: - for_input(char *, double, int, double, char *); - ~for_input(); - int get(); - int peek(); -}; - -for_input::for_input(char *vr, double t, int bim, double b, char *bd) -: var(vr), body(bd), to(t), by_is_multiplicative(bim), by(b), p(body), - done_newline(0) -{ -} - -for_input::~for_input() -{ - a_delete var; - a_delete body; -} - -int for_input::get() -{ - if (p == 0) - return EOF; - for (;;) { - if (*p != '\0') - return (unsigned char)*p++; - if (!done_newline) { - done_newline = 1; - return '\n'; - } - double val; - if (!lookup_variable(var, &val)) { - lex_error("body of `for' terminated enclosing block"); - return EOF; - } - if (by_is_multiplicative) - val *= by; - else - val += by; - define_variable(var, val); - if (val > to) { - p = 0; - return EOF; - } - p = body; - done_newline = 0; - } -} - -int for_input::peek() -{ - if (p == 0) - return EOF; - if (*p != '\0') - return (unsigned char)*p; - if (!done_newline) - return '\n'; - double val; - if (!lookup_variable(var, &val)) - return EOF; - if (by_is_multiplicative) { - if (val * by > to) - return EOF; - } - else { - if (val + by > to) - return EOF; - } - if (*body == '\0') - return EOF; - return (unsigned char)*body; -} - -void do_for(char *var, double from, double to, int by_is_multiplicative, - double by, char *body) -{ - define_variable(var, from); - if (from <= to) - input_stack::push(new for_input(var, to, by_is_multiplicative, by, body)); -} - - -void do_copy(const char *filename) -{ - errno = 0; - FILE *fp = fopen(filename, "r"); - if (fp == 0) { - lex_error("can't open `%1': %2", filename, strerror(errno)); - return; - } - input_stack::push(new file_input(fp, filename)); -} - -class copy_thru_input : public input { - int done; - char *body; - char *until; - const char *p; - const char *ap; - int argv[9]; - int argc; - string line; - int get_line(); - virtual int inget() = 0; -public: - copy_thru_input(const char *b, const char *u); - ~copy_thru_input(); - int get(); - int peek(); -}; - -class copy_file_thru_input : public copy_thru_input { - input *in; -public: - copy_file_thru_input(input *, const char *b, const char *u); - ~copy_file_thru_input(); - int inget(); -}; - -copy_file_thru_input::copy_file_thru_input(input *i, const char *b, - const char *u) -: copy_thru_input(b, u), in(i) -{ -} - -copy_file_thru_input::~copy_file_thru_input() -{ - delete in; -} - -int copy_file_thru_input::inget() -{ - if (!in) - return EOF; - else - return in->get(); -} - -class copy_rest_thru_input : public copy_thru_input { -public: - copy_rest_thru_input(const char *, const char *u); - int inget(); -}; - -copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u) -: copy_thru_input(b, u) -{ -} - -int copy_rest_thru_input::inget() -{ - while (next != 0) { - int c = next->get(); - if (c != EOF) - return c; - if (next->next == 0) - return EOF; - input *tem = next; - next = next->next; - delete tem; - } - return EOF; - -} - -copy_thru_input::copy_thru_input(const char *b, const char *u) -: done(0) -{ - ap = 0; - body = process_body(b); - p = 0; - until = strsave(u); -} - - -copy_thru_input::~copy_thru_input() -{ - a_delete body; - a_delete until; -} - -int copy_thru_input::get() -{ - if (ap) { - if (*ap != '\0') - return (unsigned char)*ap++; - ap = 0; - } - for (;;) { - if (p == 0) { - if (!get_line()) - break; - p = body; - } - if (*p == '\0') { - p = 0; - return '\n'; - } - while (*p >= ARG1 && *p <= ARG1 + 8) { - int i = *p++ - ARG1; - if (i < argc && line[argv[i]] != '\0') { - ap = line.contents() + argv[i]; - return (unsigned char)*ap++; - } - } - if (*p != '\0') - return (unsigned char)*p++; - } - return EOF; -} - -int copy_thru_input::peek() -{ - if (ap) { - if (*ap != '\0') - return (unsigned char)*ap; - ap = 0; - } - for (;;) { - if (p == 0) { - if (!get_line()) - break; - p = body; - } - if (*p == '\0') - return '\n'; - while (*p >= ARG1 && *p <= ARG1 + 8) { - int i = *p++ - ARG1; - if (i < argc && line[argv[i]] != '\0') { - ap = line.contents() + argv[i]; - return (unsigned char)*ap; - } - } - if (*p != '\0') - return (unsigned char)*p; - } - return EOF; -} - -int copy_thru_input::get_line() -{ - if (done) - return 0; - line.clear(); - argc = 0; - int c = inget(); - for (;;) { - while (c == ' ') - c = inget(); - if (c == EOF || c == '\n') - break; - if (argc == 9) { - do { - c = inget(); - } while (c != '\n' && c != EOF); - break; - } - argv[argc++] = line.length(); - do { - line += char(c); - c = inget(); - } while (c != ' ' && c != '\n'); - line += '\0'; - } - if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) { - done = 1; - return 0; - } - return argc > 0 || c == '\n'; -} - -class simple_file_input : public input { - const char *filename; - int lineno; - FILE *fp; -public: - simple_file_input(FILE *, const char *); - ~simple_file_input(); - int get(); - int peek(); - int get_location(const char **, int *); -}; - -simple_file_input::simple_file_input(FILE *p, const char *s) -: filename(s), lineno(1), fp(p) -{ -} - -simple_file_input::~simple_file_input() -{ - // don't delete the filename - fclose(fp); -} - -int simple_file_input::get() -{ - int c = getc(fp); - while (invalid_input_char(c)) { - error("invalid input character code %1", c); - c = getc(fp); - } - if (c == '\n') - lineno++; - return c; -} - -int simple_file_input::peek() -{ - int c = getc(fp); - while (invalid_input_char(c)) { - error("invalid input character code %1", c); - c = getc(fp); - } - if (c != EOF) - ungetc(c, fp); - return c; -} - -int simple_file_input::get_location(const char **fnp, int *lnp) -{ - *fnp = filename; - *lnp = lineno; - return 1; -} - - -void copy_file_thru(const char *filename, const char *body, const char *until) -{ - errno = 0; - FILE *fp = fopen(filename, "r"); - if (fp == 0) { - lex_error("can't open `%1': %2", filename, strerror(errno)); - return; - } - input *in = new copy_file_thru_input(new simple_file_input(fp, filename), - body, until); - input_stack::push(in); -} - -void copy_rest_thru(const char *body, const char *until) -{ - input_stack::push(new copy_rest_thru_input(body, until)); -} - -void push_body(const char *s) -{ - input_stack::push(new char_input('\n')); - input_stack::push(new macro_input(s)); -} - -int delim_flag = 0; - -char *get_thru_arg() -{ - int c = input_stack::peek_char(); - while (c == ' ') { - input_stack::get_char(); - c = input_stack::peek_char(); - } - if (c != EOF && csalpha(c)) { - // looks like a macro - input_stack::get_char(); - token_buffer = c; - for (;;) { - c = input_stack::peek_char(); - if (c == EOF || (!csalnum(c) && c != '_')) - break; - input_stack::get_char(); - token_buffer += char(c); - } - context_buffer = token_buffer; - token_buffer += '\0'; - char *def = macro_table.lookup(token_buffer.contents()); - if (def) - return strsave(def); - // I guess it wasn't a macro after all; so push the macro name back. - // -2 because we added a '\0' - for (int i = token_buffer.length() - 2; i >= 0; i--) - input_stack::push_back(token_buffer[i]); - } - if (get_delimited()) { - token_buffer += '\0'; - return strsave(token_buffer.contents()); - } - else - return 0; -} - -int lookahead_token = -1; -string old_context_buffer; - -void do_lookahead() -{ - if (lookahead_token == -1) { - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - } -} - -int yylex() -{ - if (delim_flag) { - assert(lookahead_token == -1); - if (delim_flag == 2) { - if ((yylval.str = get_thru_arg()) != 0) - return DELIMITED; - else - return 0; - } - else { - if (get_delimited()) { - token_buffer += '\0'; - yylval.str = strsave(token_buffer.contents()); - return DELIMITED; - } - else - return 0; - } - } - for (;;) { - int t; - if (lookahead_token >= 0) { - t = lookahead_token; - lookahead_token = -1; - } - else - t = get_token(1); - switch (t) { - case '\n': - return ';'; - case EOF: - return 0; - case DEFINE: - do_define(); - break; - case UNDEF: - do_undef(); - break; - case ORDINAL: - yylval.n = token_int; - return t; - case NUMBER: - yylval.x = token_double; - return t; - case COMMAND_LINE: - case TEXT: - token_buffer += '\0'; - if (!input_stack::get_location(&yylval.lstr.filename, - &yylval.lstr.lineno)) { - yylval.lstr.filename = 0; - yylval.lstr.lineno = -1; - } - yylval.lstr.str = strsave(token_buffer.contents()); - return t; - case LABEL: - case VARIABLE: - token_buffer += '\0'; - yylval.str = strsave(token_buffer.contents()); - return t; - case LEFT: - // change LEFT to LEFT_CORNER when followed by OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token == OF) - return LEFT_CORNER; - else - return t; - case RIGHT: - // change RIGHT to RIGHT_CORNER when followed by OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token == OF) - return RIGHT_CORNER; - else - return t; - case UPPER: - // recognise UPPER only before LEFT or RIGHT - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != LEFT && lookahead_token != RIGHT) { - yylval.str = strsave("upper"); - return VARIABLE; - } - else - return t; - case LOWER: - // recognise LOWER only before LEFT or RIGHT - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != LEFT && lookahead_token != RIGHT) { - yylval.str = strsave("lower"); - return VARIABLE; - } - else - return t; - case NORTH: - // recognise NORTH only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("north"); - return VARIABLE; - } - else - return t; - case SOUTH: - // recognise SOUTH only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("south"); - return VARIABLE; - } - else - return t; - case EAST: - // recognise EAST only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("east"); - return VARIABLE; - } - else - return t; - case WEST: - // recognise WEST only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("west"); - return VARIABLE; - } - else - return t; - case TOP: - // recognise TOP only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("top"); - return VARIABLE; - } - else - return t; - case BOTTOM: - // recognise BOTTOM only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("bottom"); - return VARIABLE; - } - else - return t; - case CENTER: - // recognise CENTER only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("center"); - return VARIABLE; - } - else - return t; - case START: - // recognise START only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("start"); - return VARIABLE; - } - else - return t; - case END: - // recognise END only before OF - old_context_buffer = context_buffer; - lookahead_token = get_token(1); - if (lookahead_token != OF) { - yylval.str = strsave("end"); - return VARIABLE; - } - else - return t; - default: - return t; - } - } -} - -void lex_error(const char *message, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - const char *filename; - int lineno; - if (!input_stack::get_location(&filename, &lineno)) - error(message, arg1, arg2, arg3); - else - error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); -} - -void lex_warning(const char *message, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - const char *filename; - int lineno; - if (!input_stack::get_location(&filename, &lineno)) - warning(message, arg1, arg2, arg3); - else - warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); -} - -void yyerror(const char *s) -{ - const char *filename; - int lineno; - const char *context = 0; - if (lookahead_token == -1) { - if (context_buffer.length() > 0) { - context_buffer += '\0'; - context = context_buffer.contents(); - } - } - else { - if (old_context_buffer.length() > 0) { - old_context_buffer += '\0'; - context = old_context_buffer.contents(); - } - } - if (!input_stack::get_location(&filename, &lineno)) { - if (context) { - if (context[0] == '\n' && context[1] == '\0') - error("%1 before newline", s); - else - error("%1 before `%2'", s, context); - } - else - error("%1 at end of picture", s); - } - else { - if (context) { - if (context[0] == '\n' && context[1] == '\0') - error_with_file_and_line(filename, lineno, "%1 before newline", s); - else - error_with_file_and_line(filename, lineno, "%1 before `%2'", - s, context); - } - else - error_with_file_and_line(filename, lineno, "%1 at end of picture", s); - } -} - diff --git a/contrib/groff/src/preproc/pic/main.cc b/contrib/groff/src/preproc/pic/main.cc deleted file mode 100644 index 124cbd5..0000000 --- a/contrib/groff/src/preproc/pic/main.cc +++ /dev/null @@ -1,635 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001, 2002 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 "pic.h" - -extern int yyparse(); -extern "C" const char *Version_string; - -output *out; - -int flyback_flag; -int zero_length_line_flag = 0; -// Non-zero means we're using a groff driver. -int driver_extension_flag = 1; -int compatible_flag = 0; -int safer_flag = 1; -int command_char = '.'; // the character that introduces lines - // that should be passed through tranparently -static int lf_flag = 1; // non-zero if we should attempt to understand - // lines beginning with `.lf' - -// Non-zero means a parse error was encountered. -static int had_parse_error = 0; - -void do_file(const char *filename); - -class top_input : public input { - FILE *fp; - int bol; - int eof; - int push_back[3]; - int start_lineno; -public: - top_input(FILE *); - int get(); - int peek(); - int get_location(const char **, int *); -}; - -top_input::top_input(FILE *p) : fp(p), bol(1), eof(0) -{ - push_back[0] = push_back[1] = push_back[2] = EOF; - start_lineno = current_lineno; -} - -int top_input::get() -{ - if (eof) - return EOF; - if (push_back[2] != EOF) { - int c = push_back[2]; - push_back[2] = EOF; - return c; - } - else if (push_back[1] != EOF) { - int c = push_back[1]; - push_back[1] = EOF; - return c; - } - else if (push_back[0] != EOF) { - int c = push_back[0]; - push_back[0] = EOF; - return c; - } - int c = getc(fp); - while (invalid_input_char(c)) { - error("invalid input character code %1", int(c)); - c = getc(fp); - bol = 0; - } - if (bol && c == '.') { - c = getc(fp); - if (c == 'P') { - c = getc(fp); - if (c == 'F' || c == 'E') { - int d = getc(fp); - if (d != EOF) - ungetc(d, fp); - if (d == EOF || d == ' ' || d == '\n' || compatible_flag) { - eof = 1; - flyback_flag = c == 'F'; - return EOF; - } - push_back[0] = c; - push_back[1] = 'P'; - return '.'; - } - if (c == 'S') { - c = getc(fp); - if (c != EOF) - ungetc(c, fp); - if (c == EOF || c == ' ' || c == '\n' || compatible_flag) { - error("nested .PS"); - eof = 1; - return EOF; - } - push_back[0] = 'S'; - push_back[1] = 'P'; - return '.'; - } - if (c != EOF) - ungetc(c, fp); - push_back[0] = 'P'; - return '.'; - } - else { - if (c != EOF) - ungetc(c, fp); - return '.'; - } - } - if (c == '\n') { - bol = 1; - current_lineno++; - return '\n'; - } - bol = 0; - if (c == EOF) { - eof = 1; - error("end of file before .PE or .PF"); - error_with_file_and_line(current_filename, start_lineno - 1, - ".PS was here"); - } - return c; -} - -int top_input::peek() -{ - if (eof) - return EOF; - if (push_back[2] != EOF) - return push_back[2]; - if (push_back[1] != EOF) - return push_back[1]; - if (push_back[0] != EOF) - return push_back[0]; - int c = getc(fp); - while (invalid_input_char(c)) { - error("invalid input character code %1", int(c)); - c = getc(fp); - bol = 0; - } - if (bol && c == '.') { - c = getc(fp); - if (c == 'P') { - c = getc(fp); - if (c == 'F' || c == 'E') { - int d = getc(fp); - if (d != EOF) - ungetc(d, fp); - if (d == EOF || d == ' ' || d == '\n' || compatible_flag) { - eof = 1; - flyback_flag = c == 'F'; - return EOF; - } - push_back[0] = c; - push_back[1] = 'P'; - push_back[2] = '.'; - return '.'; - } - if (c == 'S') { - c = getc(fp); - if (c != EOF) - ungetc(c, fp); - if (c == EOF || c == ' ' || c == '\n' || compatible_flag) { - error("nested .PS"); - eof = 1; - return EOF; - } - push_back[0] = 'S'; - push_back[1] = 'P'; - push_back[2] = '.'; - return '.'; - } - if (c != EOF) - ungetc(c, fp); - push_back[0] = 'P'; - push_back[1] = '.'; - return '.'; - } - else { - if (c != EOF) - ungetc(c, fp); - push_back[0] = '.'; - return '.'; - } - } - if (c != EOF) - ungetc(c, fp); - if (c == '\n') - return '\n'; - return c; -} - -int top_input::get_location(const char **filenamep, int *linenop) -{ - *filenamep = current_filename; - *linenop = current_lineno; - return 1; -} - -void do_picture(FILE *fp) -{ - flyback_flag = 0; - int c; - while ((c = getc(fp)) == ' ') - ; - if (c == '<') { - string filename; - while ((c = getc(fp)) == ' ') - ; - while (c != EOF && c != ' ' && c != '\n') { - filename += char(c); - c = getc(fp); - } - if (c == ' ') { - do { - c = getc(fp); - } while (c != EOF && c != '\n'); - } - if (c == '\n') - current_lineno++; - if (filename.length() == 0) - error("missing filename after `<'"); - else { - filename += '\0'; - const char *old_filename = current_filename; - int old_lineno = current_lineno; - // filenames must be permanent - do_file(strsave(filename.contents())); - current_filename = old_filename; - current_lineno = old_lineno; - } - out->set_location(current_filename, current_lineno); - } - else { - out->set_location(current_filename, current_lineno); - string start_line; - while (c != EOF) { - if (c == '\n') { - current_lineno++; - break; - } - start_line += c; - c = getc(fp); - } - if (c == EOF) - return; - start_line += '\0'; - double wid, ht; - switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) { - case 1: - ht = 0.0; - break; - case 2: - break; - default: - ht = wid = 0.0; - break; - } - out->set_desired_width_height(wid, ht); - out->set_args(start_line.contents()); - lex_init(new top_input(fp)); - if (yyparse()) { - had_parse_error = 1; - lex_error("giving up on this picture"); - } - parse_cleanup(); - lex_cleanup(); - - // skip the rest of the .PF/.PE line - while ((c = getc(fp)) != EOF && c != '\n') - ; - if (c == '\n') - current_lineno++; - out->set_location(current_filename, current_lineno); - } -} - -void do_file(const char *filename) -{ - FILE *fp; - if (strcmp(filename, "-") == 0) - fp = stdin; - else { - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) - fatal("can't open `%1': %2", filename, strerror(errno)); - } - out->set_location(filename, 1); - current_filename = filename; - current_lineno = 1; - enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - switch (state) { - case START: - if (c == '.') - state = HAD_DOT; - else { - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case MIDDLE: - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - break; - case HAD_DOT: - if (c == 'P') - state = HAD_P; - else if (lf_flag && c == 'l') - state = HAD_l; - else { - putchar('.'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_P: - if (c == 'S') - state = HAD_PS; - else { - putchar('.'); - putchar('P'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_PS: - if (c == ' ' || c == '\n' || compatible_flag) { - ungetc(c, fp); - do_picture(fp); - state = START; - } - else { - fputs(".PS", stdout); - putchar(c); - state = MIDDLE; - } - break; - case HAD_l: - if (c == 'f') - state = HAD_lf; - else { - putchar('.'); - putchar('l'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_lf: - if (c == ' ' || c == '\n' || compatible_flag) { - string line; - while (c != EOF) { - line += c; - if (c == '\n') { - current_lineno++; - break; - } - c = getc(fp); - } - line += '\0'; - interpret_lf_args(line.contents()); - printf(".lf%s", line.contents()); - state = START; - } - else { - fputs(".lf", stdout); - putchar(c); - state = MIDDLE; - } - break; - default: - assert(0); - } - } - switch (state) { - case START: - break; - case MIDDLE: - putchar('\n'); - break; - case HAD_DOT: - fputs(".\n", stdout); - break; - case HAD_P: - fputs(".P\n", stdout); - break; - case HAD_PS: - fputs(".PS\n", stdout); - break; - case HAD_l: - fputs(".l\n", stdout); - break; - case HAD_lf: - fputs(".lf\n", stdout); - break; - } - if (fp != stdin) - fclose(fp); -} - -#ifdef FIG_SUPPORT -void do_whole_file(const char *filename) -{ - // Do not set current_filename. - FILE *fp; - if (strcmp(filename, "-") == 0) - fp = stdin; - else { - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) - fatal("can't open `%1': %2", filename, strerror(errno)); - } - lex_init(new file_input(fp, filename)); - if (yyparse()) - had_parse_error = 1; - parse_cleanup(); - lex_cleanup(); -} -#endif - -void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [ -nvC ] [ filename ... ]\n", program_name); -#ifdef TEX_SUPPORT - fprintf(stream, " %s -t [ -cvzC ] [ filename ... ]\n", program_name); -#endif -#ifdef FIG_SUPPORT - fprintf(stream, " %s -f [ -v ] [ filename ]\n", program_name); -#endif -} - -#if defined(__MSDOS__) || defined(__EMX__) -static char *fix_program_name(char *arg, char *dflt) -{ - if (!arg) - return dflt; - char *prog = strchr(arg, '\0'); - for (;;) { - if (prog == arg) - break; - --prog; - if (strchr("\\/:", *prog)) { - prog++; - break; - } - } - char *ext = strchr(prog, '.'); - if (ext) - *ext = '\0'; - for (char *p = prog; *p; p++) - if ('A' <= *p && *p <= 'Z') - *p = 'a' + (*p - 'A'); - return prog; -} -#endif /* __MSDOS__ || __EMX__ */ - -int main(int argc, char **argv) -{ -#if defined(__MSDOS__) || defined(__EMX__) - argv[0] = fix_program_name(argv[0], "pic"); -#endif /* __MSDOS__ || __EMX__ */ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int opt; -#ifdef TEX_SUPPORT - int tex_flag = 0; - int tpic_flag = 0; -#endif -#ifdef FIG_SUPPORT - int whole_file_flag = 0; - int fig_flag = 0; -#endif - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "T:CDSUtcvnxzpf", long_options, NULL)) - != EOF) - switch (opt) { - case 'C': - compatible_flag = 1; - break; - case 'D': - case 'T': - break; - case 'S': - safer_flag = 1; - break; - case 'U': - safer_flag = 0; - break; - case 'f': -#ifdef FIG_SUPPORT - whole_file_flag++; - fig_flag++; -#else - fatal("fig support not included"); -#endif - break; - case 'n': - driver_extension_flag = 0; - break; - case 'p': - case 'x': - warning("-%1 option is obsolete", char(opt)); - break; - case 't': -#ifdef TEX_SUPPORT - tex_flag++; -#else - fatal("TeX support not included"); -#endif - break; - case 'c': -#ifdef TEX_SUPPORT - tpic_flag++; -#else - fatal("TeX support not included"); -#endif - break; - case 'v': - { - printf("GNU pic (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'z': - // zero length lines will be printed as dots - zero_length_line_flag++; - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - parse_init(); -#ifdef TEX_SUPPORT - if (tpic_flag) { - out = make_tpic_output(); - lf_flag = 0; - } - else if (tex_flag) { - out = make_tex_output(); - command_char = '\\'; - lf_flag = 0; - } - else -#endif -#ifdef FIG_SUPPORT - if (fig_flag) - out = make_fig_output(); - else -#endif - out = make_troff_output(); -#ifdef FIG_SUPPORT - if (whole_file_flag) { - if (optind >= argc) - do_whole_file("-"); - else if (argc - optind > 1) { - usage(stderr); - exit(1); - } else - do_whole_file(argv[optind]); - } - else { -#endif - if (optind >= argc) - do_file("-"); - else - for (int i = optind; i < argc; i++) - do_file(argv[i]); -#ifdef FIG_SUPPORT - } -#endif - delete out; - if (ferror(stdout) || fflush(stdout) < 0) - fatal("output error"); - return had_parse_error; -} - diff --git a/contrib/groff/src/preproc/pic/object.cc b/contrib/groff/src/preproc/pic/object.cc deleted file mode 100644 index fd25371..0000000 --- a/contrib/groff/src/preproc/pic/object.cc +++ /dev/null @@ -1,1894 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 - 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 "pic.h" -#include "ptable.h" -#include "object.h" - -void print_object_list(object *); - -line_type::line_type() -: type(solid), thickness(1.0) -{ -} - -output::output() : args(0), desired_height(0.0), desired_width(0.0) -{ -} - -output::~output() -{ - a_delete args; -} - -void output::set_desired_width_height(double wid, double ht) -{ - desired_width = wid; - desired_height = ht; -} - -void output::set_args(const char *s) -{ - a_delete args; - if (s == 0 || *s == '\0') - args = 0; - else - args = strsave(s); -} - -int output::supports_filled_polygons() -{ - return 0; -} - -void output::begin_block(const position &, const position &) -{ -} - -void output::end_block() -{ -} - -double output::compute_scale(double sc, const position &ll, const position &ur) -{ - distance dim = ur - ll; - if (desired_width != 0.0 || desired_height != 0.0) { - sc = 0.0; - if (desired_width != 0.0) { - if (dim.x == 0.0) - error("width specified for picture with zero width"); - else - sc = dim.x/desired_width; - } - if (desired_height != 0.0) { - if (dim.y == 0.0) - error("height specified for picture with zero height"); - else { - double tem = dim.y/desired_height; - if (tem > sc) - sc = tem; - } - } - return sc == 0.0 ? 1.0 : sc; - } - else { - if (sc <= 0.0) - sc = 1.0; - distance sdim = dim/sc; - double max_width = 0.0; - lookup_variable("maxpswid", &max_width); - double max_height = 0.0; - lookup_variable("maxpsht", &max_height); - if ((max_width > 0.0 && sdim.x > max_width) - || (max_height > 0.0 && sdim.y > max_height)) { - double xscale = dim.x/max_width; - double yscale = dim.y/max_height; - return xscale > yscale ? xscale : yscale; - } - else - return sc; - } -} - -position::position(const place &pl) -{ - if (pl.obj != 0) { - // Use two statements to work around bug in SGI C++. - object *tem = pl.obj; - *this = tem->origin(); - } - else { - x = pl.x; - y = pl.y; - } -} - -position::position() : x(0.0), y(0.0) -{ -} - -position::position(double a, double b) : x(a), y(b) -{ -} - - -int operator==(const position &a, const position &b) -{ - return a.x == b.x && a.y == b.y; -} - -int operator!=(const position &a, const position &b) -{ - return a.x != b.x || a.y != b.y; -} - -position &position::operator+=(const position &a) -{ - x += a.x; - y += a.y; - return *this; -} - -position &position::operator-=(const position &a) -{ - x -= a.x; - y -= a.y; - return *this; -} - -position &position::operator*=(double a) -{ - x *= a; - y *= a; - return *this; -} - -position &position::operator/=(double a) -{ - x /= a; - y /= a; - return *this; -} - -position operator-(const position &a) -{ - return position(-a.x, -a.y); -} - -position operator+(const position &a, const position &b) -{ - return position(a.x + b.x, a.y + b.y); -} - -position operator-(const position &a, const position &b) -{ - return position(a.x - b.x, a.y - b.y); -} - -position operator/(const position &a, double n) -{ - return position(a.x/n, a.y/n); -} - -position operator*(const position &a, double n) -{ - return position(a.x*n, a.y*n); -} - -// dot product - -double operator*(const position &a, const position &b) -{ - return a.x*b.x + a.y*b.y; -} - -double hypot(const position &a) -{ - return hypot(a.x, a.y); -} - -struct arrow_head_type { - double height; - double width; - int solid; -}; - -void draw_arrow(const position &pos, const distance &dir, - const arrow_head_type &aht, const line_type <, - char *outline_color_for_fill) -{ - double hyp = hypot(dir); - if (hyp == 0.0) { - error("cannot draw arrow on object with zero length"); - return; - } - position base = -dir; - base *= aht.height/hyp; - position n(dir.y, -dir.x); - n *= aht.width/(hyp*2.0); - line_type slt = lt; - slt.type = line_type::solid; - if (aht.solid && out->supports_filled_polygons()) { - position v[3]; - v[0] = pos; - v[1] = pos + base + n; - v[2] = pos + base - n; - // fill with outline color - out->set_color(outline_color_for_fill, outline_color_for_fill); - out->polygon(v, 3, slt, 1); - } - else { - position v[2]; - v[0] = pos; - v[1] = pos + base + n; - out->line(pos + base - n, v, 2, slt); - } -} - -object::object() : prev(0), next(0) -{ -} - -object::~object() -{ -} - -void object::move_by(const position &) -{ -} - -void object::print() -{ -} - -void object::print_text() -{ -} - -int object::blank() -{ - return 0; -} - -struct bounding_box { - int blank; - position ll; - position ur; - - bounding_box(); - void encompass(const position &); -}; - -bounding_box::bounding_box() -: blank(1) -{ -} - -void bounding_box::encompass(const position &pos) -{ - if (blank) { - ll = pos; - ur = pos; - blank = 0; - } - else { - if (pos.x < ll.x) - ll.x = pos.x; - if (pos.y < ll.y) - ll.y = pos.y; - if (pos.x > ur.x) - ur.x = pos.x; - if (pos.y > ur.y) - ur.y = pos.y; - } -} - -void object::update_bounding_box(bounding_box *) -{ -} - -position object::origin() -{ - return position(0.0,0.0); -} - -position object::north() -{ - return origin(); -} - -position object::south() -{ - return origin(); -} - -position object::east() -{ - return origin(); -} - -position object::west() -{ - return origin(); -} - -position object::north_east() -{ - return origin(); -} - -position object::north_west() -{ - return origin(); -} - -position object::south_east() -{ - return origin(); -} - -position object::south_west() -{ - return origin(); -} - -position object::start() -{ - return origin(); -} - -position object::end() -{ - return origin(); -} - -position object::center() -{ - return origin(); -} - -double object::width() -{ - return 0.0; -} - -double object::radius() -{ - return 0.0; -} - -double object::height() -{ - return 0.0; -} - -place *object::find_label(const char *) -{ - return 0; -} - -segment::segment(const position &a, int n, segment *p) -: is_absolute(n), pos(a), next(p) -{ -} - -text_item::text_item(char *t, const char *fn, int ln) -: next(0), text(t), filename(fn), lineno(ln) -{ - adj.h = CENTER_ADJUST; - adj.v = NONE_ADJUST; -} - -text_item::~text_item() -{ - a_delete text; -} - -object_spec::object_spec(object_type t) : type(t) -{ - flags = 0; - tbl = 0; - segment_list = 0; - segment_width = segment_height = 0.0; - segment_is_absolute = 0; - text = 0; - with = 0; - dir = RIGHT_DIRECTION; -} - -object_spec::~object_spec() -{ - delete tbl; - while (segment_list != 0) { - segment *tem = segment_list; - segment_list = segment_list->next; - delete tem; - } - object *p = oblist.head; - while (p != 0) { - object *tem = p; - p = p->next; - delete tem; - } - while (text != 0) { - text_item *tem = text; - text = text->next; - delete tem; - } - delete with; -} - -class command_object : public object { - char *s; - const char *filename; - int lineno; -public: - command_object(char *, const char *, int); - ~command_object(); - object_type type() { return OTHER_OBJECT; } - void print(); -}; - -command_object::command_object(char *p, const char *fn, int ln) -: s(p), filename(fn), lineno(ln) -{ -} - -command_object::~command_object() -{ - a_delete s; -} - -void command_object::print() -{ - out->command(s, filename, lineno); -} - -object *make_command_object(char *s, const char *fn, int ln) -{ - return new command_object(s, fn, ln); -} - -class mark_object : public object { -public: - mark_object(); - object_type type(); -}; - -object *make_mark_object() -{ - return new mark_object(); -} - -mark_object::mark_object() -{ -} - -object_type mark_object::type() -{ - return MARK_OBJECT; -} - -object_list::object_list() : head(0), tail(0) -{ -} - -void object_list::append(object *obj) -{ - if (tail == 0) { - obj->next = obj->prev = 0; - head = tail = obj; - } - else { - obj->prev = tail; - obj->next = 0; - tail->next = obj; - tail = obj; - } -} - -void object_list::wrap_up_block(object_list *ol) -{ - object *p; - for (p = tail; p && p->type() != MARK_OBJECT; p = p->prev) - ; - assert(p != 0); - ol->head = p->next; - if (ol->head) { - ol->tail = tail; - ol->head->prev = 0; - } - else - ol->tail = 0; - tail = p->prev; - if (tail) - tail->next = 0; - else - head = 0; - delete p; -} - -text_piece::text_piece() -: text(0), filename(0), lineno(-1) -{ - adj.h = CENTER_ADJUST; - adj.v = NONE_ADJUST; -} - -text_piece::~text_piece() -{ - a_delete text; -} - -class graphic_object : public object { - int ntext; - text_piece *text; - int aligned; -protected: - line_type lt; - char *outline_color; - char *color_fill; -public: - graphic_object(); - ~graphic_object(); - object_type type() = 0; - void print_text(); - void add_text(text_item *, int); - void set_dotted(double); - void set_dashed(double); - void set_thickness(double); - void set_invisible(); - void set_outline_color(char *); - char *get_outline_color(); - virtual void set_fill(double); - virtual void set_fill_color(char *); -}; - -graphic_object::graphic_object() -: ntext(0), text(0), aligned(0), outline_color(0), color_fill(0) -{ -} - -void graphic_object::set_dotted(double wid) -{ - lt.type = line_type::dotted; - lt.dash_width = wid; -} - -void graphic_object::set_dashed(double wid) -{ - lt.type = line_type::dashed; - lt.dash_width = wid; -} - -void graphic_object::set_thickness(double th) -{ - lt.thickness = th; -} - -void graphic_object::set_fill(double) -{ -} - -void graphic_object::set_fill_color(char *c) -{ - color_fill = c; -} - -void graphic_object::set_outline_color(char *c) -{ - outline_color = c; -} - -char *graphic_object::get_outline_color() -{ - return outline_color; -} - -void graphic_object::set_invisible() -{ - lt.type = line_type::invisible; -} - -void graphic_object::add_text(text_item *t, int a) -{ - aligned = a; - int len = 0; - text_item *p; - for (p = t; p; p = p->next) - len++; - if (len == 0) - text = 0; - else { - text = new text_piece[len]; - for (p = t, len = 0; p; p = p->next, len++) { - text[len].text = p->text; - p->text = 0; - text[len].adj = p->adj; - text[len].filename = p->filename; - text[len].lineno = p->lineno; - } - } - ntext = len; -} - -void graphic_object::print_text() -{ - double angle = 0.0; - if (aligned) { - position d(end() - start()); - if (d.x != 0.0 || d.y != 0.0) - angle = atan2(d.y, d.x); - } - if (text != 0) { - out->set_color(color_fill, get_outline_color()); - out->text(center(), text, ntext, angle); - out->reset_color(); - } -} - -graphic_object::~graphic_object() -{ - if (text) - ad_delete(ntext) text; -} - -class rectangle_object : public graphic_object { -protected: - position cent; - position dim; -public: - rectangle_object(const position &); - double width() { return dim.x; } - double height() { return dim.y; } - position origin() { return cent; } - position center() { return cent; } - position north() { return position(cent.x, cent.y + dim.y/2.0); } - position south() { return position(cent.x, cent.y - dim.y/2.0); } - position east() { return position(cent.x + dim.x/2.0, cent.y); } - position west() { return position(cent.x - dim.x/2.0, cent.y); } - position north_east() { return position(cent.x + dim.x/2.0, cent.y + dim.y/2.0); } - position north_west() { return position(cent.x - dim.x/2.0, cent.y + dim.y/2.0); } - position south_east() { return position(cent.x + dim.x/2.0, cent.y - dim.y/2.0); } - position south_west() { return position(cent.x - dim.x/2.0, cent.y - dim.y/2.0); } - object_type type() = 0; - void update_bounding_box(bounding_box *); - void move_by(const position &); -}; - -rectangle_object::rectangle_object(const position &d) -: dim(d) -{ -} - -void rectangle_object::update_bounding_box(bounding_box *p) -{ - p->encompass(cent - dim/2.0); - p->encompass(cent + dim/2.0); -} - -void rectangle_object::move_by(const position &a) -{ - cent += a; -} - -class closed_object : public rectangle_object { -public: - closed_object(const position &); - object_type type() = 0; - void set_fill(double); - void set_fill_color(char *fill); -protected: - double fill; // < 0 if not filled - char *color_fill; // = 0 if not colored -}; - -closed_object::closed_object(const position &pos) -: rectangle_object(pos), fill(-1.0), color_fill(0) -{ -} - -void closed_object::set_fill(double f) -{ - assert(f >= 0.0); - fill = f; -} - -void closed_object::set_fill_color(char *fill) -{ - color_fill = fill; -} - -class box_object : public closed_object { - double xrad; - double yrad; -public: - box_object(const position &, double); - object_type type() { return BOX_OBJECT; } - void print(); - position north_east(); - position north_west(); - position south_east(); - position south_west(); -}; - -box_object::box_object(const position &pos, double r) -: closed_object(pos), xrad(dim.x > 0 ? r : -r), yrad(dim.y > 0 ? r : -r) -{ -} - -const double CHOP_FACTOR = 1.0 - 1.0/M_SQRT2; - -position box_object::north_east() -{ - return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad, - cent.y + dim.y/2.0 - CHOP_FACTOR*yrad); -} - -position box_object::north_west() -{ - return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad, - cent.y + dim.y/2.0 - CHOP_FACTOR*yrad); -} - -position box_object::south_east() -{ - return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad, - cent.y - dim.y/2.0 + CHOP_FACTOR*yrad); -} - -position box_object::south_west() -{ - return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad, - cent.y - dim.y/2.0 + CHOP_FACTOR*yrad); -} - -void box_object::print() -{ - if (lt.type == line_type::invisible && fill < 0.0 && color_fill == 0) - return; - out->set_color(color_fill, graphic_object::get_outline_color()); - if (xrad == 0.0) { - distance dim2 = dim/2.0; - position vec[4]; - vec[0] = cent + position(dim2.x, -dim2.y); - vec[1] = cent + position(dim2.x, dim2.y); - vec[2] = cent + position(-dim2.x, dim2.y); - vec[3] = cent + position(-dim2.x, -dim2.y); - out->polygon(vec, 4, lt, fill); - } - else { - distance abs_dim(fabs(dim.x), fabs(dim.y)); - out->rounded_box(cent, abs_dim, fabs(xrad), lt, fill); - } - out->reset_color(); -} - -graphic_object *object_spec::make_box(position *curpos, direction *dirp) -{ - static double last_box_height; - static double last_box_width; - static double last_box_radius; - static int have_last_box = 0; - if (!(flags & HAS_HEIGHT)) { - if ((flags & IS_SAME) && have_last_box) - height = last_box_height; - else - lookup_variable("boxht", &height); - } - if (!(flags & HAS_WIDTH)) { - if ((flags & IS_SAME) && have_last_box) - width = last_box_width; - else - lookup_variable("boxwid", &width); - } - if (!(flags & HAS_RADIUS)) { - if ((flags & IS_SAME) && have_last_box) - radius = last_box_radius; - else - lookup_variable("boxrad", &radius); - } - last_box_width = width; - last_box_height = height; - last_box_radius = radius; - have_last_box = 1; - radius = fabs(radius); - if (radius*2.0 > fabs(width)) - radius = fabs(width/2.0); - if (radius*2.0 > fabs(height)) - radius = fabs(height/2.0); - box_object *p = new box_object(position(width, height), radius); - if (!position_rectangle(p, curpos, dirp)) { - delete p; - p = 0; - } - return p; -} - -// return non-zero for success - -int object_spec::position_rectangle(rectangle_object *p, - position *curpos, direction *dirp) -{ - position pos; - dir = *dirp; // ignore any direction in attribute list - position motion; - switch (dir) { - case UP_DIRECTION: - motion.y = p->height()/2.0; - break; - case DOWN_DIRECTION: - motion.y = -p->height()/2.0; - break; - case LEFT_DIRECTION: - motion.x = -p->width()/2.0; - break; - case RIGHT_DIRECTION: - motion.x = p->width()/2.0; - break; - default: - assert(0); - } - if (flags & HAS_AT) { - pos = at; - if (flags & HAS_WITH) { - place offset; - place here; - here.obj = p; - if (!with->follow(here, &offset)) - return 0; - pos -= offset; - } - } - else { - pos = *curpos; - pos += motion; - } - p->move_by(pos); - pos += motion; - *curpos = pos; - return 1; -} - -class block_object : public rectangle_object { - object_list oblist; - PTABLE(place) *tbl; -public: - block_object(const position &, const object_list &ol, PTABLE(place) *t); - ~block_object(); - place *find_label(const char *); - object_type type(); - void move_by(const position &); - void print(); -}; - -block_object::block_object(const position &d, const object_list &ol, - PTABLE(place) *t) -: rectangle_object(d), oblist(ol), tbl(t) -{ -} - -block_object::~block_object() -{ - delete tbl; - object *p = oblist.head; - while (p != 0) { - object *tem = p; - p = p->next; - delete tem; - } -} - -void block_object::print() -{ - out->begin_block(south_west(), north_east()); - print_object_list(oblist.head); - out->end_block(); -} - -static void adjust_objectless_places(PTABLE(place) *tbl, const position &a) -{ - // Adjust all the labels that aren't attached to objects. - PTABLE_ITERATOR(place) iter(tbl); - const char *key; - place *pl; - while (iter.next(&key, &pl)) - if (key && csupper(key[0]) && pl->obj == 0) { - pl->x += a.x; - pl->y += a.y; - } -} - -void block_object::move_by(const position &a) -{ - cent += a; - for (object *p = oblist.head; p; p = p->next) - p->move_by(a); - adjust_objectless_places(tbl, a); -} - - -place *block_object::find_label(const char *name) -{ - return tbl->lookup(name); -} - -object_type block_object::type() -{ - return BLOCK_OBJECT; -} - -graphic_object *object_spec::make_block(position *curpos, direction *dirp) -{ - bounding_box bb; - for (object *p = oblist.head; p; p = p->next) - p->update_bounding_box(&bb); - position dim; - if (!bb.blank) { - position m = -(bb.ll + bb.ur)/2.0; - for (object *p = oblist.head; p; p = p->next) - p->move_by(m); - adjust_objectless_places(tbl, m); - dim = bb.ur - bb.ll; - } - if (flags & HAS_WIDTH) - dim.x = width; - if (flags & HAS_HEIGHT) - dim.y = height; - block_object *block = new block_object(dim, oblist, tbl); - if (!position_rectangle(block, curpos, dirp)) { - delete block; - block = 0; - } - tbl = 0; - oblist.head = oblist.tail = 0; - return block; -} - -class text_object : public rectangle_object { -public: - text_object(const position &); - object_type type() { return TEXT_OBJECT; } -}; - -text_object::text_object(const position &d) -: rectangle_object(d) -{ -} - -graphic_object *object_spec::make_text(position *curpos, direction *dirp) -{ - if (!(flags & HAS_HEIGHT)) { - lookup_variable("textht", &height); - int nitems = 0; - for (text_item *t = text; t; t = t->next) - nitems++; - height *= nitems; - } - if (!(flags & HAS_WIDTH)) - lookup_variable("textwid", &width); - text_object *p = new text_object(position(width, height)); - if (!position_rectangle(p, curpos, dirp)) { - delete p; - p = 0; - } - return p; -} - - -class ellipse_object : public closed_object { -public: - ellipse_object(const position &); - position north_east() { return position(cent.x + dim.x/(M_SQRT2*2.0), - cent.y + dim.y/(M_SQRT2*2.0)); } - position north_west() { return position(cent.x - dim.x/(M_SQRT2*2.0), - cent.y + dim.y/(M_SQRT2*2.0)); } - position south_east() { return position(cent.x + dim.x/(M_SQRT2*2.0), - cent.y - dim.y/(M_SQRT2*2.0)); } - position south_west() { return position(cent.x - dim.x/(M_SQRT2*2.0), - cent.y - dim.y/(M_SQRT2*2.0)); } - double radius() { return dim.x/2.0; } - object_type type() { return ELLIPSE_OBJECT; } - void print(); -}; - -ellipse_object::ellipse_object(const position &d) -: closed_object(d) -{ -} - -void ellipse_object::print() -{ - if (lt.type == line_type::invisible && fill < 0.0 && color_fill == 0) - return; - out->set_color(color_fill, graphic_object::get_outline_color()); - out->ellipse(cent, dim, lt, fill); - out->reset_color(); -} - -graphic_object *object_spec::make_ellipse(position *curpos, direction *dirp) -{ - static double last_ellipse_height; - static double last_ellipse_width; - static int have_last_ellipse = 0; - if (!(flags & HAS_HEIGHT)) { - if ((flags & IS_SAME) && have_last_ellipse) - height = last_ellipse_height; - else - lookup_variable("ellipseht", &height); - } - if (!(flags & HAS_WIDTH)) { - if ((flags & IS_SAME) && have_last_ellipse) - width = last_ellipse_width; - else - lookup_variable("ellipsewid", &width); - } - last_ellipse_width = width; - last_ellipse_height = height; - have_last_ellipse = 1; - ellipse_object *p = new ellipse_object(position(width, height)); - if (!position_rectangle(p, curpos, dirp)) { - delete p; - return 0; - } - return p; -} - -class circle_object : public ellipse_object { -public: - circle_object(double); - object_type type() { return CIRCLE_OBJECT; } - void print(); -}; - -circle_object::circle_object(double diam) -: ellipse_object(position(diam, diam)) -{ -} - -void circle_object::print() -{ - if (lt.type == line_type::invisible && fill < 0.0 && color_fill == 0) - return; - out->set_color(color_fill, graphic_object::get_outline_color()); - out->circle(cent, dim.x/2.0, lt, fill); - out->reset_color(); -} - -graphic_object *object_spec::make_circle(position *curpos, direction *dirp) -{ - static double last_circle_radius; - static int have_last_circle = 0; - if (!(flags & HAS_RADIUS)) { - if ((flags & IS_SAME) && have_last_circle) - radius = last_circle_radius; - else - lookup_variable("circlerad", &radius); - } - last_circle_radius = radius; - have_last_circle = 1; - circle_object *p = new circle_object(radius*2.0); - if (!position_rectangle(p, curpos, dirp)) { - delete p; - return 0; - } - return p; -} - -class move_object : public graphic_object { - position strt; - position en; -public: - move_object(const position &s, const position &e); - position origin() { return en; } - object_type type() { return MOVE_OBJECT; } - void update_bounding_box(bounding_box *); - void move_by(const position &); -}; - -move_object::move_object(const position &s, const position &e) -: strt(s), en(e) -{ -} - -void move_object::update_bounding_box(bounding_box *p) -{ - p->encompass(strt); - p->encompass(en); -} - -void move_object::move_by(const position &a) -{ - strt += a; - en += a; -} - -graphic_object *object_spec::make_move(position *curpos, direction *dirp) -{ - static position last_move; - static int have_last_move = 0; - *dirp = dir; - // No need to look at at since `at' attribute sets `from' attribute. - position startpos = (flags & HAS_FROM) ? from : *curpos; - if (!(flags & HAS_SEGMENT)) { - if ((flags & IS_SAME) && have_last_move) - segment_pos = last_move; - else { - switch (dir) { - case UP_DIRECTION: - segment_pos.y = segment_height; - break; - case DOWN_DIRECTION: - segment_pos.y = -segment_height; - break; - case LEFT_DIRECTION: - segment_pos.x = -segment_width; - break; - case RIGHT_DIRECTION: - segment_pos.x = segment_width; - break; - default: - assert(0); - } - } - } - segment_list = new segment(segment_pos, segment_is_absolute, segment_list); - // Reverse the segment_list so that it's in forward order. - segment *old = segment_list; - segment_list = 0; - while (old != 0) { - segment *tem = old->next; - old->next = segment_list; - segment_list = old; - old = tem; - } - // Compute the end position. - position endpos = startpos; - for (segment *s = segment_list; s; s = s->next) - if (s->is_absolute) - endpos = s->pos; - else - endpos += s->pos; - have_last_move = 1; - last_move = endpos - startpos; - move_object *p = new move_object(startpos, endpos); - *curpos = endpos; - return p; -} - -class linear_object : public graphic_object { -protected: - char arrow_at_start; - char arrow_at_end; - arrow_head_type aht; - position strt; - position en; -public: - linear_object(const position &s, const position &e); - position start() { return strt; } - position end() { return en; } - void move_by(const position &); - void update_bounding_box(bounding_box *) = 0; - object_type type() = 0; - void add_arrows(int at_start, int at_end, const arrow_head_type &); -}; - -class line_object : public linear_object { -protected: - position *v; - int n; -public: - line_object(const position &s, const position &e, position *, int); - ~line_object(); - position origin() { return strt; } - position center() { return (strt + en)/2.0; } - position north() { return (en.y - strt.y) > 0 ? en : strt; } - position south() { return (en.y - strt.y) < 0 ? en : strt; } - position east() { return (en.x - strt.x) > 0 ? en : strt; } - position west() { return (en.x - strt.x) < 0 ? en : strt; } - object_type type() { return LINE_OBJECT; } - void update_bounding_box(bounding_box *); - void print(); - void move_by(const position &); -}; - -class arrow_object : public line_object { -public: - arrow_object(const position &, const position &, position *, int); - object_type type() { return ARROW_OBJECT; } -}; - -class spline_object : public line_object { -public: - spline_object(const position &, const position &, position *, int); - object_type type() { return SPLINE_OBJECT; } - void print(); - void update_bounding_box(bounding_box *); -}; - -linear_object::linear_object(const position &s, const position &e) -: arrow_at_start(0), arrow_at_end(0), strt(s), en(e) -{ -} - -void linear_object::move_by(const position &a) -{ - strt += a; - en += a; -} - -void linear_object::add_arrows(int at_start, int at_end, - const arrow_head_type &a) -{ - arrow_at_start = at_start; - arrow_at_end = at_end; - aht = a; -} - -line_object::line_object(const position &s, const position &e, - position *p, int i) -: linear_object(s, e), v(p), n(i) -{ -} - -void line_object::print() -{ - if (lt.type == line_type::invisible) - return; - out->set_color(0, graphic_object::get_outline_color()); - out->line(strt, v, n, lt); - if (arrow_at_start) - draw_arrow(strt, strt-v[0], aht, lt, graphic_object::get_outline_color()); - if (arrow_at_end) - draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt, - graphic_object::get_outline_color()); - out->reset_color(); -} - -void line_object::update_bounding_box(bounding_box *p) -{ - p->encompass(strt); - for (int i = 0; i < n; i++) - p->encompass(v[i]); -} - -void line_object::move_by(const position &pos) -{ - linear_object::move_by(pos); - for (int i = 0; i < n; i++) - v[i] += pos; -} - -void spline_object::update_bounding_box(bounding_box *p) -{ - p->encompass(strt); - p->encompass(en); - /* - - If - - p1 = q1/2 + q2/2 - p2 = q1/6 + q2*5/6 - p3 = q2*5/6 + q3/6 - p4 = q2/2 + q3/2 - [ the points for the Bezier cubic ] - - and - - t = .5 - - then - - (1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4 - [ the equation for the Bezier cubic ] - - = .125*q1 + .75*q2 + .125*q3 - - */ - for (int i = 1; i < n; i++) - p->encompass((i == 1 ? strt : v[i-2])*.125 + v[i-1]*.75 + v[i]*.125); -} - -arrow_object::arrow_object(const position &s, const position &e, - position *p, int i) -: line_object(s, e, p, i) -{ -} - -spline_object::spline_object(const position &s, const position &e, - position *p, int i) -: line_object(s, e, p, i) -{ -} - -void spline_object::print() -{ - if (lt.type == line_type::invisible) - return; - out->set_color(0, graphic_object::get_outline_color()); - out->spline(strt, v, n, lt); - if (arrow_at_start) - draw_arrow(strt, strt-v[0], aht, lt, graphic_object::get_outline_color()); - if (arrow_at_end) - draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt, - graphic_object::get_outline_color()); - out->reset_color(); -} - -line_object::~line_object() -{ - a_delete v; -} - -linear_object *object_spec::make_line(position *curpos, direction *dirp) -{ - static position last_line; - static int have_last_line = 0; - *dirp = dir; - // No need to look at at since `at' attribute sets `from' attribute. - position startpos = (flags & HAS_FROM) ? from : *curpos; - if (!(flags & HAS_SEGMENT)) { - if ((flags & IS_SAME) && (type == LINE_OBJECT || type == ARROW_OBJECT) - && have_last_line) - segment_pos = last_line; - else - switch (dir) { - case UP_DIRECTION: - segment_pos.y = segment_height; - break; - case DOWN_DIRECTION: - segment_pos.y = -segment_height; - break; - case LEFT_DIRECTION: - segment_pos.x = -segment_width; - break; - case RIGHT_DIRECTION: - segment_pos.x = segment_width; - break; - default: - assert(0); - } - } - segment_list = new segment(segment_pos, segment_is_absolute, segment_list); - // reverse the segment_list so that it's in forward order - segment *old = segment_list; - segment_list = 0; - while (old != 0) { - segment *tem = old->next; - old->next = segment_list; - segment_list = old; - old = tem; - } - // Absolutise all movements - position endpos = startpos; - int nsegments = 0; - segment *s; - for (s = segment_list; s; s = s->next, nsegments++) - if (s->is_absolute) - endpos = s->pos; - else { - endpos += s->pos; - s->pos = endpos; - s->is_absolute = 1; // to avoid confusion - } - // handle chop - line_object *p = 0; - position *v = new position[nsegments]; - int i = 0; - for (s = segment_list; s; s = s->next, i++) - v[i] = s->pos; - if (flags & IS_DEFAULT_CHOPPED) { - lookup_variable("circlerad", &start_chop); - end_chop = start_chop; - flags |= IS_CHOPPED; - } - if (flags & IS_CHOPPED) { - position start_chop_vec, end_chop_vec; - if (start_chop != 0.0) { - start_chop_vec = v[0] - startpos; - start_chop_vec *= start_chop / hypot(start_chop_vec); - } - if (end_chop != 0.0) { - end_chop_vec = (v[nsegments - 1] - - (nsegments > 1 ? v[nsegments - 2] : startpos)); - end_chop_vec *= end_chop / hypot(end_chop_vec); - } - startpos += start_chop_vec; - v[nsegments - 1] -= end_chop_vec; - endpos -= end_chop_vec; - } - switch (type) { - case SPLINE_OBJECT: - p = new spline_object(startpos, endpos, v, nsegments); - break; - case ARROW_OBJECT: - p = new arrow_object(startpos, endpos, v, nsegments); - break; - case LINE_OBJECT: - p = new line_object(startpos, endpos, v, nsegments); - break; - default: - assert(0); - } - have_last_line = 1; - last_line = endpos - startpos; - *curpos = endpos; - return p; -} - -class arc_object : public linear_object { - int clockwise; - position cent; - double rad; -public: - arc_object(int, const position &, const position &, const position &); - position origin() { return cent; } - position center() { return cent; } - double radius() { return rad; } - position north(); - position south(); - position east(); - position west(); - position north_east(); - position north_west(); - position south_east(); - position south_west(); - void update_bounding_box(bounding_box *); - object_type type() { return ARC_OBJECT; } - void print(); - void move_by(const position &pos); -}; - -arc_object::arc_object(int cw, const position &s, const position &e, - const position &c) -: linear_object(s, e), clockwise(cw), cent(c) -{ - rad = hypot(c - s); -} - -void arc_object::move_by(const position &pos) -{ - linear_object::move_by(pos); - cent += pos; -} - -// we get arc corners from the corresponding circle - -position arc_object::north() -{ - position result(cent); - result.y += rad; - return result; -} - -position arc_object::south() -{ - position result(cent); - result.y -= rad; - return result; -} - -position arc_object::east() -{ - position result(cent); - result.x += rad; - return result; -} - -position arc_object::west() -{ - position result(cent); - result.x -= rad; - return result; -} - -position arc_object::north_east() -{ - position result(cent); - result.x += rad/M_SQRT2; - result.y += rad/M_SQRT2; - return result; -} - -position arc_object::north_west() -{ - position result(cent); - result.x -= rad/M_SQRT2; - result.y += rad/M_SQRT2; - return result; -} - -position arc_object::south_east() -{ - position result(cent); - result.x += rad/M_SQRT2; - result.y -= rad/M_SQRT2; - return result; -} - -position arc_object::south_west() -{ - position result(cent); - result.x -= rad/M_SQRT2; - result.y -= rad/M_SQRT2; - return result; -} - - -void arc_object::print() -{ - if (lt.type == line_type::invisible) - return; - out->set_color(0, graphic_object::get_outline_color()); - if (clockwise) - out->arc(en, cent, strt, lt); - else - out->arc(strt, cent, en, lt); - if (arrow_at_start) { - position c = cent - strt; - draw_arrow(strt, - (clockwise ? position(c.y, -c.x) : position(-c.y, c.x)), - aht, lt, graphic_object::get_outline_color()); - } - if (arrow_at_end) { - position e = en - cent; - draw_arrow(en, - (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)), - aht, lt, graphic_object::get_outline_color()); - } - out->reset_color(); -} - -inline double max(double a, double b) -{ - return a > b ? a : b; -} - -void arc_object::update_bounding_box(bounding_box *p) -{ - p->encompass(strt); - p->encompass(en); - position start_offset = strt - cent; - if (start_offset.x == 0.0 && start_offset.y == 0.0) - return; - position end_offset = en - cent; - if (end_offset.x == 0.0 && end_offset.y == 0.0) - return; - double start_quad = atan2(start_offset.y, start_offset.x)/(M_PI/2.0); - double end_quad = atan2(end_offset.y, end_offset.x)/(M_PI/2.0); - if (clockwise) { - double temp = start_quad; - start_quad = end_quad; - end_quad = temp; - } - if (start_quad < 0.0) - start_quad += 4.0; - while (end_quad <= start_quad) - end_quad += 4.0; - double radius = max(hypot(start_offset), hypot(end_offset)); - for (int q = int(start_quad) + 1; q < end_quad; q++) { - position offset; - switch (q % 4) { - case 0: - offset.x = radius; - break; - case 1: - offset.y = radius; - break; - case 2: - offset.x = -radius; - break; - case 3: - offset.y = -radius; - break; - } - p->encompass(cent + offset); - } -} - -// We ignore the with attribute. The at attribute always refers to the center. - -linear_object *object_spec::make_arc(position *curpos, direction *dirp) -{ - *dirp = dir; - int cw = (flags & IS_CLOCKWISE) != 0; - // compute the start - position startpos; - if (flags & HAS_FROM) - startpos = from; - else - startpos = *curpos; - if (!(flags & HAS_RADIUS)) - lookup_variable("arcrad", &radius); - // compute the end - position endpos; - if (flags & HAS_TO) - endpos = to; - else { - position m(radius, radius); - // Adjust the signs. - if (cw) { - if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) - m.x = -m.x; - if (dir == DOWN_DIRECTION || dir == RIGHT_DIRECTION) - m.y = -m.y; - *dirp = direction((dir + 3) % 4); - } - else { - if (dir == UP_DIRECTION || dir == LEFT_DIRECTION) - m.x = -m.x; - if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) - m.y = -m.y; - *dirp = direction((dir + 1) % 4); - } - endpos = startpos + m; - } - // compute the center - position centerpos; - if (flags & HAS_AT) - centerpos = at; - else if (startpos == endpos) - centerpos = startpos; - else { - position h = (endpos - startpos)/2.0; - double d = hypot(h); - if (radius <= 0) - radius = .25; - // make the radius big enough - while (radius < d) - radius *= 2.0; - double alpha = acos(d/radius); - double theta = atan2(h.y, h.x); - if (cw) - theta -= alpha; - else - theta += alpha; - centerpos = position(cos(theta), sin(theta))*radius + startpos; - } - arc_object *p = new arc_object(cw, startpos, endpos, centerpos); - *curpos = endpos; - return p; -} - -graphic_object *object_spec::make_linear(position *curpos, direction *dirp) -{ - linear_object *obj; - if (type == ARC_OBJECT) - obj = make_arc(curpos, dirp); - else - obj = make_line(curpos, dirp); - if (type == ARROW_OBJECT - && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)) == 0) - flags |= HAS_RIGHT_ARROW_HEAD; - if (obj && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD))) { - arrow_head_type a; - int at_start = (flags & HAS_LEFT_ARROW_HEAD) != 0; - int at_end = (flags & HAS_RIGHT_ARROW_HEAD) != 0; - if (flags & HAS_HEIGHT) - a.height = height; - else - lookup_variable("arrowht", &a.height); - if (flags & HAS_WIDTH) - a.width = width; - else - lookup_variable("arrowwid", &a.width); - double solid; - lookup_variable("arrowhead", &solid); - a.solid = solid != 0.0; - obj->add_arrows(at_start, at_end, a); - } - return obj; -} - -object *object_spec::make_object(position *curpos, direction *dirp) -{ - graphic_object *obj = 0; - switch (type) { - case BLOCK_OBJECT: - obj = make_block(curpos, dirp); - break; - case BOX_OBJECT: - obj = make_box(curpos, dirp); - break; - case TEXT_OBJECT: - obj = make_text(curpos, dirp); - break; - case ELLIPSE_OBJECT: - obj = make_ellipse(curpos, dirp); - break; - case CIRCLE_OBJECT: - obj = make_circle(curpos, dirp); - break; - case MOVE_OBJECT: - obj = make_move(curpos, dirp); - break; - case ARC_OBJECT: - case LINE_OBJECT: - case SPLINE_OBJECT: - case ARROW_OBJECT: - obj = make_linear(curpos, dirp); - break; - case MARK_OBJECT: - case OTHER_OBJECT: - default: - assert(0); - break; - } - if (obj) { - if (flags & IS_INVISIBLE) - obj->set_invisible(); - if (text != 0) - obj->add_text(text, (flags & IS_ALIGNED) != 0); - if (flags & IS_DOTTED) - obj->set_dotted(dash_width); - else if (flags & IS_DASHED) - obj->set_dashed(dash_width); - double th; - if (flags & HAS_THICKNESS) - th = thickness; - else - lookup_variable("linethick", &th); - obj->set_thickness(th); - if (flags & IS_OUTLINED) - obj->set_outline_color(outlined); - if (flags & (IS_DEFAULT_FILLED|IS_FILLED)) { - if (flags & IS_SHADED) - obj->set_fill_color(shaded); - else { - if (flags & IS_DEFAULT_FILLED) - lookup_variable("fillval", &fill); - if (fill < 0.0) - error("bad fill value %1", fill); - else - obj->set_fill(fill); - } - } - } - return obj; -} - -struct string_list { - string_list *next; - char *str; - string_list(char *); - ~string_list(); -}; - -string_list::string_list(char *s) -: next(0), str(s) -{ -} - -string_list::~string_list() -{ - a_delete str; -} - -/* A path is used to hold the argument to the `with' attribute. For - example, `.nw' or `.A.s' or `.A'. The major operation on a path is to - take a place and follow the path through the place to place within the - place. Note that `.A.B.C.sw' will work. - - For compatibility with DWB pic, `with' accepts positions also (this - is incorrectly documented in CSTR 116). */ - -path::path(corner c) -: crn(c), label_list(0), ypath(0), is_position(0) -{ -} - -path::path(position p) -: crn(0), label_list(0), ypath(0), is_position(1) -{ - pos.x = p.x; - pos.y = p.y; -} - -path::path(char *l, corner c) -: crn(c), ypath(0), is_position(0) -{ - label_list = new string_list(l); -} - -path::~path() -{ - while (label_list) { - string_list *tem = label_list; - label_list = label_list->next; - delete tem; - } - delete ypath; -} - -void path::append(corner c) -{ - assert(crn == 0); - crn = c; -} - -void path::append(char *s) -{ - string_list **p; - for (p = &label_list; *p; p = &(*p)->next) - ; - *p = new string_list(s); -} - -void path::set_ypath(path *p) -{ - ypath = p; -} - -// return non-zero for success - -int path::follow(const place &pl, place *result) const -{ - if (is_position) { - result->x = pos.x; - result->y = pos.y; - result->obj = 0; - return 1; - } - const place *p = &pl; - for (string_list *lb = label_list; lb; lb = lb->next) - if (p->obj == 0 || (p = p->obj->find_label(lb->str)) == 0) { - lex_error("object does not contain a place `%1'", lb->str); - return 0; - } - if (crn == 0 || p->obj == 0) - *result = *p; - else { - position ps = ((p->obj)->*(crn))(); - result->x = ps.x; - result->y = ps.y; - result->obj = 0; - } - if (ypath) { - place tem; - if (!ypath->follow(pl, &tem)) - return 0; - result->y = tem.y; - if (result->obj != tem.obj) - result->obj = 0; - } - return 1; -} - -void print_object_list(object *p) -{ - for (; p; p = p->next) { - p->print(); - p->print_text(); - } -} - -void print_picture(object *obj) -{ - bounding_box bb; - for (object *p = obj; p; p = p->next) - p->update_bounding_box(&bb); - double scale; - lookup_variable("scale", &scale); - out->start_picture(scale, bb.ll, bb.ur); - print_object_list(obj); - out->finish_picture(); -} - diff --git a/contrib/groff/src/preproc/pic/tex.cc b/contrib/groff/src/preproc/pic/tex.cc deleted file mode 100644 index a9192ac..0000000 --- a/contrib/groff/src/preproc/pic/tex.cc +++ /dev/null @@ -1,438 +0,0 @@ -// -*- 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 "pic.h" - -#ifdef TEX_SUPPORT - -#include "common.h" - -class tex_output : public common_output { -public: - tex_output(); - ~tex_output(); - void start_picture(double, const position &ll, const position &ur); - void finish_picture(); - void text(const position &, text_piece *, int, double); - void line(const position &, const position *, int n, - const line_type &); - void polygon(const position *, int n, - const line_type &, double); - void spline(const position &, const position *, int n, - const line_type &); - void arc(const position &, const position &, const position &, - const line_type &); - void circle(const position &, double rad, const line_type &, double); - void ellipse(const position &, const distance &, const line_type &, double); - void command(const char *, const char *, int); - void set_color(char *, char *); - void reset_color(); - char *get_last_filled(); - char *get_outline_color(); - int supports_filled_polygons(); -private: - position upper_left; - double height; - double width; - double scale; - double pen_size; - - void point(const position &); - void dot(const position &, const line_type &); - void solid_arc(const position ¢, double rad, double start_angle, - double end_angle, const line_type <); - position transform(const position &); -protected: - virtual void set_pen_size(double ps); -}; - -// convert inches to milliinches - -inline int milliinches(double x) -{ - return int(x*1000.0 + .5); -} - -inline position tex_output::transform(const position &pos) -{ - return position((pos.x - upper_left.x)/scale, - (upper_left.y - pos.y)/scale); -} - -output *make_tex_output() -{ - return new tex_output; -} - -tex_output::tex_output() -{ -} - -tex_output::~tex_output() -{ -} - -const int DEFAULT_PEN_SIZE = 8; - -void tex_output::set_pen_size(double ps) -{ - if (ps < 0.0) - ps = -1.0; - if (ps != pen_size) { - pen_size = ps; - printf(" \\special{pn %d}%%\n", - ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5)); - } -} - -void tex_output::start_picture(double sc, const position &ll, - const position &ur) -{ - upper_left.x = ll.x; - upper_left.y = ur.y; - scale = compute_scale(sc, ll, ur); - height = (ur.y - ll.y)/scale; - width = (ur.x - ll.x)/scale; - /* the point of \vskip 0pt is to ensure that the vtop gets - a height of 0 rather than the height of the hbox; this - might be non-zero if text from text attributes lies outside pic's - idea of the bounding box of the picture. */ - fputs("\\expandafter\\ifx\\csname graph\\endcsname\\relax \\csname newbox\\endcsname\\graph\\fi\n" - "\\expandafter\\ifx\\csname graphtemp\\endcsname\\relax \\csname newdimen\\endcsname\\graphtemp\\fi\n" - "\\setbox\\graph=\\vtop{\\vskip 0pt\\hbox{%\n", - stdout); - pen_size = -2.0; -} - -void tex_output::finish_picture() -{ - printf(" \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n" - " \\kern %.3fin\n" - " }%%\n" - "}%%\n", - height, width); -} - -void tex_output::text(const position ¢er, text_piece *v, int n, double) -{ - position c = transform(center); - for (int i = 0; i < n; i++) - if (v[i].text != 0 && *v[i].text != '\0') { - int j = 2*i - n + 1; - if (v[i].adj.v == ABOVE_ADJUST) - j--; - else if (v[i].adj.v == BELOW_ADJUST) - j++; - if (j == 0) { - printf(" \\graphtemp=.5ex\\advance\\graphtemp by %.3fin\n", c.y); - } - else { - printf(" \\graphtemp=\\baselineskip" - "\\multiply\\graphtemp by %d" - "\\divide\\graphtemp by 2\n" - " \\advance\\graphtemp by .5ex" - "\\advance\\graphtemp by %.3fin\n", - j, c.y); - } - printf(" \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x); - fputs("\\hbox to 0pt{", stdout); - if (v[i].adj.h != LEFT_ADJUST) - fputs("\\hss ", stdout); - fputs(v[i].text, stdout); - if (v[i].adj.h != RIGHT_ADJUST) - fputs("\\hss", stdout); - fputs("}}%\n", stdout); - } -} - -void tex_output::point(const position &pos) -{ - position p = transform(pos); - printf(" \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y)); -} - -void tex_output::line(const position &start, const position *v, int n, - const line_type <) -{ - set_pen_size(lt.thickness); - point(start); - for (int i = 0; i < n; i++) - point(v[i]); - fputs(" \\special{", stdout); - switch(lt.type) { - case line_type::invisible: - fputs("ip", stdout); - break; - case line_type::solid: - fputs("fp", stdout); - break; - case line_type::dotted: - printf("dt %.3f", lt.dash_width/scale); - break; - case line_type::dashed: - printf("da %.3f", lt.dash_width/scale); - break; - } - fputs("}%\n", stdout); -} - -void tex_output::polygon(const position *v, int n, - const line_type <, double fill) -{ - if (fill >= 0.0) { - if (fill > 1.0) - fill = 1.0; - printf(" \\special{sh %.3f}%%\n", fill); - } - line(v[n-1], v, n, lt); -} - -void tex_output::spline(const position &start, const position *v, int n, - const line_type <) -{ - if (lt.type == line_type::invisible) - return; - set_pen_size(lt.thickness); - point(start); - for (int i = 0; i < n; i++) - point(v[i]); - fputs(" \\special{sp", stdout); - switch(lt.type) { - case line_type::solid: - break; - case line_type::dotted: - printf(" %.3f", -lt.dash_width/scale); - break; - case line_type::dashed: - printf(" %.3f", lt.dash_width/scale); - break; - case line_type::invisible: - assert(0); - } - fputs("}%\n", stdout); -} - -void tex_output::solid_arc(const position ¢, double rad, - double start_angle, double end_angle, - const line_type <) -{ - set_pen_size(lt.thickness); - position c = transform(cent); - printf(" \\special{ar %d %d %d %d %f %f}%%\n", - milliinches(c.x), - milliinches(c.y), - milliinches(rad/scale), - milliinches(rad/scale), - -end_angle, - (-end_angle > -start_angle) ? (double)M_PI * 2 - start_angle - : -start_angle); -} - -void tex_output::arc(const position &start, const position ¢, - const position &end, const line_type <) -{ - switch (lt.type) { - case line_type::invisible: - break; - case line_type::dashed: - dashed_arc(start, cent, end, lt); - break; - case line_type::dotted: - dotted_arc(start, cent, end, lt); - break; - case line_type::solid: - { - position c; - if (!compute_arc_center(start, cent, end, &c)) { - line(start, &end, 1, lt); - break; - } - solid_arc(c, - hypot(cent - start), - atan2(start.y - c.y, start.x - c.x), - atan2(end.y - c.y, end.x - c.x), - lt); - break; - } - } -} - -void tex_output::circle(const position ¢, double rad, - const line_type <, double fill) -{ - if (fill >= 0.0 && lt.type != line_type::solid) { - if (fill > 1.0) - fill = 1.0; - line_type ilt; - ilt.type = line_type::invisible; - ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill); - } - switch (lt.type) { - case line_type::dashed: - dashed_circle(cent, rad, lt); - break; - case line_type::invisible: - break; - case line_type::solid: - ellipse(cent, position(rad*2.0,rad*2.0), lt, fill); - break; - case line_type::dotted: - dotted_circle(cent, rad, lt); - break; - default: - assert(0); - } -} - -void tex_output::ellipse(const position ¢, const distance &dim, - const line_type <, double fill) -{ - if (lt.type == line_type::invisible) { - if (fill < 0.0) - return; - } - else - set_pen_size(lt.thickness); - if (fill >= 0.0) { - if (fill > 1.0) - fill = 1.0; - printf(" \\special{sh %.3f}%%\n", fill); - } - position c = transform(cent); - printf(" \\special{%s %d %d %d %d 0 6.28319}%%\n", - (lt.type == line_type::invisible ? "ia" : "ar"), - milliinches(c.x), - milliinches(c.y), - milliinches(dim.x/(2.0*scale)), - milliinches(dim.y/(2.0*scale))); -} - -void tex_output::command(const char *s, const char *, int) -{ - fputs(s, stdout); - putchar('%'); // avoid unwanted spaces - putchar('\n'); -} - -int tex_output::supports_filled_polygons() -{ - return 1; -} - -void tex_output::dot(const position &pos, const line_type <) -{ - if (zero_length_line_flag) { - line_type slt = lt; - slt.type = line_type::solid; - line(pos, &pos, 1, slt); - } - else { - int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5); - if (dot_rad == 0) - dot_rad = 1; - position p = transform(pos); - printf(" \\special{sh 1}%%\n" - " \\special{ia %d %d %d %d 0 6.28319}%%\n", - milliinches(p.x), milliinches(p.y), dot_rad, dot_rad); - } -} - -void tex_output::set_color(char *, char *) -{ - /* not implemented yet */ -} - -void tex_output::reset_color() -{ - /* not implemented yet */ -} - -char *tex_output::get_last_filled() -{ - /* not implemented yet */ - return NULL; -} - -char *tex_output::get_outline_color() -{ - /* not implemented yet */ - return NULL; -} - -class tpic_output : public tex_output { -public: - tpic_output(); - void command(const char *, const char *, int); -private: - void set_pen_size(double ps); - int default_pen_size; - int prev_default_pen_size; -}; - -tpic_output::tpic_output() -: default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE) -{ -} - -void tpic_output::command(const char *s, const char *filename, int lineno) -{ - assert(s[0] == '.'); - if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) { - const char *p = s + 3; - while (csspace(*p)) - p++; - if (*p == '\0') { - int temp = default_pen_size; - default_pen_size = prev_default_pen_size; - prev_default_pen_size = temp; - } - else { - char *ptr; - int temp = (int)strtol(p, &ptr, 10); - if (temp == 0 && ptr == p) - error_with_file_and_line(filename, lineno, - "argument to `.ps' not an integer"); - else if (temp < 0) - error_with_file_and_line(filename, lineno, - "negative pen size"); - else { - prev_default_pen_size = default_pen_size; - default_pen_size = temp; - } - } - } - else - printf("\\%s%%\n", s + 1); -} - -void tpic_output::set_pen_size(double ps) -{ - if (ps < 0.0) - printf(" \\special{pn %d}%%\n", default_pen_size); - else - tex_output::set_pen_size(ps); -} - -output *make_tpic_output() -{ - return new tpic_output; -} - -#endif diff --git a/contrib/groff/src/preproc/pic/troff.cc b/contrib/groff/src/preproc/pic/troff.cc deleted file mode 100644 index 7ee7293..0000000 --- a/contrib/groff/src/preproc/pic/troff.cc +++ /dev/null @@ -1,561 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "pic.h" -#include "common.h" - - -const double RELATIVE_THICKNESS = -1.0; -const double BAD_THICKNESS = -2.0; - -class simple_output : public common_output { - virtual void simple_line(const position &, const position &) = 0; - virtual void simple_spline(const position &, const position *, int n) = 0; - virtual void simple_arc(const position &, const position &, - const position &) = 0; - virtual void simple_circle(int, const position &, double rad) = 0; - virtual void simple_ellipse(int, const position &, const distance &) = 0; - virtual void simple_polygon(int, const position *, int) = 0; - virtual void line_thickness(double) = 0; - virtual void set_fill(double) = 0; - virtual void set_color(char *, char *) = 0; - virtual void reset_color() = 0; - virtual char *get_last_filled() = 0; - void dot(const position &, const line_type &) = 0; -public: - void start_picture(double sc, const position &ll, const position &ur) = 0; - void finish_picture() = 0; - void text(const position &, text_piece *, int, double) = 0; - void line(const position &, const position *, int n, - const line_type &); - void polygon(const position *, int n, - const line_type &, double); - void spline(const position &, const position *, int n, - const line_type &); - void arc(const position &, const position &, const position &, - const line_type &); - void circle(const position &, double rad, const line_type &, double); - void ellipse(const position &, const distance &, const line_type &, double); - int supports_filled_polygons(); -}; - -int simple_output::supports_filled_polygons() -{ - return driver_extension_flag != 0; -} - -void simple_output::arc(const position &start, const position ¢, - const position &end, const line_type <) -{ - switch (lt.type) { - case line_type::solid: - line_thickness(lt.thickness); - simple_arc(start, cent, end); - break; - case line_type::invisible: - break; - case line_type::dashed: - dashed_arc(start, cent, end, lt); - break; - case line_type::dotted: - dotted_arc(start, cent, end, lt); - break; - } -} - -void simple_output::line(const position &start, const position *v, int n, - const line_type <) -{ - position pos = start; - line_thickness(lt.thickness); - for (int i = 0; i < n; i++) { - switch (lt.type) { - case line_type::solid: - simple_line(pos, v[i]); - break; - case line_type::dotted: - { - distance vec(v[i] - pos); - double dist = hypot(vec); - int ndots = int(dist/lt.dash_width + .5); - if (ndots == 0) - dot(pos, lt); - else { - vec /= double(ndots); - for (int j = 0; j <= ndots; j++) - dot(pos + vec*j, lt); - } - } - break; - case line_type::dashed: - { - distance vec(v[i] - pos); - double dist = hypot(vec); - if (dist <= lt.dash_width*2.0) - simple_line(pos, v[i]); - else { - int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5); - distance dash_vec = vec*(lt.dash_width/dist); - double dash_gap = (dist - lt.dash_width)/ndashes; - distance dash_gap_vec = vec*(dash_gap/dist); - for (int j = 0; j <= ndashes; j++) { - position s(pos + dash_gap_vec*j); - simple_line(s, s + dash_vec); - } - } - } - break; - case line_type::invisible: - break; - default: - assert(0); - } - pos = v[i]; - } -} - -void simple_output::spline(const position &start, const position *v, int n, - const line_type <) -{ - line_thickness(lt.thickness); - simple_spline(start, v, n); -} - -void simple_output::polygon(const position *v, int n, - const line_type <, double fill) -{ - if (driver_extension_flag && ((fill >= 0.0) || (get_last_filled() != 0))) { - if (get_last_filled() == 0) - set_fill(fill); - simple_polygon(1, v, n); - } - if (lt.type == line_type::solid && driver_extension_flag) { - line_thickness(lt.thickness); - simple_polygon(0, v, n); - } - else if (lt.type != line_type::invisible) { - line_thickness(lt.thickness); - line(v[n - 1], v, n, lt); - } -} - -void simple_output::circle(const position ¢, double rad, - const line_type <, double fill) -{ - if (driver_extension_flag && ((fill >= 0.0) || (get_last_filled() != 0))) { - if (get_last_filled() == 0) - set_fill(fill); - simple_circle(1, cent, rad); - } - line_thickness(lt.thickness); - switch (lt.type) { - case line_type::invisible: - break; - case line_type::dashed: - dashed_circle(cent, rad, lt); - break; - case line_type::dotted: - dotted_circle(cent, rad, lt); - break; - case line_type::solid: - simple_circle(0, cent, rad); - break; - default: - assert(0); - } -} - -void simple_output::ellipse(const position ¢, const distance &dim, - const line_type <, double fill) -{ - if (driver_extension_flag && ((fill >= 0.0) || (get_last_filled() != 0))) { - if (get_last_filled() == 0) - set_fill(fill); - simple_ellipse(1, cent, dim); - } - if (lt.type != line_type::invisible) - line_thickness(lt.thickness); - switch (lt.type) { - case line_type::invisible: - break; - case line_type::dotted: - case line_type::dashed: - case line_type::solid: - simple_ellipse(0, cent, dim); - break; - default: - assert(0); - } -} - -#define FILL_MAX 1000 - -class troff_output : public simple_output { - const char *last_filename; - position upper_left; - double height; - double scale; - double last_line_thickness; - double last_fill; - char *last_filled; // color - char *last_outlined; // color -public: - troff_output(); - ~troff_output(); - void start_picture(double, const position &ll, const position &ur); - void finish_picture(); - void text(const position &, text_piece *, int, double); - void dot(const position &, const line_type &); - void command(const char *, const char *, int); - void set_location(const char *, int); - void simple_line(const position &, const position &); - void simple_spline(const position &, const position *, int n); - void simple_arc(const position &, const position &, const position &); - void simple_circle(int, const position &, double rad); - void simple_ellipse(int, const position &, const distance &); - void simple_polygon(int, const position *, int); - void line_thickness(double p); - void set_fill(double); - void set_color(char *, char *); - void reset_color(); - char *get_last_filled(); - char *get_outline_color(); - position transform(const position &); -}; - -output *make_troff_output() -{ - return new troff_output; -} - -troff_output::troff_output() -: last_filename(0), last_line_thickness(BAD_THICKNESS), - last_fill(-1.0), last_filled(0), last_outlined(0) -{ -} - -troff_output::~troff_output() -{ -} - -inline position troff_output::transform(const position &pos) -{ - return position((pos.x - upper_left.x)/scale, - (upper_left.y - pos.y)/scale); -} - -#define FILL_REG "00" - -// If this register > 0, then pic will generate \X'ps: ...' commands -// if the aligned attribute is used. -#define GROPS_REG "0p" - -// If this register is defined, geqn won't produce `\x's. -#define EQN_NO_EXTRA_SPACE_REG "0x" - -void troff_output::start_picture(double sc, - const position &ll, const position &ur) -{ - upper_left.x = ll.x; - upper_left.y = ur.y; - scale = compute_scale(sc, ll, ur); - height = (ur.y - ll.y)/scale; - double width = (ur.x - ll.x)/scale; - printf(".PS %.3fi %.3fi", height, width); - if (args) - printf(" %s\n", args); - else - putchar('\n'); - printf(".\\\" %g %g %g %g\n", ll.x, ll.y, ur.x, ur.y); - printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height, width, 0.0); - printf(".nr " FILL_REG " \\n(.u\n.nf\n"); - printf(".nr " EQN_NO_EXTRA_SPACE_REG " 1\n"); - // This guarantees that if the picture is used in a diversion it will - // have the right width. - printf("\\h'%.3fi'\n.sp -1\n", width); -} - -void troff_output::finish_picture() -{ - line_thickness(BAD_THICKNESS); - last_fill = -1.0; // force it to be reset for each picture - reset_color(); - if (!flyback_flag) - printf(".sp %.3fi+1\n", height); - printf(".if \\n(" FILL_REG " .fi\n"); - printf(".br\n"); - printf(".nr " EQN_NO_EXTRA_SPACE_REG " 0\n"); - // this is a little gross - set_location(current_filename, current_lineno); - fputs(flyback_flag ? ".PF\n" : ".PE\n", stdout); -} - -void troff_output::command(const char *s, - const char *filename, int lineno) -{ - if (filename != 0) - set_location(filename, lineno); - fputs(s, stdout); - putchar('\n'); -} - -void troff_output::simple_circle(int filled, const position ¢, double rad) -{ - position c = transform(cent); - printf("\\h'%.3fi'" - "\\v'%.3fi'" - "\\D'%c%.3fi'" - "\n.sp -1\n", - c.x - rad/scale, - c.y, - (filled ? 'C' : 'c'), - rad*2.0/scale); -} - -void troff_output::simple_ellipse(int filled, const position ¢, - const distance &dim) -{ - position c = transform(cent); - printf("\\h'%.3fi'" - "\\v'%.3fi'" - "\\D'%c%.3fi %.3fi'" - "\n.sp -1\n", - c.x - dim.x/(2.0*scale), - c.y, - (filled ? 'E' : 'e'), - dim.x/scale, dim.y/scale); -} - -void troff_output::simple_arc(const position &start, const distance ¢, - const distance &end) -{ - position s = transform(start); - position c = transform(cent); - distance cv = c - s; - distance ev = transform(end) - c; - printf("\\h'%.3fi'" - "\\v'%.3fi'" - "\\D'a%.3fi %.3fi %.3fi %.3fi'" - "\n.sp -1\n", - s.x, s.y, cv.x, cv.y, ev.x, ev.y); -} - -void troff_output::simple_line(const position &start, const position &end) -{ - position s = transform(start); - distance ev = transform(end) - s; - printf("\\h'%.3fi'" - "\\v'%.3fi'" - "\\D'l%.3fi %.3fi'" - "\n.sp -1\n", - s.x, s.y, ev.x, ev.y); -} - -void troff_output::simple_spline(const position &start, - const position *v, int n) -{ - position pos = transform(start); - printf("\\h'%.3fi'" - "\\v'%.3fi'", - pos.x, pos.y); - fputs("\\D'~", stdout); - for (int i = 0; i < n; i++) { - position temp = transform(v[i]); - distance d = temp - pos; - pos = temp; - if (i != 0) - putchar(' '); - printf("%.3fi %.3fi", d.x, d.y); - } - printf("'\n.sp -1\n"); -} - -// a solid polygon - -void troff_output::simple_polygon(int filled, const position *v, int n) -{ - position pos = transform(v[0]); - printf("\\h'%.3fi'" - "\\v'%.3fi'", - pos.x, pos.y); - printf("\\D'%c", (filled ? 'P' : 'p')); - for (int i = 1; i < n; i++) { - position temp = transform(v[i]); - distance d = temp - pos; - pos = temp; - if (i != 1) - putchar(' '); - printf("%.3fi %.3fi", d.x, d.y); - } - printf("'\n.sp -1\n"); -} - -const double TEXT_AXIS = 0.22; // in ems - -static const char *choose_delimiter(const char *text) -{ - if (strchr(text, '\'') == 0) - return "'"; - else - return "\\(ts"; -} - -void troff_output::text(const position ¢er, text_piece *v, int n, - double ang) -{ - line_thickness(BAD_THICKNESS); // the text might use lines (eg in equations) - int rotate_flag = 0; - if (driver_extension_flag && ang != 0.0) { - rotate_flag = 1; - position c = transform(center); - printf(".if \\n(" GROPS_REG " \\{\\\n" - "\\h'%.3fi'" - "\\v'%.3fi'" - "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'" - "\n.sp -1\n" - ".\\}\n", - c.x, c.y, -ang*180.0/M_PI); - } - for (int i = 0; i < n; i++) - if (v[i].text != 0 && *v[i].text != '\0') { - position c = transform(center); - if (v[i].filename != 0) - set_location(v[i].filename, v[i].lineno); - printf("\\h'%.3fi", c.x); - const char *delim = choose_delimiter(v[i].text); - if (v[i].adj.h == RIGHT_ADJUST) - printf("-\\w%s%s%su", delim, v[i].text, delim); - else if (v[i].adj.h != LEFT_ADJUST) - printf("-(\\w%s%s%su/2u)", delim, v[i].text, delim); - putchar('\''); - printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm", - c.y, - n - 1, - i, - TEXT_AXIS); - if (v[i].adj.v == ABOVE_ADJUST) - printf("-.5v"); - else if (v[i].adj.v == BELOW_ADJUST) - printf("+.5v"); - putchar('\''); - fputs(v[i].text, stdout); - fputs("\n.sp -1\n", stdout); - } - if (rotate_flag) - printf(".if '\\*(.T'ps' \\{\\\n" - "\\X'ps: exec grestore'\n.sp -1\n" - ".\\}\n"); -} - -void troff_output::line_thickness(double p) -{ - if (p < 0.0) - p = RELATIVE_THICKNESS; - if (driver_extension_flag && p != last_line_thickness) { - printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p, -p); - last_line_thickness = p; - } -} - -void troff_output::set_fill(double f) -{ - if (driver_extension_flag && f != last_fill) { - printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f*FILL_MAX), -int(f*FILL_MAX)); - last_fill = f; - } - if (last_filled) { - free(last_filled); - last_filled = 0; - printf("\\M[]\n.sp -1\n"); - } -} - -void troff_output::set_color(char *color_fill, char *color_outlined) -{ - if (driver_extension_flag) { - if (last_filled || last_outlined) { - reset_color(); - } - if (color_fill) { - printf("\\M[%s]\n.sp -1\n", color_fill); - last_filled = strdup(color_fill); - } - if (color_outlined) { - printf("\\m[%s]\n.sp -1\n", color_outlined); - last_outlined = strdup(color_outlined); - } - } -} - -void troff_output::reset_color() -{ - if (driver_extension_flag) { - if (last_filled) { - printf("\\M[]\n.sp -1\n"); - free(last_filled); - last_filled = 0; - } - if (last_outlined) { - printf("\\m[]\n.sp -1\n"); - free(last_outlined); - last_outlined = 0; - } - } -} - -char *troff_output::get_last_filled() -{ - return last_filled; -} - -char *troff_output::get_outline_color() -{ - return last_outlined; -} - -const double DOT_AXIS = .044; - -void troff_output::dot(const position ¢, const line_type <) -{ - if (driver_extension_flag) { - line_thickness(lt.thickness); - simple_line(cent, cent); - } - else { - position c = transform(cent); - printf("\\h'%.3fi-(\\w'.'u/2u)'" - "\\v'%.3fi+%.2fm'" - ".\n.sp -1\n", - c.x, - c.y, - DOT_AXIS); - } -} - -void troff_output::set_location(const char *s, int n) -{ - if (last_filename != 0 && strcmp(s, last_filename) == 0) - printf(".lf %d\n", n); - else { - printf(".lf %d %s\n", n, s); - last_filename = s; - } -} diff --git a/contrib/groff/src/preproc/refer/command.cc b/contrib/groff/src/preproc/refer/command.cc deleted file mode 100644 index a7c6bfb..0000000 --- a/contrib/groff/src/preproc/refer/command.cc +++ /dev/null @@ -1,809 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 - 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 "refer.h" -#include "refid.h" -#include "search.h" -#include "command.h" - -cset cs_field_name = csalpha; - -class input_item { - input_item *next; - char *filename; - int first_lineno; - string buffer; - const char *ptr; - const char *end; -public: - input_item(string &, const char *, int = 1); - ~input_item(); - int get_char(); - int peek_char(); - void skip_char(); - int get_location(const char **, int *); - - friend class input_stack; -}; - -input_item::input_item(string &s, const char *fn, int ln) -: filename(strsave(fn)), first_lineno(ln) -{ - buffer.move(s); - ptr = buffer.contents(); - end = ptr + buffer.length(); -} - -input_item::~input_item() -{ - a_delete filename; -} - -inline int input_item::peek_char() -{ - if (ptr >= end) - return EOF; - else - return (unsigned char)*ptr; -} - -inline int input_item::get_char() -{ - if (ptr >= end) - return EOF; - else - return (unsigned char)*ptr++; -} - -inline void input_item::skip_char() -{ - ptr++; -} - -int input_item::get_location(const char **filenamep, int *linenop) -{ - *filenamep = filename; - if (ptr == buffer.contents()) - *linenop = first_lineno; - else { - int ln = first_lineno; - const char *e = ptr - 1; - for (const char *p = buffer.contents(); p < e; p++) - if (*p == '\n') - ln++; - *linenop = ln; - } - return 1; -} - -class input_stack { - static input_item *top; -public: - static void init(); - static int get_char(); - static int peek_char(); - static void skip_char() { top->skip_char(); } - static void push_file(const char *); - static void push_string(string &, const char *, int); - static void error(const char *format, - const errarg &arg1 = empty_errarg, - const errarg &arg2 = empty_errarg, - const errarg &arg3 = empty_errarg); -}; - -input_item *input_stack::top = 0; - -void input_stack::init() -{ - while (top) { - input_item *tem = top; - top = top->next; - delete tem; - } -} - -int input_stack::get_char() -{ - while (top) { - int c = top->get_char(); - if (c >= 0) - return c; - input_item *tem = top; - top = top->next; - delete tem; - } - return -1; -} - -int input_stack::peek_char() -{ - while (top) { - int c = top->peek_char(); - if (c >= 0) - return c; - input_item *tem = top; - top = top->next; - delete tem; - } - return -1; -} - -void input_stack::push_file(const char *fn) -{ - FILE *fp; - if (strcmp(fn, "-") == 0) { - fp = stdin; - fn = ""; - } - else { - errno = 0; - fp = fopen(fn, "r"); - if (fp == 0) { - error("can't open `%1': %2", fn, strerror(errno)); - return; - } - } - string buf; - int bol = 1; - int lineno = 1; - for (;;) { - int c = getc(fp); - if (bol && c == '.') { - // replace lines beginning with .R1 or .R2 with a blank line - c = getc(fp); - if (c == 'R') { - c = getc(fp); - if (c == '1' || c == '2') { - int cc = c; - c = getc(fp); - if (compatible_flag || c == ' ' || c == '\n' || c == EOF) { - while (c != '\n' && c != EOF) - c = getc(fp); - } - else { - buf += '.'; - buf += 'R'; - buf += cc; - } - } - else { - buf += '.'; - buf += 'R'; - } - } - else - buf += '.'; - } - if (c == EOF) - break; - if (invalid_input_char(c)) - error_with_file_and_line(fn, lineno, - "invalid input character code %1", int(c)); - else { - buf += c; - if (c == '\n') { - bol = 1; - lineno++; - } - else - bol = 0; - } - } - if (fp != stdin) - fclose(fp); - if (buf.length() > 0 && buf[buf.length() - 1] != '\n') - buf += '\n'; - input_item *it = new input_item(buf, fn); - it->next = top; - top = it; -} - -void input_stack::push_string(string &s, const char *filename, int lineno) -{ - input_item *it = new input_item(s, filename, lineno); - it->next = top; - top = it; -} - -void input_stack::error(const char *format, const errarg &arg1, - const errarg &arg2, const errarg &arg3) -{ - const char *filename; - int lineno; - for (input_item *it = top; it; it = it->next) - if (it->get_location(&filename, &lineno)) { - error_with_file_and_line(filename, lineno, format, arg1, arg2, arg3); - return; - } - ::error(format, arg1, arg2, arg3); -} - -void command_error(const char *format, const errarg &arg1, - const errarg &arg2, const errarg &arg3) -{ - input_stack::error(format, arg1, arg2, arg3); -} - -// # not recognized in "" -// \ is recognized in "" -// # does not conceal newline -// if missing closing quote, word extends to end of line -// no special treatment of \ other than before newline -// \ not recognized after # -// ; allowed as alternative to newline -// ; not recognized in "" -// don't clear word_buffer; just append on -// return -1 for EOF, 0 for newline, 1 for word - -int get_word(string &word_buffer) -{ - int c = input_stack::get_char(); - for (;;) { - if (c == '#') { - do { - c = input_stack::get_char(); - } while (c != '\n' && c != EOF); - break; - } - if (c == '\\' && input_stack::peek_char() == '\n') - input_stack::skip_char(); - else if (c != ' ' && c != '\t') - break; - c = input_stack::get_char(); - } - if (c == EOF) - return -1; - if (c == '\n' || c == ';') - return 0; - if (c == '"') { - for (;;) { - c = input_stack::peek_char(); - if (c == EOF || c == '\n') - break; - input_stack::skip_char(); - if (c == '"') { - int d = input_stack::peek_char(); - if (d == '"') - input_stack::skip_char(); - else - break; - } - else if (c == '\\') { - int d = input_stack::peek_char(); - if (d == '\n') - input_stack::skip_char(); - else - word_buffer += '\\'; - } - else - word_buffer += c; - } - return 1; - } - word_buffer += c; - for (;;) { - c = input_stack::peek_char(); - if (c == ' ' || c == '\t' || c == '\n' || c == '#' || c == ';') - break; - input_stack::skip_char(); - if (c == '\\') { - int d = input_stack::peek_char(); - if (d == '\n') - input_stack::skip_char(); - else - word_buffer += '\\'; - } - else - word_buffer += c; - } - return 1; -} - -union argument { - const char *s; - int n; -}; - -// This is for debugging. - -static void echo_command(int argc, argument *argv) -{ - for (int i = 0; i < argc; i++) - fprintf(stderr, "%s\n", argv[i].s); -} - -static void include_command(int argc, argument *argv) -{ - assert(argc == 1); - input_stack::push_file(argv[0].s); -} - -static void capitalize_command(int argc, argument *argv) -{ - if (argc > 0) - capitalize_fields = argv[0].s; - else - capitalize_fields.clear(); -} - -static void accumulate_command(int, argument *) -{ - accumulate = 1; -} - -static void no_accumulate_command(int, argument *) -{ - accumulate = 0; -} - -static void move_punctuation_command(int, argument *) -{ - move_punctuation = 1; -} - -static void no_move_punctuation_command(int, argument *) -{ - move_punctuation = 0; -} - -static void sort_command(int argc, argument *argv) -{ - if (argc == 0) - sort_fields = "AD"; - else - sort_fields = argv[0].s; - accumulate = 1; -} - -static void no_sort_command(int, argument *) -{ - sort_fields.clear(); -} - -static void articles_command(int argc, argument *argv) -{ - articles.clear(); - int i; - for (i = 0; i < argc; i++) { - articles += argv[i].s; - articles += '\0'; - } - int len = articles.length(); - for (i = 0; i < len; i++) - articles[i] = cmlower(articles[i]); -} - -static void database_command(int argc, argument *argv) -{ - for (int i = 0; i < argc; i++) - database_list.add_file(argv[i].s); -} - -static void default_database_command(int, argument *) -{ - search_default = 1; -} - -static void no_default_database_command(int, argument *) -{ - search_default = 0; -} - -static void bibliography_command(int argc, argument *argv) -{ - const char *saved_filename = current_filename; - int saved_lineno = current_lineno; - int saved_label_in_text = label_in_text; - label_in_text = 0; - if (!accumulate) - fputs(".]<\n", stdout); - for (int i = 0; i < argc; i++) - do_bib(argv[i].s); - if (accumulate) - output_references(); - else - fputs(".]>\n", stdout); - current_filename = saved_filename; - current_lineno = saved_lineno; - label_in_text = saved_label_in_text; -} - -static void annotate_command(int argc, argument *argv) -{ - if (argc > 0) - annotation_field = argv[0].s[0]; - else - annotation_field = 'X'; - if (argc == 2) - annotation_macro = argv[1].s; - else - annotation_macro = "AP"; -} - -static void no_annotate_command(int, argument *) -{ - annotation_macro.clear(); - annotation_field = -1; -} - -static void reverse_command(int, argument *argv) -{ - reverse_fields = argv[0].s; -} - -static void no_reverse_command(int, argument *) -{ - reverse_fields.clear(); -} - -static void abbreviate_command(int argc, argument *argv) -{ - abbreviate_fields = argv[0].s; - period_before_initial = argc > 1 ? argv[1].s : ". "; - period_before_last_name = argc > 2 ? argv[2].s : ". "; - period_before_other = argc > 3 ? argv[3].s : ". "; - period_before_hyphen = argc > 4 ? argv[4].s : "."; -} - -static void no_abbreviate_command(int, argument *) -{ - abbreviate_fields.clear(); -} - -string search_ignore_fields; - -static void search_ignore_command(int argc, argument *argv) -{ - if (argc > 0) - search_ignore_fields = argv[0].s; - else - search_ignore_fields = "XYZ"; - search_ignore_fields += '\0'; - linear_ignore_fields = search_ignore_fields.contents(); -} - -static void no_search_ignore_command(int, argument *) -{ - linear_ignore_fields = ""; -} - -static void search_truncate_command(int argc, argument *argv) -{ - if (argc > 0) - linear_truncate_len = argv[0].n; - else - linear_truncate_len = 6; -} - -static void no_search_truncate_command(int, argument *) -{ - linear_truncate_len = -1; -} - -static void discard_command(int argc, argument *argv) -{ - if (argc == 0) - discard_fields = "XYZ"; - else - discard_fields = argv[0].s; - accumulate = 1; -} - -static void no_discard_command(int, argument *) -{ - discard_fields.clear(); -} - -static void label_command(int, argument *argv) -{ - set_label_spec(argv[0].s); -} - -static void abbreviate_label_ranges_command(int argc, argument *argv) -{ - abbreviate_label_ranges = 1; - label_range_indicator = argc > 0 ? argv[0].s : "-"; -} - -static void no_abbreviate_label_ranges_command(int, argument *) -{ - abbreviate_label_ranges = 0; -} - -static void label_in_reference_command(int, argument *) -{ - label_in_reference = 1; -} - -static void no_label_in_reference_command(int, argument *) -{ - label_in_reference = 0; -} - -static void label_in_text_command(int, argument *) -{ - label_in_text = 1; -} - -static void no_label_in_text_command(int, argument *) -{ - label_in_text = 0; -} - -static void sort_adjacent_labels_command(int, argument *) -{ - sort_adjacent_labels = 1; -} - -static void no_sort_adjacent_labels_command(int, argument *) -{ - sort_adjacent_labels = 0; -} - -static void date_as_label_command(int argc, argument *argv) -{ - if (set_date_label_spec(argc > 0 ? argv[0].s : "D%a*")) - date_as_label = 1; -} - -static void no_date_as_label_command(int, argument *) -{ - date_as_label = 0; -} - -static void short_label_command(int, argument *argv) -{ - if (set_short_label_spec(argv[0].s)) - short_label_flag = 1; -} - -static void no_short_label_command(int, argument *) -{ - short_label_flag = 0; -} - -static void compatible_command(int, argument *) -{ - compatible_flag = 1; -} - -static void no_compatible_command(int, argument *) -{ - compatible_flag = 0; -} - -static void join_authors_command(int argc, argument *argv) -{ - join_authors_exactly_two = argv[0].s; - join_authors_default = argc > 1 ? argv[1].s : argv[0].s; - join_authors_last_two = argc == 3 ? argv[2].s : argv[0].s; -} - -static void bracket_label_command(int, argument *argv) -{ - pre_label = argv[0].s; - post_label = argv[1].s; - sep_label = argv[2].s; -} - -static void separate_label_second_parts_command(int, argument *argv) -{ - separate_label_second_parts = argv[0].s; -} - -static void et_al_command(int argc, argument *argv) -{ - et_al = argv[0].s; - et_al_min_elide = argv[1].n; - if (et_al_min_elide < 1) - et_al_min_elide = 1; - et_al_min_total = argc >= 3 ? argv[2].n : 0; -} - -static void no_et_al_command(int, argument *) -{ - et_al.clear(); - et_al_min_elide = 0; -} - -typedef void (*command_t)(int, argument *); - -/* arg_types is a string describing the numbers and types of arguments. -s means a string, i means an integer, f is a list of fields, F is -a single field, -? means that the previous argument is optional, * means that the -previous argument can occur any number of times. */ - -struct { - const char *name; - command_t func; - const char *arg_types; -} command_table[] = { - { "include", include_command, "s" }, - { "echo", echo_command, "s*" }, - { "capitalize", capitalize_command, "f?" }, - { "accumulate", accumulate_command, "" }, - { "no-accumulate", no_accumulate_command, "" }, - { "move-punctuation", move_punctuation_command, "" }, - { "no-move-punctuation", no_move_punctuation_command, "" }, - { "sort", sort_command, "s?" }, - { "no-sort", no_sort_command, "" }, - { "articles", articles_command, "s*" }, - { "database", database_command, "ss*" }, - { "default-database", default_database_command, "" }, - { "no-default-database", no_default_database_command, "" }, - { "bibliography", bibliography_command, "ss*" }, - { "annotate", annotate_command, "F?s?" }, - { "no-annotate", no_annotate_command, "" }, - { "reverse", reverse_command, "s" }, - { "no-reverse", no_reverse_command, "" }, - { "abbreviate", abbreviate_command, "ss?s?s?s?" }, - { "no-abbreviate", no_abbreviate_command, "" }, - { "search-ignore", search_ignore_command, "f?" }, - { "no-search-ignore", no_search_ignore_command, "" }, - { "search-truncate", search_truncate_command, "i?" }, - { "no-search-truncate", no_search_truncate_command, "" }, - { "discard", discard_command, "f?" }, - { "no-discard", no_discard_command, "" }, - { "label", label_command, "s" }, - { "abbreviate-label-ranges", abbreviate_label_ranges_command, "s?" }, - { "no-abbreviate-label-ranges", no_abbreviate_label_ranges_command, "" }, - { "label-in-reference", label_in_reference_command, "" }, - { "no-label-in-reference", no_label_in_reference_command, "" }, - { "label-in-text", label_in_text_command, "" }, - { "no-label-in-text", no_label_in_text_command, "" }, - { "sort-adjacent-labels", sort_adjacent_labels_command, "" }, - { "no-sort-adjacent-labels", no_sort_adjacent_labels_command, "" }, - { "date-as-label", date_as_label_command, "s?" }, - { "no-date-as-label", no_date_as_label_command, "" }, - { "short-label", short_label_command, "s" }, - { "no-short-label", no_short_label_command, "" }, - { "compatible", compatible_command, "" }, - { "no-compatible", no_compatible_command, "" }, - { "join-authors", join_authors_command, "sss?" }, - { "bracket-label", bracket_label_command, "sss" }, - { "separate-label-second-parts", separate_label_second_parts_command, "s" }, - { "et-al", et_al_command, "sii?" }, - { "no-et-al", no_et_al_command, "" }, -}; - -static int check_args(const char *types, const char *name, - int argc, argument *argv) -{ - int argno = 0; - while (*types) { - if (argc == 0) { - if (types[1] == '?') - break; - else if (types[1] == '*') { - assert(types[2] == '\0'); - break; - } - else { - input_stack::error("missing argument for command `%1'", name); - return 0; - } - } - switch (*types) { - case 's': - break; - case 'i': - { - char *ptr; - long n = strtol(argv->s, &ptr, 10); - if ((n == 0 && ptr == argv->s) - || *ptr != '\0') { - input_stack::error("argument %1 for command `%2' must be an integer", - argno + 1, name); - return 0; - } - argv->n = (int)n; - break; - } - case 'f': - { - for (const char *ptr = argv->s; *ptr != '\0'; ptr++) - if (!cs_field_name(*ptr)) { - input_stack::error("argument %1 for command `%2' must be a list of fields", - argno + 1, name); - return 0; - } - break; - } - case 'F': - if (argv->s[0] == '\0' || argv->s[1] != '\0' - || !cs_field_name(argv->s[0])) { - input_stack::error("argument %1 for command `%2' must be a field name", - argno + 1, name); - return 0; - } - break; - default: - assert(0); - } - if (types[1] == '?') - types += 2; - else if (types[1] != '*') - types += 1; - --argc; - ++argv; - ++argno; - } - if (argc > 0) { - input_stack::error("too many arguments for command `%1'", name); - return 0; - } - return 1; -} - -static void execute_command(const char *name, int argc, argument *argv) -{ - for (unsigned int i = 0; - i < sizeof(command_table)/sizeof(command_table[0]); i++) - if (strcmp(name, command_table[i].name) == 0) { - if (check_args(command_table[i].arg_types, name, argc, argv)) - (*command_table[i].func)(argc, argv); - return; - } - input_stack::error("unknown command `%1'", name); -} - -static void command_loop() -{ - string command; - for (;;) { - command.clear(); - int res = get_word(command); - if (res != 1) { - if (res == 0) - continue; - break; - } - int argc = 0; - command += '\0'; - while ((res = get_word(command)) == 1) { - argc++; - command += '\0'; - } - argument *argv = new argument[argc]; - const char *ptr = command.contents(); - for (int i = 0; i < argc; i++) - argv[i].s = ptr = strchr(ptr, '\0') + 1; - execute_command(command.contents(), argc, argv); - a_delete argv; - if (res == -1) - break; - } -} - -void process_commands(const char *file) -{ - input_stack::init(); - input_stack::push_file(file); - command_loop(); -} - -void process_commands(string &s, const char *file, int lineno) -{ - input_stack::init(); - input_stack::push_string(s, file, lineno); - command_loop(); -} diff --git a/contrib/groff/src/preproc/refer/ref.cc b/contrib/groff/src/preproc/refer/ref.cc deleted file mode 100644 index 9c04078..0000000 --- a/contrib/groff/src/preproc/refer/ref.cc +++ /dev/null @@ -1,1160 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001 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 "refer.h" -#include "refid.h" -#include "ref.h" -#include "token.h" - -static const char *find_day(const char *, const char *, const char **); -static int find_month(const char *start, const char *end); -static void abbreviate_names(string &); - -#define DEFAULT_ARTICLES "the\000a\000an" - -string articles(DEFAULT_ARTICLES, sizeof(DEFAULT_ARTICLES)); - -// Multiple occurrences of fields are separated by FIELD_SEPARATOR. -const char FIELD_SEPARATOR = '\0'; - -const char MULTI_FIELD_NAMES[] = "AE"; -const char *AUTHOR_FIELDS = "AQ"; - -enum { OTHER, JOURNAL_ARTICLE, BOOK, ARTICLE_IN_BOOK, TECH_REPORT, BELL_TM }; - -const char *reference_types[] = { - "other", - "journal-article", - "book", - "article-in-book", - "tech-report", - "bell-tm", -}; - -static string temp_fields[256]; - -reference::reference(const char *start, int len, reference_id *ridp) -: h(0), merged(0), no(-1), field(0), nfields(0), label_ptr(0), - computed_authors(0), last_needed_author(-1), nauthors(-1) -{ - int i; - for (i = 0; i < 256; i++) - field_index[i] = NULL_FIELD_INDEX; - if (ridp) - rid = *ridp; - if (start == 0) - return; - if (len <= 0) - return; - const char *end = start + len; - const char *ptr = start; - assert(*ptr == '%'); - while (ptr < end) { - if (ptr + 1 < end && ptr[1] != '\0' - && ((ptr[1] != '%' && ptr[1] == annotation_field) - || (ptr + 2 < end && ptr[1] == '%' && ptr[2] != '\0' - && discard_fields.search(ptr[2]) < 0))) { - if (ptr[1] == '%') - ptr++; - string &f = temp_fields[(unsigned char)ptr[1]]; - ptr += 2; - while (ptr < end && csspace(*ptr)) - ptr++; - for (;;) { - for (;;) { - if (ptr >= end) { - f += '\n'; - break; - } - f += *ptr; - if (*ptr++ == '\n') - break; - } - if (ptr >= end || *ptr == '%') - break; - } - } - else if (ptr + 1 < end && ptr[1] != '\0' && ptr[1] != '%' - && discard_fields.search(ptr[1]) < 0) { - string &f = temp_fields[(unsigned char)ptr[1]]; - if (f.length() > 0) { - if (strchr(MULTI_FIELD_NAMES, ptr[1]) != 0) - f += FIELD_SEPARATOR; - else - f.clear(); - } - ptr += 2; - if (ptr < end) { - if (*ptr == ' ') - ptr++; - for (;;) { - const char *p = ptr; - while (ptr < end && *ptr != '\n') - ptr++; - // strip trailing white space - const char *q = ptr; - while (q > p && q[-1] != '\n' && csspace(q[-1])) - q--; - while (p < q) - f += *p++; - if (ptr >= end) - break; - ptr++; - if (ptr >= end) - break; - if (*ptr == '%') - break; - f += ' '; - } - } - } - else { - // skip this field - for (;;) { - while (ptr < end && *ptr++ != '\n') - ; - if (ptr >= end || *ptr == '%') - break; - } - } - } - for (i = 0; i < 256; i++) - if (temp_fields[i].length() > 0) - nfields++; - field = new string[nfields]; - int j = 0; - for (i = 0; i < 256; i++) - if (temp_fields[i].length() > 0) { - field[j].move(temp_fields[i]); - if (abbreviate_fields.search(i) >= 0) - abbreviate_names(field[j]); - field_index[i] = j; - j++; - } -} - -reference::~reference() -{ - if (nfields > 0) - ad_delete(nfields) field; -} - -// ref is the inline, this is the database ref - -void reference::merge(reference &ref) -{ - int i; - for (i = 0; i < 256; i++) - if (field_index[i] != NULL_FIELD_INDEX) - temp_fields[i].move(field[field_index[i]]); - for (i = 0; i < 256; i++) - if (ref.field_index[i] != NULL_FIELD_INDEX) - temp_fields[i].move(ref.field[ref.field_index[i]]); - for (i = 0; i < 256; i++) - field_index[i] = NULL_FIELD_INDEX; - int old_nfields = nfields; - nfields = 0; - for (i = 0; i < 256; i++) - if (temp_fields[i].length() > 0) - nfields++; - if (nfields != old_nfields) { - if (old_nfields > 0) - ad_delete(old_nfields) field; - field = new string[nfields]; - } - int j = 0; - for (i = 0; i < 256; i++) - if (temp_fields[i].length() > 0) { - field[j].move(temp_fields[i]); - field_index[i] = j; - j++; - } - merged = 1; -} - -void reference::insert_field(unsigned char c, string &s) -{ - assert(s.length() > 0); - if (field_index[c] != NULL_FIELD_INDEX) { - field[field_index[c]].move(s); - return; - } - assert(field_index[c] == NULL_FIELD_INDEX); - string *old_field = field; - field = new string[nfields + 1]; - int pos = 0; - int i; - for (i = 0; i < int(c); i++) - if (field_index[i] != NULL_FIELD_INDEX) - pos++; - for (i = 0; i < pos; i++) - field[i].move(old_field[i]); - field[pos].move(s); - for (i = pos; i < nfields; i++) - field[i + 1].move(old_field[i]); - if (nfields > 0) - ad_delete(nfields) old_field; - nfields++; - field_index[c] = pos; - for (i = c + 1; i < 256; i++) - if (field_index[i] != NULL_FIELD_INDEX) - field_index[i] += 1; -} - -void reference::delete_field(unsigned char c) -{ - if (field_index[c] == NULL_FIELD_INDEX) - return; - string *old_field = field; - field = new string[nfields - 1]; - int i; - for (i = 0; i < int(field_index[c]); i++) - field[i].move(old_field[i]); - for (i = field_index[c]; i < nfields - 1; i++) - field[i].move(old_field[i + 1]); - if (nfields > 0) - ad_delete(nfields) old_field; - nfields--; - field_index[c] = NULL_FIELD_INDEX; - for (i = c + 1; i < 256; i++) - if (field_index[i] != NULL_FIELD_INDEX) - field_index[i] -= 1; -} - -void reference::compute_hash_code() -{ - if (!rid.is_null()) - h = rid.hash(); - else { - h = 0; - for (int i = 0; i < nfields; i++) - if (field[i].length() > 0) { - h <<= 4; - h ^= hash_string(field[i].contents(), field[i].length()); - } - } -} - -void reference::set_number(int n) -{ - no = n; -} - -const char SORT_SEP = '\001'; -const char SORT_SUB_SEP = '\002'; -const char SORT_SUB_SUB_SEP = '\003'; - -// sep specifies additional word separators - -void sortify_words(const char *s, const char *end, const char *sep, - string &result) -{ - int non_empty = 0; - int need_separator = 0; - for (;;) { - const char *token_start = s; - if (!get_token(&s, end)) - break; - if ((s - token_start == 1 - && (*token_start == ' ' - || *token_start == '\n' - || (sep && *token_start != '\0' - && strchr(sep, *token_start) != 0))) - || (s - token_start == 2 - && token_start[0] == '\\' && token_start[1] == ' ')) { - if (non_empty) - need_separator = 1; - } - else { - const token_info *ti = lookup_token(token_start, s); - if (ti->sortify_non_empty(token_start, s)) { - if (need_separator) { - result += ' '; - need_separator = 0; - } - ti->sortify(token_start, s, result); - non_empty = 1; - } - } - } -} - -void sortify_word(const char *s, const char *end, string &result) -{ - for (;;) { - const char *token_start = s; - if (!get_token(&s, end)) - break; - const token_info *ti = lookup_token(token_start, s); - ti->sortify(token_start, s, result); - } -} - -void sortify_other(const char *s, int len, string &key) -{ - sortify_words(s, s + len, 0, key); -} - -void sortify_title(const char *s, int len, string &key) -{ - const char *end = s + len; - for (; s < end && (*s == ' ' || *s == '\n'); s++) - ; - const char *ptr = s; - for (;;) { - const char *token_start = ptr; - if (!get_token(&ptr, end)) - break; - if (ptr - token_start == 1 - && (*token_start == ' ' || *token_start == '\n')) - break; - } - if (ptr < end) { - unsigned int first_word_len = ptr - s - 1; - const char *ae = articles.contents() + articles.length(); - for (const char *a = articles.contents(); - a < ae; - a = strchr(a, '\0') + 1) - if (first_word_len == strlen(a)) { - unsigned int j; - for (j = 0; j < first_word_len; j++) - if (a[j] != cmlower(s[j])) - break; - if (j >= first_word_len) { - s = ptr; - for (; s < end && (*s == ' ' || *s == '\n'); s++) - ; - break; - } - } - } - sortify_words(s, end, 0, key); -} - -void sortify_name(const char *s, int len, string &key) -{ - const char *last_name_end; - const char *last_name = find_last_name(s, s + len, &last_name_end); - sortify_word(last_name, last_name_end, key); - key += SORT_SUB_SUB_SEP; - if (last_name > s) - sortify_words(s, last_name, ".", key); - key += SORT_SUB_SUB_SEP; - if (last_name_end < s + len) - sortify_words(last_name_end, s + len, ".,", key); -} - -void sortify_date(const char *s, int len, string &key) -{ - const char *year_end; - const char *year_start = find_year(s, s + len, &year_end); - if (!year_start) { - // Things without years are often `forthcoming', so it makes sense - // that they sort after things with explicit years. - key += 'A'; - sortify_words(s, s + len, 0, key); - return; - } - int n = year_end - year_start; - while (n < 4) { - key += '0'; - n++; - } - while (year_start < year_end) - key += *year_start++; - int m = find_month(s, s + len); - if (m < 0) - return; - key += 'A' + m; - const char *day_end; - const char *day_start = find_day(s, s + len, &day_end); - if (!day_start) - return; - if (day_end - day_start == 1) - key += '0'; - while (day_start < day_end) - key += *day_start++; -} - -// SORT_{SUB,SUB_SUB}_SEP can creep in from use of @ in label specification. - -void sortify_label(const char *s, int len, string &key) -{ - const char *end = s + len; - for (;;) { - const char *ptr; - for (ptr = s; - ptr < end && *ptr != SORT_SUB_SEP && *ptr != SORT_SUB_SUB_SEP; - ptr++) - ; - if (ptr > s) - sortify_words(s, ptr, 0, key); - s = ptr; - if (s >= end) - break; - key += *s++; - } -} - -void reference::compute_sort_key() -{ - if (sort_fields.length() == 0) - return; - sort_fields += '\0'; - const char *sf = sort_fields.contents(); - while (*sf != '\0') { - if (sf > sort_fields) - sort_key += SORT_SEP; - char f = *sf++; - int n = 1; - if (*sf == '+') { - n = INT_MAX; - sf++; - } - else if (csdigit(*sf)) { - char *ptr; - long l = strtol(sf, &ptr, 10); - if (l == 0 && ptr == sf) - ; - else { - sf = ptr; - if (l < 0) { - n = 1; - } - else { - n = int(l); - } - } - } - if (f == '.') - sortify_label(label.contents(), label.length(), sort_key); - else if (f == AUTHOR_FIELDS[0]) - sortify_authors(n, sort_key); - else - sortify_field(f, n, sort_key); - } - sort_fields.set_length(sort_fields.length() - 1); -} - -void reference::sortify_authors(int n, string &result) const -{ - for (const char *p = AUTHOR_FIELDS; *p != '\0'; p++) - if (contains_field(*p)) { - sortify_field(*p, n, result); - return; - } - sortify_field(AUTHOR_FIELDS[0], n, result); -} - -void reference::canonicalize_authors(string &result) const -{ - int len = result.length(); - sortify_authors(INT_MAX, result); - if (result.length() > len) - result += SORT_SUB_SEP; -} - -void reference::sortify_field(unsigned char f, int n, string &result) const -{ - typedef void (*sortify_t)(const char *, int, string &); - sortify_t sortifier = sortify_other; - switch (f) { - case 'A': - case 'E': - sortifier = sortify_name; - break; - case 'D': - sortifier = sortify_date; - break; - case 'B': - case 'J': - case 'T': - sortifier = sortify_title; - break; - } - int fi = field_index[(unsigned char)f]; - if (fi != NULL_FIELD_INDEX) { - string &str = field[fi]; - const char *start = str.contents(); - const char *end = start + str.length(); - for (int i = 0; i < n && start < end; i++) { - const char *p = start; - while (start < end && *start != FIELD_SEPARATOR) - start++; - if (i > 0) - result += SORT_SUB_SEP; - (*sortifier)(p, start - p, result); - if (start < end) - start++; - } - } -} - -int compare_reference(const reference &r1, const reference &r2) -{ - assert(r1.no >= 0); - assert(r2.no >= 0); - const char *s1 = r1.sort_key.contents(); - int n1 = r1.sort_key.length(); - const char *s2 = r2.sort_key.contents(); - int n2 = r2.sort_key.length(); - for (; n1 > 0 && n2 > 0; --n1, --n2, ++s1, ++s2) - if (*s1 != *s2) - return (int)(unsigned char)*s1 - (int)(unsigned char)*s2; - if (n2 > 0) - return -1; - if (n1 > 0) - return 1; - return r1.no - r2.no; -} - -int same_reference(const reference &r1, const reference &r2) -{ - if (!r1.rid.is_null() && r1.rid == r2.rid) - return 1; - if (r1.h != r2.h) - return 0; - if (r1.nfields != r2.nfields) - return 0; - int i = 0; - for (i = 0; i < 256; i++) - if (r1.field_index != r2.field_index) - return 0; - for (i = 0; i < r1.nfields; i++) - if (r1.field[i] != r2.field[i]) - return 0; - return 1; -} - -const char *find_last_name(const char *start, const char *end, - const char **endp) -{ - const char *ptr = start; - const char *last_word = start; - for (;;) { - const char *token_start = ptr; - if (!get_token(&ptr, end)) - break; - if (ptr - token_start == 1) { - if (*token_start == ',') { - *endp = token_start; - return last_word; - } - else if (*token_start == ' ' || *token_start == '\n') { - if (ptr < end && *ptr != ' ' && *ptr != '\n') - last_word = ptr; - } - } - } - *endp = end; - return last_word; -} - -void abbreviate_name(const char *ptr, const char *end, string &result) -{ - const char *last_name_end; - const char *last_name_start = find_last_name(ptr, end, &last_name_end); - int need_period = 0; - for (;;) { - const char *token_start = ptr; - if (!get_token(&ptr, last_name_start)) - break; - const token_info *ti = lookup_token(token_start, ptr); - if (need_period) { - if ((ptr - token_start == 1 && *token_start == ' ') - || (ptr - token_start == 2 && token_start[0] == '\\' - && token_start[1] == ' ')) - continue; - if (ti->is_upper()) - result += period_before_initial; - else - result += period_before_other; - need_period = 0; - } - result.append(token_start, ptr - token_start); - if (ti->is_upper()) { - const char *lower_ptr = ptr; - int first_token = 1; - for (;;) { - token_start = ptr; - if (!get_token(&ptr, last_name_start)) - break; - if ((ptr - token_start == 1 && *token_start == ' ') - || (ptr - token_start == 2 && token_start[0] == '\\' - && token_start[1] == ' ')) - break; - ti = lookup_token(token_start, ptr); - if (ti->is_hyphen()) { - const char *ptr1 = ptr; - if (get_token(&ptr1, last_name_start)) { - ti = lookup_token(ptr, ptr1); - if (ti->is_upper()) { - result += period_before_hyphen; - result.append(token_start, ptr1 - token_start); - ptr = ptr1; - } - } - } - else if (ti->is_upper()) { - // MacDougal -> MacD. - result.append(lower_ptr, ptr - lower_ptr); - lower_ptr = ptr; - first_token = 1; - } - else if (first_token && ti->is_accent()) { - result.append(token_start, ptr - token_start); - lower_ptr = ptr; - } - first_token = 0; - } - need_period = 1; - } - } - if (need_period) - result += period_before_last_name; - result.append(last_name_start, end - last_name_start); -} - -static void abbreviate_names(string &result) -{ - string str; - str.move(result); - const char *ptr = str.contents(); - const char *end = ptr + str.length(); - while (ptr < end) { - const char *name_end = (char *)memchr(ptr, FIELD_SEPARATOR, end - ptr); - if (name_end == 0) - name_end = end; - abbreviate_name(ptr, name_end, result); - if (name_end >= end) - break; - ptr = name_end + 1; - result += FIELD_SEPARATOR; - } -} - -void reverse_name(const char *ptr, const char *name_end, string &result) -{ - const char *last_name_end; - const char *last_name_start = find_last_name(ptr, name_end, &last_name_end); - result.append(last_name_start, last_name_end - last_name_start); - while (last_name_start > ptr - && (last_name_start[-1] == ' ' || last_name_start[-1] == '\n')) - last_name_start--; - if (last_name_start > ptr) { - result += ", "; - result.append(ptr, last_name_start - ptr); - } - if (last_name_end < name_end) - result.append(last_name_end, name_end - last_name_end); -} - -void reverse_names(string &result, int n) -{ - if (n <= 0) - return; - string str; - str.move(result); - const char *ptr = str.contents(); - const char *end = ptr + str.length(); - while (ptr < end) { - if (--n < 0) { - result.append(ptr, end - ptr); - break; - } - const char *name_end = (char *)memchr(ptr, FIELD_SEPARATOR, end - ptr); - if (name_end == 0) - name_end = end; - reverse_name(ptr, name_end, result); - if (name_end >= end) - break; - ptr = name_end + 1; - result += FIELD_SEPARATOR; - } -} - -// Return number of field separators. - -int join_fields(string &f) -{ - const char *ptr = f.contents(); - int len = f.length(); - int nfield_seps = 0; - int j; - for (j = 0; j < len; j++) - if (ptr[j] == FIELD_SEPARATOR) - nfield_seps++; - if (nfield_seps == 0) - return 0; - string temp; - int field_seps_left = nfield_seps; - for (j = 0; j < len; j++) { - if (ptr[j] == FIELD_SEPARATOR) { - if (nfield_seps == 1) - temp += join_authors_exactly_two; - else if (--field_seps_left == 0) - temp += join_authors_last_two; - else - temp += join_authors_default; - } - else - temp += ptr[j]; - } - f = temp; - return nfield_seps; -} - -void uppercase(const char *start, const char *end, string &result) -{ - for (;;) { - const char *token_start = start; - if (!get_token(&start, end)) - break; - const token_info *ti = lookup_token(token_start, start); - ti->upper_case(token_start, start, result); - } -} - -void lowercase(const char *start, const char *end, string &result) -{ - for (;;) { - const char *token_start = start; - if (!get_token(&start, end)) - break; - const token_info *ti = lookup_token(token_start, start); - ti->lower_case(token_start, start, result); - } -} - -void capitalize(const char *ptr, const char *end, string &result) -{ - int in_small_point_size = 0; - for (;;) { - const char *start = ptr; - if (!get_token(&ptr, end)) - break; - const token_info *ti = lookup_token(start, ptr); - const char *char_end = ptr; - int is_lower = ti->is_lower(); - if ((is_lower || ti->is_upper()) && get_token(&ptr, end)) { - const token_info *ti2 = lookup_token(char_end, ptr); - if (!ti2->is_accent()) - ptr = char_end; - } - if (is_lower) { - if (!in_small_point_size) { - result += "\\s-2"; - in_small_point_size = 1; - } - ti->upper_case(start, char_end, result); - result.append(char_end, ptr - char_end); - } - else { - if (in_small_point_size) { - result += "\\s+2"; - in_small_point_size = 0; - } - result.append(start, ptr - start); - } - } - if (in_small_point_size) - result += "\\s+2"; -} - -void capitalize_field(string &str) -{ - string temp; - capitalize(str.contents(), str.contents() + str.length(), temp); - str.move(temp); -} - -int is_terminated(const char *ptr, const char *end) -{ - const char *last_token = end; - for (;;) { - const char *p = ptr; - if (!get_token(&ptr, end)) - break; - last_token = p; - } - return end - last_token == 1 - && (*last_token == '.' || *last_token == '!' || *last_token == '?'); -} - -void reference::output(FILE *fp) -{ - fputs(".]-\n", fp); - for (int i = 0; i < 256; i++) - if (field_index[i] != NULL_FIELD_INDEX && i != annotation_field) { - string &f = field[field_index[i]]; - if (!csdigit(i)) { - int j = reverse_fields.search(i); - if (j >= 0) { - int n; - int len = reverse_fields.length(); - if (++j < len && csdigit(reverse_fields[j])) { - n = reverse_fields[j] - '0'; - for (++j; j < len && csdigit(reverse_fields[j]); j++) - // should check for overflow - n = n*10 + reverse_fields[j] - '0'; - } - else - n = INT_MAX; - reverse_names(f, n); - } - } - int is_multiple = join_fields(f) > 0; - if (capitalize_fields.search(i) >= 0) - capitalize_field(f); - if (memchr(f.contents(), '\n', f.length()) == 0) { - fprintf(fp, ".ds [%c ", i); - if (f[0] == ' ' || f[0] == '\\' || f[0] == '"') - putc('"', fp); - put_string(f, fp); - putc('\n', fp); - } - else { - fprintf(fp, ".de [%c\n", i); - put_string(f, fp); - fputs("..\n", fp); - } - if (i == 'P') { - int multiple_pages = 0; - const char *s = f.contents(); - const char *end = f.contents() + f.length(); - for (;;) { - const char *token_start = s; - if (!get_token(&s, end)) - break; - const token_info *ti = lookup_token(token_start, s); - if (ti->is_hyphen() || ti->is_range_sep()) { - multiple_pages = 1; - break; - } - } - fprintf(fp, ".nr [P %d\n", multiple_pages); - } - else if (i == 'E') - fprintf(fp, ".nr [E %d\n", is_multiple); - } - for (const char *p = "TAO"; *p; p++) { - int fi = field_index[(unsigned char)*p]; - if (fi != NULL_FIELD_INDEX) { - string &f = field[fi]; - fprintf(fp, ".nr [%c %d\n", *p, - is_terminated(f.contents(), f.contents() + f.length())); - } - } - int t = classify(); - fprintf(fp, ".][ %d %s\n", t, reference_types[t]); - if (annotation_macro.length() > 0 && annotation_field >= 0 - && field_index[annotation_field] != NULL_FIELD_INDEX) { - putc('.', fp); - put_string(annotation_macro, fp); - putc('\n', fp); - put_string(field[field_index[annotation_field]], fp); - } -} - -void reference::print_sort_key_comment(FILE *fp) -{ - fputs(".\\\"", fp); - put_string(sort_key, fp); - putc('\n', fp); -} - -const char *find_year(const char *start, const char *end, const char **endp) -{ - for (;;) { - while (start < end && !csdigit(*start)) - start++; - const char *ptr = start; - if (start == end) - break; - while (ptr < end && csdigit(*ptr)) - ptr++; - if (ptr - start == 4 || ptr - start == 3 - || (ptr - start == 2 - && (start[0] >= '4' || (start[0] == '3' && start[1] >= '2')))) { - *endp = ptr; - return start; - } - start = ptr; - } - return 0; -} - -static const char *find_day(const char *start, const char *end, - const char **endp) -{ - for (;;) { - while (start < end && !csdigit(*start)) - start++; - const char *ptr = start; - if (start == end) - break; - while (ptr < end && csdigit(*ptr)) - ptr++; - if ((ptr - start == 1 && start[0] != '0') - || (ptr - start == 2 && - (start[0] == '1' - || start[0] == '2' - || (start[0] == '3' && start[1] <= '1') - || (start[0] == '0' && start[1] != '0')))) { - *endp = ptr; - return start; - } - start = ptr; - } - return 0; -} - -static int find_month(const char *start, const char *end) -{ - static const char *months[] = { - "january", - "february", - "march", - "april", - "may", - "june", - "july", - "august", - "september", - "october", - "november", - "december", - }; - for (;;) { - while (start < end && !csalpha(*start)) - start++; - const char *ptr = start; - if (start == end) - break; - while (ptr < end && csalpha(*ptr)) - ptr++; - if (ptr - start >= 3) { - for (unsigned int i = 0; i < sizeof(months)/sizeof(months[0]); i++) { - const char *q = months[i]; - const char *p = start; - for (; p < ptr; p++, q++) - if (cmlower(*p) != *q) - break; - if (p >= ptr) - return i; - } - } - start = ptr; - } - return -1; -} - -int reference::contains_field(char c) const -{ - return field_index[(unsigned char)c] != NULL_FIELD_INDEX; -} - -int reference::classify() -{ - if (contains_field('J')) - return JOURNAL_ARTICLE; - if (contains_field('B')) - return ARTICLE_IN_BOOK; - if (contains_field('G')) - return TECH_REPORT; - if (contains_field('R')) - return TECH_REPORT; - if (contains_field('I')) - return BOOK; - if (contains_field('M')) - return BELL_TM; - return OTHER; -} - -const char *reference::get_year(const char **endp) const -{ - if (field_index['D'] != NULL_FIELD_INDEX) { - string &date = field[field_index['D']]; - const char *start = date.contents(); - const char *end = start + date.length(); - return find_year(start, end, endp); - } - else - return 0; -} - -const char *reference::get_field(unsigned char c, const char **endp) const -{ - if (field_index[c] != NULL_FIELD_INDEX) { - string &f = field[field_index[c]]; - const char *start = f.contents(); - *endp = start + f.length(); - return start; - } - else - return 0; -} - -const char *reference::get_date(const char **endp) const -{ - return get_field('D', endp); -} - -const char *nth_field(int i, const char *start, const char **endp) -{ - while (--i >= 0) { - start = (char *)memchr(start, FIELD_SEPARATOR, *endp - start); - if (!start) - return 0; - start++; - } - const char *e = (char *)memchr(start, FIELD_SEPARATOR, *endp - start); - if (e) - *endp = e; - return start; -} - -const char *reference::get_author(int i, const char **endp) const -{ - for (const char *f = AUTHOR_FIELDS; *f != '\0'; f++) { - const char *start = get_field(*f, endp); - if (start) { - if (strchr(MULTI_FIELD_NAMES, *f) != 0) - return nth_field(i, start, endp); - else if (i == 0) - return start; - else - return 0; - } - } - return 0; -} - -const char *reference::get_author_last_name(int i, const char **endp) const -{ - for (const char *f = AUTHOR_FIELDS; *f != '\0'; f++) { - const char *start = get_field(*f, endp); - if (start) { - if (strchr(MULTI_FIELD_NAMES, *f) != 0) { - start = nth_field(i, start, endp); - if (!start) - return 0; - } - if (*f == 'A') - return find_last_name(start, *endp, endp); - else - return start; - } - } - return 0; -} - -void reference::set_date(string &d) -{ - if (d.length() == 0) - delete_field('D'); - else - insert_field('D', d); -} - -int same_year(const reference &r1, const reference &r2) -{ - const char *ye1; - const char *ys1 = r1.get_year(&ye1); - const char *ye2; - const char *ys2 = r2.get_year(&ye2); - if (ys1 == 0) { - if (ys2 == 0) - return same_date(r1, r2); - else - return 0; - } - else if (ys2 == 0) - return 0; - else if (ye1 - ys1 != ye2 - ys2) - return 0; - else - return memcmp(ys1, ys2, ye1 - ys1) == 0; -} - -int same_date(const reference &r1, const reference &r2) -{ - const char *e1; - const char *s1 = r1.get_date(&e1); - const char *e2; - const char *s2 = r2.get_date(&e2); - if (s1 == 0) - return s2 == 0; - else if (s2 == 0) - return 0; - else if (e1 - s1 != e2 - s2) - return 0; - else - return memcmp(s1, s2, e1 - s1) == 0; -} - -const char *reference::get_sort_field(int i, int si, int ssi, - const char **endp) const -{ - const char *start = sort_key.contents(); - const char *end = start + sort_key.length(); - if (i < 0) { - *endp = end; - return start; - } - while (--i >= 0) { - start = (char *)memchr(start, SORT_SEP, end - start); - if (!start) - return 0; - start++; - } - const char *e = (char *)memchr(start, SORT_SEP, end - start); - if (e) - end = e; - if (si < 0) { - *endp = end; - return start; - } - while (--si >= 0) { - start = (char *)memchr(start, SORT_SUB_SEP, end - start); - if (!start) - return 0; - start++; - } - e = (char *)memchr(start, SORT_SUB_SEP, end - start); - if (e) - end = e; - if (ssi < 0) { - *endp = end; - return start; - } - while (--ssi >= 0) { - start = (char *)memchr(start, SORT_SUB_SUB_SEP, end - start); - if (!start) - return 0; - start++; - } - e = (char *)memchr(start, SORT_SUB_SUB_SEP, end - start); - if (e) - end = e; - *endp = end; - return start; -} - diff --git a/contrib/groff/src/preproc/refer/refer.cc b/contrib/groff/src/preproc/refer/refer.cc deleted file mode 100644 index 33df35c..0000000 --- a/contrib/groff/src/preproc/refer/refer.cc +++ /dev/null @@ -1,1235 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001, 2002 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 "refer.h" -#include "refid.h" -#include "ref.h" -#include "token.h" -#include "search.h" -#include "command.h" - -extern "C" const char *Version_string; - -const char PRE_LABEL_MARKER = '\013'; -const char POST_LABEL_MARKER = '\014'; -const char LABEL_MARKER = '\015'; // label_type is added on - -#define FORCE_LEFT_BRACKET 04 -#define FORCE_RIGHT_BRACKET 010 - -static FILE *outfp = stdout; - -string capitalize_fields; -string reverse_fields; -string abbreviate_fields; -string period_before_last_name = ". "; -string period_before_initial = "."; -string period_before_hyphen = ""; -string period_before_other = ". "; -string sort_fields; -int annotation_field = -1; -string annotation_macro; -string discard_fields = "XYZ"; -string pre_label = "\\*([."; -string post_label = "\\*(.]"; -string sep_label = ", "; -int accumulate = 0; -int move_punctuation = 0; -int abbreviate_label_ranges = 0; -string label_range_indicator; -int label_in_text = 1; -int label_in_reference = 1; -int date_as_label = 0; -int sort_adjacent_labels = 0; -// Join exactly two authors with this. -string join_authors_exactly_two = " and "; -// When there are more than two authors join the last two with this. -string join_authors_last_two = ", and "; -// Otherwise join authors with this. -string join_authors_default = ", "; -string separate_label_second_parts = ", "; -// Use this string to represent that there are other authors. -string et_al = " et al"; -// Use et al only if it can replace at least this many authors. -int et_al_min_elide = 2; -// Use et al only if the total number of authors is at least this. -int et_al_min_total = 3; - - -int compatible_flag = 0; - -int short_label_flag = 0; - -static int recognize_R1_R2 = 1; - -search_list database_list; -int search_default = 1; -static int default_database_loaded = 0; - -static reference **citation = 0; -static int ncitations = 0; -static int citation_max = 0; - -static reference **reference_hash_table = 0; -static int hash_table_size; -static int nreferences = 0; - -static int need_syncing = 0; -string pending_line; -string pending_lf_lines; - -static void output_pending_line(); -static unsigned immediately_handle_reference(const string &); -static void immediately_output_references(); -static unsigned store_reference(const string &); -static void divert_to_temporary_file(); -static reference *make_reference(const string &, unsigned *); -static void usage(FILE *stream); -static void do_file(const char *); -static void split_punct(string &line, string &punct); -static void output_citation_group(reference **v, int n, label_type, FILE *fp); -static void possibly_load_default_database(); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - outfp = stdout; - int finished_options = 0; - int bib_flag = 0; - int done_spec = 0; - - for (--argc, ++argv; - !finished_options && argc > 0 && argv[0][0] == '-' - && argv[0][1] != '\0'; - argv++, argc--) { - const char *opt = argv[0] + 1; - while (opt != 0 && *opt != '\0') { - switch (*opt) { - case 'C': - compatible_flag = 1; - opt++; - break; - case 'B': - bib_flag = 1; - label_in_reference = 0; - label_in_text = 0; - ++opt; - if (*opt == '\0') { - annotation_field = 'X'; - annotation_macro = "AP"; - } - else if (csalnum(opt[0]) && opt[1] == '.' && opt[2] != '\0') { - annotation_field = opt[0]; - annotation_macro = opt + 2; - } - opt = 0; - break; - case 'P': - move_punctuation = 1; - opt++; - break; - case 'R': - recognize_R1_R2 = 0; - opt++; - break; - case 'S': - // Not a very useful spec. - set_label_spec("(A.n|Q)', '(D.y|D)"); - done_spec = 1; - pre_label = " ("; - post_label = ")"; - sep_label = "; "; - opt++; - break; - case 'V': - verify_flag = 1; - opt++; - break; - case 'f': - { - const char *num = 0; - if (*++opt == '\0') { - if (argc > 1) { - num = *++argv; - --argc; - } - else { - error("option `f' requires an argument"); - usage(stderr); - exit(1); - } - } - else { - num = opt; - opt = 0; - } - const char *ptr; - for (ptr = num; *ptr; ptr++) - if (!csdigit(*ptr)) { - error("bad character `%1' in argument to -f option", *ptr); - break; - } - if (*ptr == '\0') { - string spec; - spec = '%'; - spec += num; - spec += '\0'; - set_label_spec(spec.contents()); - done_spec = 1; - } - break; - } - case 'b': - label_in_text = 0; - label_in_reference = 0; - opt++; - break; - case 'e': - accumulate = 1; - opt++; - break; - case 'c': - capitalize_fields = ++opt; - opt = 0; - break; - case 'k': - { - char buf[5]; - if (csalpha(*++opt)) - buf[0] = *opt++; - else { - if (*opt != '\0') - error("bad field name `%1'", *opt++); - buf[0] = 'L'; - } - buf[1] = '~'; - buf[2] = '%'; - buf[3] = 'a'; - buf[4] = '\0'; - set_label_spec(buf); - done_spec = 1; - } - break; - case 'a': - { - const char *ptr; - for (ptr = ++opt; *ptr; ptr++) - if (!csdigit(*ptr)) { - error("argument to `a' option not a number"); - break; - } - if (*ptr == '\0') { - reverse_fields = 'A'; - reverse_fields += opt; - } - opt = 0; - } - break; - case 'i': - linear_ignore_fields = ++opt; - opt = 0; - break; - case 'l': - { - char buf[INT_DIGITS*2 + 11]; // A.n+2D.y-3%a - strcpy(buf, "A.n"); - if (*++opt != '\0' && *opt != ',') { - char *ptr; - long n = strtol(opt, &ptr, 10); - if (n == 0 && ptr == opt) { - error("bad integer `%1' in `l' option", opt); - opt = 0; - break; - } - if (n < 0) - n = 0; - opt = ptr; - sprintf(strchr(buf, '\0'), "+%ld", n); - } - strcat(buf, "D.y"); - if (*opt == ',') - opt++; - if (*opt != '\0') { - char *ptr; - long n = strtol(opt, &ptr, 10); - if (n == 0 && ptr == opt) { - error("bad integer `%1' in `l' option", opt); - opt = 0; - break; - } - if (n < 0) - n = 0; - sprintf(strchr(buf, '\0'), "-%ld", n); - opt = ptr; - if (*opt != '\0') - error("argument to `l' option not of form `m,n'"); - } - strcat(buf, "%a"); - if (!set_label_spec(buf)) - assert(0); - done_spec = 1; - } - break; - case 'n': - search_default = 0; - opt++; - break; - case 'p': - { - const char *filename = 0; - if (*++opt == '\0') { - if (argc > 1) { - filename = *++argv; - argc--; - } - else { - error("option `p' requires an argument"); - usage(stderr); - exit(1); - } - } - else { - filename = opt; - opt = 0; - } - database_list.add_file(filename); - } - break; - case 's': - if (*++opt == '\0') - sort_fields = "AD"; - else { - sort_fields = opt; - opt = 0; - } - accumulate = 1; - break; - case 't': - { - char *ptr; - long n = strtol(opt, &ptr, 10); - if (n == 0 && ptr == opt) { - error("bad integer `%1' in `t' option", opt); - opt = 0; - break; - } - if (n < 1) - n = 1; - linear_truncate_len = int(n); - opt = ptr; - break; - } - case '-': - if (opt[1] == '\0') { - finished_options = 1; - opt++; - break; - } - if (strcmp(opt,"-version")==0) { - case 'v': - printf("GNU refer (groff) version %s\n", Version_string); - exit(0); - break; - } - if (strcmp(opt,"-help")==0) { - usage(stdout); - exit(0); - break; - } - // fall through - default: - error("unrecognized option `%1'", *opt); - usage(stderr); - exit(1); - break; - } - } - } - if (!done_spec) - set_label_spec("%1"); - if (argc <= 0) { - if (bib_flag) - do_bib("-"); - else - do_file("-"); - } - else { - for (int i = 0; i < argc; i++) { - if (bib_flag) - do_bib(argv[i]); - else - do_file(argv[i]); - } - } - if (accumulate) - output_references(); - if (fflush(stdout) < 0) - fatal("output error"); - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, -"usage: %s [-benvCPRS] [-aN] [-cXYZ] [-fN] [-iXYZ] [-kX] [-lM,N] [-p file]\n" -" [-sXYZ] [-tN] [-BL.M] [files ...]\n", - program_name); -} - -static void possibly_load_default_database() -{ - if (search_default && !default_database_loaded) { - char *filename = getenv("REFER"); - if (filename) - database_list.add_file(filename); - else - database_list.add_file(DEFAULT_INDEX, 1); - default_database_loaded = 1; - } -} - -static int is_list(const string &str) -{ - const char *start = str.contents(); - const char *end = start + str.length(); - while (end > start && csspace(end[-1])) - end--; - while (start < end && csspace(*start)) - start++; - return end - start == 6 && memcmp(start, "$LIST$", 6) == 0; -} - -static void do_file(const char *filename) -{ - FILE *fp; - if (strcmp(filename, "-") == 0) { - fp = stdin; - } - else { - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) { - error("can't open `%1': %2", filename, strerror(errno)); - return; - } - } - current_filename = filename; - fprintf(outfp, ".lf 1 %s\n", filename); - string line; - current_lineno = 0; - for (;;) { - line.clear(); - for (;;) { - int c = getc(fp); - if (c == EOF) { - if (line.length() > 0) - line += '\n'; - break; - } - if (invalid_input_char(c)) - error("invalid input character code %1", c); - else { - line += c; - if (c == '\n') - break; - } - } - int len = line.length(); - if (len == 0) - break; - current_lineno++; - if (len >= 2 && line[0] == '.' && line[1] == '[') { - int start_lineno = current_lineno; - int start_of_line = 1; - string str; - string post; - string pre(line.contents() + 2, line.length() - 3); - for (;;) { - int c = getc(fp); - if (c == EOF) { - error_with_file_and_line(current_filename, start_lineno, - "missing `.]' line"); - break; - } - if (start_of_line) - current_lineno++; - if (start_of_line && c == '.') { - int d = getc(fp); - if (d == ']') { - while ((d = getc(fp)) != '\n' && d != EOF) { - if (invalid_input_char(d)) - error("invalid input character code %1", d); - else - post += d; - } - break; - } - if (d != EOF) - ungetc(d, fp); - } - if (invalid_input_char(c)) - error("invalid input character code %1", c); - else - str += c; - start_of_line = (c == '\n'); - } - if (is_list(str)) { - output_pending_line(); - if (accumulate) - output_references(); - else - error("found `$LIST$' but not accumulating references"); - } - else { - unsigned flags = (accumulate - ? store_reference(str) - : immediately_handle_reference(str)); - if (label_in_text) { - if (accumulate && outfp == stdout) - divert_to_temporary_file(); - if (pending_line.length() == 0) { - warning("can't attach citation to previous line"); - } - else - pending_line.set_length(pending_line.length() - 1); - string punct; - if (move_punctuation) - split_punct(pending_line, punct); - int have_text = pre.length() > 0 || post.length() > 0; - label_type lt = label_type(flags & ~(FORCE_LEFT_BRACKET - |FORCE_RIGHT_BRACKET)); - if ((flags & FORCE_LEFT_BRACKET) || !have_text) - pending_line += PRE_LABEL_MARKER; - pending_line += pre; - char lm = LABEL_MARKER + (int)lt; - pending_line += lm; - pending_line += post; - if ((flags & FORCE_RIGHT_BRACKET) || !have_text) - pending_line += POST_LABEL_MARKER; - pending_line += punct; - pending_line += '\n'; - } - } - need_syncing = 1; - } - else if (len >= 4 - && line[0] == '.' && line[1] == 'l' && line[2] == 'f' - && (compatible_flag || line[3] == '\n' || line[3] == ' ')) { - pending_lf_lines += line; - line += '\0'; - if (interpret_lf_args(line.contents() + 3)) - current_lineno--; - } - else if (recognize_R1_R2 - && len >= 4 - && line[0] == '.' && line[1] == 'R' && line[2] == '1' - && (compatible_flag || line[3] == '\n' || line[3] == ' ')) { - line.clear(); - int start_of_line = 1; - int start_lineno = current_lineno; - for (;;) { - int c = getc(fp); - if (c != EOF && start_of_line) - current_lineno++; - if (start_of_line && c == '.') { - c = getc(fp); - if (c == 'R') { - c = getc(fp); - if (c == '2') { - c = getc(fp); - if (compatible_flag || c == ' ' || c == '\n' || c == EOF) { - while (c != EOF && c != '\n') - c = getc(fp); - break; - } - else { - line += '.'; - line += 'R'; - line += '2'; - } - } - else { - line += '.'; - line += 'R'; - } - } - else - line += '.'; - } - if (c == EOF) { - error_with_file_and_line(current_filename, start_lineno, - "missing `.R2' line"); - break; - } - if (invalid_input_char(c)) - error("invalid input character code %1", int(c)); - else { - line += c; - start_of_line = c == '\n'; - } - } - output_pending_line(); - if (accumulate) - output_references(); - else - nreferences = 0; - process_commands(line, current_filename, start_lineno + 1); - need_syncing = 1; - } - else { - output_pending_line(); - pending_line = line; - } - } - need_syncing = 0; - output_pending_line(); - if (fp != stdin) - fclose(fp); -} - -class label_processing_state { - enum { - NORMAL, - PENDING_LABEL, - PENDING_LABEL_POST, - PENDING_LABEL_POST_PRE, - PENDING_POST - } state; - label_type type; // type of pending labels - int count; // number of pending labels - reference **rptr; // pointer to next reference - int rcount; // number of references left - FILE *fp; - int handle_pending(int c); -public: - label_processing_state(reference **, int, FILE *); - ~label_processing_state(); - void process(int c); -}; - -static void output_pending_line() -{ - if (label_in_text && !accumulate && ncitations > 0) { - label_processing_state state(citation, ncitations, outfp); - int len = pending_line.length(); - for (int i = 0; i < len; i++) - state.process((unsigned char)(pending_line[i])); - } - else - put_string(pending_line, outfp); - pending_line.clear(); - if (pending_lf_lines.length() > 0) { - put_string(pending_lf_lines, outfp); - pending_lf_lines.clear(); - } - if (!accumulate) - immediately_output_references(); - if (need_syncing) { - fprintf(outfp, ".lf %d %s\n", current_lineno, current_filename); - need_syncing = 0; - } -} - -static void split_punct(string &line, string &punct) -{ - const char *start = line.contents(); - const char *end = start + line.length(); - const char *ptr = start; - const char *last_token_start = 0; - for (;;) { - if (ptr >= end) - break; - last_token_start = ptr; - if (*ptr == PRE_LABEL_MARKER || *ptr == POST_LABEL_MARKER - || (*ptr >= LABEL_MARKER && *ptr < LABEL_MARKER + N_LABEL_TYPES)) - ptr++; - else if (!get_token(&ptr, end)) - break; - } - if (last_token_start) { - const token_info *ti = lookup_token(last_token_start, end); - if (ti->is_punct()) { - punct.append(last_token_start, end - last_token_start); - line.set_length(last_token_start - start); - } - } -} - -static void divert_to_temporary_file() -{ - outfp = xtmpfile(); -} - -static void store_citation(reference *ref) -{ - if (ncitations >= citation_max) { - if (citation == 0) - citation = new reference*[citation_max = 100]; - else { - reference **old_citation = citation; - citation_max *= 2; - citation = new reference *[citation_max]; - memcpy(citation, old_citation, ncitations*sizeof(reference *)); - a_delete old_citation; - } - } - citation[ncitations++] = ref; -} - -static unsigned store_reference(const string &str) -{ - if (reference_hash_table == 0) { - reference_hash_table = new reference *[17]; - hash_table_size = 17; - for (int i = 0; i < hash_table_size; i++) - reference_hash_table[i] = 0; - } - unsigned flags; - reference *ref = make_reference(str, &flags); - ref->compute_hash_code(); - unsigned h = ref->hash(); - reference **ptr; - for (ptr = reference_hash_table + (h % hash_table_size); - *ptr != 0; - ((ptr == reference_hash_table) - ? (ptr = reference_hash_table + hash_table_size - 1) - : --ptr)) - if (same_reference(**ptr, *ref)) - break; - if (*ptr != 0) { - if (ref->is_merged()) - warning("fields ignored because reference already used"); - delete ref; - ref = *ptr; - } - else { - *ptr = ref; - ref->set_number(nreferences); - nreferences++; - ref->pre_compute_label(); - ref->compute_sort_key(); - if (nreferences*2 >= hash_table_size) { - // Rehash it. - reference **old_table = reference_hash_table; - int old_size = hash_table_size; - hash_table_size = next_size(hash_table_size); - reference_hash_table = new reference*[hash_table_size]; - int i; - for (i = 0; i < hash_table_size; i++) - reference_hash_table[i] = 0; - for (i = 0; i < old_size; i++) - if (old_table[i]) { - reference **p; - for (p = (reference_hash_table - + (old_table[i]->hash() % hash_table_size)); - *p; - ((p == reference_hash_table) - ? (p = reference_hash_table + hash_table_size - 1) - : --p)) - ; - *p = old_table[i]; - } - a_delete old_table; - } - } - if (label_in_text) - store_citation(ref); - return flags; -} - -unsigned immediately_handle_reference(const string &str) -{ - unsigned flags; - reference *ref = make_reference(str, &flags); - ref->set_number(nreferences); - if (label_in_text || label_in_reference) { - ref->pre_compute_label(); - ref->immediate_compute_label(); - } - nreferences++; - store_citation(ref); - return flags; -} - -static void immediately_output_references() -{ - for (int i = 0; i < ncitations; i++) { - reference *ref = citation[i]; - if (label_in_reference) { - fputs(".ds [F ", outfp); - const string &label = ref->get_label(NORMAL_LABEL); - if (label.length() > 0 - && (label[0] == ' ' || label[0] == '\\' || label[0] == '"')) - putc('"', outfp); - put_string(label, outfp); - putc('\n', outfp); - } - ref->output(outfp); - delete ref; - } - ncitations = 0; -} - -static void output_citation_group(reference **v, int n, label_type type, - FILE *fp) -{ - if (sort_adjacent_labels) { - // Do an insertion sort. Usually n will be very small. - for (int i = 1; i < n; i++) { - int num = v[i]->get_number(); - reference *temp = v[i]; - int j; - for (j = i - 1; j >= 0 && v[j]->get_number() > num; j--) - v[j + 1] = v[j]; - v[j + 1] = temp; - } - } - // This messes up if !accumulate. - if (accumulate && n > 1) { - // remove duplicates - int j = 1; - for (int i = 1; i < n; i++) - if (v[i]->get_label(type) != v[i - 1]->get_label(type)) - v[j++] = v[i]; - n = j; - } - string merged_label; - for (int i = 0; i < n; i++) { - int nmerged = v[i]->merge_labels(v + i + 1, n - i - 1, type, merged_label); - if (nmerged > 0) { - put_string(merged_label, fp); - i += nmerged; - } - else - put_string(v[i]->get_label(type), fp); - if (i < n - 1) - put_string(sep_label, fp); - } -} - - -label_processing_state::label_processing_state(reference **p, int n, FILE *f) -: state(NORMAL), count(0), rptr(p), rcount(n), fp(f) -{ -} - -label_processing_state::~label_processing_state() -{ - int handled = handle_pending(EOF); - assert(!handled); - assert(rcount == 0); -} - -int label_processing_state::handle_pending(int c) -{ - switch (state) { - case NORMAL: - break; - case PENDING_LABEL: - if (c == POST_LABEL_MARKER) { - state = PENDING_LABEL_POST; - return 1; - } - else { - output_citation_group(rptr, count, type, fp); - rptr += count ; - rcount -= count; - state = NORMAL; - } - break; - case PENDING_LABEL_POST: - if (c == PRE_LABEL_MARKER) { - state = PENDING_LABEL_POST_PRE; - return 1; - } - else { - output_citation_group(rptr, count, type, fp); - rptr += count; - rcount -= count; - put_string(post_label, fp); - state = NORMAL; - } - break; - case PENDING_LABEL_POST_PRE: - if (c >= LABEL_MARKER - && c < LABEL_MARKER + N_LABEL_TYPES - && c - LABEL_MARKER == type) { - count += 1; - state = PENDING_LABEL; - return 1; - } - else { - output_citation_group(rptr, count, type, fp); - rptr += count; - rcount -= count; - put_string(sep_label, fp); - state = NORMAL; - } - break; - case PENDING_POST: - if (c == PRE_LABEL_MARKER) { - put_string(sep_label, fp); - state = NORMAL; - return 1; - } - else { - put_string(post_label, fp); - state = NORMAL; - } - break; - } - return 0; -} - -void label_processing_state::process(int c) -{ - if (handle_pending(c)) - return; - assert(state == NORMAL); - switch (c) { - case PRE_LABEL_MARKER: - put_string(pre_label, fp); - state = NORMAL; - break; - case POST_LABEL_MARKER: - state = PENDING_POST; - break; - case LABEL_MARKER: - case LABEL_MARKER + 1: - count = 1; - state = PENDING_LABEL; - type = label_type(c - LABEL_MARKER); - break; - default: - state = NORMAL; - putc(c, fp); - break; - } -} - -extern "C" { - -int rcompare(const void *p1, const void *p2) -{ - return compare_reference(**(reference **)p1, **(reference **)p2); -} - -} - -void output_references() -{ - assert(accumulate); - if (nreferences > 0) { - int j = 0; - int i; - for (i = 0; i < hash_table_size; i++) - if (reference_hash_table[i] != 0) - reference_hash_table[j++] = reference_hash_table[i]; - assert(j == nreferences); - for (; j < hash_table_size; j++) - reference_hash_table[j] = 0; - qsort(reference_hash_table, nreferences, sizeof(reference*), rcompare); - for (i = 0; i < nreferences; i++) - reference_hash_table[i]->set_number(i); - compute_labels(reference_hash_table, nreferences); - } - if (outfp != stdout) { - rewind(outfp); - { - label_processing_state state(citation, ncitations, stdout); - int c; - while ((c = getc(outfp)) != EOF) - state.process(c); - } - ncitations = 0; - fclose(outfp); - outfp = stdout; - } - if (nreferences > 0) { - fputs(".]<\n", outfp); - for (int i = 0; i < nreferences; i++) { - if (sort_fields.length() > 0) - reference_hash_table[i]->print_sort_key_comment(outfp); - if (label_in_reference) { - fputs(".ds [F ", outfp); - const string &label = reference_hash_table[i]->get_label(NORMAL_LABEL); - if (label.length() > 0 - && (label[0] == ' ' || label[0] == '\\' || label[0] == '"')) - putc('"', outfp); - put_string(label, outfp); - putc('\n', outfp); - } - reference_hash_table[i]->output(outfp); - delete reference_hash_table[i]; - reference_hash_table[i] = 0; - } - fputs(".]>\n", outfp); - nreferences = 0; - } - clear_labels(); -} - -static reference *find_reference(const char *query, int query_len) -{ - // This is so that error messages look better. - while (query_len > 0 && csspace(query[query_len - 1])) - query_len--; - string str; - for (int i = 0; i < query_len; i++) - str += query[i] == '\n' ? ' ' : query[i]; - str += '\0'; - possibly_load_default_database(); - search_list_iterator iter(&database_list, str.contents()); - reference_id rid; - const char *start; - int len; - if (!iter.next(&start, &len, &rid)) { - error("no matches for `%1'", str.contents()); - return 0; - } - const char *end = start + len; - while (start < end) { - if (*start == '%') - break; - while (start < end && *start++ != '\n') - ; - } - if (start >= end) { - error("found a reference for `%1' but it didn't contain any fields", - str.contents()); - return 0; - } - reference *result = new reference(start, end - start, &rid); - if (iter.next(&start, &len, &rid)) - warning("multiple matches for `%1'", str.contents()); - return result; -} - -static reference *make_reference(const string &str, unsigned *flagsp) -{ - const char *start = str.contents(); - const char *end = start + str.length(); - const char *ptr = start; - while (ptr < end) { - if (*ptr == '%') - break; - while (ptr < end && *ptr++ != '\n') - ; - } - *flagsp = 0; - for (; start < ptr; start++) { - if (*start == '#') - *flagsp = (SHORT_LABEL | (*flagsp & (FORCE_RIGHT_BRACKET - | FORCE_LEFT_BRACKET))); - else if (*start == '[') - *flagsp |= FORCE_LEFT_BRACKET; - else if (*start == ']') - *flagsp |= FORCE_RIGHT_BRACKET; - else if (!csspace(*start)) - break; - } - if (start >= end) { - error("empty reference"); - return new reference; - } - reference *database_ref = 0; - if (start < ptr) - database_ref = find_reference(start, ptr - start); - reference *inline_ref = 0; - if (ptr < end) - inline_ref = new reference(ptr, end - ptr); - if (inline_ref) { - if (database_ref) { - database_ref->merge(*inline_ref); - delete inline_ref; - return database_ref; - } - else - return inline_ref; - } - else if (database_ref) - return database_ref; - else - return new reference; -} - -static void do_ref(const string &str) -{ - if (accumulate) - (void)store_reference(str); - else { - (void)immediately_handle_reference(str); - immediately_output_references(); - } -} - -static void trim_blanks(string &str) -{ - const char *start = str.contents(); - const char *end = start + str.length(); - while (end > start && end[-1] != '\n' && csspace(end[-1])) - --end; - str.set_length(end - start); -} - -void do_bib(const char *filename) -{ - FILE *fp; - if (strcmp(filename, "-") == 0) - fp = stdin; - else { - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) { - error("can't open `%1': %2", filename, strerror(errno)); - return; - } - current_filename = filename; - } - enum { - START, MIDDLE, BODY, BODY_START, BODY_BLANK, BODY_DOT - } state = START; - string body; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - if (invalid_input_char(c)) { - error("invalid input character code %1", c); - continue; - } - switch (state) { - case START: - if (c == '%') { - body = c; - state = BODY; - } - else if (c != '\n') - state = MIDDLE; - break; - case MIDDLE: - if (c == '\n') - state = START; - break; - case BODY: - body += c; - if (c == '\n') - state = BODY_START; - break; - case BODY_START: - if (c == '\n') { - do_ref(body); - state = START; - } - else if (c == '.') - state = BODY_DOT; - else if (csspace(c)) { - state = BODY_BLANK; - body += c; - } - else { - body += c; - state = BODY; - } - break; - case BODY_BLANK: - if (c == '\n') { - trim_blanks(body); - do_ref(body); - state = START; - } - else if (csspace(c)) - body += c; - else { - body += c; - state = BODY; - } - break; - case BODY_DOT: - if (c == ']') { - do_ref(body); - state = MIDDLE; - } - else { - body += '.'; - body += c; - state = c == '\n' ? BODY_START : BODY; - } - break; - default: - assert(0); - } - if (c == '\n') - current_lineno++; - } - switch (state) { - case START: - case MIDDLE: - break; - case BODY: - body += '\n'; - do_ref(body); - break; - case BODY_DOT: - case BODY_START: - do_ref(body); - break; - case BODY_BLANK: - trim_blanks(body); - do_ref(body); - break; - } - fclose(fp); -} - -// from the Dragon Book - -unsigned hash_string(const char *s, int len) -{ - const char *end = s + len; - unsigned h = 0, g; - while (s < end) { - h <<= 4; - h += *s++; - if ((g = h & 0xf0000000) != 0) { - h ^= g >> 24; - h ^= g; - } - } - return h; -} - -int next_size(int n) -{ - static const int table_sizes[] = { - 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, - 80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009, - 16000057, 32000011, 64000031, 128000003, 0 - }; - - const int *p; - for (p = table_sizes; *p <= n && *p != 0; p++) - ; - assert(*p != 0); - return *p; -} - diff --git a/contrib/groff/src/preproc/refer/token.cc b/contrib/groff/src/preproc/refer/token.cc deleted file mode 100644 index e9fac5d..0000000 --- a/contrib/groff/src/preproc/refer/token.cc +++ /dev/null @@ -1,378 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001 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 "refer.h" -#include "token.h" - -#define TOKEN_TABLE_SIZE 1009 -// I believe in Icelandic thorn sorts after z. -#define THORN_SORT_KEY "{" - -struct token_table_entry { - const char *tok; - token_info ti; - token_table_entry(); -}; - -token_table_entry token_table[TOKEN_TABLE_SIZE]; -int ntokens = 0; - -static void skip_name(const char **ptr, const char *end) -{ - if (*ptr < end) { - switch (*(*ptr)++) { - case '(': - if (*ptr < end) { - *ptr += 1; - if (*ptr < end) - *ptr += 1; - } - break; - case '[': - while (*ptr < end) - if (*(*ptr)++ == ']') - break; - break; - } - } -} - -int get_token(const char **ptr, const char *end) -{ - if (*ptr >= end) - return 0; - char c = *(*ptr)++; - if (c == '\\' && *ptr < end) { - switch (**ptr) { - default: - *ptr += 1; - break; - case '(': - case '[': - skip_name(ptr, end); - break; - case '*': - case 'f': - *ptr += 1; - skip_name(ptr, end); - break; - } - } - return 1; -} - -token_info::token_info() -: type(TOKEN_OTHER), sort_key(0), other_case(0) -{ -} - -void token_info::set(token_type t, const char *sk, const char *oc) -{ - assert(oc == 0 || t == TOKEN_UPPER || t == TOKEN_LOWER); - type = t; - sort_key = sk; - other_case = oc; -} - -void token_info::sortify(const char *start, const char *end, string &result) - const -{ - if (sort_key) - result += sort_key; - else if (type == TOKEN_UPPER || type == TOKEN_LOWER) { - for (; start < end; start++) - if (csalpha(*start)) - result += cmlower(*start); - } -} - -int token_info::sortify_non_empty(const char *start, const char *end) const -{ - if (sort_key) - return *sort_key != '\0'; - if (type != TOKEN_UPPER && type != TOKEN_LOWER) - return 0; - for (; start < end; start++) - if (csalpha(*start)) - return 1; - return 0; -} - - -void token_info::lower_case(const char *start, const char *end, - string &result) const -{ - if (type != TOKEN_UPPER) { - while (start < end) - result += *start++; - } - else if (other_case) - result += other_case; - else { - while (start < end) - result += cmlower(*start++); - } -} - -void token_info::upper_case(const char *start, const char *end, - string &result) const -{ - if (type != TOKEN_LOWER) { - while (start < end) - result += *start++; - } - else if (other_case) - result += other_case; - else { - while (start < end) - result += cmupper(*start++); - } -} - -token_table_entry::token_table_entry() -: tok(0) -{ -} - -static void store_token(const char *tok, token_type typ, - const char *sk = 0, const char *oc = 0) -{ - unsigned n = hash_string(tok, strlen(tok)) % TOKEN_TABLE_SIZE; - for (;;) { - if (token_table[n].tok == 0) { - if (++ntokens == TOKEN_TABLE_SIZE) - assert(0); - token_table[n].tok = tok; - break; - } - if (strcmp(tok, token_table[n].tok) == 0) - break; - if (n == 0) - n = TOKEN_TABLE_SIZE - 1; - else - --n; - } - token_table[n].ti.set(typ, sk, oc); -} - - -token_info default_token_info; - -const token_info *lookup_token(const char *start, const char *end) -{ - unsigned n = hash_string(start, end - start) % TOKEN_TABLE_SIZE; - for (;;) { - if (token_table[n].tok == 0) - break; - if (strlen(token_table[n].tok) == size_t(end - start) - && memcmp(token_table[n].tok, start, end - start) == 0) - return &(token_table[n].ti); - if (n == 0) - n = TOKEN_TABLE_SIZE - 1; - else - --n; - } - return &default_token_info; -} - -static void init_ascii() -{ - const char *p; - for (p = "abcdefghijklmnopqrstuvwxyz"; *p; p++) { - char buf[2]; - buf[0] = *p; - buf[1] = '\0'; - store_token(strsave(buf), TOKEN_LOWER); - buf[0] = cmupper(buf[0]); - store_token(strsave(buf), TOKEN_UPPER); - } - for (p = "0123456789"; *p; p++) { - char buf[2]; - buf[0] = *p; - buf[1] = '\0'; - const char *s = strsave(buf); - store_token(s, TOKEN_OTHER, s); - } - for (p = ".,:;?!"; *p; p++) { - char buf[2]; - buf[0] = *p; - buf[1] = '\0'; - store_token(strsave(buf), TOKEN_PUNCT); - } - store_token("-", TOKEN_HYPHEN); -} - -static void store_letter(const char *lower, const char *upper, - const char *sort_key = 0) -{ - store_token(lower, TOKEN_LOWER, sort_key, upper); - store_token(upper, TOKEN_UPPER, sort_key, lower); -} - -static void init_letter(unsigned char uc_code, unsigned char lc_code, - const char *sort_key) -{ - char lbuf[2]; - lbuf[0] = lc_code; - lbuf[1] = 0; - char ubuf[2]; - ubuf[0] = uc_code; - ubuf[1] = 0; - store_letter(strsave(lbuf), strsave(ubuf), sort_key); -} - -static void init_latin1() -{ - init_letter(0xc0, 0xe0, "a"); - init_letter(0xc1, 0xe1, "a"); - init_letter(0xc2, 0xe2, "a"); - init_letter(0xc3, 0xe3, "a"); - init_letter(0xc4, 0xe4, "a"); - init_letter(0xc5, 0xe5, "a"); - init_letter(0xc6, 0xe6, "ae"); - init_letter(0xc7, 0xe7, "c"); - init_letter(0xc8, 0xe8, "e"); - init_letter(0xc9, 0xe9, "e"); - init_letter(0xca, 0xea, "e"); - init_letter(0xcb, 0xeb, "e"); - init_letter(0xcc, 0xec, "i"); - init_letter(0xcd, 0xed, "i"); - init_letter(0xce, 0xee, "i"); - init_letter(0xcf, 0xef, "i"); - - init_letter(0xd0, 0xf0, "d"); - init_letter(0xd1, 0xf1, "n"); - init_letter(0xd2, 0xf2, "o"); - init_letter(0xd3, 0xf3, "o"); - init_letter(0xd4, 0xf4, "o"); - init_letter(0xd5, 0xf5, "o"); - init_letter(0xd6, 0xf6, "o"); - init_letter(0xd8, 0xf8, "o"); - init_letter(0xd9, 0xf9, "u"); - init_letter(0xda, 0xfa, "u"); - init_letter(0xdb, 0xfb, "u"); - init_letter(0xdc, 0xfc, "u"); - init_letter(0xdd, 0xfd, "y"); - init_letter(0xde, 0xfe, THORN_SORT_KEY); - - store_token("\337", TOKEN_LOWER, "ss", "SS"); - store_token("\377", TOKEN_LOWER, "y", "Y"); -} - -static void init_two_char_letter(char l1, char l2, char u1, char u2, - const char *sk = 0) -{ - char buf[6]; - buf[0] = '\\'; - buf[1] = '('; - buf[2] = l1; - buf[3] = l2; - buf[4] = '\0'; - const char *p = strsave(buf); - buf[2] = u1; - buf[3] = u2; - store_letter(p, strsave(buf), sk); - buf[1] = '['; - buf[4] = ']'; - buf[5] = '\0'; - p = strsave(buf); - buf[2] = l1; - buf[3] = l2; - store_letter(strsave(buf), p, sk); - -} - -static void init_special_chars() -{ - const char *p; - for (p = "':^`~"; *p; p++) - for (const char *q = "aeiouy"; *q; q++) { - // Use a variable to work around bug in gcc 2.0 - char c = cmupper(*q); - init_two_char_letter(*p, *q, *p, c); - } - for (p = "/l/o~n,coeaeij"; *p; p += 2) { - // Use variables to work around bug in gcc 2.0 - char c0 = cmupper(p[0]); - char c1 = cmupper(p[1]); - init_two_char_letter(p[0], p[1], c0, c1); - } - init_two_char_letter('v', 's', 'v', 'S', "s"); - init_two_char_letter('v', 'z', 'v', 'Z', "z"); - init_two_char_letter('o', 'a', 'o', 'A', "a"); - init_two_char_letter('T', 'p', 'T', 'P', THORN_SORT_KEY); - init_two_char_letter('-', 'd', '-', 'D'); - - store_token("\\(ss", TOKEN_LOWER, 0, "SS"); - store_token("\\[ss]", TOKEN_LOWER, 0, "SS"); - - store_token("\\(Sd", TOKEN_LOWER, "d", "\\(-D"); - store_token("\\[Sd]", TOKEN_LOWER, "d", "\\[-D]"); - store_token("\\(hy", TOKEN_HYPHEN); - store_token("\\[hy]", TOKEN_HYPHEN); - store_token("\\(en", TOKEN_RANGE_SEP); - store_token("\\[en]", TOKEN_RANGE_SEP); -} - -static void init_strings() -{ - char buf[6]; - buf[0] = '\\'; - buf[1] = '*'; - for (const char *p = "'`^^,:~v_o./;"; *p; p++) { - buf[2] = *p; - buf[3] = '\0'; - store_token(strsave(buf), TOKEN_ACCENT); - buf[2] = '['; - buf[3] = *p; - buf[4] = ']'; - buf[5] = '\0'; - store_token(strsave(buf), TOKEN_ACCENT); - } - - // -ms special letters - store_letter("\\*(th", "\\*(Th", THORN_SORT_KEY); - store_letter("\\*[th]", "\\*[Th]", THORN_SORT_KEY); - store_letter("\\*(d-", "\\*(D-"); - store_letter("\\*[d-]", "\\*[D-]"); - store_letter("\\*(ae", "\\*(Ae", "ae"); - store_letter("\\*[ae]", "\\*[Ae]", "ae"); - store_letter("\\*(oe", "\\*(Oe", "oe"); - store_letter("\\*[oe]", "\\*[Oe]", "oe"); - - store_token("\\*3", TOKEN_LOWER, "y", "Y"); - store_token("\\*8", TOKEN_LOWER, "ss", "SS"); - store_token("\\*q", TOKEN_LOWER, "o", "O"); -} - -struct token_initer { - token_initer(); -}; - -static token_initer the_token_initer; - -token_initer::token_initer() -{ - init_ascii(); - init_latin1(); - init_special_chars(); - init_strings(); - default_token_info.set(TOKEN_OTHER); -} diff --git a/contrib/groff/src/preproc/soelim/soelim.cc b/contrib/groff/src/preproc/soelim/soelim.cc deleted file mode 100644 index 006b04a..0000000 --- a/contrib/groff/src/preproc/soelim/soelim.cc +++ /dev/null @@ -1,346 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001 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 "lib.h" - -#include -#include -#include -#include -#include "errarg.h" -#include "error.h" -#include "stringclass.h" -#include "nonposix.h" - -static size_t include_list_length; -static char **include_list; - -int compatible_flag = 0; - -extern int interpret_lf_args(const char *); -extern "C" const char *Version_string; - -int do_file(const char *filename); - - -static void -include_path_append(char *path) -{ - ++include_list_length; - size_t nbytes = include_list_length * sizeof(char *); - if (include_list) - include_list = (char **)realloc((void *)include_list, nbytes); - else - include_list = (char **)malloc(nbytes); - if (include_list == NULL) - { - fprintf(stderr, "%s: out of memory\n", program_name); - exit(2); - } - include_list[include_list_length - 1] = path; -} - - -void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [ -vC ] [ -I file ] [ files ]\n", program_name); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - include_path_append("."); - int opt; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "CI:v", long_options, NULL)) != EOF) - switch (opt) { - case 'v': - { - printf("GNU soelim (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'C': - compatible_flag = 1; - break; - case 'I': - include_path_append(optarg); - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - int nbad = 0; - if (optind >= argc) - nbad += !do_file("-"); - else - for (int i = optind; i < argc; i++) - nbad += !do_file(argv[i]); - if (ferror(stdout) || fflush(stdout) < 0) - fatal("output error"); - return nbad != 0; -} - -void set_location() -{ - printf(".lf %d %s\n", current_lineno, current_filename); -} - -void do_so(const char *line) -{ - const char *p = line; - while (*p == ' ') - p++; - string filename; - int success = 1; - for (const char *q = p; - success && *q != '\0' && *q != '\n' && *q != ' '; - q++) - if (*q == '\\') { - switch (*++q) { - case 'e': - case '\\': - filename += '\\'; - break; - case ' ': - filename += ' '; - break; - default: - success = 0; - break; - } - } - else - filename += char(*q); - if (success && filename.length() > 0) { - filename += '\0'; - const char *fn = current_filename; - int ln = current_lineno; - current_lineno--; - if (do_file(filename.contents())) { - current_filename = fn; - current_lineno = ln; - set_location(); - return; - } - current_lineno++; - } - fputs(".so", stdout); - fputs(line, stdout); -} - -int do_file(const char *filename) -{ - FILE *fp; - string whole_filename; - if (strcmp(filename, "-") == 0) { - fp = stdin; - whole_filename = filename; - whole_filename += '\0'; - } - else if (IS_ABSOLUTE(filename)) { - whole_filename = filename; - whole_filename += '\0'; - errno = 0; - fp = fopen(filename, "r"); - if (fp == 0) { - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } - } - else { - size_t j; - for (j = 0; j < include_list_length; ++j) - { - char *path = include_list[j]; - if (0 == strcmp(path, ".")) - whole_filename = filename; - else - whole_filename = string(path) + "/" + filename; - whole_filename += '\0'; - errno = 0; - fp = fopen(whole_filename.contents(), "r"); - if (fp != 0) - break; - if (errno != ENOENT) { - error("can't open `%1': %2", - whole_filename.contents(), strerror(errno)); - return 0; - } - } - if (j >= include_list_length) - { - errno = ENOENT; - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } - } - current_filename = whole_filename.contents(); - current_lineno = 1; - set_location(); - enum { START, MIDDLE, HAD_DOT, HAD_s, HAD_so, HAD_l, HAD_lf } state = START; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - switch (state) { - case START: - if (c == '.') - state = HAD_DOT; - else { - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case MIDDLE: - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - break; - case HAD_DOT: - if (c == 's') - state = HAD_s; - else if (c == 'l') - state = HAD_l; - else { - putchar('.'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_s: - if (c == 'o') - state = HAD_so; - else { - putchar('.'); - putchar('s'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_so: - if (c == ' ' || c == '\n' || compatible_flag) { - string line; - for (; c != EOF && c != '\n'; c = getc(fp)) - line += c; - current_lineno++; - line += '\n'; - line += '\0'; - do_so(line.contents()); - state = START; - } - else { - fputs(".so", stdout); - putchar(c); - state = MIDDLE; - } - break; - case HAD_l: - if (c == 'f') - state = HAD_lf; - else { - putchar('.'); - putchar('l'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_lf: - if (c == ' ' || c == '\n' || compatible_flag) { - string line; - for (; c != EOF && c != '\n'; c = getc(fp)) - line += c; - current_lineno++; - line += '\n'; - line += '\0'; - interpret_lf_args(line.contents()); - printf(".lf%s", line.contents()); - state = START; - } - else { - fputs(".lf", stdout); - putchar(c); - state = MIDDLE; - } - break; - default: - assert(0); - } - } - switch (state) { - case HAD_DOT: - fputs(".\n", stdout); - break; - case HAD_l: - fputs(".l\n", stdout); - break; - case HAD_s: - fputs(".s\n", stdout); - break; - case HAD_lf: - fputs(".lf\n", stdout); - break; - case HAD_so: - fputs(".so\n", stdout); - break; - case MIDDLE: - putc('\n', stdout); - break; - case START: - break; - } - if (fp != stdin) - fclose(fp); - current_filename = 0; - return 1; -} diff --git a/contrib/groff/src/preproc/tbl/main.cc b/contrib/groff/src/preproc/tbl/main.cc deleted file mode 100644 index dc0bdce..0000000 --- a/contrib/groff/src/preproc/tbl/main.cc +++ /dev/null @@ -1,1529 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "table.h" - -#define MAX_POINT_SIZE 99 -#define MAX_VERTICAL_SPACING 72 - -extern "C" const char *Version_string; - -static int compatible_flag = 0; - -class table_input { - FILE *fp; - enum { START, MIDDLE, REREAD_T, REREAD_TE, REREAD_E, END, ERROR } state; - string unget_stack; -public: - table_input(FILE *); - int get(); - int ended() { return unget_stack.empty() && state == END; } - void unget(char); -}; - -table_input::table_input(FILE *p) -: fp(p), state(START) -{ -} - -void table_input::unget(char c) -{ - assert(c != '\0'); - unget_stack += c; - if (c == '\n') - current_lineno--; -} - -int table_input::get() -{ - int len = unget_stack.length(); - if (len != 0) { - unsigned char c = unget_stack[len - 1]; - unget_stack.set_length(len - 1); - if (c == '\n') - current_lineno++; - return c; - } - int c; - for (;;) { - switch (state) { - case START: - if ((c = getc(fp)) == '.') { - if ((c = getc(fp)) == 'T') { - if ((c = getc(fp)) == 'E') { - if (compatible_flag) { - state = END; - return EOF; - } - else { - c = getc(fp); - if (c != EOF) - ungetc(c, fp); - if (c == EOF || c == ' ' || c == '\n') { - state = END; - return EOF; - } - state = REREAD_TE; - return '.'; - } - } - else { - if (c != EOF) - ungetc(c, fp); - state = REREAD_T; - return '.'; - } - } - else { - if (c != EOF) - ungetc(c, fp); - state = MIDDLE; - return '.'; - } - } - else if (c == EOF) { - state = ERROR; - return EOF; - } - else { - if (c == '\n') - current_lineno++; - else { - state = MIDDLE; - if (c == '\0') { - error("invalid input character code 0"); - break; - } - } - return c; - } - break; - case MIDDLE: - // handle line continuation - if ((c = getc(fp)) == '\\') { - c = getc(fp); - if (c == '\n') - c = getc(fp); // perhaps state ought to be START now - else { - if (c != EOF) - ungetc(c, fp); - c = '\\'; - } - } - if (c == EOF) { - state = ERROR; - return EOF; - } - else { - if (c == '\n') { - state = START; - current_lineno++; - } - else if (c == '\0') { - error("invalid input character code 0"); - break; - } - return c; - } - case REREAD_T: - state = MIDDLE; - return 'T'; - case REREAD_TE: - state = REREAD_E; - return 'T'; - case REREAD_E: - state = MIDDLE; - return 'E'; - case END: - case ERROR: - return EOF; - } - } -} - -void process_input_file(FILE *); -void process_table(table_input &in); - -void process_input_file(FILE *fp) -{ - enum { START, MIDDLE, HAD_DOT, HAD_T, HAD_TS, HAD_l, HAD_lf } state; - state = START; - int c; - while ((c = getc(fp)) != EOF) - switch (state) { - case START: - if (c == '.') - state = HAD_DOT; - else { - if (c == '\n') - current_lineno++; - else - state = MIDDLE; - putchar(c); - } - break; - case MIDDLE: - if (c == '\n') { - current_lineno++; - state = START; - } - putchar(c); - break; - case HAD_DOT: - if (c == 'T') - state = HAD_T; - else if (c == 'l') - state = HAD_l; - else { - putchar('.'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_T: - if (c == 'S') - state = HAD_TS; - else { - putchar('.'); - putchar('T'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_TS: - if (c == ' ' || c == '\n' || compatible_flag) { - putchar('.'); - putchar('T'); - putchar('S'); - while (c != '\n') { - if (c == EOF) { - error("end of file at beginning of table"); - return; - } - putchar(c); - c = getc(fp); - } - putchar('\n'); - current_lineno++; - { - table_input input(fp); - process_table(input); - set_troff_location(current_filename, current_lineno); - if (input.ended()) { - fputs(".TE", stdout); - while ((c = getc(fp)) != '\n') { - if (c == EOF) { - putchar('\n'); - return; - } - putchar(c); - } - putchar('\n'); - current_lineno++; - } - } - state = START; - } - else { - fputs(".TS", stdout); - putchar(c); - state = MIDDLE; - } - break; - case HAD_l: - if (c == 'f') - state = HAD_lf; - else { - putchar('.'); - putchar('l'); - putchar(c); - if (c == '\n') { - current_lineno++; - state = START; - } - else - state = MIDDLE; - } - break; - case HAD_lf: - if (c == ' ' || c == '\n' || compatible_flag) { - string line; - while (c != EOF) { - line += c; - if (c == '\n') { - current_lineno++; - break; - } - c = getc(fp); - } - line += '\0'; - interpret_lf_args(line.contents()); - printf(".lf%s", line.contents()); - state = START; - } - else { - fputs(".lf", stdout); - putchar(c); - state = MIDDLE; - } - break; - default: - assert(0); - } - switch(state) { - case START: - break; - case MIDDLE: - putchar('\n'); - break; - case HAD_DOT: - fputs(".\n", stdout); - break; - case HAD_l: - fputs(".l\n", stdout); - break; - case HAD_T: - fputs(".T\n", stdout); - break; - case HAD_lf: - fputs(".lf\n", stdout); - break; - case HAD_TS: - fputs(".TS\n", stdout); - break; - } - if (fp != stdin) - fclose(fp); -} - -struct options { - unsigned flags; - int linesize; - char delim[2]; - char tab_char; - char decimal_point_char; - - options(); -}; - -options::options() -: flags(0), linesize(0), tab_char('\t'), decimal_point_char('.') -{ - delim[0] = delim[1] = '\0'; -} - -// Return non-zero if p and q are the same ignoring case. - -int strieq(const char *p, const char *q) -{ - for (; cmlower(*p) == cmlower(*q); p++, q++) - if (*p == '\0') - return 1; - return 0; -} - -// return 0 if we should give up in this table - -options *process_options(table_input &in) -{ - options *opt = new options; - string line; - int level = 0; - for (;;) { - int c = in.get(); - if (c == EOF) { - int i = line.length(); - while (--i >= 0) - in.unget(line[i]); - return opt; - } - if (c == '\n') { - in.unget(c); - int i = line.length(); - while (--i >= 0) - in.unget(line[i]); - return opt; - } - else if (c == '(') - level++; - else if (c == ')') - level--; - else if (c == ';' && level == 0) { - line += '\0'; - break; - } - line += c; - } - if (line.empty()) - return opt; - char *p = &line[0]; - for (;;) { - while (!csalpha(*p) && *p != '\0') - p++; - if (*p == '\0') - break; - char *q = p; - while (csalpha(*q)) - q++; - char *arg = 0; - if (*q != '(' && *q != '\0') - *q++ = '\0'; - while (csspace(*q)) - q++; - if (*q == '(') { - *q++ = '\0'; - arg = q; - while (*q != ')' && *q != '\0') - q++; - if (*q == '\0') - error("missing `)'"); - else - *q++ = '\0'; - } - if (*p == '\0') { - if (arg) - error("argument without option"); - } - else if (strieq(p, "tab")) { - if (!arg) - error("`tab' option requires argument in parentheses"); - else { - if (arg[0] == '\0' || arg[1] != '\0') - error("argument to `tab' option must be a single character"); - else - opt->tab_char = arg[0]; - } - } - else if (strieq(p, "linesize")) { - if (!arg) - error("`linesize' option requires argument in parentheses"); - else { - if (sscanf(arg, "%d", &opt->linesize) != 1) - error("bad linesize `%s'", arg); - else if (opt->linesize <= 0) { - error("linesize must be positive"); - opt->linesize = 0; - } - } - } - else if (strieq(p, "delim")) { - if (!arg) - error("`delim' option requires argument in parentheses"); - else if (arg[0] == '\0' || arg[1] == '\0' || arg[2] != '\0') - error("argument to `delim' option must be two characters"); - else { - opt->delim[0] = arg[0]; - opt->delim[1] = arg[1]; - } - } - else if (strieq(p, "center") || strieq(p, "centre")) { - if (arg) - error("`center' option does not take an argument"); - opt->flags |= table::CENTER; - } - else if (strieq(p, "expand")) { - if (arg) - error("`expand' option does not take an argument"); - opt->flags |= table::EXPAND; - } - else if (strieq(p, "box") || strieq(p, "frame")) { - if (arg) - error("`box' option does not take an argument"); - opt->flags |= table::BOX; - } - else if (strieq(p, "doublebox") || strieq(p, "doubleframe")) { - if (arg) - error("`doublebox' option does not take an argument"); - opt->flags |= table::DOUBLEBOX; - } - else if (strieq(p, "allbox")) { - if (arg) - error("`allbox' option does not take an argument"); - opt->flags |= table::ALLBOX; - } - else if (strieq(p, "nokeep")) { - if (arg) - error("`nokeep' option does not take an argument"); - opt->flags |= table::NOKEEP; - } - else if (strieq(p, "nospaces")) { - if (arg) - error("`nospaces' option does not take an argument"); - opt->flags |= table::NOSPACES; - } - else if (strieq(p, "decimalpoint")) { - if (!arg) - error("`decimalpoint' option requires argument in parentheses"); - else { - if (arg[0] == '\0' || arg[1] != '\0') - error("argument to `decimalpoint' option must be a single character"); - else - opt->decimal_point_char = arg[0]; - } - } - else { - error("unrecognised global option `%1'", p); - // delete opt; - // return 0; - } - p = q; - } - return opt; -} - -entry_modifier::entry_modifier() -: vertical_alignment(CENTER), zero_width(0), stagger(0) -{ - vertical_spacing.inc = vertical_spacing.val = 0; - point_size.inc = point_size.val = 0; -} - -entry_modifier::~entry_modifier() -{ -} - -entry_format::entry_format() : type(FORMAT_LEFT) -{ -} - -entry_format::entry_format(format_type t) : type(t) -{ -} - -void entry_format::debug_print() const -{ - switch (type) { - case FORMAT_LEFT: - putc('l', stderr); - break; - case FORMAT_CENTER: - putc('c', stderr); - break; - case FORMAT_RIGHT: - putc('r', stderr); - break; - case FORMAT_NUMERIC: - putc('n', stderr); - break; - case FORMAT_ALPHABETIC: - putc('a', stderr); - break; - case FORMAT_SPAN: - putc('s', stderr); - break; - case FORMAT_VSPAN: - putc('^', stderr); - break; - case FORMAT_HLINE: - putc('_', stderr); - break; - case FORMAT_DOUBLE_HLINE: - putc('=', stderr); - break; - default: - assert(0); - break; - } - if (point_size.val != 0) { - putc('p', stderr); - if (point_size.inc > 0) - putc('+', stderr); - else if (point_size.inc < 0) - putc('-', stderr); - fprintf(stderr, "%d ", point_size.val); - } - if (vertical_spacing.val != 0) { - putc('v', stderr); - if (vertical_spacing.inc > 0) - putc('+', stderr); - else if (vertical_spacing.inc < 0) - putc('-', stderr); - fprintf(stderr, "%d ", vertical_spacing.val); - } - if (!font.empty()) { - putc('f', stderr); - put_string(font, stderr); - putc(' ', stderr); - } - switch (vertical_alignment) { - case entry_modifier::CENTER: - break; - case entry_modifier::TOP: - putc('t', stderr); - break; - case entry_modifier::BOTTOM: - putc('d', stderr); - break; - } - if (zero_width) - putc('z', stderr); - if (stagger) - putc('u', stderr); -} - -struct format { - int nrows; - int ncolumns; - int *separation; - string *width; - char *equal; - entry_format **entry; - char **vline; - - format(int nr, int nc); - ~format(); - void add_rows(int n); -}; - -format::format(int nr, int nc) : nrows(nr), ncolumns(nc) -{ - int i; - separation = ncolumns > 1 ? new int[ncolumns - 1] : 0; - for (i = 0; i < ncolumns-1; i++) - separation[i] = -1; - width = new string[ncolumns]; - equal = new char[ncolumns]; - for (i = 0; i < ncolumns; i++) - equal[i] = 0; - entry = new entry_format *[nrows]; - for (i = 0; i < nrows; i++) - entry[i] = new entry_format[ncolumns]; - vline = new char*[nrows]; - for (i = 0; i < nrows; i++) { - vline[i] = new char[ncolumns+1]; - for (int j = 0; j < ncolumns+1; j++) - vline[i][j] = 0; - } -} - -void format::add_rows(int n) -{ - int i; - char **old_vline = vline; - vline = new char*[nrows + n]; - for (i = 0; i < nrows; i++) - vline[i] = old_vline[i]; - a_delete old_vline; - for (i = 0; i < n; i++) { - vline[nrows + i] = new char[ncolumns + 1]; - for (int j = 0; j < ncolumns + 1; j++) - vline[nrows + i][j] = 0; - } - entry_format **old_entry = entry; - entry = new entry_format *[nrows + n]; - for (i = 0; i < nrows; i++) - entry[i] = old_entry[i]; - a_delete old_entry; - for (i = 0; i < n; i++) - entry[nrows + i] = new entry_format[ncolumns]; - nrows += n; -} - -format::~format() -{ - a_delete separation; - ad_delete(ncolumns) width; - a_delete equal; - for (int i = 0; i < nrows; i++) { - a_delete vline[i]; - ad_delete(ncolumns) entry[i]; - } - a_delete vline; - a_delete entry; -} - -struct input_entry_format : public entry_format { - input_entry_format *next; - string width; - int separation; - int vline; - int pre_vline; - int last_column; - int equal; - input_entry_format(format_type, input_entry_format * = 0); - ~input_entry_format(); - void debug_print(); -}; - -input_entry_format::input_entry_format(format_type t, input_entry_format *p) -: entry_format(t), next(p) -{ - separation = -1; - last_column = 0; - vline = 0; - pre_vline = 0; - equal = 0; -} - -input_entry_format::~input_entry_format() -{ -} - -void free_input_entry_format_list(input_entry_format *list) -{ - while (list) { - input_entry_format *tem = list; - list = list->next; - delete tem; - } -} - -void input_entry_format::debug_print() -{ - int i; - for (i = 0; i < pre_vline; i++) - putc('|', stderr); - entry_format::debug_print(); - if (!width.empty()) { - putc('w', stderr); - putc('(', stderr); - put_string(width, stderr); - putc(')', stderr); - } - if (equal) - putc('e', stderr); - if (separation >= 0) - fprintf(stderr, "%d", separation); - for (i = 0; i < vline; i++) - putc('|', stderr); - if (last_column) - putc(',', stderr); -} - -// Return zero if we should give up on this table. -// If this is a continuation format line, current_format will be the current -// format line. - -format *process_format(table_input &in, options *opt, - format *current_format = 0) -{ - input_entry_format *list = 0; - int c = in.get(); - for (;;) { - int pre_vline = 0; - int got_format = 0; - int got_period = 0; - format_type t = FORMAT_LEFT; - for (;;) { - if (c == EOF) { - error("end of input while processing format"); - free_input_entry_format_list(list); - return 0; - } - switch (c) { - case 'n': - case 'N': - t = FORMAT_NUMERIC; - got_format = 1; - break; - case 'a': - case 'A': - got_format = 1; - t = FORMAT_ALPHABETIC; - break; - case 'c': - case 'C': - got_format = 1; - t = FORMAT_CENTER; - break; - case 'l': - case 'L': - got_format = 1; - t = FORMAT_LEFT; - break; - case 'r': - case 'R': - got_format = 1; - t = FORMAT_RIGHT; - break; - case 's': - case 'S': - got_format = 1; - t = FORMAT_SPAN; - break; - case '^': - got_format = 1; - t = FORMAT_VSPAN; - break; - case '_': - case '-': // tbl also accepts this - got_format = 1; - t = FORMAT_HLINE; - break; - case '=': - got_format = 1; - t = FORMAT_DOUBLE_HLINE; - break; - case '.': - got_period = 1; - break; - case '|': - pre_vline++; - break; - case ' ': - case '\t': - case '\n': - break; - default: - if (c == opt->tab_char) - break; - error("unrecognised format `%1'", char(c)); - free_input_entry_format_list(list); - return 0; - } - if (got_period) - break; - c = in.get(); - if (got_format) - break; - } - if (got_period) - break; - list = new input_entry_format(t, list); - if (pre_vline) - list->pre_vline = pre_vline; - int success = 1; - do { - switch (c) { - case 't': - case 'T': - c = in.get(); - list->vertical_alignment = entry_modifier::TOP; - break; - case 'd': - case 'D': - c = in.get(); - list->vertical_alignment = entry_modifier::BOTTOM; - break; - case 'u': - case 'U': - c = in.get(); - list->stagger = 1; - break; - case 'z': - case 'Z': - c = in.get(); - list->zero_width = 1; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - int w = 0; - do { - w = w*10 + (c - '0'); - c = in.get(); - } while (c != EOF && csdigit(c)); - list->separation = w; - } - break; - case 'f': - case 'F': - do { - c = in.get(); - } while (c == ' ' || c == '\t'); - if (c == EOF) { - error("missing font name"); - break; - } - if (c == '(') { - for (;;) { - c = in.get(); - if (c == EOF || c == ' ' || c == '\t') { - error("missing `)'"); - break; - } - if (c == ')') { - c = in.get(); - break; - } - list->font += char(c); - } - } - else { - list->font = c; - char cc = c; - c = in.get(); - if (!csdigit(cc) - && c != EOF && c != ' ' && c != '\t' && c != '.' && c != '\n') { - list->font += char(c); - c = in.get(); - } - } - break; - case 'v': - case 'V': - c = in.get(); - list->vertical_spacing.val = 0; - list->vertical_spacing.inc = 0; - if (c == '+' || c == '-') { - list->vertical_spacing.inc = (c == '+' ? 1 : -1); - c = in.get(); - } - if (c == EOF || !csdigit(c)) { - error("`v' modifier must be followed by number"); - list->vertical_spacing.inc = 0; - } - else { - do { - list->vertical_spacing.val *= 10; - list->vertical_spacing.val += c - '0'; - c = in.get(); - } while (c != EOF && csdigit(c)); - } - if (list->vertical_spacing.val > MAX_VERTICAL_SPACING - || list->vertical_spacing.val < -MAX_VERTICAL_SPACING) { - error("unreasonable point size"); - list->vertical_spacing.val = 0; - list->vertical_spacing.inc = 0; - } - break; - case 'p': - case 'P': - c = in.get(); - list->point_size.val = 0; - list->point_size.inc = 0; - if (c == '+' || c == '-') { - list->point_size.inc = (c == '+' ? 1 : -1); - c = in.get(); - } - if (c == EOF || !csdigit(c)) { - error("`p' modifier must be followed by number"); - list->point_size.inc = 0; - } - else { - do { - list->point_size.val *= 10; - list->point_size.val += c - '0'; - c = in.get(); - } while (c != EOF && csdigit(c)); - } - if (list->point_size.val > MAX_POINT_SIZE - || list->point_size.val < -MAX_POINT_SIZE) { - error("unreasonable point size"); - list->point_size.val = 0; - list->point_size.inc = 0; - } - break; - case 'w': - case 'W': - c = in.get(); - while (c == ' ' || c == '\t') - c = in.get(); - if (c == '(') { - list->width = ""; - c = in.get(); - while (c != ')') { - if (c == EOF || c == '\n') { - error("missing `)'"); - free_input_entry_format_list(list); - return 0; - } - list->width += c; - c = in.get(); - } - c = in.get(); - } - else { - if (c == '+' || c == '-') { - list->width = char(c); - c = in.get(); - } - else - list->width = ""; - if (c == EOF || !csdigit(c)) - error("bad argument for `w' modifier"); - else { - do { - list->width += char(c); - c = in.get(); - } while (c != EOF && csdigit(c)); - } - } - break; - case 'e': - case 'E': - c = in.get(); - list->equal++; - break; - case '|': - c = in.get(); - list->vline++; - break; - case 'B': - case 'b': - c = in.get(); - list->font = "B"; - break; - case 'I': - case 'i': - c = in.get(); - list->font = "I"; - break; - case ' ': - case '\t': - c = in.get(); - break; - default: - if (c == opt->tab_char) - c = in.get(); - else - success = 0; - break; - } - } while (success); - if (list->vline > 2) { - list->vline = 2; - error("more than 2 vertical bars between key letters"); - } - if (c == '\n' || c == ',') { - c = in.get(); - list->last_column = 1; - } - } - if (c == '.') { - do { - c = in.get(); - } while (c == ' ' || c == '\t'); - if (c != '\n') { - error("`.' not last character on line"); - free_input_entry_format_list(list); - return 0; - } - } - if (!list) { - error("no format"); - free_input_entry_format_list(list); - return 0; - } - list->last_column = 1; - // now reverse the list so that the first row is at the beginning - input_entry_format *rev = 0; - while (list != 0) { - input_entry_format *tem = list->next; - list->next = rev; - rev = list; - list = tem; - } - list = rev; - input_entry_format *tem; - -#if 0 - for (tem = list; tem; tem = tem->next) - tem->debug_print(); - putc('\n', stderr); -#endif - // compute number of columns and rows - int ncolumns = 0; - int nrows = 0; - int col = 0; - for (tem = list; tem; tem = tem->next) { - if (tem->last_column) { - if (col >= ncolumns) - ncolumns = col + 1; - col = 0; - nrows++; - } - else - col++; - } - int row; - format *f; - if (current_format) { - if (ncolumns > current_format->ncolumns) { - error("cannot increase the number of columns in a continued format"); - free_input_entry_format_list(list); - return 0; - } - f = current_format; - row = f->nrows; - f->add_rows(nrows); - } - else { - f = new format(nrows, ncolumns); - row = 0; - } - col = 0; - for (tem = list; tem; tem = tem->next) { - f->entry[row][col] = *tem; - if (col < ncolumns-1) { - // use the greatest separation - if (tem->separation > f->separation[col]) { - if (current_format) - error("cannot change column separation in continued format"); - else - f->separation[col] = tem->separation; - } - } - else if (tem->separation >= 0) - error("column separation specified for last column"); - if (tem->equal && !f->equal[col]) { - if (current_format) - error("cannot change which columns are equal in continued format"); - else - f->equal[col] = 1; - } - if (!tem->width.empty()) { - // use the last width - if (!f->width[col].empty() && f->width[col] != tem->width) - error("multiple widths for column %1", col+1); - f->width[col] = tem->width; - } - if (tem->pre_vline) { - assert(col == 0); - f->vline[row][col] = tem->pre_vline; - } - f->vline[row][col+1] = tem->vline; - if (tem->last_column) { - row++; - col = 0; - } - else - col++; - } - free_input_entry_format_list(list); - for (col = 0; col < ncolumns; col++) { - entry_format *e = f->entry[f->nrows-1] + col; - if (e->type != FORMAT_HLINE - && e->type != FORMAT_DOUBLE_HLINE - && e->type != FORMAT_SPAN) - break; - } - if (col >= ncolumns) { - error("last row of format is all lines"); - delete f; - return 0; - } - return f; -} - -table *process_data(table_input &in, format *f, options *opt) -{ - char tab_char = opt->tab_char; - int ncolumns = f->ncolumns; - int current_row = 0; - int format_index = 0; - int give_up = 0; - enum { DATA_INPUT_LINE, TROFF_INPUT_LINE, SINGLE_HLINE, DOUBLE_HLINE } type; - table *tbl = new table(ncolumns, opt->flags, opt->linesize, - opt->decimal_point_char); - if (opt->delim[0] != '\0') - tbl->set_delim(opt->delim[0], opt->delim[1]); - for (;;) { - // first determine what type of line this is - int c = in.get(); - if (c == EOF) - break; - if (c == '.') { - int d = in.get(); - if (d != EOF && csdigit(d)) { - in.unget(d); - type = DATA_INPUT_LINE; - } - else { - in.unget(d); - type = TROFF_INPUT_LINE; - } - } - else if (c == '_' || c == '=') { - int d = in.get(); - if (d == '\n') { - if (c == '_') - type = SINGLE_HLINE; - else - type = DOUBLE_HLINE; - } - else { - in.unget(d); - type = DATA_INPUT_LINE; - } - } - else { - type = DATA_INPUT_LINE; - } - switch (type) { - case DATA_INPUT_LINE: - { - string input_entry; - if (format_index >= f->nrows) - format_index = f->nrows - 1; - // A format row that is all lines doesn't use up a data line. - while (format_index < f->nrows - 1) { - int c; - for (c = 0; c < ncolumns; c++) { - entry_format *e = f->entry[format_index] + c; - if (e->type != FORMAT_HLINE - && e->type != FORMAT_DOUBLE_HLINE - // Unfortunately tbl treats a span as needing data. - // && e->type != FORMAT_SPAN - ) - break; - } - if (c < ncolumns) - break; - for (c = 0; c < ncolumns; c++) - tbl->add_entry(current_row, c, input_entry, - f->entry[format_index] + c, current_filename, - current_lineno); - tbl->add_vlines(current_row, f->vline[format_index]); - format_index++; - current_row++; - } - entry_format *line_format = f->entry[format_index]; - int col = 0; - int row_comment = 0; - for (;;) { - if (c == tab_char || c == '\n') { - int ln = current_lineno; - if (c == '\n') - --ln; - if ((opt->flags & table::NOSPACES)) - input_entry.remove_spaces(); - while (col < ncolumns - && line_format[col].type == FORMAT_SPAN) { - tbl->add_entry(current_row, col, "", &line_format[col], - current_filename, ln); - col++; - } - if (c == '\n' && input_entry.length() == 2 - && input_entry[0] == 'T' && input_entry[1] == '{') { - input_entry = ""; - ln++; - enum { - START, MIDDLE, GOT_T, GOT_RIGHT_BRACE, GOT_DOT, - GOT_l, GOT_lf, END - } state = START; - while (state != END) { - c = in.get(); - if (c == EOF) - break; - switch (state) { - case START: - if (c == 'T') - state = GOT_T; - else if (c == '.') - state = GOT_DOT; - else { - input_entry += c; - if (c != '\n') - state = MIDDLE; - } - break; - case GOT_T: - if (c == '}') - state = GOT_RIGHT_BRACE; - else { - input_entry += 'T'; - input_entry += c; - state = c == '\n' ? START : MIDDLE; - } - break; - case GOT_DOT: - if (c == 'l') - state = GOT_l; - else { - input_entry += '.'; - input_entry += c; - state = c == '\n' ? START : MIDDLE; - } - break; - case GOT_l: - if (c == 'f') - state = GOT_lf; - else { - input_entry += ".l"; - input_entry += c; - state = c == '\n' ? START : MIDDLE; - } - break; - case GOT_lf: - if (c == ' ' || c == '\n' || compatible_flag) { - string args; - input_entry += ".lf"; - while (c != EOF) { - args += c; - if (c == '\n') - break; - c = in.get(); - } - args += '\0'; - interpret_lf_args(args.contents()); - // remove the '\0' - args.set_length(args.length() - 1); - input_entry += args; - state = START; - } - else { - input_entry += ".lf"; - input_entry += c; - state = MIDDLE; - } - break; - case GOT_RIGHT_BRACE: - if (c == '\n' || c == tab_char) - state = END; - else { - input_entry += 'T'; - input_entry += '}'; - input_entry += c; - state = c == '\n' ? START : MIDDLE; - } - break; - case MIDDLE: - if (c == '\n') - state = START; - input_entry += c; - break; - case END: - default: - assert(0); - } - } - if (c == EOF) { - error("end of data in middle of text block"); - give_up = 1; - break; - } - } - if (col >= ncolumns) { - if (!input_entry.empty()) { - if (input_entry.length() >= 2 - && input_entry[0] == '\\' - && input_entry[1] == '"') - row_comment = 1; - else if (!row_comment) { - if (c == '\n') - in.unget(c); - input_entry += '\0'; - error("excess data entry `%1' discarded", - input_entry.contents()); - if (c == '\n') - (void)in.get(); - } - } - } - else - tbl->add_entry(current_row, col, input_entry, - &line_format[col], current_filename, ln); - col++; - if (c == '\n') - break; - input_entry = ""; - } - else - input_entry += c; - c = in.get(); - if (c == EOF) - break; - } - if (give_up) - break; - input_entry = ""; - for (; col < ncolumns; col++) - tbl->add_entry(current_row, col, input_entry, &line_format[col], - current_filename, current_lineno - 1); - tbl->add_vlines(current_row, f->vline[format_index]); - current_row++; - format_index++; - } - break; - case TROFF_INPUT_LINE: - { - string line; - int ln = current_lineno; - for (;;) { - line += c; - if (c == '\n') - break; - c = in.get(); - if (c == EOF) { - break; - } - } - tbl->add_text_line(current_row, line, current_filename, ln); - if (line.length() >= 4 - && line[0] == '.' && line[1] == 'T' && line[2] == '&') { - format *newf = process_format(in, opt, f); - if (newf == 0) - give_up = 1; - else - f = newf; - } - if (line.length() >= 3 - && line[0] == '.' && line[1] == 'l' && line[2] == 'f') { - line += '\0'; - interpret_lf_args(line.contents() + 3); - } - } - break; - case SINGLE_HLINE: - tbl->add_single_hline(current_row); - break; - case DOUBLE_HLINE: - tbl->add_double_hline(current_row); - break; - default: - assert(0); - } - if (give_up) - break; - } - if (!give_up && current_row == 0) { - error("no real data"); - give_up = 1; - } - if (give_up) { - delete tbl; - return 0; - } - // Do this here rather than at the beginning in case continued formats - // change it. - int i; - for (i = 0; i < ncolumns - 1; i++) - if (f->separation[i] >= 0) - tbl->set_column_separation(i, f->separation[i]); - for (i = 0; i < ncolumns; i++) - if (!f->width[i].empty()) - tbl->set_minimum_width(i, f->width[i]); - for (i = 0; i < ncolumns; i++) - if (f->equal[i]) - tbl->set_equal_column(i); - return tbl; -} - -void process_table(table_input &in) -{ - int c; - options *opt = 0; - format *form = 0; - table *tbl = 0; - if ((opt = process_options(in)) != 0 - && (form = process_format(in, opt)) != 0 - && (tbl = process_data(in, form, opt)) != 0) { - tbl->print(); - delete tbl; - } - else { - error("giving up on this table"); - while ((c = in.get()) != EOF) - ; - } - delete opt; - delete form; - if (!in.ended()) - error("premature end of file"); -} - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [ -vC ] [ files... ]\n", program_name); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int opt; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "vCT:", long_options, NULL)) != EOF) - switch (opt) { - case 'C': - compatible_flag = 1; - break; - case 'v': - { - printf("GNU tbl (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'T': - // I'm sick of getting bug reports from IRIX users - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - printf(".if !\\n(.g .ab GNU tbl requires GNU troff.\n" - ".if !dTS .ds TS\n" - ".if !dTE .ds TE\n"); - if (argc > optind) { - for (int i = optind; i < argc; i++) - if (argv[i][0] == '-' && argv[i][1] == '\0') { - current_filename = "-"; - current_lineno = 1; - printf(".lf 1 -\n"); - process_input_file(stdin); - } - else { - errno = 0; - FILE *fp = fopen(argv[i], "r"); - if (fp == 0) { - current_lineno = -1; - error("can't open `%1': %2", argv[i], strerror(errno)); - } - else { - current_lineno = 1; - current_filename = argv[i]; - printf(".lf 1 %s\n", current_filename); - process_input_file(fp); - } - } - } - else { - current_filename = "-"; - current_lineno = 1; - printf(".lf 1 -\n"); - process_input_file(stdin); - } - if (ferror(stdout) || fflush(stdout) < 0) - fatal("output error"); - return 0; -} - diff --git a/contrib/groff/src/preproc/tbl/table.cc b/contrib/groff/src/preproc/tbl/table.cc deleted file mode 100644 index c7f96cd..0000000 --- a/contrib/groff/src/preproc/tbl/table.cc +++ /dev/null @@ -1,2778 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000 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 "table.h" - -#define BAR_HEIGHT ".25m" -#define DOUBLE_LINE_SEP "2p" -#define HALF_DOUBLE_LINE_SEP "1p" -#define LINE_SEP "2p" -#define BODY_DEPTH ".25m" - -const int DEFAULT_COLUMN_SEPARATION = 3; - -#define DELIMITER_CHAR "\\[tbl]" -#define PREFIX "3" -#define SEPARATION_FACTOR_REG PREFIX "sep" -#define BOTTOM_REG PREFIX "bot" -#define RESET_MACRO_NAME PREFIX "init" -#define LINESIZE_REG PREFIX "lps" -#define TOP_REG PREFIX "top" -#define CURRENT_ROW_REG PREFIX "crow" -#define LAST_PASSED_ROW_REG PREFIX "passed" -#define TRANSPARENT_STRING_NAME PREFIX "trans" -#define QUOTE_STRING_NAME PREFIX "quote" -#define SECTION_DIVERSION_NAME PREFIX "section" -#define SECTION_DIVERSION_FLAG_REG PREFIX "sflag" -#define SAVED_VERTICAL_POS_REG PREFIX "vert" -#define NEED_BOTTOM_RULE_REG PREFIX "brule" -#define KEEP_MACRO_NAME PREFIX "keep" -#define RELEASE_MACRO_NAME PREFIX "release" -#define SAVED_FONT_REG PREFIX "fnt" -#define SAVED_SIZE_REG PREFIX "sz" -#define SAVED_FILL_REG PREFIX "fll" -#define SAVED_INDENT_REG PREFIX "ind" -#define SAVED_CENTER_REG PREFIX "cent" -#define TABLE_DIVERSION_NAME PREFIX "table" -#define TABLE_DIVERSION_FLAG_REG PREFIX "tflag" -#define TABLE_KEEP_MACRO_NAME PREFIX "tkeep" -#define TABLE_RELEASE_MACRO_NAME PREFIX "trelease" -#define NEEDED_REG PREFIX "needed" -#define REPEATED_MARK_MACRO PREFIX "rmk" -#define REPEATED_VPT_MACRO PREFIX "rvpt" -#define SUPPRESS_BOTTOM_REG PREFIX "supbot" -#define SAVED_DN_REG PREFIX "dn" - -// this must be one character -#define COMPATIBLE_REG PREFIX "c" - -#define BLOCK_WIDTH_PREFIX PREFIX "tbw" -#define BLOCK_DIVERSION_PREFIX PREFIX "tbd" -#define BLOCK_HEIGHT_PREFIX PREFIX "tbh" -#define SPAN_WIDTH_PREFIX PREFIX "w" -#define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw" -#define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw" -#define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw" -#define COLUMN_SEPARATION_PREFIX PREFIX "cs" -#define ROW_START_PREFIX PREFIX "rs" -#define COLUMN_START_PREFIX PREFIX "cl" -#define COLUMN_END_PREFIX PREFIX "ce" -#define COLUMN_DIVIDE_PREFIX PREFIX "cd" -#define ROW_TOP_PREFIX PREFIX "rt" - -string block_width_reg(int r, int c); -string block_diversion_name(int r, int c); -string block_height_reg(int r, int c); -string span_width_reg(int start_col, int end_col); -string span_left_numeric_width_reg(int start_col, int end_col); -string span_right_numeric_width_reg(int start_col, int end_col); -string span_alphabetic_width_reg(int start_col, int end_col); -string column_separation_reg(int col); -string row_start_reg(int r); -string column_start_reg(int c); -string column_end_reg(int c); -string column_divide_reg(int c); -string row_top_reg(int r); - -void set_inline_modifier(const entry_modifier *); -void restore_inline_modifier(const entry_modifier *m); -void set_modifier(const entry_modifier *); -int find_decimal_point(const char *s, char decimal_point_char, - const char *delim); - -string an_empty_string; -int location_force_filename = 0; - -void printfs(const char *, - const string &arg1 = an_empty_string, - const string &arg2 = an_empty_string, - const string &arg3 = an_empty_string, - const string &arg4 = an_empty_string, - const string &arg5 = an_empty_string); - -void prints(const string &); - -inline void prints(char c) -{ - putchar(c); -} - -inline void prints(const char *s) -{ - fputs(s, stdout); -} - -void prints(const string &s) -{ - if (!s.empty()) - fwrite(s.contents(), 1, s.length(), stdout); -} - -struct horizontal_span { - horizontal_span *next; - short start_col; - short end_col; - horizontal_span(int, int, horizontal_span *); -}; - -struct single_line_entry; -struct double_line_entry; -struct simple_entry; - -class table_entry { -friend class table; - table_entry *next; - int input_lineno; - const char *input_filename; -protected: - int start_row; - int end_row; - short start_col; - short end_col; - const entry_modifier *mod; -public: - void set_location(); - table_entry(const entry_modifier *); - virtual ~table_entry(); - virtual int divert(int ncols, const string *mw, int *sep); - virtual void do_width(); - virtual void do_depth(); - virtual void print() = 0; - virtual void position_vertically() = 0; - virtual single_line_entry *to_single_line_entry(); - virtual double_line_entry *to_double_line_entry(); - virtual simple_entry *to_simple_entry(); - virtual int line_type(); - virtual void note_double_vrule_on_right(int); - virtual void note_double_vrule_on_left(int); -}; - -class simple_entry : public table_entry { -public: - simple_entry(const entry_modifier *); - void print(); - void position_vertically(); - simple_entry *to_simple_entry(); - virtual void add_tab(); - virtual void simple_print(int); -}; - -class empty_entry : public simple_entry { -public: - empty_entry(const entry_modifier *); - int line_type(); -}; - -class text_entry : public simple_entry { -protected: - char *contents; - void print_contents(); -public: - text_entry(char *, const entry_modifier *); - ~text_entry(); -}; - -void text_entry::print_contents() -{ - set_inline_modifier(mod); - prints(contents); - restore_inline_modifier(mod); -} - -class repeated_char_entry : public text_entry { -public: - repeated_char_entry(char *s, const entry_modifier *m); - void simple_print(int); -}; - -class simple_text_entry : public text_entry { -public: - simple_text_entry(char *s, const entry_modifier *m); - void do_width(); -}; - -class left_text_entry : public simple_text_entry { -public: - left_text_entry(char *s, const entry_modifier *m); - void simple_print(int); - void add_tab(); -}; - -class right_text_entry : public simple_text_entry { -public: - right_text_entry(char *s, const entry_modifier *m); - void simple_print(int); - void add_tab(); -}; - -class center_text_entry : public simple_text_entry { -public: - center_text_entry(char *s, const entry_modifier *m); - void simple_print(int); - void add_tab(); -}; - -class numeric_text_entry : public text_entry { - int dot_pos; -public: - numeric_text_entry(char *s, const entry_modifier *m, int pos); - void do_width(); - void simple_print(int); -}; - -class alphabetic_text_entry : public text_entry { -public: - alphabetic_text_entry(char *s, const entry_modifier *m); - void do_width(); - void simple_print(int); - void add_tab(); -}; - -class line_entry : public simple_entry { -protected: - char double_vrule_on_right; - char double_vrule_on_left; -public: - line_entry(const entry_modifier *); - void note_double_vrule_on_right(int); - void note_double_vrule_on_left(int); - void simple_print(int) = 0; -}; - -class single_line_entry : public line_entry { -public: - single_line_entry(const entry_modifier *m); - void simple_print(int); - single_line_entry *to_single_line_entry(); - int line_type(); -}; - -class double_line_entry : public line_entry { -public: - double_line_entry(const entry_modifier *m); - void simple_print(int); - double_line_entry *to_double_line_entry(); - int line_type(); -}; - -class short_line_entry : public simple_entry { -public: - short_line_entry(const entry_modifier *m); - void simple_print(int); - int line_type(); -}; - -class short_double_line_entry : public simple_entry { -public: - short_double_line_entry(const entry_modifier *m); - void simple_print(int); - int line_type(); -}; - -class block_entry : public table_entry { - char *contents; -protected: - void do_divert(int alphabetic, int ncols, const string *mw, int *sep); -public: - block_entry(char *s, const entry_modifier *m); - ~block_entry(); - int divert(int ncols, const string *mw, int *sep); - void do_width(); - void do_depth(); - void position_vertically(); - void print() = 0; -}; - -class left_block_entry : public block_entry { -public: - left_block_entry(char *s, const entry_modifier *m); - void print(); -}; - -class right_block_entry : public block_entry { -public: - right_block_entry(char *s, const entry_modifier *m); - void print(); -}; - -class center_block_entry : public block_entry { -public: - center_block_entry(char *s, const entry_modifier *m); - void print(); -}; - -class alphabetic_block_entry : public block_entry { -public: - alphabetic_block_entry(char *s, const entry_modifier *m); - void print(); - int divert(int ncols, const string *mw, int *sep); -}; - -table_entry::table_entry(const entry_modifier *m) -: next(0), input_lineno(-1), input_filename(0), - start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m) -{ -} - -table_entry::~table_entry() -{ -} - -int table_entry::divert(int, const string *, int *) -{ - return 0; -} - -void table_entry::do_width() -{ -} - -single_line_entry *table_entry::to_single_line_entry() -{ - return 0; -} - -double_line_entry *table_entry::to_double_line_entry() -{ - return 0; -} - -simple_entry *table_entry::to_simple_entry() -{ - return 0; -} - -void table_entry::do_depth() -{ -} - -void table_entry::set_location() -{ - set_troff_location(input_filename, input_lineno); -} - -int table_entry::line_type() -{ - return -1; -} - -void table_entry::note_double_vrule_on_right(int) -{ -} - -void table_entry::note_double_vrule_on_left(int) -{ -} - -simple_entry::simple_entry(const entry_modifier *m) : table_entry(m) -{ -} - -void simple_entry::add_tab() -{ - // do nothing -} - -void simple_entry::simple_print(int) -{ - // do nothing -} - -void simple_entry::position_vertically() -{ - if (start_row != end_row) - switch (mod->vertical_alignment) { - case entry_modifier::TOP: - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - break; - case entry_modifier::CENTER: - // Peform the motion in two stages so that the center is rounded - // vertically upwards even if net vertical motion is upwards. - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-1v/2u\n", - row_start_reg(start_row)); - break; - case entry_modifier::BOTTOM: - printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-1v\n", - row_start_reg(start_row)); - break; - default: - assert(0); - } -} - -void simple_entry::print() -{ - prints(".ta"); - add_tab(); - prints('\n'); - set_location(); - prints("\\&"); - simple_print(0); - prints('\n'); -} - -simple_entry *simple_entry::to_simple_entry() -{ - return this; -} - -empty_entry::empty_entry(const entry_modifier *m) -: simple_entry(m) -{ -} - -int empty_entry::line_type() -{ - return 0; -} - -text_entry::text_entry(char *s, const entry_modifier *m) -: simple_entry(m), contents(s) -{ -} - -text_entry::~text_entry() -{ - a_delete contents; -} - - -repeated_char_entry::repeated_char_entry(char *s, const entry_modifier *m) -: text_entry(s, m) -{ -} - -void repeated_char_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - set_inline_modifier(mod); - printfs("\\l" DELIMITER_CHAR "\\n[%1]u\\&", - span_width_reg(start_col, end_col)); - prints(contents); - prints(DELIMITER_CHAR); - restore_inline_modifier(mod); -} - -simple_text_entry::simple_text_entry(char *s, const entry_modifier *m) -: text_entry(s, m) -{ -} - -void simple_text_entry::do_width() -{ - set_location(); - printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, - span_width_reg(start_col, end_col)); - print_contents(); - prints(DELIMITER_CHAR "\n"); -} - -left_text_entry::left_text_entry(char *s, const entry_modifier *m) -: simple_text_entry(s, m) -{ -} - -void left_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - print_contents(); -} - -// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. - -void left_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -right_text_entry::right_text_entry(char *s, const entry_modifier *m) -: simple_text_entry(s, m) -{ -} - -void right_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - prints("\002\003"); - print_contents(); - prints("\002"); -} - -void right_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -center_text_entry::center_text_entry(char *s, const entry_modifier *m) -: simple_text_entry(s, m) -{ -} - -void center_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - prints("\002\003"); - print_contents(); - prints("\003\002"); -} - -void center_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -numeric_text_entry::numeric_text_entry(char *s, const entry_modifier *m, int pos) -: text_entry(s, m), dot_pos(pos) -{ -} - -void numeric_text_entry::do_width() -{ - if (dot_pos != 0) { - set_location(); - printfs(".nr %1 0\\w" DELIMITER_CHAR, - block_width_reg(start_row, start_col)); - set_inline_modifier(mod); - for (int i = 0; i < dot_pos; i++) - prints(contents[i]); - restore_inline_modifier(mod); - prints(DELIMITER_CHAR "\n"); - printfs(".nr %1 \\n[%1]>?\\n[%2]\n", - span_left_numeric_width_reg(start_col, end_col), - block_width_reg(start_row, start_col)); - } - else - printfs(".nr %1 0\n", block_width_reg(start_row, start_col)); - if (contents[dot_pos] != '\0') { - set_location(); - printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, - span_right_numeric_width_reg(start_col, end_col)); - set_inline_modifier(mod); - prints(contents + dot_pos); - restore_inline_modifier(mod); - prints(DELIMITER_CHAR "\n"); - } -} - -void numeric_text_entry::simple_print(int) -{ - printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'", - span_width_reg(start_col, end_col), - span_left_numeric_width_reg(start_col, end_col), - span_right_numeric_width_reg(start_col, end_col), - column_start_reg(start_col), - block_width_reg(start_row, start_col)); - print_contents(); -} - -alphabetic_text_entry::alphabetic_text_entry(char *s, const entry_modifier *m) -: text_entry(s, m) -{ -} - -void alphabetic_text_entry::do_width() -{ - set_location(); - printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, - span_alphabetic_width_reg(start_col, end_col)); - print_contents(); - prints(DELIMITER_CHAR "\n"); -} - -void alphabetic_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - printfs("\\h'\\n[%1]u-\\n[%2]u/2u'", - span_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col)); - print_contents(); -} - -// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. - -void alphabetic_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -block_entry::block_entry(char *s, const entry_modifier *m) -: table_entry(m), contents(s) -{ -} - -block_entry::~block_entry() -{ - a_delete contents; -} - -void block_entry::position_vertically() -{ - if (start_row != end_row) - switch(mod->vertical_alignment) { - case entry_modifier::TOP: - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - break; - case entry_modifier::CENTER: - // Peform the motion in two stages so that the center is rounded - // vertically upwards even if net vertical motion is upwards. - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u/2u\n", - row_start_reg(start_row), - block_height_reg(start_row, start_col)); - break; - case entry_modifier::BOTTOM: - printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u\n", - row_start_reg(start_row), - block_height_reg(start_row, start_col)); - break; - default: - assert(0); - } - if (mod->stagger) - prints(".sp -.5v\n"); -} - -int block_entry::divert(int ncols, const string *mw, int *sep) -{ - do_divert(0, ncols, mw, sep); - return 1; -} - -void block_entry::do_divert(int alphabetic, int ncols, const string *mw, - int *sep) -{ - printfs(".di %1\n", block_diversion_name(start_row, start_col)); - prints(".if \\n[" SAVED_FILL_REG "] .fi\n" - ".in 0\n"); - prints(".ll "); - int i; - for (i = start_col; i <= end_col; i++) - if (mw[i].empty()) - break; - if (i > end_col) { - // Every column spanned by this entry has a minimum width. - for (int j = start_col; j <= end_col; j++) { - if (j > start_col) { - if (sep) - printfs("+%1n", as_string(sep[j - 1])); - prints('+'); - } - printfs("(n;%1)", mw[j]); - } - printfs(">?\\n[%1]u", span_width_reg(start_col, end_col)); - } - else - printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))", - span_width_reg(start_col, end_col), - as_string(end_col - start_col + 1), - as_string(ncols + 1)); - if (alphabetic) - prints("-2n"); - prints("\n"); - set_modifier(mod); - prints(".cp \\n(" COMPATIBLE_REG "\n"); - set_location(); - prints(contents); - prints(".br\n.di\n.cp 0\n"); - if (!mod->zero_width) { - if (alphabetic) { - printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n", - span_width_reg(start_col, end_col)); - printfs(".nr %1 \\n[%1]>?\\n[dl]\n", - span_alphabetic_width_reg(start_col, end_col)); - } - else - printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col, end_col)); - } - printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row, start_col)); - printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row, start_col)); - prints("." RESET_MACRO_NAME "\n" - ".in \\n[" SAVED_INDENT_REG "]u\n" - ".nf\n"); - // the block might have contained .lf commands - location_force_filename = 1; -} - -void block_entry::do_width() -{ - // do nothing; the action happens in divert -} - -void block_entry::do_depth() -{ - printfs(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?(\\n[%1]+\\n[%2])\n", - row_start_reg(start_row), - block_height_reg(start_row, start_col)); -} - -left_block_entry::left_block_entry(char *s, const entry_modifier *m) -: block_entry(s, m) -{ -} - -void left_block_entry::print() -{ - printfs(".in +\\n[%1]u\n", column_start_reg(start_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - - - -right_block_entry::right_block_entry(char *s, const entry_modifier *m) -: block_entry(s, m) -{ -} - -void right_block_entry::print() -{ - printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n", - column_start_reg(start_col), - span_width_reg(start_col, end_col), - block_width_reg(start_row, start_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - -center_block_entry::center_block_entry(char *s, const entry_modifier *m) -: block_entry(s, m) -{ -} - -void center_block_entry::print() -{ - printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", - column_start_reg(start_col), - span_width_reg(start_col, end_col), - block_width_reg(start_row, start_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - -alphabetic_block_entry::alphabetic_block_entry(char *s, - const entry_modifier *m) -: block_entry(s, m) -{ -} - -int alphabetic_block_entry::divert(int ncols, const string *mw, int *sep) -{ - do_divert(1, ncols, mw, sep); - return 1; -} - -void alphabetic_block_entry::print() -{ - printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", - column_start_reg(start_col), - span_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - -line_entry::line_entry(const entry_modifier *m) -: simple_entry(m), double_vrule_on_right(0), double_vrule_on_left(0) -{ -} - -void line_entry::note_double_vrule_on_right(int is_corner) -{ - double_vrule_on_right = is_corner ? 1 : 2; -} - -void line_entry::note_double_vrule_on_left(int is_corner) -{ - double_vrule_on_left = is_corner ? 1 : 2; -} - - -single_line_entry::single_line_entry(const entry_modifier *m) -: line_entry(m) -{ -} - -int single_line_entry::line_type() -{ - return 1; -} - -void single_line_entry::simple_print(int dont_move) -{ - printfs("\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (double_vrule_on_left) { - prints(double_vrule_on_left == 1 ? "-" : "+"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints("'"); - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\s[\\n[" LINESIZE_REG "]]" "\\D'l |\\n[%1]u", - column_divide_reg(end_col+1)); - if (double_vrule_on_right) { - prints(double_vrule_on_left == 1 ? "+" : "-"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints("0'\\s0"); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); -} - -single_line_entry *single_line_entry::to_single_line_entry() -{ - return this; -} - -double_line_entry::double_line_entry(const entry_modifier *m) -: line_entry(m) -{ -} - -int double_line_entry::line_type() -{ - return 2; -} - -void double_line_entry::simple_print(int dont_move) -{ - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (double_vrule_on_left) { - prints(double_vrule_on_left == 1 ? "-" : "+"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints("'"); - printfs("\\v'-" HALF_DOUBLE_LINE_SEP "'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\D'l |\\n[%1]u", - column_divide_reg(end_col+1)); - if (double_vrule_on_right) - prints("-" HALF_DOUBLE_LINE_SEP); - prints(" 0'"); - printfs("\\v'" DOUBLE_LINE_SEP "'" - "\\D'l |\\n[%1]u", - column_divide_reg(start_col)); - if (double_vrule_on_right) { - prints(double_vrule_on_left == 1 ? "+" : "-"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints(" 0'"); - prints("\\s0" - "\\v'-" HALF_DOUBLE_LINE_SEP "'"); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); -} - -double_line_entry *double_line_entry::to_double_line_entry() -{ - return this; -} - -short_line_entry::short_line_entry(const entry_modifier *m) -: simple_entry(m) -{ -} - -int short_line_entry::line_type() -{ - return 1; -} - -void short_line_entry::simple_print(int dont_move) -{ - if (mod->stagger) - prints("\\v'-.5v'"); - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - printfs("\\s[\\n[" LINESIZE_REG "]]" - "\\D'l \\n[%1]u 0'" - "\\s0", - span_width_reg(start_col, end_col)); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); - if (mod->stagger) - prints("\\v'.5v'"); -} - -short_double_line_entry::short_double_line_entry(const entry_modifier *m) -: simple_entry(m) -{ -} - -int short_double_line_entry::line_type() -{ - return 2; -} - -void short_double_line_entry::simple_print(int dont_move) -{ - if (mod->stagger) - prints("\\v'-.5v'"); - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\h'|\\n[%2]u'" - "\\v'-" HALF_DOUBLE_LINE_SEP "'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\D'l \\n[%1]u 0'" - "\\v'" DOUBLE_LINE_SEP "'" - "\\D'l |\\n[%2]u 0'" - "\\s0" - "\\v'-" HALF_DOUBLE_LINE_SEP "'", - span_width_reg(start_col, end_col), - column_start_reg(start_col)); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); - if (mod->stagger) - prints("\\v'.5v'"); -} - -void set_modifier(const entry_modifier *m) -{ - if (!m->font.empty()) - printfs(".ft %1\n", m->font); - if (m->point_size.val != 0) { - prints(".ps "); - if (m->point_size.inc > 0) - prints('+'); - else if (m->point_size.inc < 0) - prints('-'); - printfs("%1\n", as_string(m->point_size.val)); - } - if (m->vertical_spacing.val != 0) { - prints(".vs "); - if (m->vertical_spacing.inc > 0) - prints('+'); - else if (m->vertical_spacing.inc < 0) - prints('-'); - printfs("%1\n", as_string(m->vertical_spacing.val)); - } -} - -void set_inline_modifier(const entry_modifier *m) -{ - if (!m->font.empty()) - printfs("\\f[%1]", m->font); - if (m->point_size.val != 0) { - prints("\\s["); - if (m->point_size.inc > 0) - prints('+'); - else if (m->point_size.inc < 0) - prints('-'); - printfs("%1]", as_string(m->point_size.val)); - } - if (m->stagger) - prints("\\v'-.5v'"); -} - -void restore_inline_modifier(const entry_modifier *m) -{ - if (!m->font.empty()) - prints("\\f[\\n[" SAVED_FONT_REG "]]"); - if (m->point_size.val != 0) - prints("\\s[\\n[" SAVED_SIZE_REG "]]"); - if (m->stagger) - prints("\\v'.5v'"); -} - - -struct stuff { - stuff *next; - int row; // occurs before row `row' - char printed; // has it been printed? - - stuff(int); - virtual void print(table *) = 0; - virtual ~stuff(); - virtual int is_single_line() { return 0; }; - virtual int is_double_line() { return 0; }; -}; - -stuff::stuff(int r) : next(0), row(r), printed(0) -{ -} - -stuff::~stuff() -{ -} - -struct text_stuff : public stuff { - string contents; - const char *filename; - int lineno; - - text_stuff(const string &, int r, const char *fn, int ln); - ~text_stuff(); - void print(table *); -}; - - -text_stuff::text_stuff(const string &s, int r, const char *fn, int ln) -: stuff(r), contents(s), filename(fn), lineno(ln) -{ -} - -text_stuff::~text_stuff() -{ -} - -void text_stuff::print(table *) -{ - printed = 1; - prints(".cp \\n(" COMPATIBLE_REG "\n"); - set_troff_location(filename, lineno); - prints(contents); - prints(".cp 0\n"); - location_force_filename = 1; // it might have been a .lf command -} - -struct single_hline_stuff : public stuff { - single_hline_stuff(int r); - void print(table *); - int is_single_line(); -}; - -single_hline_stuff::single_hline_stuff(int r) : stuff(r) -{ -} - -void single_hline_stuff::print(table *tbl) -{ - printed = 1; - tbl->print_single_hline(row); -} - -int single_hline_stuff::is_single_line() -{ - return 1; -} - -struct double_hline_stuff : stuff { - double_hline_stuff(int r); - void print(table *); - int is_double_line(); -}; - -double_hline_stuff::double_hline_stuff(int r) : stuff(r) -{ -} - -void double_hline_stuff::print(table *tbl) -{ - printed = 1; - tbl->print_double_hline(row); -} - -int double_hline_stuff::is_double_line() -{ - return 1; -} - -struct vertical_rule { - vertical_rule *next; - int start_row; - int end_row; - short col; - char is_double; - string top_adjust; - string bot_adjust; - - vertical_rule(int sr, int er, int c, int dbl, vertical_rule *); - ~vertical_rule(); - void contribute_to_bottom_macro(table *); - void print(); -}; - -vertical_rule::vertical_rule(int sr, int er, int c, int dbl, vertical_rule *p) -: next(p), start_row(sr), end_row(er), col(c), is_double(dbl) -{ -} - -vertical_rule::~vertical_rule() -{ -} - -void vertical_rule::contribute_to_bottom_macro(table *tbl) -{ - printfs(".if \\n[" CURRENT_ROW_REG "]>=%1", - as_string(start_row)); - if (end_row != tbl->get_nrows() - 1) - printfs("&(\\n[" CURRENT_ROW_REG "]<%1)", - as_string(end_row)); - prints(" \\{"); - printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG "] .nr %2 \\n[#T]\n", - as_string(start_row), - row_top_reg(start_row)); - const char *offset_table[3]; - if (is_double) { - offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; - offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; - offset_table[2] = 0; - } - else { - offset_table[0] = ""; - offset_table[1] = 0; - } - for (const char **offsetp = offset_table; *offsetp; offsetp++) { - prints(".sp -1\n" - "\\v'" BODY_DEPTH); - if (!bot_adjust.empty()) - printfs("+%1", bot_adjust); - prints("'"); - printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG "]]\\D'l 0 |\\n[%2]u-1v", - column_divide_reg(col), - row_top_reg(start_row), - *offsetp); - if (!bot_adjust.empty()) - printfs("-(%1)", bot_adjust); - // don't perform the top adjustment if the top is actually #T - if (!top_adjust.empty()) - printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG "]))", - top_adjust, - as_string(start_row)); - prints("'\\s0\n"); - } - prints(".\\}\n"); -} - -void vertical_rule::print() -{ - printfs("\\*[" TRANSPARENT_STRING_NAME "]" - ".if %1<=\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "] " - ".nr %2 \\*[" QUOTE_STRING_NAME "]\\n[#T]\n", - as_string(start_row), - row_top_reg(start_row)); - const char *offset_table[3]; - if (is_double) { - offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; - offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; - offset_table[2] = 0; - } - else { - offset_table[0] = ""; - offset_table[1] = 0; - } - for (const char **offsetp = offset_table; *offsetp; offsetp++) { - prints("\\*[" TRANSPARENT_STRING_NAME "].sp -1\n" - "\\*[" TRANSPARENT_STRING_NAME "]\\v'" BODY_DEPTH); - if (!bot_adjust.empty()) - printfs("+%1", bot_adjust); - prints("'"); - printfs("\\h'\\n[%1]u%3'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\D'l 0 |\\*[" QUOTE_STRING_NAME "]\\n[%2]u-1v", - column_divide_reg(col), - row_top_reg(start_row), - *offsetp); - if (!bot_adjust.empty()) - printfs("-(%1)", bot_adjust); - // don't perform the top adjustment if the top is actually #T - if (!top_adjust.empty()) - printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME "]\\n[" - LAST_PASSED_ROW_REG "]))", - top_adjust, - as_string(start_row)); - prints("'" - "\\s0\n"); - } -} - -table::table(int nc, unsigned f, int ls, char dpc) -: flags(f), nrows(0), ncolumns(nc), linesize(ls), decimal_point_char(dpc), - vrule_list(0), stuff_list(0), span_list(0), - entry_list(0), entry_list_tailp(&entry_list), entry(0), - vline(0), row_is_all_lines(0), left_separation(0), right_separation(0), - allocated_rows(0) -{ - minimum_width = new string[ncolumns]; - column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0; - equal = new char[ncolumns]; - int i; - for (i = 0; i < ncolumns; i++) - equal[i] = 0; - for (i = 0; i < ncolumns-1; i++) - column_separation[i] = DEFAULT_COLUMN_SEPARATION; - delim[0] = delim[1] = '\0'; -} - -table::~table() -{ - for (int i = 0; i < nrows; i++) { - a_delete entry[i]; - a_delete vline[i]; - } - a_delete entry; - a_delete vline; - while (entry_list) { - table_entry *tem = entry_list; - entry_list = entry_list->next; - delete tem; - } - ad_delete(ncolumns) minimum_width; - a_delete column_separation; - a_delete equal; - while (stuff_list) { - stuff *tem = stuff_list; - stuff_list = stuff_list->next; - delete tem; - } - while (vrule_list) { - vertical_rule *tem = vrule_list; - vrule_list = vrule_list->next; - delete tem; - } - a_delete row_is_all_lines; - while (span_list) { - horizontal_span *tem = span_list; - span_list = span_list->next; - delete tem; - } -} - -void table::set_delim(char c1, char c2) -{ - delim[0] = c1; - delim[1] = c2; -} - -void table::set_minimum_width(int c, const string &w) -{ - assert(c >= 0 && c < ncolumns); - minimum_width[c] = w; -} - -void table::set_column_separation(int c, int n) -{ - assert(c >= 0 && c < ncolumns - 1); - column_separation[c] = n; -} - -void table::set_equal_column(int c) -{ - assert(c >= 0 && c < ncolumns); - equal[c] = 1; -} - -void table::add_stuff(stuff *p) -{ - stuff **pp; - for (pp = &stuff_list; *pp; pp = &(*pp)->next) - ; - *pp = p; -} - -void table::add_text_line(int r, const string &s, const char *filename, int lineno) -{ - add_stuff(new text_stuff(s, r, filename, lineno)); -} - -void table::add_single_hline(int r) -{ - add_stuff(new single_hline_stuff(r)); -} - -void table::add_double_hline(int r) -{ - add_stuff(new double_hline_stuff(r)); -} - -void table::allocate(int r) -{ - if (r >= nrows) { - typedef table_entry **PPtable_entry; // work around g++ 1.36.1 bug - if (r >= allocated_rows) { - if (allocated_rows == 0) { - allocated_rows = 16; - if (allocated_rows <= r) - allocated_rows = r + 1; - entry = new PPtable_entry[allocated_rows]; - vline = new char*[allocated_rows]; - } - else { - table_entry ***old_entry = entry; - int old_allocated_rows = allocated_rows; - allocated_rows *= 2; - if (allocated_rows <= r) - allocated_rows = r + 1; - entry = new PPtable_entry[allocated_rows]; - memcpy(entry, old_entry, sizeof(table_entry**)*old_allocated_rows); - a_delete old_entry; - char **old_vline = vline; - vline = new char*[allocated_rows]; - memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows); - a_delete old_vline; - } - } - assert(allocated_rows > r); - while (nrows <= r) { - entry[nrows] = new table_entry*[ncolumns]; - int i; - for (i = 0; i < ncolumns; i++) - entry[nrows][i] = 0; - vline[nrows] = new char[ncolumns+1]; - for (i = 0; i < ncolumns+1; i++) - vline[nrows][i] = 0; - nrows++; - } - } -} - -void table::do_hspan(int r, int c) -{ - assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); - if (c == 0) { - error("first column cannot be horizontally spanned"); - return; - } - table_entry *e = entry[r][c]; - if (e) { - assert(e->start_row <= r && r <= e->end_row - && e->start_col <= c && c <= e->end_col - && e->end_row - e->start_row > 0 - && e->end_col - e->start_col > 0); - return; - } - e = entry[r][c-1]; - // e can be 0 if we had an empty entry or an error - if (e == 0) - return; - if (e->start_row != r) { - /* - l l - ^ s */ - error("impossible horizontal span at row %1, column %2", r + 1, c + 1); - } - else { - e->end_col = c; - entry[r][c] = e; - } -} - -void table::do_vspan(int r, int c) -{ - assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); - if (r == 0) { - error("first row cannot be vertically spanned"); - return; - } - table_entry *e = entry[r][c]; - if (e) { - assert(e->start_row <= r && r <= e->end_row - && e->start_col <= c && c <= e->end_col - && e->end_row - e->start_row > 0 - && e->end_col - e->start_col > 0); - return; - } - e = entry[r-1][c]; - // e can be 0 if we had an empty entry or an error - if (e == 0) - return; - if (e->start_col != c) { - /* l s - l ^ */ - error("impossible vertical span at row %1, column %2", r + 1, c + 1); - } - else { - for (int i = c; i <= e->end_col; i++) { - assert(entry[r][i] == 0); - entry[r][i] = e; - } - e->end_row = r; - } -} - -int find_decimal_point(const char *s, char decimal_point_char, - const char *delim) -{ - if (s == 0 || *s == '\0') - return -1; - const char *p; - int in_delim = 0; // is p within eqn delimiters? - // tbl recognises \& even within eqn delimiters; I don't - for (p = s; *p; p++) - if (in_delim) { - if (*p == delim[1]) - in_delim = 0; - } - else if (*p == delim[0]) - in_delim = 1; - else if (p[0] == '\\' && p[1] == '&') - return p - s; - int possible_pos = -1; - in_delim = 0; - for (p = s; *p; p++) - if (in_delim) { - if (*p == delim[1]) - in_delim = 0; - } - else if (*p == delim[0]) - in_delim = 1; - else if (p[0] == decimal_point_char && csdigit(p[1])) - possible_pos = p - s; - if (possible_pos >= 0) - return possible_pos; - in_delim = 0; - for (p = s; *p; p++) - if (in_delim) { - if (*p == delim[1]) - in_delim = 0; - } - else if (*p == delim[0]) - in_delim = 1; - else if (csdigit(*p)) - possible_pos = p + 1 - s; - return possible_pos; -} - -void table::add_entry(int r, int c, const string &str, const entry_format *f, - const char *fn, int ln) -{ - allocate(r); - table_entry *e = 0; - if (str == "\\_") { - e = new short_line_entry(f); - } - else if (str == "\\=") { - e = new short_double_line_entry(f); - } - else if (str == "_") { - single_line_entry *lefte; - if (c > 0 && entry[r][c-1] != 0 && - (lefte = entry[r][c-1]->to_single_line_entry()) != 0 - && lefte->start_row == r - && lefte->mod->stagger == f->stagger) { - lefte->end_col = c; - entry[r][c] = lefte; - } - else - e = new single_line_entry(f); - } - else if (str == "=") { - double_line_entry *lefte; - if (c > 0 && entry[r][c-1] != 0 && - (lefte = entry[r][c-1]->to_double_line_entry()) != 0 - && lefte->start_row == r - && lefte->mod->stagger == f->stagger) { - lefte->end_col = c; - entry[r][c] = lefte; - } - else - e = new double_line_entry(f); - } - else if (str == "\\^") { - do_vspan(r, c); - } - else if (str.length() > 2 && str[0] == '\\' && str[1] == 'R') { - if (str.search('\n') >= 0) - error_with_file_and_line(fn, ln, "bad repeated character"); - else { - char *s = str.substring(2, str.length() - 2).extract(); - e = new repeated_char_entry(s, f); - } - } - else { - int is_block = str.search('\n') >= 0; - char *s; - switch (f->type) { - case FORMAT_SPAN: - assert(str.empty()); - do_hspan(r, c); - break; - case FORMAT_LEFT: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new left_block_entry(s, f); - else - e = new left_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_CENTER: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new center_block_entry(s, f); - else - e = new center_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_RIGHT: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new right_block_entry(s, f); - else - e = new right_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_NUMERIC: - if (!str.empty()) { - s = str.extract(); - if (is_block) { - error_with_file_and_line(fn, ln, "can't have numeric text block"); - e = new left_block_entry(s, f); - } - else { - int pos = find_decimal_point(s, decimal_point_char, delim); - if (pos < 0) - e = new center_text_entry(s, f); - else - e = new numeric_text_entry(s, f, pos); - } - } - else - e = new empty_entry(f); - break; - case FORMAT_ALPHABETIC: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new alphabetic_block_entry(s, f); - else - e = new alphabetic_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_VSPAN: - do_vspan(r, c); - break; - case FORMAT_HLINE: - if (str.length() != 0) - error_with_file_and_line(fn, ln, - "non-empty data entry for `_' format ignored"); - e = new single_line_entry(f); - break; - case FORMAT_DOUBLE_HLINE: - if (str.length() != 0) - error_with_file_and_line(fn, ln, - "non-empty data entry for `=' format ignored"); - e = new double_line_entry(f); - break; - default: - assert(0); - } - } - if (e) { - table_entry *preve = entry[r][c]; - if (preve) { - /* c s - ^ l */ - error_with_file_and_line(fn, ln, "row %1, column %2 already spanned", - r + 1, c + 1); - delete e; - } - else { - e->input_lineno = ln; - e->input_filename = fn; - e->start_row = e->end_row = r; - e->start_col = e->end_col = c; - *entry_list_tailp = e; - entry_list_tailp = &e->next; - entry[r][c] = e; - } - } -} - -// add vertical lines for row r - -void table::add_vlines(int r, const char *v) -{ - allocate(r); - for (int i = 0; i < ncolumns+1; i++) - vline[r][i] = v[i]; -} - -void table::check() -{ - table_entry *p = entry_list; - int i, j; - while (p) { - for (i = p->start_row; i <= p->end_row; i++) - for (j = p->start_col; j <= p->end_col; j++) - assert(entry[i][j] == p); - p = p->next; - } -} - -void table::print() -{ - location_force_filename = 1; - check(); - init_output(); - determine_row_type(); - compute_widths(); - if (!(flags & CENTER)) - prints(".if \\n[" SAVED_CENTER_REG "] \\{"); - prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2>?-\\n[.i])\n" - ".nr " SAVED_INDENT_REG " \\n[.i]\n"); - if (!(flags & CENTER)) - prints(".\\}\n"); - build_vrule_list(); - define_bottom_macro(); - do_top(); - for (int i = 0; i < nrows; i++) - do_row(i); - do_bottom(); -} - -void table::determine_row_type() -{ - row_is_all_lines = new char[nrows]; - for (int i = 0; i < nrows; i++) { - int had_single = 0; - int had_double = 0; - int had_non_line = 0; - for (int c = 0; c < ncolumns; c++) { - table_entry *e = entry[i][c]; - if (e != 0) { - if (e->start_row == e->end_row) { - int t = e->line_type(); - switch (t) { - case -1: - had_non_line = 1; - break; - case 0: - // empty - break; - case 1: - had_single = 1; - break; - case 2: - had_double = 1; - break; - default: - assert(0); - } - if (had_non_line) - break; - } - c = e->end_col; - } - } - if (had_non_line) - row_is_all_lines[i] = 0; - else if (had_double) - row_is_all_lines[i] = 2; - else if (had_single) - row_is_all_lines[i] = 1; - else - row_is_all_lines[i] = 0; - } -} - - -void table::init_output() -{ - prints(".nr " COMPATIBLE_REG " \\n(.C\n" - ".cp 0\n"); - if (linesize > 0) - printfs(".nr " LINESIZE_REG " %1\n", as_string(linesize)); - else - prints(".nr " LINESIZE_REG " \\n[.s]\n"); - if (!(flags & CENTER)) - prints(".nr " SAVED_CENTER_REG " \\n[.ce]\n"); - prints(".de " RESET_MACRO_NAME "\n" - ".ft \\n[.f]\n" - ".ps \\n[.s]\n" - ".vs \\n[.v]u\n" - ".in \\n[.i]u\n" - ".ll \\n[.l]u\n" - ".ls \\n[.L]\n" - ".ad \\n[.j]\n" - ".ie \\n[.u] .fi\n" - ".el .nf\n" - ".ce \\n[.ce]\n" - "..\n" - ".nr " SAVED_INDENT_REG " \\n[.i]\n" - ".nr " SAVED_FONT_REG " \\n[.f]\n" - ".nr " SAVED_SIZE_REG " \\n[.s]\n" - ".nr " SAVED_FILL_REG " \\n[.u]\n" - ".nr T. 0\n" - ".nr " CURRENT_ROW_REG " 0-1\n" - ".nr " LAST_PASSED_ROW_REG " 0-1\n" - ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" - ".ds " TRANSPARENT_STRING_NAME "\n" - ".ds " QUOTE_STRING_NAME "\n" - ".nr " NEED_BOTTOM_RULE_REG " 1\n" - ".nr " SUPPRESS_BOTTOM_REG " 0\n" - ".eo\n" - ".de " REPEATED_MARK_MACRO "\n" - ".mk \\$1\n" - ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO " \"\\$1\"\n" - "..\n" - ".de " REPEATED_VPT_MACRO "\n" - ".vpt \\$1\n" - ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO " \"\\$1\"\n" - "..\n"); - if (!(flags & NOKEEP)) - prints(".de " KEEP_MACRO_NAME "\n" - ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME " \\\\\n" - ".ds " TRANSPARENT_STRING_NAME " \\!\n" - ".di " SECTION_DIVERSION_NAME "\n" - ".nr " SECTION_DIVERSION_FLAG_REG " 1\n" - ".in 0\n" - ".\\}\n" - "..\n" - ".de " RELEASE_MACRO_NAME "\n" - ".if \\n[" SECTION_DIVERSION_FLAG_REG "] \\{" - ".di\n" - ".in \\n[" SAVED_INDENT_REG "]u\n" - ".nr " SAVED_DN_REG " \\n[dn]\n" - ".ds " QUOTE_STRING_NAME "\n" - ".ds " TRANSPARENT_STRING_NAME "\n" - ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" - ".if \\n[.t]<=\\n[dn] \\{" - ".nr T. 1\n" - ".T#\n" - ".nr " SUPPRESS_BOTTOM_REG " 1\n" - ".sp \\n[.t]u\n" - ".nr " SUPPRESS_BOTTOM_REG " 0\n" - ".mk #T\n" - ".\\}\n" - ".if \\n[.t]<=\\n[" SAVED_DN_REG "] " - /* Since we turn off traps, it won't get into an infinite loop - when we try and print it; it will just go off the bottom of the - page. */ - ".tm warning: page \\n%: table text block will not fit on one page\n" - ".nf\n" - ".ls 1\n" - "." SECTION_DIVERSION_NAME "\n" - ".ls\n" - ".rm " SECTION_DIVERSION_NAME "\n" - ".\\}\n" - "..\n" - ".nr " TABLE_DIVERSION_FLAG_REG " 0\n" - ".de " TABLE_KEEP_MACRO_NAME "\n" - ".if '\\n[.z]'' \\{" - ".di " TABLE_DIVERSION_NAME "\n" - ".nr " TABLE_DIVERSION_FLAG_REG " 1\n" - ".\\}\n" - "..\n" - ".de " TABLE_RELEASE_MACRO_NAME "\n" - ".if \\n[" TABLE_DIVERSION_FLAG_REG "] \\{.br\n" - ".di\n" - ".nr " SAVED_DN_REG " \\n[dn]\n" - ".ne \\n[dn]u+\\n[.V]u\n" - ".ie \\n[.t]<=\\n[" SAVED_DN_REG "] " - ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH with a supporting macro package\n" - ".el \\{" - ".in 0\n" - ".ls 1\n" - ".nf\n" - "." TABLE_DIVERSION_NAME "\n" - ".\\}\n" - ".rm " TABLE_DIVERSION_NAME "\n" - ".\\}\n" - "..\n"); - prints(".ec\n" - ".ce 0\n" - ".nf\n"); -} - -string block_width_reg(int r, int c) -{ - static char name[sizeof(BLOCK_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, BLOCK_WIDTH_PREFIX "%d,%d", r, c); - return string(name); -} - -string block_diversion_name(int r, int c) -{ - static char name[sizeof(BLOCK_DIVERSION_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, BLOCK_DIVERSION_PREFIX "%d,%d", r, c); - return string(name); -} - -string block_height_reg(int r, int c) -{ - static char name[sizeof(BLOCK_HEIGHT_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, BLOCK_HEIGHT_PREFIX "%d,%d", r, c); - return string(name); -} - -string span_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - -string span_left_numeric_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_LEFT_NUMERIC_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - -string span_right_numeric_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - -string span_alphabetic_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_ALPHABETIC_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - - -string column_separation_reg(int col) -{ - static char name[sizeof(COLUMN_SEPARATION_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_SEPARATION_PREFIX "%d", col); - return string(name); -} - -string row_start_reg(int row) -{ - static char name[sizeof(ROW_START_PREFIX)+INT_DIGITS]; - sprintf(name, ROW_START_PREFIX "%d", row); - return string(name); -} - -string column_start_reg(int col) -{ - static char name[sizeof(COLUMN_START_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_START_PREFIX "%d", col); - return string(name); -} - -string column_end_reg(int col) -{ - static char name[sizeof(COLUMN_END_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_END_PREFIX "%d", col); - return string(name); -} - -string column_divide_reg(int col) -{ - static char name[sizeof(COLUMN_DIVIDE_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_DIVIDE_PREFIX "%d", col); - return string(name); -} - -string row_top_reg(int row) -{ - static char name[sizeof(ROW_TOP_PREFIX)+INT_DIGITS]; - sprintf(name, ROW_TOP_PREFIX "%d", row); - return string(name); -} - -void init_span_reg(int start_col, int end_col) -{ - printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n", - span_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col), - span_left_numeric_width_reg(start_col, end_col), - span_right_numeric_width_reg(start_col, end_col)); -} - -void compute_span_width(int start_col, int end_col) -{ - printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n" - ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n", - span_width_reg(start_col, end_col), - span_left_numeric_width_reg(start_col, end_col), - span_right_numeric_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col)); - -} - -// Increase the widths of columns so that the width of any spanning entry -// is no greater than the sum of the widths of the columns that it spans. -// Ensure that the widths of columns remain equal. - -void table::divide_span(int start_col, int end_col) -{ - assert(end_col > start_col); - printfs(".nr " NEEDED_REG " \\n[%1]-(\\n[%2]", - span_width_reg(start_col, end_col), - span_width_reg(start_col, start_col)); - int i; - for (i = start_col + 1; i <= end_col; i++) { - // The column separation may shrink with the expand option. - if (!(flags & EXPAND)) - printfs("+%1n", as_string(column_separation[i - 1])); - printfs("+\\n[%1]", span_width_reg(i, i)); - } - prints(")\n"); - printfs(".nr " NEEDED_REG " \\n[" NEEDED_REG "]/%1\n", - as_string(end_col - start_col + 1)); - prints(".if \\n[" NEEDED_REG "] \\{"); - for (i = start_col; i <= end_col; i++) - printfs(".nr %1 +\\n[" NEEDED_REG "]\n", - span_width_reg(i, i)); - int equal_flag = 0; - for (i = start_col; i <= end_col && !equal_flag; i++) - if (equal[i]) - equal_flag = 1; - if (equal_flag) { - for (i = 0; i < ncolumns; i++) - if (i < start_col || i > end_col) - printfs(".nr %1 +\\n[" NEEDED_REG "]\n", - span_width_reg(i, i)); - } - prints(".\\}\n"); -} - - -void table::sum_columns(int start_col, int end_col) -{ - assert(end_col > start_col); - printfs(".nr %1 \\n[%2]", - span_width_reg(start_col, end_col), - span_width_reg(start_col, start_col)); - for (int i = start_col + 1; i <= end_col; i++) - printfs("+(%1*\\n[" SEPARATION_FACTOR_REG "])+\\n[%2]", - as_string(column_separation[i - 1]), - span_width_reg(i, i)); - prints('\n'); -} - -horizontal_span::horizontal_span(int sc, int ec, horizontal_span *p) -: next(p), start_col(sc), end_col(ec) -{ -} - -void table::build_span_list() -{ - span_list = 0; - table_entry *p = entry_list; - while (p) { - if (p->end_col != p->start_col) { - horizontal_span *q; - for (q = span_list; q; q = q->next) - if (q->start_col == p->start_col - && q->end_col == p->end_col) - break; - if (!q) - span_list = new horizontal_span(p->start_col, p->end_col, span_list); - } - p = p->next; - } - // Now sort span_list primarily by order of end_row, and secondarily - // by reverse order of start_row. This ensures that if we divide - // spans using the order in span_list, we will get reasonable results. - horizontal_span *unsorted = span_list; - span_list = 0; - while (unsorted) { - horizontal_span **pp; - for (pp = &span_list; *pp; pp = &(*pp)->next) - if (unsorted->end_col < (*pp)->end_col - || (unsorted->end_col == (*pp)->end_col - && (unsorted->start_col > (*pp)->start_col))) - break; - horizontal_span *tem = unsorted->next; - unsorted->next = *pp; - *pp = unsorted; - unsorted = tem; - } -} - - -void table::compute_separation_factor() -{ - if (flags & (ALLBOX|BOX|DOUBLEBOX)) - left_separation = right_separation = 1; - else { - for (int i = 0; i < nrows; i++) { - if (vline[i][0] > 0) - left_separation = 1; - if (vline[i][ncolumns] > 0) - right_separation = 1; - } - } - if (flags & EXPAND) { - int total_sep = left_separation + right_separation; - int i; - for (i = 0; i < ncolumns - 1; i++) - total_sep += column_separation[i]; - if (total_sep != 0) { - // Don't let the separation factor be negative. - prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]"); - for (i = 0; i < ncolumns; i++) - printfs("-\\n[%1]", span_width_reg(i, i)); - printfs("/%1>?0\n", as_string(total_sep)); - } - } -} - -void table::compute_column_positions() -{ - printfs(".nr %1 0\n", column_divide_reg(0)); - printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG "]\n", - column_start_reg(0), - as_string(left_separation)); - int i; - for (i = 1;; i++) { - printfs(".nr %1 \\n[%2]+\\n[%3]\n", - column_end_reg(i-1), - column_start_reg(i-1), - span_width_reg(i-1, i-1)); - if (i >= ncolumns) - break; - printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", - column_start_reg(i), - column_end_reg(i-1), - as_string(column_separation[i-1])); - printfs(".nr %1 \\n[%2]+\\n[%3]/2\n", - column_divide_reg(i), - column_end_reg(i-1), - column_start_reg(i)); - } - printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", - column_divide_reg(ncolumns), - column_end_reg(i-1), - as_string(right_separation)); - printfs(".nr TW \\n[%1]\n", - column_divide_reg(ncolumns)); - if (flags & DOUBLEBOX) { - printfs(".nr %1 +" DOUBLE_LINE_SEP "\n", column_divide_reg(0)); - printfs(".nr %1 -" DOUBLE_LINE_SEP "\n", column_divide_reg(ncolumns)); - } -} - -void table::make_columns_equal() -{ - int first = -1; // index of first equal column - int i; - for (i = 0; i < ncolumns; i++) - if (equal[i]) { - if (first < 0) { - printfs(".nr %1 \\n[%1]", span_width_reg(i, i)); - first = i; - } - else - printfs(">?\\n[%1]", span_width_reg(i, i)); - } - if (first >= 0) { - prints('\n'); - for (i = first + 1; i < ncolumns; i++) - if (equal[i]) - printfs(".nr %1 \\n[%2]\n", - span_width_reg(i, i), - span_width_reg(first, first)); - } -} - -void table::compute_widths() -{ - build_span_list(); - int i; - horizontal_span *p; - prints(".nr " SEPARATION_FACTOR_REG " 1n\n"); - for (i = 0; i < ncolumns; i++) { - init_span_reg(i, i); - if (!minimum_width[i].empty()) - printfs(".nr %1 %2\n", span_width_reg(i, i), minimum_width[i]); - } - for (p = span_list; p; p = p->next) - init_span_reg(p->start_col, p->end_col); - table_entry *q; - for (q = entry_list; q; q = q->next) - if (!q->mod->zero_width) - q->do_width(); - for (i = 0; i < ncolumns; i++) - compute_span_width(i, i); - for (p = span_list; p; p = p->next) - compute_span_width(p->start_col, p->end_col); - make_columns_equal(); - // Note that divide_span keeps equal width columns equal. - for (p = span_list; p; p = p->next) - divide_span(p->start_col, p->end_col); - for (p = span_list; p; p = p->next) - sum_columns(p->start_col, p->end_col); - int had_spanning_block = 0; - int had_equal_block = 0; - for (q = entry_list; q; q = q->next) - if (q->divert(ncolumns, minimum_width, - (flags & EXPAND) ? column_separation : 0)) { - if (q->end_col > q->start_col) - had_spanning_block = 1; - for (i = q->start_col; i <= q->end_col && !had_equal_block; i++) - if (equal[i]) - had_equal_block = 1; - } - if (had_equal_block) - make_columns_equal(); - if (had_spanning_block) - for (p = span_list; p; p = p->next) - divide_span(p->start_col, p->end_col); - compute_separation_factor(); - for (p = span_list; p; p = p->next) - sum_columns(p->start_col, p->end_col); - compute_column_positions(); -} - -void table::print_single_hline(int r) -{ - prints(".vs " LINE_SEP ">?\\n[.V]u\n" - ".ls 1\n" - "\\v'" BODY_DEPTH "'" - "\\s[\\n[" LINESIZE_REG "]]"); - if (r > nrows - 1) - prints("\\D'l |\\n[TW]u 0'"); - else { - int start_col = 0; - for (;;) { - while (start_col < ncolumns - && entry[r][start_col] != 0 - && entry[r][start_col]->start_row != r) - start_col++; - int end_col; - for (end_col = start_col; - end_col < ncolumns - && (entry[r][end_col] == 0 - || entry[r][end_col]->start_row == r); - end_col++) - ; - if (end_col <= start_col) - break; - printfs("\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if ((r > 0 && vline[r-1][start_col] == 2) - || (r < nrows && vline[r][start_col] == 2)) - prints("-" HALF_DOUBLE_LINE_SEP); - prints("'"); - printfs("\\D'l |\\n[%1]u", - column_divide_reg(end_col)); - if ((r > 0 && vline[r-1][end_col] == 2) - || (r < nrows && vline[r][end_col] == 2)) - prints("+" HALF_DOUBLE_LINE_SEP); - prints(" 0'"); - start_col = end_col; - } - } - prints("\\s0\n"); - prints(".ls\n" - ".vs\n"); -} - -void table::print_double_hline(int r) -{ - prints(".vs " LINE_SEP "+" DOUBLE_LINE_SEP - ">?\\n[.V]u\n" - ".ls 1\n" - "\\v'" BODY_DEPTH "'" - "\\s[\\n[" LINESIZE_REG "]]"); - if (r > nrows - 1) - prints("\\v'-" DOUBLE_LINE_SEP "'" - "\\D'l |\\n[TW]u 0'" - "\\v'" DOUBLE_LINE_SEP "'" - "\\h'|0'" - "\\D'l |\\n[TW]u 0'"); - else { - int start_col = 0; - for (;;) { - while (start_col < ncolumns - && entry[r][start_col] != 0 - && entry[r][start_col]->start_row != r) - start_col++; - int end_col; - for (end_col = start_col; - end_col < ncolumns - && (entry[r][end_col] == 0 - || entry[r][end_col]->start_row == r); - end_col++) - ; - if (end_col <= start_col) - break; - const char *left_adjust = 0; - if ((r > 0 && vline[r-1][start_col] == 2) - || (r < nrows && vline[r][start_col] == 2)) - left_adjust = "-" HALF_DOUBLE_LINE_SEP; - const char *right_adjust = 0; - if ((r > 0 && vline[r-1][end_col] == 2) - || (r < nrows && vline[r][end_col] == 2)) - right_adjust = "+" HALF_DOUBLE_LINE_SEP; - printfs("\\v'-" DOUBLE_LINE_SEP "'" - "\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (left_adjust) - prints(left_adjust); - prints("'"); - printfs("\\D'l |\\n[%1]u", - column_divide_reg(end_col)); - if (right_adjust) - prints(right_adjust); - prints(" 0'"); - printfs("\\v'" DOUBLE_LINE_SEP "'" - "\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (left_adjust) - prints(left_adjust); - prints("'"); - printfs("\\D'l |\\n[%1]u", - column_divide_reg(end_col)); - if (right_adjust) - prints(right_adjust); - prints(" 0'"); - start_col = end_col; - } - } - prints("\\s0\n" - ".ls\n" - ".vs\n"); -} - -void table::compute_vrule_top_adjust(int start_row, int col, string &result) -{ - if (row_is_all_lines[start_row] && start_row < nrows - 1) { - if (row_is_all_lines[start_row] == 2) - result = LINE_SEP ">?\\n[.V]u" "+" DOUBLE_LINE_SEP; - else - result = LINE_SEP ">?\\n[.V]u"; - start_row++; - } - else { - result = ""; - if (start_row == 0) - return; - for (stuff *p = stuff_list; p && p->row <= start_row; p = p->next) - if (p->row == start_row - && (p->is_single_line() || p->is_double_line())) - return; - } - int left = 0; - if (col > 0) { - table_entry *e = entry[start_row-1][col-1]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - left = 2; - else if (e->to_single_line_entry() != 0) - left = 1; - } - } - int right = 0; - if (col < ncolumns) { - table_entry *e = entry[start_row-1][col]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - right = 2; - else if (e->to_single_line_entry() != 0) - right = 1; - } - } - if (row_is_all_lines[start_row-1] == 0) { - if (left > 0 || right > 0) { - result += "-" BODY_DEPTH "-" BAR_HEIGHT; - if ((left == 2 && right != 2) || (right == 2 && left != 2)) - result += "-" HALF_DOUBLE_LINE_SEP; - else if (left == 2 && right == 2) - result += "+" HALF_DOUBLE_LINE_SEP; - } - } - else if (row_is_all_lines[start_row-1] == 2) { - if ((left == 2 && right != 2) || (right == 2 && left != 2)) - result += "-" DOUBLE_LINE_SEP; - else if (left == 1 || right == 1) - result += "-" HALF_DOUBLE_LINE_SEP; - } -} - -void table::compute_vrule_bot_adjust(int end_row, int col, string &result) -{ - if (row_is_all_lines[end_row] && end_row > 0) { - end_row--; - result = ""; - } - else { - stuff *p; - for (p = stuff_list; p && p->row < end_row + 1; p = p->next) - ; - if (p && p->row == end_row + 1 && p->is_double_line()) { - result = "-" DOUBLE_LINE_SEP; - return; - } - if ((p != 0 && p->row == end_row + 1) - || end_row == nrows - 1) { - result = ""; - return; - } - if (row_is_all_lines[end_row+1] == 1) - result = LINE_SEP; - else if (row_is_all_lines[end_row+1] == 2) - result = LINE_SEP "+" DOUBLE_LINE_SEP; - else - result = ""; - } - int left = 0; - if (col > 0) { - table_entry *e = entry[end_row+1][col-1]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - left = 2; - else if (e->to_single_line_entry() != 0) - left = 1; - } - } - int right = 0; - if (col < ncolumns) { - table_entry *e = entry[end_row+1][col]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - right = 2; - else if (e->to_single_line_entry() != 0) - right = 1; - } - } - if (row_is_all_lines[end_row+1] == 0) { - if (left > 0 || right > 0) { - result = "1v-" BODY_DEPTH "-" BAR_HEIGHT; - if ((left == 2 && right != 2) || (right == 2 && left != 2)) - result += "+" HALF_DOUBLE_LINE_SEP; - else if (left == 2 && right == 2) - result += "-" HALF_DOUBLE_LINE_SEP; - } - } - else if (row_is_all_lines[end_row+1] == 2) { - if (left == 2 && right == 2) - result += "-" DOUBLE_LINE_SEP; - else if (left != 2 && right != 2 && (left == 1 || right == 1)) - result += "-" HALF_DOUBLE_LINE_SEP; - } -} - -void table::add_vertical_rule(int start_row, int end_row, int col, int is_double) -{ - vrule_list = new vertical_rule(start_row, end_row, col, is_double, - vrule_list); - compute_vrule_top_adjust(start_row, col, vrule_list->top_adjust); - compute_vrule_bot_adjust(end_row, col, vrule_list->bot_adjust); -} - -void table::build_vrule_list() -{ - int col; - if (flags & ALLBOX) { - for (col = 1; col < ncolumns; col++) { - int start_row = 0; - for (;;) { - while (start_row < nrows && vline_spanned(start_row, col)) - start_row++; - if (start_row >= nrows) - break; - int end_row = start_row; - while (end_row < nrows && !vline_spanned(end_row, col)) - end_row++; - end_row--; - add_vertical_rule(start_row, end_row, col, 0); - start_row = end_row + 1; - } - } - } - if (flags & (BOX|ALLBOX|DOUBLEBOX)) { - add_vertical_rule(0, nrows - 1, 0, 0); - add_vertical_rule(0, nrows - 1, ncolumns, 0); - } - for (int end_row = 0; end_row < nrows; end_row++) - for (col = 0; col < ncolumns+1; col++) - if (vline[end_row][col] > 0 - && !vline_spanned(end_row, col) - && (end_row == nrows - 1 - || vline[end_row+1][col] != vline[end_row][col] - || vline_spanned(end_row+1, col))) { - int start_row; - for (start_row = end_row - 1; - start_row >= 0 - && vline[start_row][col] == vline[end_row][col] - && !vline_spanned(start_row, col); - start_row--) - ; - start_row++; - add_vertical_rule(start_row, end_row, col, vline[end_row][col] > 1); - } - for (vertical_rule *p = vrule_list; p; p = p->next) - if (p->is_double) - for (int r = p->start_row; r <= p->end_row; r++) { - if (p->col > 0 && entry[r][p->col-1] != 0 - && entry[r][p->col-1]->end_col == p->col-1) { - int is_corner = r == p->start_row || r == p->end_row; - entry[r][p->col-1]->note_double_vrule_on_right(is_corner); - } - if (p->col < ncolumns && entry[r][p->col] != 0 - && entry[r][p->col]->start_col == p->col) { - int is_corner = r == p->start_row || r == p->end_row; - entry[r][p->col]->note_double_vrule_on_left(is_corner); - } - } -} - -void table::define_bottom_macro() -{ - prints(".eo\n" - ".de T#\n" - ".if !\\n[" SUPPRESS_BOTTOM_REG "] \\{" - "." REPEATED_VPT_MACRO " 0\n" - ".mk " SAVED_VERTICAL_POS_REG "\n"); - if (flags & (BOX|ALLBOX|DOUBLEBOX)) { - prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG "] \\{"); - print_single_hline(0); - prints(".\\}\n"); - } - prints(".ls 1\n"); - for (vertical_rule *p = vrule_list; p; p = p->next) - p->contribute_to_bottom_macro(this); - if (flags & DOUBLEBOX) - prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n" - "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" - "\\D'l \\n[TW]u 0'\\s0\n" - ".vs\n" - ".\\}\n" - ".if \\n[" LAST_PASSED_ROW_REG "]>=0 " - ".nr " TOP_REG " \\n[#T]-" DOUBLE_LINE_SEP "\n" - ".sp -1\n" - "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" - "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n" - ".sp -1\n" - "\\v'" BODY_DEPTH "'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG "]]" - "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n"); - prints(".ls\n"); - prints(".nr " LAST_PASSED_ROW_REG " \\n[" CURRENT_ROW_REG "]\n" - ".sp |\\n[" SAVED_VERTICAL_POS_REG "]u\n" - "." REPEATED_VPT_MACRO " 1\n" - ".\\}\n" - "..\n" - ".ec\n"); -} - - -// is the vertical line before column c in row r horizontally spanned? - -int table::vline_spanned(int r, int c) -{ - assert(r >= 0 && r < nrows && c >= 0 && c < ncolumns + 1); - return (c != 0 && c != ncolumns && entry[r][c] != 0 - && entry[r][c]->start_col != c - // horizontally spanning lines don't count - && entry[r][c]->to_double_line_entry() == 0 - && entry[r][c]->to_single_line_entry() == 0); -} - -int table::row_begins_section(int r) -{ - assert(r >= 0 && r < nrows); - for (int i = 0; i < ncolumns; i++) - if (entry[r][i] && entry[r][i]->start_row != r) - return 0; - return 1; -} - -int table::row_ends_section(int r) -{ - assert(r >= 0 && r < nrows); - for (int i = 0; i < ncolumns; i++) - if (entry[r][i] && entry[r][i]->end_row != r) - return 0; - return 1; -} - -void table::do_row(int r) -{ - if (!(flags & NOKEEP) && row_begins_section(r)) - prints("." KEEP_MACRO_NAME "\n"); - int had_line = 0; - stuff *p; - for (p = stuff_list; p && p->row < r; p = p->next) - ; - for (stuff *p1 = p; p1 && p1->row == r; p1 = p1->next) - if (!p1->printed && (p1->is_single_line() || p1->is_double_line())) { - had_line = 1; - break; - } - if (!had_line && !row_is_all_lines[r]) - printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); - had_line = 0; - for (; p && p->row == r; p = p->next) - if (!p->printed) { - p->print(this); - if (!had_line && (p->is_single_line() || p->is_double_line())) { - printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); - had_line = 1; - } - } - // Change the row *after* printing the stuff list (which might contain .TH). - printfs("\\*[" TRANSPARENT_STRING_NAME "].nr " CURRENT_ROW_REG " %1\n", - as_string(r)); - if (!had_line && row_is_all_lines[r]) - printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); - // we might have had a .TH, for example, since we last tried - if (!(flags & NOKEEP) && row_begins_section(r)) - prints("." KEEP_MACRO_NAME "\n"); - printfs(".mk %1\n", row_start_reg(r)); - prints(".mk " BOTTOM_REG "\n" - "." REPEATED_VPT_MACRO " 0\n"); - int c; - int row_is_blank = 1; - int first_start_row = r; - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r) { - e->do_depth(); - if (e->start_row < first_start_row) - first_start_row = e->start_row; - row_is_blank = 0; - } - c = e->end_col; - } - } - if (row_is_blank) - prints(".nr " BOTTOM_REG " +1v\n"); - if (row_is_all_lines[r]) { - prints(".vs " LINE_SEP); - if (row_is_all_lines[r] == 2) - prints("+" DOUBLE_LINE_SEP); - prints(">?\\n[.V]u\n.ls 1\n"); - prints("\\&"); - prints("\\v'" BODY_DEPTH); - if (row_is_all_lines[r] == 2) - prints("-" HALF_DOUBLE_LINE_SEP); - prints("'"); - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == e->start_row) - e->to_simple_entry()->simple_print(1); - c = e->end_col; - } - } - prints("\n"); - prints(".ls\n" - ".vs\n"); - prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); - printfs(".sp |\\n[%1]u\n", row_start_reg(r)); - } - for (int i = row_is_all_lines[r] ? r - 1 : r; - i >= first_start_row; - i--) { - simple_entry *first = 0; - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r && e->start_row == i) { - simple_entry *simple = e->to_simple_entry(); - if (simple) { - if (!first) { - prints(".ta"); - first = simple; - } - simple->add_tab(); - } - } - c = e->end_col; - } - } - if (first) { - prints('\n'); - first->position_vertically(); - first->set_location(); - prints("\\&"); - first->simple_print(0); - for (c = first->end_col + 1; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r && e->start_row == i) { - simple_entry *simple = e->to_simple_entry(); - if (simple) - simple->simple_print(0); - } - c = e->end_col; - } - } - prints('\n'); - prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); - printfs(".sp |\\n[%1]u\n", row_start_reg(r)); - } - } - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r && e->to_simple_entry() == 0) { - e->position_vertically(); - e->print(); - prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); - printfs(".sp |\\n[%1]u\n", row_start_reg(r)); - } - c = e->end_col; - } - } - prints("." REPEATED_VPT_MACRO " 1\n" - ".sp |\\n[" BOTTOM_REG "]u\n" - "\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 1\n"); - if (r != nrows - 1 && (flags & ALLBOX)) { - print_single_hline(r + 1); - prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 0\n"); - } - if (r != nrows - 1) { - if (p && p->row == r + 1 - && (p->is_single_line() || p->is_double_line())) { - p->print(this); - prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG - " 0\n"); - } - int printed_one = 0; - for (vertical_rule *vr = vrule_list; vr; vr = vr->next) - if (vr->end_row == r) { - if (!printed_one) { - prints("." REPEATED_VPT_MACRO " 0\n"); - printed_one = 1; - } - vr->print(); - } - if (printed_one) - prints("." REPEATED_VPT_MACRO " 1\n"); - if (!(flags & NOKEEP) && row_ends_section(r)) - prints("." RELEASE_MACRO_NAME "\n"); - } -} - -void table::do_top() -{ - prints(".fc \002\003\n"); - if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) - prints("." TABLE_KEEP_MACRO_NAME "\n"); - if (flags & DOUBLEBOX) { - prints(".ls 1\n" - ".vs " LINE_SEP ">?\\n[.V]u\n" - "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]\\D'l \\n[TW]u 0'\\s0\n" - ".vs\n" - "." REPEATED_MARK_MACRO " " TOP_REG "\n" - ".vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n"); - printfs("\\v'" BODY_DEPTH "'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\h'\\n[%1]u'" - "\\D'l |\\n[%2]u 0'" - "\\s0" - "\n", - column_divide_reg(0), - column_divide_reg(ncolumns)); - prints(".ls\n" - ".vs\n"); - } - else if (flags & (ALLBOX|BOX)) { - print_single_hline(0); - } - //printfs(".mk %1\n", row_top_reg(0)); -} - -void table::do_bottom() -{ - // print stuff after last row - for (stuff *p = stuff_list; p; p = p->next) - if (p->row > nrows - 1) - p->print(this); - if (!(flags & NOKEEP)) - prints("." RELEASE_MACRO_NAME "\n"); - printfs(".mk %1\n", row_top_reg(nrows)); - prints(".nr " NEED_BOTTOM_RULE_REG " 1\n" - ".nr T. 1\n" - ".T#\n"); - if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) - prints("." TABLE_RELEASE_MACRO_NAME "\n"); - if (flags & DOUBLEBOX) - prints(".sp " DOUBLE_LINE_SEP "\n"); - prints("." RESET_MACRO_NAME "\n" - ".fc\n" - ".cp \\n(" COMPATIBLE_REG "\n"); -} - -int table::get_nrows() -{ - return nrows; -} - -const char *last_filename = 0; - -void set_troff_location(const char *fn, int ln) -{ - if (!location_force_filename && last_filename != 0 - && strcmp(fn, last_filename) == 0) - printfs(".lf %1\n", as_string(ln)); - else { - printfs(".lf %1 %2\n", as_string(ln), fn); - last_filename = fn; - location_force_filename = 0; - } -} - -void printfs(const char *s, const string &arg1, const string &arg2, - const string &arg3, const string &arg4, const string &arg5) -{ - if (s) { - char c; - while ((c = *s++) != '\0') { - if (c == '%') { - switch (*s++) { - case '1': - prints(arg1); - break; - case '2': - prints(arg2); - break; - case '3': - prints(arg3); - break; - case '4': - prints(arg4); - break; - case '5': - prints(arg5); - break; - case '6': - case '7': - case '8': - case '9': - break; - case '%': - prints('%'); - break; - default: - assert(0); - } - } - else - prints(c); - } - } -} - diff --git a/contrib/groff/src/roff/groff/groff.cc b/contrib/groff/src/roff/groff/groff.cc deleted file mode 100644 index 49104b2..0000000 --- a/contrib/groff/src/roff/groff/groff.cc +++ /dev/null @@ -1,753 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-2000, 2001, 2002 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. */ - -// A front end for groff. - -#include "lib.h" - -#include -#include -#include - -#include "assert.h" -#include "errarg.h" -#include "error.h" -#include "stringclass.h" -#include "cset.h" -#include "font.h" -#include "device.h" -#include "pipeline.h" -#include "nonposix.h" -#include "defs.h" - -#define GXDITVIEW "gxditview" - -// troff will be passed an argument of -rXREG=1 if the -X option is -// specified -#define XREG ".X" - -#ifdef NEED_DECLARATION_PUTENV -extern "C" { - int putenv(const char *); -} -#endif /* NEED_DECLARATION_PUTENV */ - -// The number of commands must be in sync with MAX_COMMANDS in pipeline.h -const int SOELIM_INDEX = 0; -const int REFER_INDEX = SOELIM_INDEX + 1; -const int GRAP_INDEX = REFER_INDEX + 1; -const int PIC_INDEX = GRAP_INDEX + 1; -const int TBL_INDEX = PIC_INDEX + 1; -const int GRN_INDEX = TBL_INDEX + 1; -const int EQN_INDEX = GRN_INDEX + 1; -const int TROFF_INDEX = EQN_INDEX + 1; -const int POST_INDEX = TROFF_INDEX + 1; -const int SPOOL_INDEX = POST_INDEX + 1; - -const int NCOMMANDS = SPOOL_INDEX + 1; - -class possible_command { - char *name; - string args; - char **argv; - - void build_argv(); -public: - possible_command(); - ~possible_command(); - void set_name(const char *); - void set_name(const char *, const char *); - const char *get_name(); - void append_arg(const char *, const char * = 0); - void insert_arg(const char *); - void insert_args(string s); - void clear_args(); - char **get_argv(); - void print(int is_last, FILE *fp); -}; - -extern "C" const char *Version_string; - -int lflag = 0; -char *spooler = 0; -char *postdriver = 0; -char *predriver = 0; - -possible_command commands[NCOMMANDS]; - -int run_commands(int no_pipe); -void print_commands(); -void append_arg_to_string(const char *arg, string &str); -void handle_unknown_desc_command(const char *command, const char *arg, - const char *filename, int lineno); -const char *xbasename(const char *); - -void usage(FILE *stream); -void help(); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - assert(NCOMMANDS <= MAX_COMMANDS); - string Pargs, Largs, Fargs; - int vflag = 0; - int Vflag = 0; - int zflag = 0; - int iflag = 0; - int Xflag = 0; - int safer_flag = 1; - int opt; - const char *command_prefix = getenv("GROFF_COMMAND_PREFIX"); - if (!command_prefix) - command_prefix = PROG_PREFIX; - commands[TROFF_INDEX].set_name(command_prefix, "troff"); - static const struct option long_options[] = { - { "help", no_argument, 0, 'h' }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, - "abcCd:eEf:F:gGhiI:lL:m:M:n:No:pP:r:RsStT:UvVw:W:XzZ", - long_options, NULL)) - != EOF) { - char buf[3]; - buf[0] = '-'; - buf[1] = opt; - buf[2] = '\0'; - switch (opt) { - case 'i': - iflag = 1; - break; - case 'I': - commands[SOELIM_INDEX].set_name(command_prefix, "soelim"); - commands[SOELIM_INDEX].append_arg(buf, optarg); - break; - case 't': - commands[TBL_INDEX].set_name(command_prefix, "tbl"); - break; - case 'p': - commands[PIC_INDEX].set_name(command_prefix, "pic"); - break; - case 'g': - commands[GRN_INDEX].set_name(command_prefix, "grn"); - break; - case 'G': - commands[GRAP_INDEX].set_name(command_prefix, "grap"); - break; - case 'e': - commands[EQN_INDEX].set_name(command_prefix, "eqn"); - break; - case 's': - commands[SOELIM_INDEX].set_name(command_prefix, "soelim"); - break; - case 'R': - commands[REFER_INDEX].set_name(command_prefix, "refer"); - break; - case 'z': - case 'a': - commands[TROFF_INDEX].append_arg(buf); - // fall through - case 'Z': - zflag++; - break; - case 'l': - lflag++; - break; - case 'V': - Vflag++; - break; - case 'v': - vflag = 1; - { - printf("GNU groff version %s\n", Version_string); - printf("Copyright (C) 2002 Free Software Foundation, Inc.\n" - "GNU groff comes with ABSOLUTELY NO WARRANTY.\n" - "You may redistribute copies of groff and its subprograms\n" - "under the terms of the GNU General Public License.\n" - "For more information about these matters, see the file named COPYING.\n"); - printf("\ncalled subprograms:\n\n"); - fflush(stdout); - } - commands[POST_INDEX].append_arg(buf); - // fall through - case 'C': - commands[SOELIM_INDEX].append_arg(buf); - commands[REFER_INDEX].append_arg(buf); - commands[PIC_INDEX].append_arg(buf); - commands[GRAP_INDEX].append_arg(buf); - commands[TBL_INDEX].append_arg(buf); - commands[GRN_INDEX].append_arg(buf); - commands[EQN_INDEX].append_arg(buf); - commands[TROFF_INDEX].append_arg(buf); - break; - case 'N': - commands[EQN_INDEX].append_arg(buf); - break; - case 'h': - help(); - break; - case 'E': - case 'b': - commands[TROFF_INDEX].append_arg(buf); - break; - case 'c': - commands[TROFF_INDEX].append_arg(buf); - break; - case 'S': - safer_flag = 1; - break; - case 'U': - safer_flag = 0; - break; - case 'T': - if (strcmp(optarg, "html") == 0) { - // force soelim to aid the html preprocessor - commands[SOELIM_INDEX].set_name(command_prefix, "soelim"); - } - if (strcmp(optarg, "Xps") == 0) { - warning("-TXps option is obsolete: use -X -Tps instead"); - device = "ps"; - Xflag++; - } - else - device = optarg; - break; - case 'F': - font::command_line_font_dir(optarg); - if (Fargs.length() > 0) { - Fargs += PATH_SEP[0]; - Fargs += optarg; - } - else - Fargs = optarg; - break; - case 'f': - case 'o': - case 'm': - case 'r': - case 'd': - case 'n': - case 'w': - case 'W': - commands[TROFF_INDEX].append_arg(buf, optarg); - break; - case 'M': - commands[EQN_INDEX].append_arg(buf, optarg); - commands[GRAP_INDEX].append_arg(buf, optarg); - commands[GRN_INDEX].append_arg(buf, optarg); - commands[TROFF_INDEX].append_arg(buf, optarg); - break; - case 'P': - Pargs += optarg; - Pargs += '\0'; - break; - case 'L': - append_arg_to_string(optarg, Largs); - break; - case 'X': - Xflag++; - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - break; - } - } - if (safer_flag) - commands[PIC_INDEX].append_arg("-S"); - else - commands[TROFF_INDEX].insert_arg("-U"); - font::set_unknown_desc_command_handler(handle_unknown_desc_command); - if (!font::load_desc()) - fatal("invalid device `%1'", device); - if (!postdriver) - fatal("no `postpro' command in DESC file for device `%1'", device); - if (predriver && !zflag) { - commands[TROFF_INDEX].insert_arg(commands[TROFF_INDEX].get_name()); - commands[TROFF_INDEX].set_name(predriver); - // pass the device arguments to the predrivers as well - commands[TROFF_INDEX].insert_args(Pargs); - if (vflag) - commands[TROFF_INDEX].insert_arg("-v"); - } - const char *real_driver = 0; - if (Xflag) { - real_driver = postdriver; - postdriver = GXDITVIEW; - commands[TROFF_INDEX].append_arg("-r" XREG "=", "1"); - } - if (postdriver) - commands[POST_INDEX].set_name(postdriver); - int gxditview_flag = postdriver && strcmp(xbasename(postdriver), GXDITVIEW) == 0; - if (gxditview_flag && argc - optind == 1) { - commands[POST_INDEX].append_arg("-title"); - commands[POST_INDEX].append_arg(argv[optind]); - commands[POST_INDEX].append_arg("-xrm"); - commands[POST_INDEX].append_arg("*iconName:", argv[optind]); - string filename_string("|"); - append_arg_to_string(argv[0], filename_string); - append_arg_to_string("-Z", filename_string); - for (int i = 1; i < argc; i++) - append_arg_to_string(argv[i], filename_string); - filename_string += '\0'; - commands[POST_INDEX].append_arg("-filename"); - commands[POST_INDEX].append_arg(filename_string.contents()); - } - if (gxditview_flag && Xflag) { - string print_string(real_driver); - if (spooler) { - print_string += " | "; - print_string += spooler; - print_string += Largs; - } - print_string += '\0'; - commands[POST_INDEX].append_arg("-printCommand"); - commands[POST_INDEX].append_arg(print_string.contents()); - } - const char *p = Pargs.contents(); - const char *end = p + Pargs.length(); - while (p < end) { - commands[POST_INDEX].append_arg(p); - p = strchr(p, '\0') + 1; - } - if (gxditview_flag) - commands[POST_INDEX].append_arg("-"); - if (lflag && !Xflag && spooler) { - commands[SPOOL_INDEX].set_name(BSHELL); - commands[SPOOL_INDEX].append_arg(BSHELL_DASH_C); - Largs += '\0'; - Largs = spooler + Largs; - commands[SPOOL_INDEX].append_arg(Largs.contents()); - } - if (zflag) { - commands[POST_INDEX].set_name(0); - commands[SPOOL_INDEX].set_name(0); - } - commands[TROFF_INDEX].append_arg("-T", device); - // html renders equations as images via ps - if (strcmp(device, "html") == 0) - commands[EQN_INDEX].append_arg("-Tps:html"); - else - commands[EQN_INDEX].append_arg("-T", device); - - commands[GRN_INDEX].append_arg("-T", device); - - int first_index; - for (first_index = 0; first_index < TROFF_INDEX; first_index++) - if (commands[first_index].get_name() != 0) - break; - if (optind < argc) { - if (argv[optind][0] == '-' && argv[optind][1] != '\0') - commands[first_index].append_arg("--"); - for (int i = optind; i < argc; i++) - commands[first_index].append_arg(argv[i]); - if (iflag) - commands[first_index].append_arg("-"); - } - if (Fargs.length() > 0) { - string e = "GROFF_FONT_PATH"; - e += '='; - e += Fargs; - char *fontpath = getenv("GROFF_FONT_PATH"); - if (fontpath && *fontpath) { - e += PATH_SEP[0]; - e += fontpath; - } - e += '\0'; - if (putenv(strsave(e.contents()))) - fatal("putenv failed"); - } - { - // we save the original path in GROFF_PATH__ and put it into the - // environment -- troff will pick it up later. - char *path = getenv("PATH"); - string e = "GROFF_PATH__"; - e += '='; - if (path && *path) - e += path; - e += '\0'; - if (putenv(strsave(e.contents()))) - fatal("putenv failed"); - char *binpath = getenv("GROFF_BIN_PATH"); - string f = "PATH"; - f += '='; - if (binpath && *binpath) - f += binpath; - else - f += BINPATH; - if (path && *path) { - f += PATH_SEP[0]; - f += path; - } - f += '\0'; - if (putenv(strsave(f.contents()))) - fatal("putenv failed"); - } - if (Vflag) { - print_commands(); - exit(0); - } - return run_commands(vflag); -} - -const char *xbasename(const char *s) -{ - if (!s) - return 0; - // DIR_SEPS[] are possible directory separator characters, see nonposix.h - // We want the rightmost separator of all possible ones. - // Example: d:/foo\\bar. - const char *p = strrchr(s, DIR_SEPS[0]), *p1; - const char *sep = &DIR_SEPS[1]; - - while (*sep) - { - p1 = strrchr(s, *sep); - if (p1 && (!p || p1 > p)) - p = p1; - sep++; - } - return p ? p + 1 : s; -} - -void handle_unknown_desc_command(const char *command, const char *arg, - const char *filename, int lineno) -{ - if (strcmp(command, "print") == 0) { - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`print' command requires an argument"); - else - spooler = strsave(arg); - } - if (strcmp(command, "prepro") == 0) { - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`prepro' command requires an argument"); - else { - for (const char *p = arg; *p; p++) - if (csspace(*p)) { - error_with_file_and_line(filename, lineno, - "invalid `prepro' argument `%1'" - ": program name required", arg); - return; - } - predriver = strsave(arg); - } - } - if (strcmp(command, "postpro") == 0) { - if (arg == 0) - error_with_file_and_line(filename, lineno, - "`postpro' command requires an argument"); - else { - for (const char *p = arg; *p; p++) - if (csspace(*p)) { - error_with_file_and_line(filename, lineno, - "invalid `postpro' argument `%1'" - ": program name required", arg); - return; - } - postdriver = strsave(arg); - } - } -} - -void print_commands() -{ - int last; - for (last = SPOOL_INDEX; last >= 0; last--) - if (commands[last].get_name() != 0) - break; - for (int i = 0; i <= last; i++) - if (commands[i].get_name() != 0) - commands[i].print(i == last, stdout); -} - -// Run the commands. Return the code with which to exit. - -int run_commands(int no_pipe) -{ - char **v[NCOMMANDS]; - int j = 0; - for (int i = 0; i < NCOMMANDS; i++) - if (commands[i].get_name() != 0) - v[j++] = commands[i].get_argv(); - return run_pipeline(j, v, no_pipe); -} - -possible_command::possible_command() -: name(0), argv(0) -{ -} - -possible_command::~possible_command() -{ - a_delete name; - a_delete argv; -} - -void possible_command::set_name(const char *s) -{ - a_delete name; - name = strsave(s); -} - -void possible_command::set_name(const char *s1, const char *s2) -{ - a_delete name; - name = new char[strlen(s1) + strlen(s2) + 1]; - strcpy(name, s1); - strcat(name, s2); -} - -const char *possible_command::get_name() -{ - return name; -} - -void possible_command::clear_args() -{ - args.clear(); -} - -void possible_command::append_arg(const char *s, const char *t) -{ - args += s; - if (t) - args += t; - args += '\0'; -} - -void possible_command::insert_arg(const char *s) -{ - string str(s); - str += '\0'; - str += args; - args = str; -} - -void possible_command::insert_args(string s) -{ - const char *p = s.contents(); - const char *end = p + s.length(); - int l = 0; - if (p >= end) - return; - // find the total number of arguments in our string - do { - l++; - p = strchr(p, '\0') + 1; - } while (p < end); - // now insert each argument preserving the order - for (int i = l - 1; i >= 0; i--) { - p = s.contents(); - for (int j = 0; j < i; j++) - p = strchr(p, '\0') + 1; - insert_arg(p); - } -} - -void possible_command::build_argv() -{ - if (argv) - return; - // Count the number of arguments. - int len = args.length(); - int argc = 1; - char *p = 0; - if (len > 0) { - p = &args[0]; - for (int i = 0; i < len; i++) - if (p[i] == '\0') - argc++; - } - // Build an argument vector. - argv = new char *[argc + 1]; - argv[0] = name; - for (int i = 1; i < argc; i++) { - argv[i] = p; - p = strchr(p, '\0') + 1; - } - argv[argc] = 0; -} - -void possible_command::print(int is_last, FILE *fp) -{ - build_argv(); - if (IS_BSHELL(argv[0]) - && argv[1] != 0 && strcmp(argv[1], BSHELL_DASH_C) == 0 - && argv[2] != 0 && argv[3] == 0) - fputs(argv[2], fp); - else { - fputs(argv[0], fp); - string str; - for (int i = 1; argv[i] != 0; i++) { - str.clear(); - append_arg_to_string(argv[i], str); - put_string(str, fp); - } - } - if (is_last) - putc('\n', fp); - else - fputs(" | ", fp); -} - -void append_arg_to_string(const char *arg, string &str) -{ - str += ' '; - int needs_quoting = 0; - int contains_single_quote = 0; - const char*p; - for (p = arg; *p != '\0'; p++) - switch (*p) { - case ';': - case '&': - case '(': - case ')': - case '|': - case '^': - case '<': - case '>': - case '\n': - case ' ': - case '\t': - case '\\': - case '"': - case '$': - case '?': - case '*': - needs_quoting = 1; - break; - case '\'': - contains_single_quote = 1; - break; - } - if (contains_single_quote || arg[0] == '\0') { - str += '"'; - for (p = arg; *p != '\0'; p++) - switch (*p) { - case '"': - case '\\': - case '$': - str += '\\'; - // fall through - default: - str += *p; - break; - } - str += '"'; - } - else if (needs_quoting) { - str += '\''; - str += arg; - str += '\''; - } - else - str += arg; -} - -char **possible_command::get_argv() -{ - build_argv(); - return argv; -} - -void synopsis(FILE *stream) -{ - fprintf(stream, -"usage: %s [-abceghilpstvzCENRSUVXZ] [-Fdir] [-mname] [-Tdev] [-ffam]\n" -" [-wname] [-Wname] [-Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg]\n" -" [-Larg] [-Idir] [files...]\n", - program_name); -} - -void help() -{ - synopsis(stdout); - fputs("\n" -"-h\tprint this message\n" -"-t\tpreprocess with tbl\n" -"-p\tpreprocess with pic\n" -"-e\tpreprocess with eqn\n" -"-g\tpreprocess with grn\n" -"-G\tpreprocess with grap\n" -"-s\tpreprocess with soelim\n" -"-R\tpreprocess with refer\n" -"-Tdev\tuse device dev\n" -"-X\tuse X11 previewer rather than usual postprocessor\n" -"-mname\tread macros tmac.name\n" -"-dcs\tdefine a string c as s\n" -"-rcn\tdefine a number register c as n\n" -"-nnum\tnumber first page n\n" -"-olist\toutput only pages in list\n" -"-ffam\tuse fam as the default font family\n" -"-Fdir\tsearch dir for device directories\n" -"-Mdir\tsearch dir for macro files\n" -"-v\tprint version number\n" -"-z\tsuppress formatted output\n" -"-Z\tdon't postprocess\n" -"-a\tproduce ASCII description of output\n" -"-i\tread standard input after named input files\n" -"-wname\tenable warning name\n" -"-Wname\tinhibit warning name\n" -"-E\tinhibit all errors\n" -"-b\tprint backtraces with errors or warnings\n" -"-l\tspool the output\n" -"-c\tdisable color output\n" -"-C\tenable compatibility mode\n" -"-V\tprint commands on stdout instead of running them\n" -"-Parg\tpass arg to the postprocessor\n" -"-Larg\tpass arg to the spooler\n" -"-N\tdon't allow newlines within eqn delimiters\n" -"-S\tenable safer mode (the default)\n" -"-U\tenable unsafe mode\n" -"-Idir\tsearch dir for soelim. Implies -s\n" -"\n", - stdout); - exit(0); -} - -void usage(FILE *stream) -{ - synopsis(stream); - fprintf(stream, "%s -h gives more help\n", program_name); -} - -extern "C" { - -void c_error(const char *format, const char *arg1, const char *arg2, - const char *arg3) -{ - error(format, arg1, arg2, arg3); -} - -void c_fatal(const char *format, const char *arg1, const char *arg2, - const char *arg3) -{ - fatal(format, arg1, arg2, arg3); -} - -} diff --git a/contrib/groff/src/roff/troff/column.cc b/contrib/groff/src/roff/troff/column.cc deleted file mode 100644 index 8d6a6eb..0000000 --- a/contrib/groff/src/roff/troff/column.cc +++ /dev/null @@ -1,732 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000 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. */ - -#ifdef COLUMN - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "div.h" -#include "reg.h" -#include "stringclass.h" - -void output_file::vjustify(vunits, symbol) -{ - // do nothing -} - -struct justification_spec; -struct output_line; - -class column : public output_file { -private: - output_file *out; - vunits bottom; - output_line *col; - output_line **tail; - void add_output_line(output_line *); - void begin_page(int pageno, vunits page_length); - void flush(); - void print_line(hunits, vunits, node *, vunits, vunits); - void vjustify(vunits, symbol); - void transparent_char(unsigned char c); - void copy_file(hunits, vunits, const char *); - int is_printing(); - void check_bottom(); -public: - column(); - ~column(); - void start(); - void output(); - void justify(const justification_spec &); - void trim(); - void reset(); - vunits get_bottom(); - vunits get_last_extra_space(); - int is_active() { return out != 0; } -}; - -column *the_column = 0; - -struct transparent_output_line; -struct vjustify_output_line; - -class output_line { - output_line *next; -public: - output_line(); - virtual ~output_line(); - virtual void output(output_file *, vunits); - virtual transparent_output_line *as_transparent_output_line(); - virtual vjustify_output_line *as_vjustify_output_line(); - virtual vunits distance(); - virtual vunits height(); - virtual void reset(); - virtual vunits extra_space(); // post line - friend class column; - friend class justification_spec; -}; - -class position_output_line : public output_line { - vunits dist; -public: - position_output_line(vunits); - vunits distance(); -}; - -class node_output_line : public position_output_line { - node *nd; - hunits page_offset; - vunits before; - vunits after; -public: - node_output_line(vunits, node *, hunits, vunits, vunits); - ~node_output_line(); - void output(output_file *, vunits); - vunits height(); - vunits extra_space(); -}; - -class vjustify_output_line : public position_output_line { - vunits current; - symbol typ; -public: - vjustify_output_line(vunits dist, symbol); - vunits height(); - vjustify_output_line *as_vjustify_output_line(); - void vary(vunits amount); - void reset(); - symbol type(); -}; - -inline symbol vjustify_output_line::type() -{ - return typ; -} - -class copy_file_output_line : public position_output_line { - symbol filename; - hunits hpos; -public: - copy_file_output_line(vunits, const char *, hunits); - void output(output_file *, vunits); -}; - -class transparent_output_line : public output_line { - string buf; -public: - transparent_output_line(); - void output(output_file *, vunits); - void append_char(unsigned char c); - transparent_output_line *as_transparent_output_line(); -}; - -output_line::output_line() : next(0) -{ -} - -output_line::~output_line() -{ -} - -void output_line::reset() -{ -} - -transparent_output_line *output_line::as_transparent_output_line() -{ - return 0; -} - -vjustify_output_line *output_line::as_vjustify_output_line() -{ - return 0; -} - -void output_line::output(output_file *, vunits) -{ -} - -vunits output_line::distance() -{ - return V0; -} - -vunits output_line::height() -{ - return V0; -} - -vunits output_line::extra_space() -{ - return V0; -} - -position_output_line::position_output_line(vunits d) -: dist(d) -{ -} - -vunits position_output_line::distance() -{ - return dist; -} - -node_output_line::node_output_line(vunits d, node *n, hunits po, vunits b, vunits a) -: position_output_line(d), nd(n), page_offset(po), before(b), after(a) -{ -} - -node_output_line::~node_output_line() -{ - delete_node_list(nd); -} - -void node_output_line::output(output_file *out, vunits pos) -{ - out->print_line(page_offset, pos, nd, before, after); - nd = 0; -} - -vunits node_output_line::height() -{ - return after; -} - -vunits node_output_line::extra_space() -{ - return after; -} - -vjustify_output_line::vjustify_output_line(vunits d, symbol t) -: position_output_line(d), typ(t) -{ -} - -void vjustify_output_line::reset() -{ - current = V0; -} - -vunits vjustify_output_line::height() -{ - return current; -} - -vjustify_output_line *vjustify_output_line::as_vjustify_output_line() -{ - return this; -} - -inline void vjustify_output_line::vary(vunits amount) -{ - current += amount; -} - -transparent_output_line::transparent_output_line() -{ -} - -transparent_output_line *transparent_output_line::as_transparent_output_line() -{ - return this; -} - -void transparent_output_line::append_char(unsigned char c) -{ - assert(c != 0); - buf += c; -} - -void transparent_output_line::output(output_file *out, vunits) -{ - int len = buf.length(); - for (int i = 0; i < len; i++) - out->transparent_char(buf[i]); -} - -copy_file_output_line::copy_file_output_line(vunits d, const char *f, hunits h) -: position_output_line(d), hpos(h), filename(f) -{ -} - -void copy_file_output_line::output(output_file *out, vunits pos) -{ - out->copy_file(hpos, pos, filename.contents()); -} - -column::column() -: bottom(V0), col(0), tail(&col), out(0) -{ -} - -column::~column() -{ - assert(out != 0); - error("automatically outputting column before exiting"); - output(); - delete the_output; -} - -void column::start() -{ - assert(out == 0); - if (!the_output) - init_output(); - assert(the_output != 0); - out = the_output; - the_output = this; -} - -void column::begin_page(int pageno, vunits page_length) -{ - assert(out != 0); - if (col) { - error("automatically outputting column before beginning next page"); - output(); - the_output->begin_page(pageno, page_length); - } - else - out->begin_page(pageno, page_length); - -} - -void column::flush() -{ - assert(out != 0); - out->flush(); -} - -int column::is_printing() -{ - assert(out != 0); - return out->is_printing(); -} - -vunits column::get_bottom() -{ - return bottom; -} - -void column::add_output_line(output_line *ln) -{ - *tail = ln; - bottom += ln->distance(); - bottom += ln->height(); - ln->next = 0; - tail = &(*tail)->next; -} - -void column::print_line(hunits page_offset, vunits pos, node *nd, - vunits before, vunits after) -{ - assert(out != 0); - add_output_line(new node_output_line(pos - bottom, nd, page_offset, before, after)); -} - -void column::vjustify(vunits pos, symbol typ) -{ - assert(out != 0); - add_output_line(new vjustify_output_line(pos - bottom, typ)); -} - -void column::transparent_char(unsigned char c) -{ - assert(out != 0); - transparent_output_line *tl = 0; - if (*tail) - tl = (*tail)->as_transparent_output_line(); - if (!tl) { - tl = new transparent_output_line; - add_output_line(tl); - } - tl->append_char(c); -} - -void column::copy_file(hunits page_offset, vunits pos, const char *filename) -{ - assert(out != 0); - add_output_line(new copy_file_output_line(pos - bottom, filename, page_offset)); -} - -void column::trim() -{ - output_line **spp = 0; - for (output_line **pp = &col; *pp; pp = &(*pp)->next) - if ((*pp)->as_vjustify_output_line() == 0) - spp = 0; - else if (!spp) - spp = pp; - if (spp) { - output_line *ln = *spp; - *spp = 0; - tail = spp; - while (ln) { - output_line *tem = ln->next; - bottom -= ln->distance(); - bottom -= ln->height(); - delete ln; - ln = tem; - } - } -} - -void column::reset() -{ - bottom = V0; - for (output_line *ln = col; ln; ln = ln->next) { - bottom += ln->distance(); - ln->reset(); - bottom += ln->height(); - } -} - -void column::check_bottom() -{ - vunits b; - for (output_line *ln = col; ln; ln = ln->next) { - b += ln->distance(); - b += ln->height(); - } - assert(b == bottom); -} - -void column::output() -{ - assert(out != 0); - vunits vpos(V0); - output_line *ln = col; - while (ln) { - vpos += ln->distance(); - ln->output(out, vpos); - vpos += ln->height(); - output_line *tem = ln->next; - delete ln; - ln = tem; - } - tail = &col; - bottom = V0; - col = 0; - the_output = out; - out = 0; -} - -vunits column::get_last_extra_space() -{ - if (!col) - return V0; - for (output_line *p = col; p->next; p = p->next) - ; - return p->extra_space(); -} - -class justification_spec { - vunits height; - symbol *type; - vunits *amount; - int n; - int maxn; -public: - justification_spec(vunits); - ~justification_spec(); - void append(symbol t, vunits v); - void justify(output_line *, vunits *bottomp) const; -}; - -justification_spec::justification_spec(vunits h) -: height(h), n(0), maxn(10) -{ - type = new symbol[maxn]; - amount = new vunits[maxn]; -} - -justification_spec::~justification_spec() -{ - a_delete type; - a_delete amount; -} - -void justification_spec::append(symbol t, vunits v) -{ - if (v <= V0) { - if (v < V0) - warning(WARN_RANGE, - "maximum space for vertical justification must not be negative"); - else - warning(WARN_RANGE, - "maximum space for vertical justification must not be zero"); - return; - } - if (n >= maxn) { - maxn *= 2; - symbol *old_type = type; - type = new symbol[maxn]; - int i; - for (i = 0; i < n; i++) - type[i] = old_type[i]; - a_delete old_type; - vunits *old_amount = amount; - amount = new vunits[maxn]; - for (i = 0; i < n; i++) - amount[i] = old_amount[i]; - a_delete old_amount; - } - assert(n < maxn); - type[n] = t; - amount[n] = v; - n++; -} - -void justification_spec::justify(output_line *col, vunits *bottomp) const -{ - if (*bottomp >= height) - return; - vunits total; - output_line *p; - for (p = col; p; p = p->next) { - vjustify_output_line *sp = p->as_vjustify_output_line(); - if (sp) { - symbol t = sp->type(); - for (int i = 0; i < n; i++) { - if (t == type[i]) - total += amount[i]; - } - } - } - vunits gap = height - *bottomp; - for (p = col; p; p = p->next) { - vjustify_output_line *sp = p->as_vjustify_output_line(); - if (sp) { - symbol t = sp->type(); - for (int i = 0; i < n; i++) { - if (t == type[i]) { - if (total <= gap) { - sp->vary(amount[i]); - gap -= amount[i]; - } - else { - // gap < total - vunits v = scale(amount[i], gap, total); - sp->vary(v); - gap -= v; - } - total -= amount[i]; - } - } - } - } - assert(total == V0); - *bottomp = height - gap; -} - -void column::justify(const justification_spec &js) -{ - check_bottom(); - js.justify(col, &bottom); - check_bottom(); -} - -void column_justify() -{ - vunits height; - if (!the_column->is_active()) - error("can't justify column - column not active"); - else if (get_vunits(&height, 'v')) { - justification_spec js(height); - symbol nm = get_long_name(1); - if (!nm.is_null()) { - vunits v; - if (get_vunits(&v, 'v')) { - js.append(nm, v); - int err = 0; - while (has_arg()) { - nm = get_long_name(1); - if (nm.is_null()) { - err = 1; - break; - } - if (!get_vunits(&v, 'v')) { - err = 1; - break; - } - js.append(nm, v); - } - if (!err) - the_column->justify(js); - } - } - } - skip_line(); -} - -void column_start() -{ - if (the_column->is_active()) - error("can't start column - column already active"); - else - the_column->start(); - skip_line(); -} - -void column_output() -{ - if (!the_column->is_active()) - error("can't output column - column not active"); - else - the_column->output(); - skip_line(); -} - -void column_trim() -{ - if (!the_column->is_active()) - error("can't trim column - column not active"); - else - the_column->trim(); - skip_line(); -} - -void column_reset() -{ - if (!the_column->is_active()) - error("can't reset column - column not active"); - else - the_column->reset(); - skip_line(); -} - -class column_bottom_reg : public reg { -public: - const char *get_string(); -}; - -const char *column_bottom_reg::get_string() -{ - return i_to_a(the_column->get_bottom().to_units()); -} - -class column_extra_space_reg : public reg { -public: - const char *get_string(); -}; - -const char *column_extra_space_reg::get_string() -{ - return i_to_a(the_column->get_last_extra_space().to_units()); -} - -class column_active_reg : public reg { -public: - const char *get_string(); -}; - -const char *column_active_reg::get_string() -{ - return the_column->is_active() ? "1" : "0"; -} - -static int no_vjustify_mode = 0; - -class vjustify_node : public node { - symbol typ; -public: - vjustify_node(symbol); - int reread(int *); - const char *type(); - int same(node *); - node *copy(); -}; - -vjustify_node::vjustify_node(symbol t) -: typ(t) -{ -} - -node *vjustify_node::copy() -{ - return new vjustify_node(typ); -} - -const char *vjustify_node::type() -{ - return "vjustify_node"; -} - -int vjustify_node::same(node *nd) -{ - return typ == ((vjustify_node *)nd)->typ; -} - -int vjustify_node::reread(int *bolp) -{ - curdiv->vjustify(typ); - *bolp = 1; - return 1; -} - -void macro_diversion::vjustify(symbol type) -{ - if (!no_vjustify_mode) - mac->append(new vjustify_node(type)); -} - -void top_level_diversion::vjustify(symbol type) -{ - if (no_space_mode || no_vjustify_mode) - return; - assert(first_page_begun); // I'm not sure about this. - the_output->vjustify(vertical_position, type); -} - -void no_vjustify() -{ - skip_line(); - no_vjustify_mode = 1; -} - -void restore_vjustify() -{ - skip_line(); - no_vjustify_mode = 0; -} - -void init_column_requests() -{ - the_column = new column; - init_request("cols", column_start); - init_request("colo", column_output); - init_request("colj", column_justify); - init_request("colr", column_reset); - init_request("colt", column_trim); - init_request("nvj", no_vjustify); - init_request("rvj", restore_vjustify); - number_reg_dictionary.define(".colb", new column_bottom_reg); - number_reg_dictionary.define(".colx", new column_extra_space_reg); - number_reg_dictionary.define(".cola", new column_active_reg); - number_reg_dictionary.define(".nvj", - new constant_int_reg(&no_vjustify_mode)); -} - -#endif /* COLUMN */ diff --git a/contrib/groff/src/roff/troff/dictionary.cc b/contrib/groff/src/roff/troff/dictionary.cc deleted file mode 100644 index a70ebb0..0000000 --- a/contrib/groff/src/roff/troff/dictionary.cc +++ /dev/null @@ -1,212 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001 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 "troff.h" -#include "symbol.h" -#include "dictionary.h" - -// is `p' a good size for a hash table - -static int is_good_size(unsigned int p) -{ - const unsigned int SMALL = 10; - unsigned int i; - for (i = 2; i <= p/2; i++) - if (p % i == 0) - return 0; - for (i = 0x100; i != 0; i <<= 8) - if (i % p <= SMALL || i % p > p - SMALL) - return 0; - return 1; -} - -dictionary::dictionary(int n) : size(n), used(0), threshold(0.5), factor(1.5) -{ - table = new association[n]; -} - -// see Knuth, Sorting and Searching, p518, Algorithm L -// we can't use double-hashing because we want a remove function - -void *dictionary::lookup(symbol s, void *v) -{ - int i; - for (i = int(s.hash() % size); - table[i].v != 0; - i == 0 ? i = size - 1: --i) - if (s == table[i].s) { - if (v != 0) { - void *temp = table[i].v; - table[i].v = v; - return temp; - } - else - return table[i].v; - } - if (v == 0) - return 0; - ++used; - table[i].v = v; - table[i].s = s; - if ((double)used/(double)size >= threshold || used + 1 >= size) { - int old_size = size; - size = int(size*factor); - while (!is_good_size(size)) - ++size; - association *old_table = table; - table = new association[size]; - used = 0; - for (i = 0; i < old_size; i++) - if (old_table[i].v != 0) - (void)lookup(old_table[i].s, old_table[i].v); - a_delete old_table; - } - return 0; -} - -void *dictionary::lookup(const char *p) -{ - symbol s(p, MUST_ALREADY_EXIST); - if (s.is_null()) - return 0; - else - return lookup(s); -} - -// see Knuth, Sorting and Searching, p527, Algorithm R - -void *dictionary::remove(symbol s) -{ - // this relies on the fact that we are using linear probing - int i; - for (i = int(s.hash() % size); - table[i].v != 0 && s != table[i].s; - i == 0 ? i = size - 1: --i) - ; - void *p = table[i].v; - while (table[i].v != 0) { - table[i].v = 0; - int j = i; - int r; - do { - --i; - if (i < 0) - i = size - 1; - if (table[i].v == 0) - break; - r = int(table[i].s.hash() % size); - } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r)); - table[j] = table[i]; - } - if (p != 0) - --used; - return p; -} - -dictionary_iterator::dictionary_iterator(dictionary &d) : dict(&d), i(0) -{ -} - -int dictionary_iterator::get(symbol *sp, void **vp) -{ - for (; i < dict->size; i++) - if (dict->table[i].v) { - *sp = dict->table[i].s; - *vp = dict->table[i].v; - i++; - return 1; - } - return 0; -} - -object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od) -: di(od.d) -{ -} - -object::object() : rcount(0) -{ -} - -object::~object() -{ -} - -void object::add_reference() -{ - rcount += 1; -} - -void object::remove_reference() -{ - if (--rcount == 0) - delete this; -} - -object_dictionary::object_dictionary(int n) : d(n) -{ -} - -object *object_dictionary::lookup(symbol nm) -{ - return (object *)d.lookup(nm); -} - -void object_dictionary::define(symbol nm, object *obj) -{ - obj->add_reference(); - obj = (object *)d.lookup(nm, obj); - if (obj) - obj->remove_reference(); -} - -void object_dictionary::rename(symbol oldnm, symbol newnm) -{ - object *obj = (object *)d.remove(oldnm); - if (obj) { - obj = (object *)d.lookup(newnm, obj); - if (obj) - obj->remove_reference(); - } -} - -void object_dictionary::remove(symbol nm) -{ - object *obj = (object *)d.remove(nm); - if (obj) - obj->remove_reference(); -} - -// Return non-zero if oldnm was defined. - -int object_dictionary::alias(symbol newnm, symbol oldnm) -{ - object *obj = (object *)d.lookup(oldnm); - if (obj) { - obj->add_reference(); - obj = (object *)d.lookup(newnm, obj); - if (obj) - obj->remove_reference(); - return 1; - } - return 0; -} - diff --git a/contrib/groff/src/roff/troff/div.cc b/contrib/groff/src/roff/troff/div.cc deleted file mode 100644 index 14c7399..0000000 --- a/contrib/groff/src/roff/troff/div.cc +++ /dev/null @@ -1,1185 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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. */ - - -// diversions - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "div.h" -#include "reg.h" - -int exit_started = 0; // the exit process has started -int done_end_macro = 0; // the end macro (if any) has finished -int seen_last_page_ejector = 0; // seen the LAST_PAGE_EJECTOR cookie -int last_page_number = 0; // if > 0, the number of the last page - // specified with -o -static int began_page_in_end_macro = 0; // a new page was begun during the end macro - -static int last_post_line_extra_space = 0; // needed for \n(.a -static int nl_reg_contents = -1; -static int dl_reg_contents = 0; -static int dn_reg_contents = 0; -static int vertical_position_traps_flag = 1; -static vunits truncated_space; -static vunits needed_space; - -diversion::diversion(symbol s) -: prev(0), nm(s), vertical_position(V0), high_water_mark(V0), - no_space_mode(0), marked_place(V0) -{ -} - -struct vertical_size { - vunits pre_extra, post_extra, pre, post; - vertical_size(vunits vs, vunits post_vs); -}; - -vertical_size::vertical_size(vunits vs, vunits post_vs) -: pre_extra(V0), post_extra(V0), pre(vs), post(post_vs) -{ -} - -void node::set_vertical_size(vertical_size *) -{ -} - -void extra_size_node::set_vertical_size(vertical_size *v) -{ - if (n < V0) { - if (-n > v->pre_extra) - v->pre_extra = -n; - } - else if (n > v->post_extra) - v->post_extra = n; -} - -void vertical_size_node::set_vertical_size(vertical_size *v) -{ - if (n < V0) - v->pre = -n; - else - v->post = n; -} - -top_level_diversion *topdiv; - -diversion *curdiv; - -void do_divert(int append, int boxing) -{ - tok.skip(); - symbol nm = get_name(); - if (nm.is_null()) { - if (curdiv->prev) { - if (boxing) { - curenv->line = curdiv->saved_line; - curenv->width_total = curdiv->saved_width_total; - curenv->space_total = curdiv->saved_space_total; - curenv->saved_indent = curdiv->saved_saved_indent; - curenv->target_text_length = curdiv->saved_target_text_length; - curenv->prev_line_interrupted = curdiv->saved_prev_line_interrupted; - } - diversion *temp = curdiv; - curdiv = curdiv->prev; - delete temp; - } - else - warning(WARN_DI, "diversion stack underflow"); - } - else { - macro_diversion *md = new macro_diversion(nm, append); - md->prev = curdiv; - curdiv = md; - if (boxing) { - curdiv->saved_line = curenv->line; - curdiv->saved_width_total = curenv->width_total; - curdiv->saved_space_total = curenv->space_total; - curdiv->saved_saved_indent = curenv->saved_indent; - curdiv->saved_target_text_length = curenv->target_text_length; - curdiv->saved_prev_line_interrupted = curenv->prev_line_interrupted; - curenv->line = 0; - curenv->start_line(); - } - } - skip_line(); -} - -void divert() -{ - do_divert(0, 0); -} - -void divert_append() -{ - do_divert(1, 0); -} - -void box() -{ - do_divert(0, 1); -} - -void box_append() -{ - do_divert(1, 1); -} - -void diversion::need(vunits n) -{ - vunits d = distance_to_next_trap(); - if (d < n) { - space(d, 1); - truncated_space = -d; - needed_space = n; - } -} - -macro_diversion::macro_diversion(symbol s, int append) -: diversion(s), max_width(H0) -{ -#if 0 - if (append) { - /* We don't allow recursive appends eg: - - .da a - .a - .di - - This causes an infinite loop in troff anyway. - This is because the user could do - - .as a foo - - in the diversion, and this would mess things up royally, - since there would be two things appending to the same - macro_header. - To make it work, we would have to copy the _contents_ - of the macro into which we were diverting; this doesn't - strike me as worthwhile. - However, - - .di a - .a - .a - .di - - will work and will make `a' contain two copies of what it contained - before; in troff, `a' would contain nothing. */ - request_or_macro *rm - = (request_or_macro *)request_dictionary.remove(s); - if (!rm || (mac = rm->to_macro()) == 0) - mac = new macro; - } - else - mac = new macro; -#endif - // We can now catch the situation described above by comparing - // the length of the charlist in the macro_header with the length - // stored in the macro. When we detect this, we copy the contents. - mac = new macro; - if (append) { - request_or_macro *rm - = (request_or_macro *)request_dictionary.lookup(s); - if (rm) { - macro *m = rm->to_macro(); - if (m) - *mac = *m; - } - } -} - -macro_diversion::~macro_diversion() -{ - request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); - macro *m = rm ? rm->to_macro() : 0; - if (m) { - *m = *mac; - delete mac; - } - else - request_dictionary.define(nm, mac); - mac = 0; - dl_reg_contents = max_width.to_units(); - dn_reg_contents = vertical_position.to_units(); -} - -vunits macro_diversion::distance_to_next_trap() -{ - if (!diversion_trap.is_null() && diversion_trap_pos > vertical_position) - return diversion_trap_pos - vertical_position; - else - // Substract vresolution so that vunits::vunits does not overflow. - return vunits(INT_MAX - vresolution); -} - -void macro_diversion::transparent_output(unsigned char c) -{ - mac->append(c); -} - -void macro_diversion::transparent_output(node *n) -{ - mac->append(n); -} - -void macro_diversion::output(node *nd, int retain_size, - vunits vs, vunits post_vs, hunits width) -{ - no_space_mode = 0; - vertical_size v(vs, post_vs); - while (nd != 0) { - nd->set_vertical_size(&v); - node *temp = nd; - nd = nd->next; - if (temp->interpret(mac)) { - delete temp; - } - else { -#if 1 - temp->freeze_space(); -#endif - mac->append(temp); - } - } - last_post_line_extra_space = v.post_extra.to_units(); - if (!retain_size) { - v.pre = vs; - v.post = post_vs; - } - if (width > max_width) - max_width = width; - vunits x = v.pre + v.pre_extra + v.post + v.post_extra; - if (vertical_position_traps_flag - && !diversion_trap.is_null() && diversion_trap_pos > vertical_position - && diversion_trap_pos <= vertical_position + x) { - vunits trunc = vertical_position + x - diversion_trap_pos; - if (trunc > v.post) - trunc = v.post; - v.post -= trunc; - x -= trunc; - truncated_space = trunc; - spring_trap(diversion_trap); - } - mac->append(new vertical_size_node(-v.pre)); - mac->append(new vertical_size_node(v.post)); - mac->append('\n'); - vertical_position += x; - if (vertical_position - v.post > high_water_mark) - high_water_mark = vertical_position - v.post; -} - -void macro_diversion::space(vunits n, int) -{ - if (vertical_position_traps_flag - && !diversion_trap.is_null() && diversion_trap_pos > vertical_position - && diversion_trap_pos <= vertical_position + n) { - truncated_space = vertical_position + n - diversion_trap_pos; - n = diversion_trap_pos - vertical_position; - spring_trap(diversion_trap); - } - else if (n + vertical_position < V0) - n = -vertical_position; - mac->append(new diverted_space_node(n)); - vertical_position += n; -} - -void macro_diversion::copy_file(const char *filename) -{ - mac->append(new diverted_copy_file_node(filename)); -} - -top_level_diversion::top_level_diversion() -: page_number(0), page_count(0), last_page_count(-1), - page_length(units_per_inch*11), - prev_page_offset(units_per_inch), page_offset(units_per_inch), - page_trap_list(0), have_next_page_number(0), - ejecting_page(0), before_first_page(1) -{ -} - -// find the next trap after pos - -trap *top_level_diversion::find_next_trap(vunits *next_trap_pos) -{ - trap *next_trap = 0; - for (trap *pt = page_trap_list; pt != 0; pt = pt->next) - if (!pt->nm.is_null()) { - if (pt->position >= V0) { - if (pt->position > vertical_position - && pt->position < page_length - && (next_trap == 0 || pt->position < *next_trap_pos)) { - next_trap = pt; - *next_trap_pos = pt->position; - } - } - else { - vunits pos = pt->position; - pos += page_length; - if (pos > 0 && pos > vertical_position && (next_trap == 0 || pos < *next_trap_pos)) { - next_trap = pt; - *next_trap_pos = pos; - } - } - } - return next_trap; -} - -vunits top_level_diversion::distance_to_next_trap() -{ - vunits d; - if (!find_next_trap(&d)) - return page_length - vertical_position; - else - return d - vertical_position; -} - -void top_level_diversion::output(node *nd, int retain_size, - vunits vs, vunits post_vs, hunits width) -{ - no_space_mode = 0; - vunits next_trap_pos; - trap *next_trap = find_next_trap(&next_trap_pos); - if (before_first_page && begin_page()) - fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); - vertical_size v(vs, post_vs); - for (node *tem = nd; tem != 0; tem = tem->next) - tem->set_vertical_size(&v); - last_post_line_extra_space = v.post_extra.to_units(); - if (!retain_size) { - v.pre = vs; - v.post = post_vs; - } - vertical_position += v.pre; - vertical_position += v.pre_extra; - the_output->print_line(page_offset, vertical_position, nd, - v.pre + v.pre_extra, v.post_extra, width); - vertical_position += v.post_extra; - if (vertical_position > high_water_mark) - high_water_mark = vertical_position; - if (vertical_position_traps_flag && vertical_position >= page_length) - begin_page(); - else if (vertical_position_traps_flag - && next_trap != 0 && vertical_position >= next_trap_pos) { - nl_reg_contents = vertical_position.to_units(); - truncated_space = v.post; - spring_trap(next_trap->nm); - } - else if (v.post > V0) { - vertical_position += v.post; - if (vertical_position_traps_flag - && next_trap != 0 && vertical_position >= next_trap_pos) { - truncated_space = vertical_position - next_trap_pos; - vertical_position = next_trap_pos; - nl_reg_contents = vertical_position.to_units(); - spring_trap(next_trap->nm); - } - else if (vertical_position_traps_flag && vertical_position >= page_length) - begin_page(); - else - nl_reg_contents = vertical_position.to_units(); - } - else - nl_reg_contents = vertical_position.to_units(); -} - -void top_level_diversion::transparent_output(unsigned char c) -{ - if (before_first_page && begin_page()) - // This can only happen with the .output request. - fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); - const char *s = asciify(c); - while (*s) - the_output->transparent_char(*s++); -} - -void top_level_diversion::transparent_output(node * /*n*/) -{ - error("can't transparently output node at top level"); -} - -void top_level_diversion::copy_file(const char *filename) -{ - if (before_first_page && begin_page()) - fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); - the_output->copy_file(page_offset, vertical_position, filename); -} - -void top_level_diversion::space(vunits n, int forced) -{ - if (no_space_mode) { - if (!forced) - return; - else - no_space_mode = 0; - } - if (before_first_page) { - if (begin_page()) { - // This happens if there's a top of page trap, and the first-page - // transition is caused by `'sp'. - truncated_space = n > V0 ? n : V0; - return; - } - } - vunits next_trap_pos; - trap *next_trap = find_next_trap(&next_trap_pos); - vunits y = vertical_position + n; - if (vertical_position_traps_flag && next_trap != 0 && y >= next_trap_pos) { - vertical_position = next_trap_pos; - nl_reg_contents = vertical_position.to_units(); - truncated_space = y - vertical_position; - spring_trap(next_trap->nm); - } - else if (y < V0) { - vertical_position = V0; - nl_reg_contents = vertical_position.to_units(); - } - else if (vertical_position_traps_flag && y >= page_length && n >= V0) - begin_page(); - else { - vertical_position = y; - nl_reg_contents = vertical_position.to_units(); - } -} - -trap::trap(symbol s, vunits n, trap *p) -: next(p), position(n), nm(s) -{ -} - -void top_level_diversion::add_trap(symbol nm, vunits pos) -{ - trap *first_free_slot = 0; - trap **p; - for (p = &page_trap_list; *p; p = &(*p)->next) { - if ((*p)->nm.is_null()) { - if (first_free_slot == 0) - first_free_slot = *p; - } - else if ((*p)->position == pos) { - (*p)->nm = nm; - return; - } - } - if (first_free_slot) { - first_free_slot->nm = nm; - first_free_slot->position = pos; - } - else - *p = new trap(nm, pos, 0); -} - -void top_level_diversion::remove_trap(symbol nm) -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->nm == nm) { - p->nm = NULL_SYMBOL; - return; - } -} - -void top_level_diversion::remove_trap_at(vunits pos) -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->position == pos) { - p->nm = NULL_SYMBOL; - return; - } -} - -void top_level_diversion::change_trap(symbol nm, vunits pos) -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->nm == nm) { - p->position = pos; - return; - } -} - -void top_level_diversion::print_traps() -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->nm.is_null()) - fprintf(stderr, " empty\n"); - else - fprintf(stderr, "%s\t%d\n", p->nm.contents(), p->position.to_units()); - fflush(stderr); -} - -void end_diversions() -{ - while (curdiv != topdiv) { - error("automatically ending diversion `%1' on exit", - curdiv->nm.contents()); - diversion *tem = curdiv; - curdiv = curdiv->prev; - delete tem; - } -} - -void cleanup_and_exit(int exit_code) -{ - if (the_output) { - the_output->trailer(topdiv->get_page_length()); - delete the_output; - } - exit(exit_code); -} - -// returns non-zero if it sprung a top of page trap - -int top_level_diversion::begin_page() -{ - if (exit_started) { - if (page_count == last_page_count - ? curenv->is_empty() - : (done_end_macro && (seen_last_page_ejector || began_page_in_end_macro))) - cleanup_and_exit(0); - if (!done_end_macro) - began_page_in_end_macro = 1; - } - if (last_page_number > 0 && page_number == last_page_number) - cleanup_and_exit(0); - if (!the_output) - init_output(); - ++page_count; - if (have_next_page_number) { - page_number = next_page_number; - have_next_page_number = 0; - } - else if (before_first_page == 1) - page_number = 1; - else - page_number++; - // spring the top of page trap if there is one - vunits next_trap_pos; - vertical_position = -vresolution; - trap *next_trap = find_next_trap(&next_trap_pos); - vertical_position = V0; - high_water_mark = V0; - ejecting_page = 0; - // If before_first_page was 2, then the top of page transition was undone - // using eg .nr nl 0-1. See nl_reg::set_value. - if (before_first_page != 2) - the_output->begin_page(page_number, page_length); - before_first_page = 0; - nl_reg_contents = vertical_position.to_units(); - if (vertical_position_traps_flag && next_trap != 0 && next_trap_pos == V0) { - truncated_space = V0; - spring_trap(next_trap->nm); - return 1; - } - else - return 0; -} - -void continue_page_eject() -{ - if (topdiv->get_ejecting()) { - if (curdiv != topdiv) - error("can't continue page ejection because of current diversion"); - else if (!vertical_position_traps_flag) - error("can't continue page ejection because vertical position traps disabled"); - else { - push_page_ejector(); - topdiv->space(topdiv->get_page_length(), 1); - } - } -} - -void top_level_diversion::set_next_page_number(int n) -{ - next_page_number= n; - have_next_page_number = 1; -} - -int top_level_diversion::get_next_page_number() -{ - return have_next_page_number ? next_page_number : page_number + 1; -} - -void top_level_diversion::set_page_length(vunits n) -{ - page_length = n; -} - -diversion::~diversion() -{ -} - -void page_offset() -{ - hunits n; - // The troff manual says that the default scaling indicator is v, - // but it is in fact m: v wouldn't make sense for a horizontally - // oriented request. - if (!has_arg() || !get_hunits(&n, 'm', topdiv->page_offset)) - n = topdiv->prev_page_offset; - topdiv->prev_page_offset = topdiv->page_offset; - topdiv->page_offset = n; - curenv->add_html_tag(0, ".po", n.to_units()); - skip_line(); -} - -void page_length() -{ - vunits n; - if (has_arg() && get_vunits(&n, 'v', topdiv->get_page_length())) - topdiv->set_page_length(n); - else - topdiv->set_page_length(11*units_per_inch); - skip_line(); -} - -void when_request() -{ - vunits n; - if (get_vunits(&n, 'v')) { - symbol s = get_name(); - if (s.is_null()) - topdiv->remove_trap_at(n); - else - topdiv->add_trap(s, n); - } - skip_line(); -} - -void begin_page() -{ - int got_arg = 0; - int n; - if (has_arg() && get_integer(&n, topdiv->get_page_number())) - got_arg = 1; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (curdiv == topdiv) { - if (topdiv->before_first_page) { - if (!break_flag) { - if (got_arg) - topdiv->set_next_page_number(n); - if (got_arg || !topdiv->no_space_mode) - topdiv->begin_page(); - } - else if (topdiv->no_space_mode && !got_arg) - topdiv->begin_page(); - else { - /* Given this - - .wh 0 x - .de x - .tm \\n% - .. - .bp 3 - - troff prints - - 1 - 3 - - This code makes groff do the same. */ - - push_page_ejector(); - topdiv->begin_page(); - if (got_arg) - topdiv->set_next_page_number(n); - topdiv->set_ejecting(); - } - } - else { - push_page_ejector(); - if (break_flag) - curenv->do_break(); - if (got_arg) - topdiv->set_next_page_number(n); - if (!(topdiv->no_space_mode && !got_arg)) - topdiv->set_ejecting(); - } - } - tok.next(); -} - -void no_space() -{ - curdiv->no_space_mode = 1; - skip_line(); -} - -void restore_spacing() -{ - curdiv->no_space_mode = 0; - skip_line(); -} - -/* It is necessary to generate a break before before reading the argument, -because otherwise arguments using | will be wrong. But if we just -generate a break as usual, then the line forced out may spring a trap -and thus push a macro onto the input stack before we have had a chance -to read the argument to the sp request. We resolve this dilemma by -setting, before generating the break, a flag which will postpone the -actual pushing of the macro associated with the trap sprung by the -outputting of the line forced out by the break till after we have read -the argument to the request. If the break did cause a trap to be -sprung, then we don't actually do the space. */ - -void space_request() -{ - postpone_traps(); - if (break_flag) - curenv->do_break(); - vunits n; - if (!has_arg() || !get_vunits(&n, 'v')) - n = curenv->get_vertical_spacing(); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (!unpostpone_traps() && !curdiv->no_space_mode) - curdiv->space(n); - else - // The line might have had line spacing that was truncated. - truncated_space += n; - curenv->add_html_tag(1, ".sp", n.to_units()); - tok.next(); -} - -void blank_line() -{ - curenv->do_break(); - if (!trap_sprung_flag && !curdiv->no_space_mode) { - curdiv->space(curenv->get_vertical_spacing()); - curenv->add_html_tag(1, ".sp", 1); - } else - truncated_space += curenv->get_vertical_spacing(); -} - -/* need_space might spring a trap and so we must be careful that the -BEGIN_TRAP token is not skipped over. */ - -void need_space() -{ - vunits n; - if (!has_arg() || !get_vunits(&n, 'v')) - n = curenv->get_vertical_spacing(); - while (!tok.newline() && !tok.eof()) - tok.next(); - curdiv->need(n); - tok.next(); -} - -void page_number() -{ - int n; - - // the ps4html register is set if we are using -Tps - // to generate images for html - reg *r = (reg *)number_reg_dictionary.lookup("ps4html"); - if (r == NULL) - if (has_arg() && get_integer(&n, topdiv->get_page_number())) - topdiv->set_next_page_number(n); - skip_line(); -} - -vunits saved_space; - -void save_vertical_space() -{ - vunits x; - if (!has_arg() || !get_vunits(&x, 'v')) - x = curenv->get_vertical_spacing(); - if (curdiv->distance_to_next_trap() > x) - curdiv->space(x, 1); - else - saved_space = x; - skip_line(); -} - -void output_saved_vertical_space() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (saved_space > V0) - curdiv->space(saved_space, 1); - saved_space = V0; - tok.next(); -} - -void flush_output() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (the_output) - the_output->flush(); - curenv->add_html_tag(1, ".fl"); - tok.next(); -} - -void macro_diversion::set_diversion_trap(symbol s, vunits n) -{ - diversion_trap = s; - diversion_trap_pos = n; -} - -void macro_diversion::clear_diversion_trap() -{ - diversion_trap = NULL_SYMBOL; -} - -void top_level_diversion::set_diversion_trap(symbol, vunits) -{ - error("can't set diversion trap when no current diversion"); -} - -void top_level_diversion::clear_diversion_trap() -{ - error("can't set diversion trap when no current diversion"); -} - -void diversion_trap() -{ - vunits n; - if (has_arg() && get_vunits(&n, 'v')) { - symbol s = get_name(); - if (!s.is_null()) - curdiv->set_diversion_trap(s, n); - else - curdiv->clear_diversion_trap(); - } - else - curdiv->clear_diversion_trap(); - skip_line(); -} - -void change_trap() -{ - symbol s = get_name(1); - if (!s.is_null()) { - vunits x; - if (has_arg() && get_vunits(&x, 'v')) - topdiv->change_trap(s, x); - else - topdiv->remove_trap(s); - } - skip_line(); -} - -void print_traps() -{ - topdiv->print_traps(); - skip_line(); -} - -void mark() -{ - symbol s = get_name(); - if (s.is_null()) - curdiv->marked_place = curdiv->get_vertical_position(); - else if (curdiv == topdiv) - set_number_reg(s, nl_reg_contents); - else - set_number_reg(s, curdiv->get_vertical_position().to_units()); - skip_line(); -} - -// This is truly bizarre. It is documented in the SQ manual. - -void return_request() -{ - vunits dist = curdiv->marked_place - curdiv->get_vertical_position(); - if (has_arg()) { - if (tok.ch() == '-') { - tok.next(); - vunits x; - if (get_vunits(&x, 'v')) - dist = -x; - } - else { - vunits x; - if (get_vunits(&x, 'v')) - dist = x >= V0 ? x - curdiv->get_vertical_position() : V0; - } - } - if (dist < V0) - curdiv->space(dist); - skip_line(); -} - -void vertical_position_traps() -{ - int n; - if (has_arg() && get_integer(&n)) - vertical_position_traps_flag = (n != 0); - else - vertical_position_traps_flag = 1; - skip_line(); -} - -class page_offset_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int page_offset_reg::get_value(units *res) -{ - *res = topdiv->get_page_offset().to_units(); - return 1; -} - -const char *page_offset_reg::get_string() -{ - return i_to_a(topdiv->get_page_offset().to_units()); -} - -class page_length_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int page_length_reg::get_value(units *res) -{ - *res = topdiv->get_page_length().to_units(); - return 1; -} - -const char *page_length_reg::get_string() -{ - return i_to_a(topdiv->get_page_length().to_units()); -} - -class vertical_position_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int vertical_position_reg::get_value(units *res) -{ - if (curdiv == topdiv && topdiv->before_first_page) - *res = -1; - else - *res = curdiv->get_vertical_position().to_units(); - return 1; -} - -const char *vertical_position_reg::get_string() -{ - if (curdiv == topdiv && topdiv->before_first_page) - return "-1"; - else - return i_to_a(curdiv->get_vertical_position().to_units()); -} - -class high_water_mark_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int high_water_mark_reg::get_value(units *res) -{ - *res = curdiv->get_high_water_mark().to_units(); - return 1; -} - -const char *high_water_mark_reg::get_string() -{ - return i_to_a(curdiv->get_high_water_mark().to_units()); -} - -class distance_to_next_trap_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int distance_to_next_trap_reg::get_value(units *res) -{ - *res = curdiv->distance_to_next_trap().to_units(); - return 1; -} - -const char *distance_to_next_trap_reg::get_string() -{ - return i_to_a(curdiv->distance_to_next_trap().to_units()); -} - -class diversion_name_reg : public reg { -public: - const char *get_string(); -}; - -const char *diversion_name_reg::get_string() -{ - return curdiv->get_diversion_name(); -} - -class page_number_reg : public general_reg { -public: - page_number_reg(); - int get_value(units *); - void set_value(units); -}; - -page_number_reg::page_number_reg() -{ -} - -void page_number_reg::set_value(units n) -{ - topdiv->set_page_number(n); -} - -int page_number_reg::get_value(units *res) -{ - *res = topdiv->get_page_number(); - return 1; -} - -class next_page_number_reg : public reg { -public: - const char *get_string(); -}; - -const char *next_page_number_reg::get_string() -{ - return i_to_a(topdiv->get_next_page_number()); -} - -class page_ejecting_reg : public reg { -public: - const char *get_string(); -}; - -const char *page_ejecting_reg::get_string() -{ - return i_to_a(topdiv->get_ejecting()); -} - -class constant_vunits_reg : public reg { - vunits *p; -public: - constant_vunits_reg(vunits *); - const char *get_string(); -}; - -constant_vunits_reg::constant_vunits_reg(vunits *q) : p(q) -{ -} - -const char *constant_vunits_reg::get_string() -{ - return i_to_a(p->to_units()); -} - -class nl_reg : public variable_reg { -public: - nl_reg(); - void set_value(units); -}; - -nl_reg::nl_reg() : variable_reg(&nl_reg_contents) -{ -} - -void nl_reg::set_value(units n) -{ - variable_reg::set_value(n); - // Setting nl to a negative value when the vertical position in - // the top-level diversion is 0 undoes the top of page transition, - // so that the header macro will be called as if the top of page - // transition hasn't happened. This is used by Larry Wall's - // wrapman program. Setting before_first_page to 2 rather than 1, - // tells top_level_diversion::begin_page not to call - // output_file::begin_page again. - if (n < 0 && topdiv->get_vertical_position() == V0) - topdiv->before_first_page = 2; -} - -class no_space_mode_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int no_space_mode_reg::get_value(units *val) -{ - *val = curdiv->no_space_mode; - return 1; -} - -const char *no_space_mode_reg::get_string() -{ - return curdiv->no_space_mode ? "1" : "0"; -} - -void init_div_requests() -{ - init_request("wh", when_request); - init_request("ch", change_trap); - init_request("pl", page_length); - init_request("po", page_offset); - init_request("rs", restore_spacing); - init_request("ns", no_space); - init_request("sp", space_request); - init_request("di", divert); - init_request("da", divert_append); - init_request("box", box); - init_request("boxa", box_append); - init_request("bp", begin_page); - init_request("ne", need_space); - init_request("pn", page_number); - init_request("dt", diversion_trap); - init_request("rt", return_request); - init_request("mk", mark); - init_request("sv", save_vertical_space); - init_request("os", output_saved_vertical_space); - init_request("fl", flush_output); - init_request("vpt", vertical_position_traps); - init_request("ptr", print_traps); - number_reg_dictionary.define(".a", - new constant_int_reg(&last_post_line_extra_space)); - number_reg_dictionary.define(".z", new diversion_name_reg); - number_reg_dictionary.define(".o", new page_offset_reg); - number_reg_dictionary.define(".p", new page_length_reg); - number_reg_dictionary.define(".ns", new no_space_mode_reg); - number_reg_dictionary.define(".d", new vertical_position_reg); - number_reg_dictionary.define(".h", new high_water_mark_reg); - number_reg_dictionary.define(".t", new distance_to_next_trap_reg); - number_reg_dictionary.define("dl", new variable_reg(&dl_reg_contents)); - number_reg_dictionary.define("dn", new variable_reg(&dn_reg_contents)); - number_reg_dictionary.define("nl", new nl_reg); - number_reg_dictionary.define(".vpt", - new constant_int_reg(&vertical_position_traps_flag)); - number_reg_dictionary.define("%", new page_number_reg); - number_reg_dictionary.define(".pn", new next_page_number_reg); - number_reg_dictionary.define(".trunc", - new constant_vunits_reg(&truncated_space)); - number_reg_dictionary.define(".ne", - new constant_vunits_reg(&needed_space)); - number_reg_dictionary.define(".pe", new page_ejecting_reg); -} diff --git a/contrib/groff/src/roff/troff/env.cc b/contrib/groff/src/roff/troff/env.cc deleted file mode 100644 index b14ffb6..0000000 --- a/contrib/groff/src/roff/troff/env.cc +++ /dev/null @@ -1,3829 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "div.h" -#include "reg.h" -#include "charinfo.h" -#include "macropath.h" -#include "input.h" -#include - -symbol default_family("T"); - -enum { ADJUST_LEFT = 0, ADJUST_BOTH = 1, ADJUST_CENTER = 3, ADJUST_RIGHT = 5 }; - -enum { HYPHEN_LAST_LINE = 2, HYPHEN_LAST_CHARS = 4, HYPHEN_FIRST_CHARS = 8 }; - -struct env_list { - environment *env; - env_list *next; - env_list(environment *e, env_list *p) : env(e), next(p) {} -}; - -env_list *env_stack; -const int NENVIRONMENTS = 10; -environment *env_table[NENVIRONMENTS]; -dictionary env_dictionary(10); -environment *curenv; -static int next_line_number = 0; - -charinfo *field_delimiter_char; -charinfo *padding_indicator_char; - -int translate_space_to_dummy = 0; - -class pending_output_line { - node *nd; - int no_fill; - vunits vs; - vunits post_vs; - hunits width; -#ifdef WIDOW_CONTROL - int last_line; // Is it the last line of the paragraph? -#endif /* WIDOW_CONTROL */ -public: - pending_output_line *next; - - pending_output_line(node *, int, vunits, vunits, hunits, - pending_output_line * = 0); - ~pending_output_line(); - int output(); - -#ifdef WIDOW_CONTROL - friend void environment::mark_last_line(); - friend void environment::output(node *, int, vunits, vunits, hunits); -#endif /* WIDOW_CONTROL */ -}; - -pending_output_line::pending_output_line(node *n, int nf, vunits v, vunits pv, - hunits w, pending_output_line *p) -: nd(n), no_fill(nf), vs(v), post_vs(pv), width(w), -#ifdef WIDOW_CONTROL - last_line(0), -#endif /* WIDOW_CONTROL */ - next(p) -{ -} - -pending_output_line::~pending_output_line() -{ - delete_node_list(nd); -} - -int pending_output_line::output() -{ - if (trap_sprung_flag) - return 0; -#ifdef WIDOW_CONTROL - if (next && next->last_line && !no_fill) { - curdiv->need(vs + post_vs + vunits(vresolution)); - if (trap_sprung_flag) { - next->last_line = 0; // Try to avoid infinite loops. - return 0; - } - } -#endif - curdiv->output(nd, no_fill, vs, post_vs, width); - nd = 0; - return 1; -} - -void environment::output(node *nd, int no_fill, vunits vs, vunits post_vs, - hunits width) -{ -#ifdef WIDOW_CONTROL - while (pending_lines) { - if (widow_control && !pending_lines->no_fill && !pending_lines->next) - break; - if (!pending_lines->output()) - break; - pending_output_line *tem = pending_lines; - pending_lines = pending_lines->next; - delete tem; - } -#else /* WIDOW_CONTROL */ - output_pending_lines(); -#endif /* WIDOW_CONTROL */ - if (!trap_sprung_flag && !pending_lines -#ifdef WIDOW_CONTROL - && (!widow_control || no_fill) -#endif /* WIDOW_CONTROL */ - ) { - curdiv->output(nd, no_fill, vs, post_vs, width); - emitted_node = 1; - } else { - pending_output_line **p; - for (p = &pending_lines; *p; p = &(*p)->next) - ; - *p = new pending_output_line(nd, no_fill, vs, post_vs, width); - } -} - -// a line from .tl goes at the head of the queue - -void environment::output_title(node *nd, int no_fill, vunits vs, - vunits post_vs, hunits width) -{ - if (!trap_sprung_flag) - curdiv->output(nd, no_fill, vs, post_vs, width); - else - pending_lines = new pending_output_line(nd, no_fill, vs, post_vs, width, - pending_lines); -} - -void environment::output_pending_lines() -{ - while (pending_lines && pending_lines->output()) { - pending_output_line *tem = pending_lines; - pending_lines = pending_lines->next; - delete tem; - } -} - -#ifdef WIDOW_CONTROL - -void environment::mark_last_line() -{ - if (!widow_control || !pending_lines) - return; - for (pending_output_line *p = pending_lines; p->next; p = p->next) - ; - if (!p->no_fill) - p->last_line = 1; -} - -void widow_control_request() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->widow_control = n != 0; - else - curenv->widow_control = 1; - skip_line(); -} - -#endif /* WIDOW_CONTROL */ - -/* font_size functions */ - -size_range *font_size::size_table = 0; -int font_size::nranges = 0; - -extern "C" { - -int compare_ranges(const void *p1, const void *p2) -{ - return ((size_range *)p1)->min - ((size_range *)p2)->min; -} - -} - -void font_size::init_size_table(int *sizes) -{ - nranges = 0; - while (sizes[nranges*2] != 0) - nranges++; - assert(nranges > 0); - size_table = new size_range[nranges]; - for (int i = 0; i < nranges; i++) { - size_table[i].min = sizes[i*2]; - size_table[i].max = sizes[i*2 + 1]; - } - qsort(size_table, nranges, sizeof(size_range), compare_ranges); -} - -font_size::font_size(int sp) -{ - for (int i = 0; i < nranges; i++) { - if (sp < size_table[i].min) { - if (i > 0 && size_table[i].min - sp >= sp - size_table[i - 1].max) - p = size_table[i - 1].max; - else - p = size_table[i].min; - return; - } - if (sp <= size_table[i].max) { - p = sp; - return; - } - } - p = size_table[nranges - 1].max; -} - -int font_size::to_units() -{ - return scale(p, units_per_inch, sizescale*72); -} - -// we can't do this in a static constructor because various dictionaries -// have to get initialized first - -void init_environments() -{ - curenv = env_table[0] = new environment("0"); -} - -void tab_character() -{ - curenv->tab_char = get_optional_char(); - skip_line(); -} - -void leader_character() -{ - curenv->leader_char = get_optional_char(); - skip_line(); -} - -void environment::add_char(charinfo *ci) -{ - int s; - if (interrupted) - ; - // don't allow fields in dummy environments - else if (ci == field_delimiter_char && !dummy) { - if (current_field) - wrap_up_field(); - else - start_field(); - } - else if (current_field && ci == padding_indicator_char) - add_padding(); - else if (current_tab) { - if (tab_contents == 0) - tab_contents = new line_start_node; - if (ci != hyphen_indicator_char) - tab_contents = tab_contents->add_char(ci, this, &tab_width, &s); - else - tab_contents = tab_contents->add_discretionary_hyphen(); - } - else { - if (line == 0) - start_line(); - if (ci != hyphen_indicator_char) - line = line->add_char(ci, this, &width_total, &space_total); - else - line = line->add_discretionary_hyphen(); - } -} - -node *environment::make_char_node(charinfo *ci) -{ - return make_node(ci, this); -} - -void environment::add_node(node *n) -{ - if (n == 0) - return; - if (current_tab || current_field) - n->freeze_space(); - if (interrupted) { - delete n; - } - else if (current_tab) { - n->next = tab_contents; - tab_contents = n; - tab_width += n->width(); - } - else { - if (line == 0) { - if (discarding && n->discardable()) { - // XXX possibly: input_line_start -= n->width(); - delete n; - return; - } - start_line(); - } - width_total += n->width(); - space_total += n->nspaces(); - n->next = line; - line = n; - } -} - - -void environment::add_hyphen_indicator() -{ - if (current_tab || interrupted || current_field - || hyphen_indicator_char != 0) - return; - if (line == 0) - start_line(); - line = line->add_discretionary_hyphen(); -} - -int environment::get_hyphenation_flags() -{ - return hyphenation_flags; -} - -int environment::get_hyphen_line_max() -{ - return hyphen_line_max; -} - -int environment::get_hyphen_line_count() -{ - return hyphen_line_count; -} - -int environment::get_center_lines() -{ - return center_lines; -} - -int environment::get_right_justify_lines() -{ - return right_justify_lines; -} - -void environment::add_italic_correction() -{ - if (current_tab) { - if (tab_contents) - tab_contents = tab_contents->add_italic_correction(&tab_width); - } - else if (line) - line = line->add_italic_correction(&width_total); -} - -void environment::space_newline() -{ - assert(!current_tab && !current_field); - if (interrupted) - return; - hunits x = H0; - hunits sw = env_space_width(this); - hunits ssw = env_sentence_space_width(this); - if (!translate_space_to_dummy) { - x = sw; - if (node_list_ends_sentence(line) == 1) - x += ssw; - } - width_list *w = new width_list(sw, ssw); - if (node_list_ends_sentence(line) == 1) - w->next = new width_list(sw, ssw); - if (line != 0 && line->merge_space(x, sw, ssw)) { - width_total += x; - return; - } - add_node(new word_space_node(x, get_fill_color(), w)); - possibly_break_line(0, spread_flag); - spread_flag = 0; -} - -void environment::space() -{ - space(env_space_width(this), env_sentence_space_width(this)); -} - -void environment::space(hunits space_width, hunits sentence_space_width) -{ - if (interrupted) - return; - if (current_field && padding_indicator_char == 0) { - add_padding(); - return; - } - hunits x = translate_space_to_dummy ? H0 : space_width; - node *p = current_tab ? tab_contents : line; - hunits *tp = current_tab ? &tab_width : &width_total; - if (p && p->nspaces() == 1 && p->width() == x - && node_list_ends_sentence(p->next) == 1) { - hunits xx = translate_space_to_dummy ? H0 : sentence_space_width; - if (p->merge_space(xx, space_width, sentence_space_width)) { - *tp += xx; - return; - } - } - if (p && p->merge_space(x, space_width, sentence_space_width)) { - *tp += x; - return; - } - add_node(new word_space_node(x, - get_fill_color(), - new width_list(space_width, - sentence_space_width))); - possibly_break_line(0, spread_flag); - spread_flag = 0; -} - -node *do_underline_special(int); - -void environment::set_font(symbol nm) -{ - if (interrupted) - return; - if (nm == symbol("P") || nm.is_empty()) { - if (family->make_definite(prev_fontno) < 0) - return; - int tem = fontno; - fontno = prev_fontno; - prev_fontno = tem; - } - else { - prev_fontno = fontno; - int n = symbol_fontno(nm); - if (n < 0) { - n = next_available_font_position(); - if (!mount_font(n, nm)) - return; - } - if (family->make_definite(n) < 0) - return; - fontno = n; - } - if (underline_spaces && fontno != prev_fontno) { - if (fontno == get_underline_fontno()) - add_node(do_underline_special(1)); - if (prev_fontno == get_underline_fontno()) - add_node(do_underline_special(0)); - } -} - -void environment::set_font(int n) -{ - if (interrupted) - return; - if (is_good_fontno(n)) { - prev_fontno = fontno; - fontno = n; - } - else - warning(WARN_FONT, "bad font number"); -} - -void environment::set_family(symbol fam) -{ - if (interrupted) - return; - if (fam.is_null() || fam.is_empty()) { - if (prev_family->make_definite(fontno) < 0) - return; - font_family *tem = family; - family = prev_family; - prev_family = tem; - } - else { - font_family *f = lookup_family(fam); - if (f->make_definite(fontno) < 0) - return; - prev_family = family; - family = f; - } -} - -void environment::set_size(int n) -{ - if (interrupted) - return; - if (n == 0) { - font_size temp = prev_size; - prev_size = size; - size = temp; - int temp2 = prev_requested_size; - prev_requested_size = requested_size; - requested_size = temp2; - } - else { - prev_size = size; - size = font_size(n); - prev_requested_size = requested_size; - requested_size = n; - } -} - -void environment::set_char_height(int n) -{ - if (interrupted) - return; - if (n == requested_size || n <= 0) - char_height = 0; - else - char_height = n; -} - -void environment::set_char_slant(int n) -{ - if (interrupted) - return; - char_slant = n; -} - -color *environment::get_prev_glyph_color() -{ - return prev_glyph_color; -} - -color *environment::get_glyph_color() -{ - return glyph_color; -} - -color *environment::get_prev_fill_color() -{ - return prev_fill_color; -} - -color *environment::get_fill_color() -{ - return fill_color; -} - -void environment::set_glyph_color(color *c) -{ - if (interrupted) - return; - curenv->prev_glyph_color = curenv->glyph_color; - curenv->glyph_color = c; -} - -void environment::set_fill_color(color *c) -{ - if (interrupted) - return; - curenv->prev_fill_color = curenv->fill_color; - curenv->fill_color = c; -} - -environment::environment(symbol nm) -: dummy(0), - prev_line_length((units_per_inch*13)/2), - line_length((units_per_inch*13)/2), - prev_title_length((units_per_inch*13)/2), - title_length((units_per_inch*13)/2), - prev_size(sizescale*10), - size(sizescale*10), - requested_size(sizescale*10), - prev_requested_size(sizescale*10), - char_height(0), - char_slant(0), - space_size(12), - sentence_space_size(12), - adjust_mode(ADJUST_BOTH), - fill(1), - interrupted(0), - prev_line_interrupted(0), - center_lines(0), - right_justify_lines(0), - prev_vertical_spacing(points_to_units(12)), - vertical_spacing(points_to_units(12)), - prev_post_vertical_spacing(0), - post_vertical_spacing(0), - prev_line_spacing(1), - line_spacing(1), - prev_indent(0), - indent(0), - temporary_indent(0), - have_temporary_indent(0), - underline_lines(0), - underline_spaces(0), - input_trap_count(0), - continued_input_trap(0), - line(0), - prev_text_length(0), - width_total(0), - space_total(0), - input_line_start(0), - tabs(units_per_inch/2, TAB_LEFT), - line_tabs(0), - current_tab(TAB_NONE), - leader_node(0), - tab_char(0), - leader_char(charset_table['.']), - current_field(0), - discarding(0), - spread_flag(0), - margin_character_flags(0), - margin_character_node(0), - margin_character_distance(points_to_units(10)), - numbering_nodes(0), - number_text_separation(1), - line_number_indent(0), - line_number_multiple(1), - no_number_count(0), - hyphenation_flags(1), - hyphen_line_count(0), - hyphen_line_max(-1), - hyphenation_space(H0), - hyphenation_margin(H0), - composite(0), - pending_lines(0), -#ifdef WIDOW_CONTROL - widow_control(0), -#endif /* WIDOW_CONTROL */ - ignore_next_eol(0), - emitted_node(0), - glyph_color(&default_color), - prev_glyph_color(&default_color), - fill_color(&default_color), - prev_fill_color(&default_color), - name(nm), - control_char('.'), - no_break_control_char('\''), - hyphen_indicator_char(0) -{ - prev_family = family = lookup_family(default_family); - prev_fontno = fontno = 1; - if (!is_good_fontno(1)) - fatal("font number 1 not a valid font"); - if (family->make_definite(1) < 0) - fatal("invalid default family `%1'", default_family.contents()); - prev_fontno = fontno; -} - -environment::environment(const environment *e) -: dummy(1), - prev_line_length(e->prev_line_length), - line_length(e->line_length), - prev_title_length(e->prev_title_length), - title_length(e->title_length), - prev_size(e->prev_size), - size(e->size), - requested_size(e->requested_size), - prev_requested_size(e->prev_requested_size), - char_height(e->char_height), - char_slant(e->char_slant), - prev_fontno(e->prev_fontno), - fontno(e->fontno), - prev_family(e->prev_family), - family(e->family), - space_size(e->space_size), - sentence_space_size(e->sentence_space_size), - adjust_mode(e->adjust_mode), - fill(e->fill), - interrupted(0), - prev_line_interrupted(0), - center_lines(0), - right_justify_lines(0), - prev_vertical_spacing(e->prev_vertical_spacing), - vertical_spacing(e->vertical_spacing), - prev_post_vertical_spacing(e->prev_post_vertical_spacing), - post_vertical_spacing(e->post_vertical_spacing), - prev_line_spacing(e->prev_line_spacing), - line_spacing(e->line_spacing), - prev_indent(e->prev_indent), - indent(e->indent), - temporary_indent(0), - have_temporary_indent(0), - underline_lines(0), - underline_spaces(0), - input_trap_count(0), - continued_input_trap(0), - line(0), - prev_text_length(e->prev_text_length), - width_total(0), - space_total(0), - input_line_start(0), - tabs(e->tabs), - line_tabs(e->line_tabs), - current_tab(TAB_NONE), - leader_node(0), - tab_char(e->tab_char), - leader_char(e->leader_char), - current_field(0), - discarding(0), - spread_flag(0), - margin_character_flags(e->margin_character_flags), - margin_character_node(e->margin_character_node), - margin_character_distance(e->margin_character_distance), - numbering_nodes(0), - number_text_separation(e->number_text_separation), - line_number_indent(e->line_number_indent), - line_number_multiple(e->line_number_multiple), - no_number_count(e->no_number_count), - hyphenation_flags(e->hyphenation_flags), - hyphen_line_count(0), - hyphen_line_max(e->hyphen_line_max), - hyphenation_space(e->hyphenation_space), - hyphenation_margin(e->hyphenation_margin), - composite(0), - pending_lines(0), -#ifdef WIDOW_CONTROL - widow_control(e->widow_control), -#endif /* WIDOW_CONTROL */ - ignore_next_eol(0), - emitted_node(0), - glyph_color(e->glyph_color), - prev_glyph_color(e->prev_glyph_color), - fill_color(e->fill_color), - prev_fill_color(e->prev_fill_color), - name(e->name), // so that eg `.if "\n[.ev]"0"' works - control_char(e->control_char), - no_break_control_char(e->no_break_control_char), - hyphen_indicator_char(e->hyphen_indicator_char) -{ -} - -void environment::copy(const environment *e) -{ - prev_line_length = e->prev_line_length; - line_length = e->line_length; - prev_title_length = e->prev_title_length; - title_length = e->title_length; - prev_size = e->prev_size; - size = e->size; - prev_requested_size = e->prev_requested_size; - requested_size = e->requested_size; - char_height = e->char_height; - char_slant = e->char_slant; - space_size = e->space_size; - sentence_space_size = e->sentence_space_size; - adjust_mode = e->adjust_mode; - fill = e->fill; - interrupted = 0; - prev_line_interrupted = 0; - center_lines = 0; - right_justify_lines = 0; - prev_vertical_spacing = e->prev_vertical_spacing; - vertical_spacing = e->vertical_spacing; - prev_post_vertical_spacing = e->prev_post_vertical_spacing, - post_vertical_spacing = e->post_vertical_spacing, - prev_line_spacing = e->prev_line_spacing; - line_spacing = e->line_spacing; - prev_indent = e->prev_indent; - indent = e->indent; - have_temporary_indent = 0; - temporary_indent = 0; - underline_lines = 0; - underline_spaces = 0; - input_trap_count = 0; - continued_input_trap = 0; - prev_text_length = e->prev_text_length; - width_total = 0; - space_total = 0; - input_line_start = 0; - control_char = e->control_char; - no_break_control_char = e->no_break_control_char; - hyphen_indicator_char = e->hyphen_indicator_char; - spread_flag = 0; - line = 0; - pending_lines = 0; - discarding = 0; - tabs = e->tabs; - line_tabs = e->line_tabs; - current_tab = TAB_NONE; - current_field = 0; - margin_character_flags = e->margin_character_flags; - margin_character_node = e->margin_character_node; - margin_character_distance = e->margin_character_distance; - numbering_nodes = 0; - number_text_separation = e->number_text_separation; - line_number_multiple = e->line_number_multiple; - line_number_indent = e->line_number_indent; - no_number_count = e->no_number_count; - tab_char = e->tab_char; - leader_char = e->leader_char; - hyphenation_flags = e->hyphenation_flags; - fontno = e->fontno; - prev_fontno = e->prev_fontno; - dummy = e->dummy; - family = e->family; - prev_family = e->prev_family; - leader_node = 0; -#ifdef WIDOW_CONTROL - widow_control = e->widow_control; -#endif /* WIDOW_CONTROL */ - hyphen_line_max = e->hyphen_line_max; - hyphen_line_count = 0; - hyphenation_space = e->hyphenation_space; - hyphenation_margin = e->hyphenation_margin; - composite = 0; - ignore_next_eol = e->ignore_next_eol; - emitted_node = e->emitted_node; - glyph_color= e->glyph_color; - prev_glyph_color = e->prev_glyph_color; - fill_color = e->fill_color; - prev_fill_color = e->prev_fill_color; -} - -environment::~environment() -{ - delete leader_node; - delete_node_list(line); - delete_node_list(numbering_nodes); -} - -hunits environment::get_input_line_position() -{ - hunits n; - if (line == 0) - n = -input_line_start; - else - n = width_total - input_line_start; - if (current_tab) - n += tab_width; - return n; -} - -void environment::set_input_line_position(hunits n) -{ - input_line_start = line == 0 ? -n : width_total - n; - if (current_tab) - input_line_start += tab_width; -} - -hunits environment::get_line_length() -{ - return line_length; -} - -hunits environment::get_saved_line_length() -{ - if (line) - return target_text_length + saved_indent; - else - return line_length; -} - -vunits environment::get_vertical_spacing() -{ - return vertical_spacing; -} - -vunits environment::get_post_vertical_spacing() -{ - return post_vertical_spacing; -} - -int environment::get_line_spacing() -{ - return line_spacing; -} - -vunits environment::total_post_vertical_spacing() -{ - vunits tem(post_vertical_spacing); - if (line_spacing > 1) - tem += (line_spacing - 1)*vertical_spacing; - return tem; -} - -int environment::get_bold() -{ - return get_bold_fontno(fontno); -} - -hunits environment::get_digit_width() -{ - return env_digit_width(this); -} - -int environment::get_adjust_mode() -{ - return adjust_mode; -} - -int environment::get_fill() -{ - return fill; -} - -hunits environment::get_indent() -{ - return indent; -} - -hunits environment::get_saved_indent() -{ - if (line) - return saved_indent; - else if (have_temporary_indent) - return temporary_indent; - else - return indent; -} - -hunits environment::get_temporary_indent() -{ - return temporary_indent; -} - -hunits environment::get_title_length() -{ - return title_length; -} - -node *environment::get_prev_char() -{ - for (node *n = current_tab ? tab_contents : line; n; n = n->next) { - node *last = n->last_char_node(); - if (last) - return last; - } - return 0; -} - -hunits environment::get_prev_char_width() -{ - node *last = get_prev_char(); - if (!last) - return H0; - return last->width(); -} - -hunits environment::get_prev_char_skew() -{ - node *last = get_prev_char(); - if (!last) - return H0; - return last->skew(); -} - -vunits environment::get_prev_char_height() -{ - node *last = get_prev_char(); - if (!last) - return V0; - vunits min, max; - last->vertical_extent(&min, &max); - return -min; -} - -vunits environment::get_prev_char_depth() -{ - node *last = get_prev_char(); - if (!last) - return V0; - vunits min, max; - last->vertical_extent(&min, &max); - return max; -} - -hunits environment::get_text_length() -{ - hunits n = line == 0 ? H0 : width_total; - if (current_tab) - n += tab_width; - return n; -} - -hunits environment::get_prev_text_length() -{ - return prev_text_length; -} - - -static int sb_reg_contents = 0; -static int st_reg_contents = 0; -static int ct_reg_contents = 0; -static int rsb_reg_contents = 0; -static int rst_reg_contents = 0; -static int skw_reg_contents = 0; -static int ssc_reg_contents = 0; - -void environment::width_registers() -{ - // this is used to implement \w; it sets the st, sb, ct registers - vunits min = 0, max = 0, cur = 0; - int character_type = 0; - ssc_reg_contents = line ? line->subscript_correction().to_units() : 0; - skw_reg_contents = line ? line->skew().to_units() : 0; - line = reverse_node_list(line); - vunits real_min = V0; - vunits real_max = V0; - vunits v1, v2; - for (node *tem = line; tem; tem = tem->next) { - tem->vertical_extent(&v1, &v2); - v1 += cur; - if (v1 < real_min) - real_min = v1; - v2 += cur; - if (v2 > real_max) - real_max = v2; - if ((cur += tem->vertical_width()) < min) - min = cur; - else if (cur > max) - max = cur; - character_type |= tem->character_type(); - } - line = reverse_node_list(line); - st_reg_contents = -min.to_units(); - sb_reg_contents = -max.to_units(); - rst_reg_contents = -real_min.to_units(); - rsb_reg_contents = -real_max.to_units(); - ct_reg_contents = character_type; -} - -node *environment::extract_output_line() -{ - if (current_tab) - wrap_up_tab(); - node *n = line; - line = 0; - return n; -} - -/* environment related requests */ - -void environment_switch() -{ - int pop = 0; // 1 means pop, 2 means pop but no error message on underflow - if (curenv->is_dummy()) - error("can't switch environments when current environment is dummy"); - else if (!has_arg()) - pop = 1; - else { - symbol nm; - if (!tok.delimiter()) { - // It looks like a number. - int n; - if (get_integer(&n)) { - if (n >= 0 && n < NENVIRONMENTS) { - env_stack = new env_list(curenv, env_stack); - if (env_table[n] == 0) - env_table[n] = new environment(i_to_a(n)); - curenv = env_table[n]; - } - else - nm = i_to_a(n); - } - else - pop = 2; - } - else { - nm = get_long_name(1); - if (nm.is_null()) - pop = 2; - } - if (!nm.is_null()) { - environment *e = (environment *)env_dictionary.lookup(nm); - if (!e) { - e = new environment(nm); - (void)env_dictionary.lookup(nm, e); - } - env_stack = new env_list(curenv, env_stack); - curenv = e; - } - } - if (pop) { - if (env_stack == 0) { - if (pop == 1) - error("environment stack underflow"); - } - else { - curenv = env_stack->env; - env_list *tem = env_stack; - env_stack = env_stack->next; - delete tem; - } - } - skip_line(); -} - -void environment_copy() -{ - symbol nm; - environment *e=0; - tok.skip(); - if (!tok.delimiter()) { - // It looks like a number. - int n; - if (get_integer(&n)) { - if (n >= 0 && n < NENVIRONMENTS) - e = env_table[n]; - else - nm = i_to_a(n); - } - } - else - nm = get_long_name(1); - if (!e && !nm.is_null()) - e = (environment *)env_dictionary.lookup(nm); - if (e == 0) { - error("No environment to copy from"); - return; - } - else - curenv->copy(e); - skip_line(); -} - -static symbol P_symbol("P"); - -void font_change() -{ - symbol s = get_name(); - int is_number = 1; - if (s.is_null() || s == P_symbol) { - s = P_symbol; - is_number = 0; - } - else { - for (const char *p = s.contents(); p != 0 && *p != 0; p++) - if (!csdigit(*p)) { - is_number = 0; - break; - } - } - if (is_number) - curenv->set_font(atoi(s.contents())); - else - curenv->set_font(s); - skip_line(); -} - -void family_change() -{ - symbol s = get_name(); - curenv->set_family(s); - skip_line(); -} - -void point_size() -{ - int n; - if (has_arg() && get_number(&n, 'z', curenv->get_requested_point_size())) { - if (n <= 0) - n = 1; - curenv->set_size(n); - curenv->add_html_tag(1, ".ps", n); - } - else - curenv->set_size(0); - skip_line(); -} - -void override_sizes() -{ - int n = 16; - int *sizes = new int[n]; - int i = 0; - char *buf = read_string(); - if (!buf) - return; - char *p = strtok(buf, " \t"); - for (;;) { - if (!p) - break; - int lower, upper; - switch (sscanf(p, "%d-%d", &lower, &upper)) { - case 1: - upper = lower; - // fall through - case 2: - if (lower <= upper && lower >= 0) - break; - // fall through - default: - warning(WARN_RANGE, "bad size range `%1'", p); - return; - } - if (i + 2 > n) { - int *old_sizes = sizes; - sizes = new int[n*2]; - memcpy(sizes, old_sizes, n*sizeof(int)); - n *= 2; - a_delete old_sizes; - } - sizes[i++] = lower; - if (lower == 0) - break; - sizes[i++] = upper; - p = strtok(0, " \t"); - } - font_size::init_size_table(sizes); -} - -void space_size() -{ - int n; - if (get_integer(&n)) { - curenv->space_size = n; - if (has_arg() && get_integer(&n)) - curenv->sentence_space_size = n; - else - curenv->sentence_space_size = curenv->space_size; - } - skip_line(); -} - -void fill() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->fill = 1; - curenv->add_html_tag(1, ".fi"); - curenv->add_html_tag(0, ".br"); - tok.next(); -} - -void no_fill() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->fill = 0; - curenv->add_html_tag(1, ".nf"); - curenv->add_html_tag(0, ".br"); - curenv->add_html_tag(0, ".po", topdiv->get_page_offset().to_units()); - tok.next(); -} - -void center() -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - else if (n < 0) - n = 0; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->right_justify_lines = 0; - curenv->center_lines = n; - curenv->add_html_tag(1, ".ce", n); - tok.next(); -} - -void right_justify() -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - else if (n < 0) - n = 0; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->center_lines = 0; - curenv->right_justify_lines = n; - curenv->add_html_tag(1, ".rj", n); - tok.next(); -} - -void line_length() -{ - hunits temp; - if (has_arg() && get_hunits(&temp, 'm', curenv->line_length)) { - if (temp < H0) { - warning(WARN_RANGE, "bad line length %1u", temp.to_units()); - temp = H0; - } - } - else - temp = curenv->prev_line_length; - curenv->prev_line_length = curenv->line_length; - curenv->line_length = temp; - curenv->add_html_tag(1, ".ll", temp.to_units()); - skip_line(); -} - -void title_length() -{ - hunits temp; - if (has_arg() && get_hunits(&temp, 'm', curenv->title_length)) { - if (temp < H0) { - warning(WARN_RANGE, "bad title length %1u", temp.to_units()); - temp = H0; - } - } - else - temp = curenv->prev_title_length; - curenv->prev_title_length = curenv->title_length; - curenv->title_length = temp; - skip_line(); -} - -void vertical_spacing() -{ - vunits temp; - if (has_arg() && get_vunits(&temp, 'p', curenv->vertical_spacing)) { - if (temp <= V0) { - warning(WARN_RANGE, "vertical spacing must be greater than 0"); - temp = vresolution; - } - } - else - temp = curenv->prev_vertical_spacing; - curenv->prev_vertical_spacing = curenv->vertical_spacing; - curenv->vertical_spacing = temp; - skip_line(); -} - -void post_vertical_spacing() -{ - vunits temp; - if (has_arg() && get_vunits(&temp, 'p', curenv->post_vertical_spacing)) { - if (temp < V0) { - warning(WARN_RANGE, - "post vertical spacing must be greater than or equal to 0"); - temp = V0; - } - } - else - temp = curenv->prev_post_vertical_spacing; - curenv->prev_post_vertical_spacing = curenv->post_vertical_spacing; - curenv->post_vertical_spacing = temp; - skip_line(); -} - -void line_spacing() -{ - int temp; - if (has_arg() && get_integer(&temp)) { - if (temp < 1) { - warning(WARN_RANGE, "value %1 out of range: interpreted as 1", temp); - temp = 1; - } - } - else - temp = curenv->prev_line_spacing; - curenv->prev_line_spacing = curenv->line_spacing; - curenv->line_spacing = temp; - skip_line(); -} - -void indent() -{ - hunits temp; - if (has_arg() && get_hunits(&temp, 'm', curenv->indent)) { - if (temp < H0) { - warning(WARN_RANGE, "indent cannot be negative"); - temp = H0; - } - } - else - temp = curenv->prev_indent; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->have_temporary_indent = 0; - curenv->prev_indent = curenv->indent; - curenv->indent = temp; - if (break_flag) - curenv->add_html_tag(1, ".in", temp.to_units()); - tok.next(); -} - -void temporary_indent() -{ - int err = 0; - hunits temp; - if (!get_hunits(&temp, 'm', curenv->get_indent())) - err = 1; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (temp < H0) { - warning(WARN_RANGE, "total indent cannot be negative"); - temp = H0; - } - if (!err) { - curenv->temporary_indent = temp; - curenv->have_temporary_indent = 1; - curenv->add_html_tag(1, ".ti", temp.to_units()); - } - tok.next(); -} - -node *do_underline_special(int underline_spaces) -{ - macro m; - m.append_str("x u "); - m.append(underline_spaces + '0'); - return new special_node(m, 1); -} - -void do_underline(int underline_spaces) -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - if (n <= 0) { - if (curenv->underline_lines > 0) { - curenv->prev_fontno = curenv->fontno; - curenv->fontno = curenv->pre_underline_fontno; - if (underline_spaces) { - curenv->underline_spaces = 0; - curenv->add_node(do_underline_special(0)); - } - } - curenv->underline_lines = 0; - } - else { - curenv->underline_lines = n; - curenv->pre_underline_fontno = curenv->fontno; - curenv->fontno = get_underline_fontno(); - if (underline_spaces) { - curenv->underline_spaces = 1; - curenv->add_node(do_underline_special(1)); - } - } - skip_line(); -} - -void continuous_underline() -{ - do_underline(1); -} - -void underline() -{ - do_underline(0); -} - -void control_char() -{ - curenv->control_char = '.'; - if (has_arg()) { - if (tok.ch() == 0) - error("bad control character"); - else - curenv->control_char = tok.ch(); - } - skip_line(); -} - -void no_break_control_char() -{ - curenv->no_break_control_char = '\''; - if (has_arg()) { - if (tok.ch() == 0) - error("bad control character"); - else - curenv->no_break_control_char = tok.ch(); - } - skip_line(); -} - -void margin_character() -{ - while (tok.space()) - tok.next(); - charinfo *ci = tok.get_char(); - if (ci) { - // Call tok.next() only after making the node so that - // .mc \s+9\(br\s0 works. - node *nd = curenv->make_char_node(ci); - tok.next(); - if (nd) { - delete curenv->margin_character_node; - curenv->margin_character_node = nd; - curenv->margin_character_flags = (MARGIN_CHARACTER_ON - |MARGIN_CHARACTER_NEXT); - hunits d; - if (has_arg() && get_hunits(&d, 'm')) - curenv->margin_character_distance = d; - } - } - else { - check_missing_character(); - curenv->margin_character_flags &= ~MARGIN_CHARACTER_ON; - if (curenv->margin_character_flags == 0) { - delete curenv->margin_character_node; - curenv->margin_character_node = 0; - } - } - skip_line(); -} - -void number_lines() -{ - delete_node_list(curenv->numbering_nodes); - curenv->numbering_nodes = 0; - if (has_arg()) { - node *nd = 0; - for (int i = '9'; i >= '0'; i--) { - node *tem = make_node(charset_table[i], curenv); - if (!tem) { - skip_line(); - return; - } - tem->next = nd; - nd = tem; - } - curenv->numbering_nodes = nd; - curenv->line_number_digit_width = env_digit_width(curenv); - int n; - if (!tok.delimiter()) { - if (get_integer(&n, next_line_number)) { - next_line_number = n; - if (next_line_number < 0) { - warning(WARN_RANGE, "negative line number"); - next_line_number = 0; - } - } - } - else - while (!tok.space() && !tok.newline() && !tok.eof()) - tok.next(); - if (has_arg()) { - if (!tok.delimiter()) { - if (get_integer(&n)) { - if (n <= 0) { - warning(WARN_RANGE, "negative or zero line number multiple"); - } - else - curenv->line_number_multiple = n; - } - } - else - while (!tok.space() && !tok.newline() && !tok.eof()) - tok.next(); - if (has_arg()) { - if (!tok.delimiter()) { - if (get_integer(&n)) - curenv->number_text_separation = n; - } - else - while (!tok.space() && !tok.newline() && !tok.eof()) - tok.next(); - if (has_arg() && !tok.delimiter() && get_integer(&n)) - curenv->line_number_indent = n; - } - } - } - skip_line(); -} - -void no_number() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->no_number_count = n > 0 ? n : 0; - else - curenv->no_number_count = 1; - skip_line(); -} - -void no_hyphenate() -{ - curenv->hyphenation_flags = 0; - skip_line(); -} - -void hyphenate_request() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->hyphenation_flags = n; - else - curenv->hyphenation_flags = 1; - skip_line(); -} - -void hyphen_char() -{ - curenv->hyphen_indicator_char = get_optional_char(); - skip_line(); -} - -void hyphen_line_max_request() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->hyphen_line_max = n; - else - curenv->hyphen_line_max = -1; - skip_line(); -} - -void environment::interrupt() -{ - if (!dummy) { - add_node(new transparent_dummy_node); - interrupted = 1; - } -} - -void environment::newline() -{ - if (underline_lines > 0) { - if (--underline_lines == 0) { - prev_fontno = fontno; - fontno = pre_underline_fontno; - if (underline_spaces) { - underline_spaces = 0; - add_node(do_underline_special(0)); - } - } - } - if (current_field) - wrap_up_field(); - if (current_tab) - wrap_up_tab(); - // strip trailing spaces - while (line != 0 && line->discardable()) { - width_total -= line->width(); - space_total -= line->nspaces(); - node *tem = line; - line = line->next; - delete tem; - } - node *to_be_output = 0; - hunits to_be_output_width; - prev_line_interrupted = 0; - if (dummy) - space_newline(); - else if (interrupted) { - interrupted = 0; - // see environment::final_break - prev_line_interrupted = exit_started ? 2 : 1; - } - else if (center_lines > 0) { - --center_lines; - hunits x = target_text_length - width_total; - if (x > H0) - saved_indent += x/2; - to_be_output = line; - if (is_html) { - node *n = make_html_tag("eol.ce"); - n->next = to_be_output; - to_be_output = n; - } - to_be_output_width = width_total; - line = 0; - } - else if (right_justify_lines > 0) { - --right_justify_lines; - hunits x = target_text_length - width_total; - if (x > H0) - saved_indent += x; - to_be_output = line; - to_be_output_width = width_total; - line = 0; - } - else if (fill) - space_newline(); - else { - to_be_output = line; - to_be_output_width = width_total; - line = 0; - } - input_line_start = line == 0 ? H0 : width_total; - if (to_be_output) { - if (is_html && !fill) { - if (curdiv == topdiv) { - node *n = make_html_tag("eol"); - - n->next = to_be_output; - to_be_output = n; - } - } - output_line(to_be_output, to_be_output_width); - hyphen_line_count = 0; - } - if (input_trap_count > 0) { - if (!(continued_input_trap && prev_line_interrupted)) - if (--input_trap_count == 0) - spring_trap(input_trap); - } -} - -void environment::output_line(node *n, hunits width) -{ - prev_text_length = width; - if (margin_character_flags) { - hunits d = line_length + margin_character_distance - saved_indent - width; - if (d > 0) { - n = new hmotion_node(d, get_fill_color(), n); - width += d; - } - margin_character_flags &= ~MARGIN_CHARACTER_NEXT; - node *tem; - if (!margin_character_flags) { - tem = margin_character_node; - margin_character_node = 0; - } - else - tem = margin_character_node->copy(); - tem->next = n; - n = tem; - width += tem->width(); - } - node *nn = 0; - while (n != 0) { - node *tem = n->next; - n->next = nn; - nn = n; - n = tem; - } - if (!saved_indent.is_zero()) - nn = new hmotion_node(saved_indent, get_fill_color(), nn); - width += saved_indent; - if (no_number_count > 0) - --no_number_count; - else if (numbering_nodes) { - hunits w = (line_number_digit_width - *(3+line_number_indent+number_text_separation)); - if (next_line_number % line_number_multiple != 0) - nn = new hmotion_node(w, get_fill_color(), nn); - else { - hunits x = w; - nn = new hmotion_node(number_text_separation * line_number_digit_width, - get_fill_color(), nn); - x -= number_text_separation*line_number_digit_width; - char buf[30]; - sprintf(buf, "%3d", next_line_number); - for (char *p = strchr(buf, '\0') - 1; p >= buf && *p != ' '; --p) { - node *gn = numbering_nodes; - for (int count = *p - '0'; count > 0; count--) - gn = gn->next; - gn = gn->copy(); - x -= gn->width(); - gn->next = nn; - nn = gn; - } - nn = new hmotion_node(x, get_fill_color(), nn); - } - width += w; - ++next_line_number; - } - output(nn, !fill, vertical_spacing, total_post_vertical_spacing(), width); -} - -void environment::start_line() -{ - assert(line == 0); - discarding = 0; - line = new line_start_node; - if (have_temporary_indent) { - saved_indent = temporary_indent; - have_temporary_indent = 0; - } - else - saved_indent = indent; - target_text_length = line_length - saved_indent; - width_total = H0; - space_total = 0; -} - -hunits environment::get_hyphenation_space() -{ - return hyphenation_space; -} - -void hyphenation_space_request() -{ - hunits n; - if (get_hunits(&n, 'm')) { - if (n < H0) { - warning(WARN_RANGE, "hyphenation space cannot be negative"); - n = H0; - } - curenv->hyphenation_space = n; - } - skip_line(); -} - -hunits environment::get_hyphenation_margin() -{ - return hyphenation_margin; -} - -void hyphenation_margin_request() -{ - hunits n; - if (get_hunits(&n, 'm')) { - if (n < H0) { - warning(WARN_RANGE, "hyphenation margin cannot be negative"); - n = H0; - } - curenv->hyphenation_margin = n; - } - skip_line(); -} - -breakpoint *environment::choose_breakpoint() -{ - hunits x = width_total; - int s = space_total; - node *n = line; - breakpoint *best_bp = 0; // the best breakpoint so far - int best_bp_fits = 0; - while (n != 0) { - x -= n->width(); - s -= n->nspaces(); - breakpoint *bp = n->get_breakpoints(x, s); - while (bp != 0) { - if (bp->width <= target_text_length) { - if (!bp->hyphenated) { - breakpoint *tem = bp->next; - bp->next = 0; - while (tem != 0) { - breakpoint *tem1 = tem; - tem = tem->next; - delete tem1; - } - if (best_bp_fits - // Decide whether to use the hyphenated breakpoint. - && (hyphen_line_max < 0 - // Only choose the hyphenated breakpoint if it would not - // exceed the maximum number of consecutive hyphenated - // lines. - || hyphen_line_count + 1 <= hyphen_line_max) - && !(adjust_mode == ADJUST_BOTH - // Don't choose the hyphenated breakpoint if the line - // can be justified by adding no more than - // hyphenation_space to any word space. - ? (bp->nspaces > 0 - && (((target_text_length - bp->width - + (bp->nspaces - 1)*hresolution)/bp->nspaces) - <= hyphenation_space)) - // Don't choose the hyphenated breakpoint if the line - // is no more than hyphenation_margin short. - : target_text_length - bp->width <= hyphenation_margin)) { - delete bp; - return best_bp; - } - if (best_bp) - delete best_bp; - return bp; - } - else { - if ((adjust_mode == ADJUST_BOTH - ? hyphenation_space == H0 - : hyphenation_margin == H0) - && (hyphen_line_max < 0 - || hyphen_line_count + 1 <= hyphen_line_max)) { - // No need to consider a non-hyphenated breakpoint. - if (best_bp) - delete best_bp; - return bp; - } - // It fits but it's hyphenated. - if (!best_bp_fits) { - if (best_bp) - delete best_bp; - best_bp = bp; - bp = bp->next; - best_bp_fits = 1; - } - else { - breakpoint *tem = bp; - bp = bp->next; - delete tem; - } - } - } - else { - if (best_bp) - delete best_bp; - best_bp = bp; - bp = bp->next; - } - } - n = n->next; - } - if (best_bp) { - if (!best_bp_fits) - output_warning(WARN_BREAK, "can't break line"); - return best_bp; - } - return 0; -} - -void environment::hyphenate_line(int start_here) -{ - if (line == 0) - return; - hyphenation_type prev_type = line->get_hyphenation_type(); - node **startp; - if (start_here) - startp = &line; - else - for (startp = &line->next; *startp != 0; startp = &(*startp)->next) { - hyphenation_type this_type = (*startp)->get_hyphenation_type(); - if (prev_type == HYPHEN_BOUNDARY && this_type == HYPHEN_MIDDLE) - break; - prev_type = this_type; - } - if (*startp == 0) - return; - node *tem = *startp; - int i = 0; - do { - ++i; - tem = tem->next; - } while (tem != 0 && tem->get_hyphenation_type() == HYPHEN_MIDDLE); - int inhibit = (tem != 0 && tem->get_hyphenation_type() == HYPHEN_INHIBIT); - node *end = tem; - hyphen_list *sl = 0; - tem = *startp; - node *forward = 0; - while (tem != end) { - sl = tem->get_hyphen_list(sl); - node *tem1 = tem; - tem = tem->next; - tem1->next = forward; - forward = tem1; - } - if (!inhibit) { - // this is for characters like hyphen and emdash - int prev_code = 0; - for (hyphen_list *h = sl; h; h = h->next) { - h->breakable = (prev_code != 0 - && h->next != 0 - && h->next->hyphenation_code != 0); - prev_code = h->hyphenation_code; - } - } - if (hyphenation_flags != 0 - && !inhibit - // this may not be right if we have extra space on this line - && !((hyphenation_flags & HYPHEN_LAST_LINE) - && (curdiv->distance_to_next_trap() - <= vertical_spacing + total_post_vertical_spacing())) - && i >= 4) - hyphenate(sl, hyphenation_flags); - while (forward != 0) { - node *tem1 = forward; - forward = forward->next; - tem1->next = 0; - tem = tem1->add_self(tem, &sl); - } - *startp = tem; -} - -static node *node_list_reverse(node *n) -{ - node *res = 0; - while (n) { - node *tem = n; - n = n->next; - tem->next = res; - res = tem; - } - return res; -} - -static void distribute_space(node *n, int nspaces, hunits desired_space, - int force_reverse = 0) -{ - static int reverse = 0; - if (force_reverse || reverse) - n = node_list_reverse(n); - if (!force_reverse && nspaces > 0 && spread_limit >= 0 - && desired_space.to_units() > 0) { - hunits em = curenv->get_size(); - double Ems = (double)desired_space.to_units() / nspaces - / (em.is_zero() ? hresolution : em.to_units()); - if (Ems > spread_limit) - output_warning(WARN_BREAK, "spreading %1m per space", Ems); - } - for (node *tem = n; tem; tem = tem->next) - tem->spread_space(&nspaces, &desired_space); - if (force_reverse || reverse) - (void)node_list_reverse(n); - if (!force_reverse) - reverse = !reverse; - assert(desired_space.is_zero() && nspaces == 0); -} - -void environment::possibly_break_line(int start_here, int forced) -{ - if (!fill || current_tab || current_field || dummy) - return; - while (line != 0 - && (forced - // When a macro follows a paragraph in fill mode, the - // current line should not be empty. - || (width_total - line->width()) > target_text_length)) { - hyphenate_line(start_here); - breakpoint *bp = choose_breakpoint(); - if (bp == 0) - // we'll find one eventually - return; - node *pre, *post; - node **ndp = &line; - while (*ndp != bp->nd) - ndp = &(*ndp)->next; - bp->nd->split(bp->index, &pre, &post); - *ndp = post; - hunits extra_space_width = H0; - switch(adjust_mode) { - case ADJUST_BOTH: - if (bp->nspaces != 0) - extra_space_width = target_text_length - bp->width; - else if (bp->width > 0 && target_text_length > 0 - && target_text_length > bp->width) - output_warning(WARN_BREAK, "cannot adjust line"); - break; - case ADJUST_CENTER: - saved_indent += (target_text_length - bp->width)/2; - break; - case ADJUST_RIGHT: - saved_indent += target_text_length - bp->width; - break; - } - distribute_space(pre, bp->nspaces, extra_space_width); - hunits output_width = bp->width + extra_space_width; - input_line_start -= output_width; - if (bp->hyphenated) - hyphen_line_count++; - else - hyphen_line_count = 0; - delete bp; - space_total = 0; - width_total = 0; - node *first_non_discardable = 0; - node *tem; - for (tem = line; tem != 0; tem = tem->next) - if (!tem->discardable()) - first_non_discardable = tem; - node *to_be_discarded; - if (first_non_discardable) { - to_be_discarded = first_non_discardable->next; - first_non_discardable->next = 0; - for (tem = line; tem != 0; tem = tem->next) { - width_total += tem->width(); - space_total += tem->nspaces(); - } - discarding = 0; - } - else { - discarding = 1; - to_be_discarded = line; - line = 0; - } - // Do output_line() here so that line will be 0 iff the - // the environment will be empty. - output_line(pre, output_width); - while (to_be_discarded != 0) { - tem = to_be_discarded; - to_be_discarded = to_be_discarded->next; - input_line_start -= tem->width(); - delete tem; - } - if (line != 0) { - if (have_temporary_indent) { - saved_indent = temporary_indent; - have_temporary_indent = 0; - } - else - saved_indent = indent; - target_text_length = line_length - saved_indent; - } - } -} - -/* -Do the break at the end of input after the end macro (if any). - -Unix troff behaves as follows: if the last line is - -foo bar\c - -it will output foo on the current page, and bar on the next page; -if the last line is - -foo\c - -or - -foo bar - -everything will be output on the current page. This behaviour must be -considered a bug. - -The problem is that some macro packages rely on this. For example, -the ATK macros have an end macro that emits \c if it needs to print a -table of contents but doesn't do a 'bp in the end macro; instead the -'bp is done in the bottom of page trap. This works with Unix troff, -provided that the current environment is not empty at the end of the -input file. - -The following will make macro packages that do that sort of thing work -even if the current environment is empty at the end of the input file. -If the last input line used \c and this line occurred in the end macro, -then we'll force everything out on the current page, but we'll make -sure that the environment isn't empty so that we won't exit at the -bottom of this page. -*/ - -void environment::final_break() -{ - if (prev_line_interrupted == 2) { - do_break(); - add_node(new transparent_dummy_node); - } - else - do_break(); -} - -/* - * add_html_tag - emits a special html-tag: to help post-grohtml understand - * the key troff commands - */ - -void environment::add_html_tag(int force, const char *name) -{ - if (!force && (curdiv != topdiv)) - return; - - if (is_html) { - /* - * need to emit tag for post-grohtml - * but we check to see whether we can emit specials - */ - if (curdiv == topdiv && topdiv->before_first_page) - topdiv->begin_page(); - macro *m = new macro; - m->append_str("html-tag:"); - for (const char *p = name; *p; p++) - if (!invalid_input_char((unsigned char)*p)) - m->append(*p); - curdiv->output(new special_node(*m), 1, 0, 0, 0); - if (strcmp(name, ".nf") == 0) - curenv->ignore_next_eol = 1; - } -} - -/* - * add_html_tag - emits a special html-tag: to help post-grohtml understand - * the key troff commands, it appends a string representation - * of i. - */ - -void environment::add_html_tag(int force, const char *name, int i) -{ - if (!force && (curdiv != topdiv)) - return; - - if (is_html) { - /* - * need to emit tag for post-grohtml - * but we check to see whether we can emit specials - */ - if (curdiv == topdiv && topdiv->before_first_page) - topdiv->begin_page(); - macro *m = new macro; - m->append_str("html-tag:"); - for (const char *p = name; *p; p++) - if (!invalid_input_char((unsigned char)*p)) - m->append(*p); - m->append(' '); - m->append_int(i); - node *n = new special_node(*m); - curdiv->output(n, 1, 0, 0, 0); - } -} - -/* - * add_html_tag_tabs - emits the tab settings for post-grohtml - */ - -void environment::add_html_tag_tabs(int force) -{ - if (!force && (curdiv != topdiv)) - return; - - if (is_html) { - /* - * need to emit tag for post-grohtml - * but we check to see whether we can emit specials - */ - if (curdiv == topdiv && topdiv->before_first_page) - topdiv->begin_page(); - macro *m = new macro; - hunits d, l; - enum tab_type t; - m->append_str("html-tag:.ta "); - do { - t = curenv->tabs.distance_to_next_tab(l, &d); - l += d; - switch (t) { - case TAB_LEFT: - m->append_str(" L "); - m->append_int(l.to_units()); - break; - case TAB_CENTER: - m->append_str(" C "); - m->append_int(l.to_units()); - break; - case TAB_RIGHT: - m->append_str(" R "); - m->append_int(l.to_units()); - break; - case TAB_NONE: - break; - } - } while ((t != TAB_NONE) && (l < get_line_length())); - curdiv->output(new special_node(*m), 1, 0, 0, 0); - } -} - -node *environment::make_html_tag(const char *name, int i) -{ - if (is_html) { - /* - * need to emit tag for post-grohtml - * but we check to see whether we can emit specials - */ - if (curdiv == topdiv && topdiv->before_first_page) - topdiv->begin_page(); - macro *m = new macro; - m->append_str("html-tag:"); - for (const char *p = name; *p; p++) - if (!invalid_input_char((unsigned char)*p)) - m->append(*p); - m->append(' '); - m->append_int(i); - return new special_node(*m); - } - return 0; -} - -node *environment::make_html_tag(const char *name) -{ - if (is_html) { - /* - * need to emit tag for post-grohtml - * but we check to see whether we can emit specials - */ - if (curdiv == topdiv && topdiv->before_first_page) - topdiv->begin_page(); - macro *m = new macro; - m->append_str("html-tag:"); - for (const char *p = name; *p; p++) - if (!invalid_input_char((unsigned char)*p)) - m->append(*p); - return new special_node(*m); - } - return 0; -} - -void environment::do_break(int spread) -{ - if (curdiv == topdiv && topdiv->before_first_page) { - topdiv->begin_page(); - return; - } - if (current_tab) - wrap_up_tab(); - if (line) { - // this is so that hyphenation works - line = new space_node(H0, get_fill_color(), line); - space_total++; - possibly_break_line(0, spread); - } - while (line != 0 && line->discardable()) { - width_total -= line->width(); - space_total -= line->nspaces(); - node *tem = line; - line = line->next; - delete tem; - } - discarding = 0; - input_line_start = H0; - if (line != 0) { - if (fill) { - switch (adjust_mode) { - case ADJUST_CENTER: - saved_indent += (target_text_length - width_total)/2; - break; - case ADJUST_RIGHT: - saved_indent += target_text_length - width_total; - break; - } - } - node *tem = line; - line = 0; - output_line(tem, width_total); - hyphen_line_count = 0; - } - prev_line_interrupted = 0; -#ifdef WIDOW_CONTROL - mark_last_line(); - output_pending_lines(); -#endif /* WIDOW_CONTROL */ -} - -int environment::is_empty() -{ - return !current_tab && line == 0 && pending_lines == 0; -} - -void do_break_request(int spread) -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) { - curenv->do_break(spread); - curenv->add_html_tag(0, ".br"); - } - tok.next(); -} - -void break_request() -{ - do_break_request(0); -} - -void break_spread_request() -{ - do_break_request(1); -} - -void title() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_title(); - return; - } - node *part[3]; - hunits part_width[3]; - part[0] = part[1] = part[2] = 0; - environment env(curenv); - environment *oldenv = curenv; - curenv = &env; - read_title_parts(part, part_width); - curenv = oldenv; - curenv->size = env.size; - curenv->prev_size = env.prev_size; - curenv->requested_size = env.requested_size; - curenv->prev_requested_size = env.prev_requested_size; - curenv->char_height = env.char_height; - curenv->char_slant = env.char_slant; - curenv->fontno = env.fontno; - curenv->prev_fontno = env.prev_fontno; - curenv->glyph_color = env.glyph_color; - curenv->prev_glyph_color = env.prev_glyph_color; - curenv->fill_color = env.fill_color; - curenv->prev_fill_color = env.prev_fill_color; - node *n = 0; - node *p = part[2]; - while (p != 0) { - node *tem = p; - p = p->next; - tem->next = n; - n = tem; - } - hunits title_length(curenv->title_length); - hunits f = title_length - part_width[1]; - hunits f2 = f/2; - n = new hmotion_node(f2 - part_width[2], curenv->get_fill_color(), n); - p = part[1]; - while (p != 0) { - node *tem = p; - p = p->next; - tem->next = n; - n = tem; - } - n = new hmotion_node(f - f2 - part_width[0], curenv->get_fill_color(), n); - p = part[0]; - while (p != 0) { - node *tem = p; - p = p->next; - tem->next = n; - n = tem; - } - curenv->output_title(n, !curenv->fill, curenv->vertical_spacing, - curenv->total_post_vertical_spacing(), title_length); - curenv->hyphen_line_count = 0; - tok.next(); -} - -void adjust() -{ - curenv->adjust_mode |= 1; - if (has_arg()) { - switch (tok.ch()) { - case 'l': - curenv->adjust_mode = ADJUST_LEFT; - break; - case 'r': - curenv->adjust_mode = ADJUST_RIGHT; - break; - case 'c': - curenv->adjust_mode = ADJUST_CENTER; - break; - case 'b': - case 'n': - curenv->adjust_mode = ADJUST_BOTH; - break; - default: - int n; - if (get_integer(&n)) { - if (n < 0) - warning(WARN_RANGE, "negative adjustment mode"); - else if (n > 5) { - curenv->adjust_mode = 5; - warning(WARN_RANGE, "adjustment mode `%1' out of range", n); - } - else - curenv->adjust_mode = n; - } - } - } - skip_line(); -} - -void no_adjust() -{ - curenv->adjust_mode &= ~1; - skip_line(); -} - -void do_input_trap(int continued) -{ - curenv->input_trap_count = 0; - if (continued) - curenv->continued_input_trap = 1; - int n; - if (has_arg() && get_integer(&n)) { - if (n <= 0) - warning(WARN_RANGE, - "number of lines for input trap must be greater than zero"); - else { - symbol s = get_name(1); - if (!s.is_null()) { - curenv->input_trap_count = n; - curenv->input_trap = s; - } - } - } - skip_line(); -} - -void input_trap() -{ - do_input_trap(0); -} - -void input_trap_continued() -{ - do_input_trap(1); -} - -/* tabs */ - -// must not be R or C or L or a legitimate part of a number expression -const char TAB_REPEAT_CHAR = 'T'; - -struct tab { - tab *next; - hunits pos; - tab_type type; - tab(hunits, tab_type); - enum { BLOCK = 1024 }; - static tab *free_list; - void *operator new(size_t); - void operator delete(void *); -}; - -tab *tab::free_list = 0; - -void *tab::operator new(size_t n) -{ - assert(n == sizeof(tab)); - if (!free_list) { - free_list = (tab *)new char[sizeof(tab)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - tab *p = free_list; - free_list = (tab *)(free_list->next); - p->next = 0; - return p; -} - -#ifdef __GNUG__ -/* cfront can't cope with this. */ -inline -#endif -void tab::operator delete(void *p) -{ - if (p) { - ((tab *)p)->next = free_list; - free_list = (tab *)p; - } -} - -tab::tab(hunits x, tab_type t) : next(0), pos(x), type(t) -{ -} - -tab_stops::tab_stops(hunits distance, tab_type type) -: initial_list(0) -{ - repeated_list = new tab(distance, type); -} - -tab_stops::~tab_stops() -{ - clear(); -} - -tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance) -{ - hunits nextpos; - - return distance_to_next_tab(curpos, distance, &nextpos); -} - -tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance, - hunits *nextpos) -{ - hunits lastpos = 0; - tab *tem; - for (tem = initial_list; tem && tem->pos <= curpos; tem = tem->next) - lastpos = tem->pos; - if (tem) { - *distance = tem->pos - curpos; - *nextpos = tem->pos; - return tem->type; - } - if (repeated_list == 0) - return TAB_NONE; - hunits base = lastpos; - for (;;) { - for (tem = repeated_list; tem && tem->pos + base <= curpos; tem = tem->next) - lastpos = tem->pos; - if (tem) { - *distance = tem->pos + base - curpos; - *nextpos = tem->pos + base; - return tem->type; - } - assert(lastpos > 0); - base += lastpos; - } - return TAB_NONE; -} - -const char *tab_stops::to_string() -{ - static char *buf = 0; - static int buf_size = 0; - // figure out a maximum on the amount of space we can need - int count = 0; - tab *p; - for (p = initial_list; p; p = p->next) - ++count; - for (p = repeated_list; p; p = p->next) - ++count; - // (10 for digits + 1 for u + 1 for 'C' or 'R') + 2 for ' &' + 1 for '\0' - int need = count*12 + 3; - if (buf == 0 || need > buf_size) { - if (buf) - a_delete buf; - buf_size = need; - buf = new char[buf_size]; - } - char *ptr = buf; - for (p = initial_list; p; p = p->next) { - strcpy(ptr, i_to_a(p->pos.to_units())); - ptr = strchr(ptr, '\0'); - *ptr++ = 'u'; - *ptr = '\0'; - switch (p->type) { - case TAB_LEFT: - break; - case TAB_RIGHT: - *ptr++ = 'R'; - break; - case TAB_CENTER: - *ptr++ = 'C'; - break; - case TAB_NONE: - default: - assert(0); - } - } - if (repeated_list) - *ptr++ = TAB_REPEAT_CHAR; - for (p = repeated_list; p; p = p->next) { - strcpy(ptr, i_to_a(p->pos.to_units())); - ptr = strchr(ptr, '\0'); - *ptr++ = 'u'; - *ptr = '\0'; - switch (p->type) { - case TAB_LEFT: - break; - case TAB_RIGHT: - *ptr++ = 'R'; - break; - case TAB_CENTER: - *ptr++ = 'C'; - break; - case TAB_NONE: - default: - assert(0); - } - } - *ptr++ = '\0'; - return buf; -} - -tab_stops::tab_stops() : initial_list(0), repeated_list(0) -{ -} - -tab_stops::tab_stops(const tab_stops &ts) -: initial_list(0), repeated_list(0) -{ - tab **p = &initial_list; - tab *t = ts.initial_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } - p = &repeated_list; - t = ts.repeated_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } -} - -void tab_stops::clear() -{ - while (initial_list) { - tab *tem = initial_list; - initial_list = initial_list->next; - delete tem; - } - while (repeated_list) { - tab *tem = repeated_list; - repeated_list = repeated_list->next; - delete tem; - } -} - -void tab_stops::add_tab(hunits pos, tab_type type, int repeated) -{ - tab **p; - for (p = repeated ? &repeated_list : &initial_list; *p; p = &(*p)->next) - ; - *p = new tab(pos, type); -} - - -void tab_stops::operator=(const tab_stops &ts) -{ - clear(); - tab **p = &initial_list; - tab *t = ts.initial_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } - p = &repeated_list; - t = ts.repeated_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } -} - -void set_tabs() -{ - hunits pos; - hunits prev_pos = 0; - int first = 1; - int repeated = 0; - tab_stops tabs; - while (has_arg()) { - if (tok.ch() == TAB_REPEAT_CHAR) { - tok.next(); - repeated = 1; - prev_pos = 0; - } - if (!get_hunits(&pos, 'm', prev_pos)) - break; - tab_type type = TAB_LEFT; - if (tok.ch() == 'C') { - tok.next(); - type = TAB_CENTER; - } - else if (tok.ch() == 'R') { - tok.next(); - type = TAB_RIGHT; - } - else if (tok.ch() == 'L') { - tok.next(); - } - if (pos <= prev_pos && !first) - warning(WARN_RANGE, - "positions of tab stops must be strictly increasing"); - else { - tabs.add_tab(pos, type, repeated); - prev_pos = pos; - first = 0; - } - } - curenv->tabs = tabs; - curenv->add_html_tag_tabs(1); - skip_line(); -} - -const char *environment::get_tabs() -{ - return tabs.to_string(); -} - -#if 0 -tab_stops saved_tabs; - -void tabs_save() -{ - saved_tabs = curenv->tabs; - skip_line(); -} - -void tabs_restore() -{ - curenv->tabs = saved_tabs; - skip_line(); -} -#endif - -tab_type environment::distance_to_next_tab(hunits *distance) -{ - return line_tabs - ? curenv->tabs.distance_to_next_tab(get_text_length(), distance) - : curenv->tabs.distance_to_next_tab(get_input_line_position(), distance); -} - -tab_type environment::distance_to_next_tab(hunits *distance, hunits *leftpos) -{ - return line_tabs - ? curenv->tabs.distance_to_next_tab(get_text_length(), distance, leftpos) - : curenv->tabs.distance_to_next_tab(get_input_line_position(), distance, - leftpos); -} - -void field_characters() -{ - field_delimiter_char = get_optional_char(); - if (field_delimiter_char) - padding_indicator_char = get_optional_char(); - else - padding_indicator_char = 0; - skip_line(); -} - -void line_tabs_request() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->line_tabs = n != 0; - else - curenv->line_tabs = 1; - skip_line(); -} - -int environment::get_line_tabs() -{ - return line_tabs; -} - -void environment::wrap_up_tab() -{ - if (!current_tab) - return; - if (line == 0) - start_line(); - hunits tab_amount; - switch (current_tab) { - case TAB_RIGHT: - tab_amount = tab_distance - tab_width; - line = make_tab_node(tab_amount, line); - break; - case TAB_CENTER: - tab_amount = tab_distance - tab_width/2; - line = make_tab_node(tab_amount, line); - break; - case TAB_NONE: - case TAB_LEFT: - default: - assert(0); - } - width_total += tab_amount; - width_total += tab_width; - if (current_field) { - if (tab_precedes_field) { - pre_field_width += tab_amount; - tab_precedes_field = 0; - } - field_distance -= tab_amount; - field_spaces += tab_field_spaces; - } - if (tab_contents != 0) { - node *tem; - for (tem = tab_contents; tem->next != 0; tem = tem->next) - ; - tem->next = line; - line = tab_contents; - } - tab_field_spaces = 0; - tab_contents = 0; - tab_width = H0; - tab_distance = H0; - current_tab = TAB_NONE; -} - -node *environment::make_tab_node(hunits d, node *next) -{ - if (leader_node != 0 && d < 0) { - error("motion generated by leader cannot be negative"); - delete leader_node; - leader_node = 0; - } - if (!leader_node) - return new hmotion_node(d, 1, 0, get_fill_color(), next); - node *n = new hline_node(d, leader_node, next); - leader_node = 0; - return n; -} - -void environment::handle_tab(int is_leader) -{ - hunits d; - hunits abs; - if (current_tab) - wrap_up_tab(); - charinfo *ci = is_leader ? leader_char : tab_char; - delete leader_node; - leader_node = ci ? make_char_node(ci) : 0; - tab_type t = distance_to_next_tab(&d, &abs); - switch (t) { - case TAB_NONE: - return; - case TAB_LEFT: - add_node(make_tab_node(d)); - add_node(make_html_tag("tab L", abs.to_units())); - return; - case TAB_RIGHT: - add_node(make_html_tag("tab R", abs.to_units())); - break; - case TAB_CENTER: - add_node(make_html_tag("tab C", abs.to_units())); - break; - default: - assert(0); - } - tab_width = 0; - tab_distance = d; - tab_contents = 0; - current_tab = t; - tab_field_spaces = 0; -} - -void environment::start_field() -{ - assert(!current_field); - hunits d; - if (distance_to_next_tab(&d) != TAB_NONE) { - pre_field_width = get_text_length(); - field_distance = d; - current_field = 1; - field_spaces = 0; - tab_field_spaces = 0; - for (node *p = line; p; p = p->next) - if (p->nspaces()) { - p->freeze_space(); - space_total--; - } - tab_precedes_field = current_tab != TAB_NONE; - } - else - error("zero field width"); -} - -void environment::wrap_up_field() -{ - if (!current_tab && field_spaces == 0) - add_padding(); - hunits padding = field_distance - (get_text_length() - pre_field_width); - if (current_tab && tab_field_spaces != 0) { - hunits tab_padding = scale(padding, - tab_field_spaces, - field_spaces + tab_field_spaces); - padding -= tab_padding; - distribute_space(tab_contents, tab_field_spaces, tab_padding, 1); - tab_field_spaces = 0; - tab_width += tab_padding; - } - if (field_spaces != 0) { - distribute_space(line, field_spaces, padding, 1); - width_total += padding; - if (current_tab) { - // the start of the tab has been moved to the right by padding, so - tab_distance -= padding; - if (tab_distance <= H0) { - // use the next tab stop instead - current_tab = tabs.distance_to_next_tab(get_input_line_position() - - tab_width, - &tab_distance); - if (current_tab == TAB_NONE || current_tab == TAB_LEFT) { - width_total += tab_width; - if (current_tab == TAB_LEFT) { - line = make_tab_node(tab_distance, line); - width_total += tab_distance; - current_tab = TAB_NONE; - } - if (tab_contents != 0) { - node *tem; - for (tem = tab_contents; tem->next != 0; tem = tem->next) - ; - tem->next = line; - line = tab_contents; - tab_contents = 0; - } - tab_width = H0; - tab_distance = H0; - } - } - } - } - current_field = 0; -} - -void environment::add_padding() -{ - if (current_tab) { - tab_contents = new space_node(H0, get_fill_color(), tab_contents); - tab_field_spaces++; - } - else { - if (line == 0) - start_line(); - line = new space_node(H0, get_fill_color(), line); - field_spaces++; - } -} - -typedef int (environment::*INT_FUNCP)(); -typedef vunits (environment::*VUNITS_FUNCP)(); -typedef hunits (environment::*HUNITS_FUNCP)(); -typedef const char *(environment::*STRING_FUNCP)(); - -class int_env_reg : public reg { - INT_FUNCP func; - public: - int_env_reg(INT_FUNCP); - const char *get_string(); - int get_value(units *val); -}; - -class vunits_env_reg : public reg { - VUNITS_FUNCP func; - public: - vunits_env_reg(VUNITS_FUNCP f); - const char *get_string(); - int get_value(units *val); -}; - - -class hunits_env_reg : public reg { - HUNITS_FUNCP func; - public: - hunits_env_reg(HUNITS_FUNCP f); - const char *get_string(); - int get_value(units *val); -}; - -class string_env_reg : public reg { - STRING_FUNCP func; -public: - string_env_reg(STRING_FUNCP); - const char *get_string(); -}; - -int_env_reg::int_env_reg(INT_FUNCP f) : func(f) -{ -} - -int int_env_reg::get_value(units *val) -{ - *val = (curenv->*func)(); - return 1; -} - -const char *int_env_reg::get_string() -{ - return i_to_a((curenv->*func)()); -} - -vunits_env_reg::vunits_env_reg(VUNITS_FUNCP f) : func(f) -{ -} - -int vunits_env_reg::get_value(units *val) -{ - *val = (curenv->*func)().to_units(); - return 1; -} - -const char *vunits_env_reg::get_string() -{ - return i_to_a((curenv->*func)().to_units()); -} - -hunits_env_reg::hunits_env_reg(HUNITS_FUNCP f) : func(f) -{ -} - -int hunits_env_reg::get_value(units *val) -{ - *val = (curenv->*func)().to_units(); - return 1; -} - -const char *hunits_env_reg::get_string() -{ - return i_to_a((curenv->*func)().to_units()); -} - -string_env_reg::string_env_reg(STRING_FUNCP f) : func(f) -{ -} - -const char *string_env_reg::get_string() -{ - return (curenv->*func)(); -} - -class horizontal_place_reg : public general_reg { -public: - horizontal_place_reg(); - int get_value(units *); - void set_value(units); -}; - -horizontal_place_reg::horizontal_place_reg() -{ -} - -int horizontal_place_reg::get_value(units *res) -{ - *res = curenv->get_input_line_position().to_units(); - return 1; -} - -void horizontal_place_reg::set_value(units n) -{ - curenv->set_input_line_position(hunits(n)); -} - -const char *environment::get_font_family_string() -{ - return family->nm.contents(); -} - -const char *environment::get_font_name_string() -{ - symbol f = get_font_name(fontno, this); - return f.contents(); -} - -const char *environment::get_name_string() -{ - return name.contents(); -} - -// Convert a quantity in scaled points to ascii decimal fraction. - -const char *sptoa(int sp) -{ - assert(sp > 0); - assert(sizescale > 0); - if (sizescale == 1) - return i_to_a(sp); - if (sp % sizescale == 0) - return i_to_a(sp/sizescale); - // See if 1/sizescale is exactly representable as a decimal fraction, - // ie its only prime factors are 2 and 5. - int n = sizescale; - int power2 = 0; - while ((n & 1) == 0) { - n >>= 1; - power2++; - } - int power5 = 0; - while ((n % 5) == 0) { - n /= 5; - power5++; - } - if (n == 1) { - int decimal_point = power5 > power2 ? power5 : power2; - if (decimal_point <= 10) { - int factor = 1; - int t; - for (t = decimal_point - power2; --t >= 0;) - factor *= 2; - for (t = decimal_point - power5; --t >= 0;) - factor *= 5; - if (factor == 1 || sp <= INT_MAX/factor) - return if_to_a(sp*factor, decimal_point); - } - } - double s = double(sp)/double(sizescale); - double factor = 10.0; - double val = s; - int decimal_point = 0; - do { - double v = ceil(s*factor); - if (v > INT_MAX) - break; - val = v; - factor *= 10.0; - } while (++decimal_point < 10); - return if_to_a(int(val), decimal_point); -} - -const char *environment::get_point_size_string() -{ - return sptoa(curenv->get_point_size()); -} - -const char *environment::get_requested_point_size_string() -{ - return sptoa(curenv->get_requested_point_size()); -} - -#define init_int_env_reg(name, func) \ - number_reg_dictionary.define(name, new int_env_reg(&environment::func)) - -#define init_vunits_env_reg(name, func) \ - number_reg_dictionary.define(name, new vunits_env_reg(&environment::func)) - -#define init_hunits_env_reg(name, func) \ - number_reg_dictionary.define(name, new hunits_env_reg(&environment::func)) - -#define init_string_env_reg(name, func) \ - number_reg_dictionary.define(name, new string_env_reg(&environment::func)) - -void init_env_requests() -{ - init_request("it", input_trap); - init_request("itc", input_trap_continued); - init_request("ad", adjust); - init_request("na", no_adjust); - init_request("ev", environment_switch); - init_request("evc", environment_copy); - init_request("lt", title_length); - init_request("ps", point_size); - init_request("sizes", override_sizes); - init_request("ft", font_change); - init_request("fam", family_change); - init_request("ss", space_size); - init_request("fi", fill); - init_request("nf", no_fill); - init_request("ce", center); - init_request("rj", right_justify); - init_request("vs", vertical_spacing); - init_request("ls", line_spacing); - init_request("ll", line_length); - init_request("in", indent); - init_request("ti", temporary_indent); - init_request("ul", underline); - init_request("cu", continuous_underline); - init_request("cc", control_char); - init_request("c2", no_break_control_char); - init_request("br", break_request); - init_request("brp", break_spread_request); - init_request("tl", title); - init_request("ta", set_tabs); - init_request("linetabs", line_tabs_request); - init_request("fc", field_characters); - init_request("mc", margin_character); - init_request("nn", no_number); - init_request("nm", number_lines); - init_request("tc", tab_character); - init_request("lc", leader_character); - init_request("hy", hyphenate_request); - init_request("hc", hyphen_char); - init_request("nh", no_hyphenate); - init_request("hlm", hyphen_line_max_request); -#ifdef WIDOW_CONTROL - init_request("wdc", widow_control_request); -#endif /* WIDOW_CONTROL */ -#if 0 - init_request("tas", tabs_save); - init_request("tar", tabs_restore); -#endif - init_request("hys", hyphenation_space_request); - init_request("hym", hyphenation_margin_request); - init_request("pvs", post_vertical_spacing); - init_int_env_reg(".f", get_font); - init_int_env_reg(".b", get_bold); - init_hunits_env_reg(".i", get_indent); - init_hunits_env_reg(".in", get_saved_indent); - init_int_env_reg(".int", get_prev_line_interrupted); - init_int_env_reg(".j", get_adjust_mode); - init_hunits_env_reg(".k", get_text_length); - init_hunits_env_reg(".l", get_line_length); - init_hunits_env_reg(".ll", get_saved_line_length); - init_int_env_reg(".L", get_line_spacing); - init_hunits_env_reg(".n", get_prev_text_length); - init_string_env_reg(".s", get_point_size_string); - init_string_env_reg(".sr", get_requested_point_size_string); - init_int_env_reg(".ps", get_point_size); - init_int_env_reg(".psr", get_requested_point_size); - init_int_env_reg(".u", get_fill); - init_vunits_env_reg(".v", get_vertical_spacing); - init_vunits_env_reg(".pvs", get_post_vertical_spacing); - init_hunits_env_reg(".w", get_prev_char_width); - init_int_env_reg(".ss", get_space_size); - init_int_env_reg(".sss", get_sentence_space_size); - init_string_env_reg(".fam", get_font_family_string); - init_string_env_reg(".fn", get_font_name_string); - init_string_env_reg(".ev", get_name_string); - init_int_env_reg(".hy", get_hyphenation_flags); - init_int_env_reg(".hlm", get_hyphen_line_max); - init_int_env_reg(".hlc", get_hyphen_line_count); - init_hunits_env_reg(".lt", get_title_length); - init_string_env_reg(".tabs", get_tabs); - init_int_env_reg(".linetabs", get_line_tabs); - init_hunits_env_reg(".csk", get_prev_char_skew); - init_vunits_env_reg(".cht", get_prev_char_height); - init_vunits_env_reg(".cdp", get_prev_char_depth); - init_int_env_reg(".ce", get_center_lines); - init_int_env_reg(".rj", get_right_justify_lines); - init_hunits_env_reg(".hys", get_hyphenation_space); - init_hunits_env_reg(".hym", get_hyphenation_margin); - number_reg_dictionary.define("ln", new variable_reg(&next_line_number)); - number_reg_dictionary.define("ct", new variable_reg(&ct_reg_contents)); - number_reg_dictionary.define("sb", new variable_reg(&sb_reg_contents)); - number_reg_dictionary.define("st", new variable_reg(&st_reg_contents)); - number_reg_dictionary.define("rsb", new variable_reg(&rsb_reg_contents)); - number_reg_dictionary.define("rst", new variable_reg(&rst_reg_contents)); - number_reg_dictionary.define("ssc", new variable_reg(&ssc_reg_contents)); - number_reg_dictionary.define("skw", new variable_reg(&skw_reg_contents)); - number_reg_dictionary.define("hp", new horizontal_place_reg); -} - -// Hyphenation - TeX's hyphenation algorithm with a less fancy implementation. - -struct trie_node; - -class trie { - trie_node *tp; - virtual void do_match(int len, void *val) = 0; - virtual void do_delete(void *) = 0; - void delete_trie_node(trie_node *); -public: - trie() : tp(0) {} - virtual ~trie(); // virtual to shut up g++ - void insert(const char *, int, void *); - // find calls do_match for each match it finds - void find(const char *pat, int patlen); - void clear(); -}; - -class hyphen_trie : private trie { - int *h; - void do_match(int i, void *v); - void do_delete(void *v); - void insert_pattern(const char *pat, int patlen, int *num); - void insert_hyphenation(dictionary ex, const char *pat, int patlen); - int hpf_getc(FILE *f); -public: - hyphen_trie() {} - ~hyphen_trie() {} - void hyphenate(const char *word, int len, int *hyphens); - void read_patterns_file(const char *name, int append, dictionary ex); -}; - -struct hyphenation_language { - symbol name; - dictionary exceptions; - hyphen_trie patterns; - hyphenation_language(symbol nm) : name(nm), exceptions(501) {} - ~hyphenation_language() { } -}; - -dictionary language_dictionary(5); -hyphenation_language *current_language = 0; - -static void set_hyphenation_language() -{ - symbol nm = get_name(1); - if (!nm.is_null()) { - current_language = (hyphenation_language *)language_dictionary.lookup(nm); - if (!current_language) { - current_language = new hyphenation_language(nm); - (void)language_dictionary.lookup(nm, (void *)current_language); - } - } - skip_line(); -} - -const int WORD_MAX = 256; // we use unsigned char for offsets in - // hyphenation exceptions - -static void hyphen_word() -{ - if (!current_language) { - error("no current hyphenation language"); - skip_line(); - return; - } - char buf[WORD_MAX + 1]; - unsigned char pos[WORD_MAX + 2]; - for (;;) { - tok.skip(); - if (tok.newline() || tok.eof()) - break; - int i = 0; - int npos = 0; - while (i < WORD_MAX && !tok.space() && !tok.newline() && !tok.eof()) { - charinfo *ci = tok.get_char(1); - if (ci == 0) { - skip_line(); - return; - } - tok.next(); - if (ci->get_ascii_code() == '-') { - if (i > 0 && (npos == 0 || pos[npos - 1] != i)) - pos[npos++] = i; - } - else { - int c = ci->get_hyphenation_code(); - if (c == 0) - break; - buf[i++] = c; - } - } - if (i > 0) { - pos[npos] = 0; - buf[i] = 0; - unsigned char *tem = new unsigned char[npos + 1]; - memcpy(tem, pos, npos + 1); - tem = (unsigned char *)current_language->exceptions.lookup(symbol(buf), - tem); - if (tem) - a_delete tem; - } - } - skip_line(); -} - -struct trie_node { - char c; - trie_node *down; - trie_node *right; - void *val; - trie_node(char, trie_node *); -}; - -trie_node::trie_node(char ch, trie_node *p) -: c(ch), down(0), right(p), val(0) -{ -} - -trie::~trie() -{ - clear(); -} - -void trie::clear() -{ - delete_trie_node(tp); - tp = 0; -} - - -void trie::delete_trie_node(trie_node *p) -{ - if (p) { - delete_trie_node(p->down); - delete_trie_node(p->right); - if (p->val) - do_delete(p->val); - delete p; - } -} - -void trie::insert(const char *pat, int patlen, void *val) -{ - trie_node **p = &tp; - assert(patlen > 0 && pat != 0); - for (;;) { - while (*p != 0 && (*p)->c < pat[0]) - p = &((*p)->right); - if (*p == 0 || (*p)->c != pat[0]) - *p = new trie_node(pat[0], *p); - if (--patlen == 0) { - (*p)->val = val; - break; - } - ++pat; - p = &((*p)->down); - } -} - -void trie::find(const char *pat, int patlen) -{ - trie_node *p = tp; - for (int i = 0; p != 0 && i < patlen; i++) { - while (p != 0 && p->c < pat[i]) - p = p->right; - if (p != 0 && p->c == pat[i]) { - if (p->val != 0) - do_match(i+1, p->val); - p = p->down; - } - else - break; - } -} - -struct operation { - operation *next; - short distance; - short num; - operation(int, int, operation *); -}; - -operation::operation(int i, int j, operation *op) -: next(op), distance(j), num(i) -{ -} - -void hyphen_trie::insert_pattern(const char *pat, int patlen, int *num) -{ - operation *op = 0; - for (int i = 0; i < patlen+1; i++) - if (num[i] != 0) - op = new operation(num[i], patlen - i, op); - insert(pat, patlen, op); -} - -void hyphen_trie::insert_hyphenation(dictionary ex, const char *pat, - int patlen) -{ - char buf[WORD_MAX + 1]; - unsigned char pos[WORD_MAX + 2]; - int i = 0, j = 0; - int npos = 0; - while (j < patlen) { - unsigned char c = pat[j++]; - if (c == '-') { - if (i > 0 && (npos == 0 || pos[npos - 1] != i)) - pos[npos++] = i; - } - else - buf[i++] = hpf_code_table[c]; - } - if (i > 0) { - pos[npos] = 0; - buf[i] = 0; - unsigned char *tem = new unsigned char[npos + 1]; - memcpy(tem, pos, npos + 1); - tem = (unsigned char *)ex.lookup(symbol(buf), tem); - if (tem) - a_delete tem; - } -} - -void hyphen_trie::hyphenate(const char *word, int len, int *hyphens) -{ - int j; - for (j = 0; j < len + 1; j++) - hyphens[j] = 0; - for (j = 0; j < len - 1; j++) { - h = hyphens + j; - find(word + j, len - j); - } -} - -inline int max(int m, int n) -{ - return m > n ? m : n; -} - -void hyphen_trie::do_match(int i, void *v) -{ - operation *op = (operation *)v; - while (op != 0) { - h[i - op->distance] = max(h[i - op->distance], op->num); - op = op->next; - } -} - -void hyphen_trie::do_delete(void *v) -{ - operation *op = (operation *)v; - while (op) { - operation *tem = op; - op = tem->next; - delete tem; - } -} - -/* We use very simple rules to parse TeX's hyphenation patterns. - - . `%' starts a comment even if preceded by `\'. - - . No support for digraphs and like `\$'. - - . `^^xx' (`x' is 0-9 or a-f), and `^^x' (character code of `x' in the - range 0-127) are recognized; other use of `^' causes an error. - - . No macro expansion. - - . We check for the expression `\patterns{...}' (possibly with - whitespace before and after the braces). Everything between the - braces is taken as hyphenation patterns. Consequently, `{' and `}' - are not allowed in patterns. - - . Similarly, `\hyphenation{...}' gives a list of hyphenation - exceptions. - - . `\endinput' is recognized also. - - . For backwards compatibility, if `\patterns' is missing, the - whole file is treated as a list of hyphenation patterns (only - recognizing `%' as the start of a comment. - -*/ - -int hyphen_trie::hpf_getc(FILE *f) -{ - int c = getc(f); - int c1; - int cc = 0; - if (c != '^') - return c; - c = getc(f); - if (c != '^') - goto fail; - c = getc(f); - c1 = getc(f); - if (((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) - && ((c1 >= '0' && c1 <= '9') || (c1 >= 'a' && c1 <= 'f'))) { - if (c >= '0' && c <= '9') - c -= '0'; - else - c = c - 'a' + 10; - if (c1 >= '0' && c1 <= '9') - c1 -= '0'; - else - c1 = c1 - 'a' + 10; - cc = c * 16 + c1; - } - else { - ungetc(c1, f); - if (c >= 0 && c <= 63) - cc = c + 64; - else if (c >= 64 && c <= 127) - cc = c - 64; - else - goto fail; - } - return cc; -fail: - error("invalid ^, ^^x, or ^^xx character in hyphenation patterns file"); - return c; -} - -void hyphen_trie::read_patterns_file(const char *name, int append, - dictionary ex) -{ - if (!append) - clear(); - char buf[WORD_MAX]; - int num[WORD_MAX+1]; - errno = 0; - char *path = 0; - FILE *fp = mac_path->open_file(name, &path); - if (fp == 0) { - error("can't find hyphenation patterns file `%1'", name); - return; - } - int c = hpf_getc(fp); - int have_patterns = 0; // we've seen \patterns - int final_pattern = 0; // 1 if we have a trailing closing brace - int have_hyphenation = 0; // we've seen \hyphenation - int final_hyphenation = 0; // 1 if we have a trailing closing brace - int have_keyword = 0; // we've seen either \patterns or \hyphenation - int traditional = 0; // don't handle \patterns - for (;;) { - for (;;) { - if (c == '%') { // skip comments - do { - c = getc(fp); - } while (c != EOF && c != '\n'); - } - if (c == EOF || !csspace(c)) - break; - c = hpf_getc(fp); - } - if (c == EOF) { - if (have_keyword || traditional) // we are done - break; - else { // rescan file in `traditional' mode - rewind(fp); - traditional = 1; - c = hpf_getc(fp); - continue; - } - } - int i = 0; - num[0] = 0; - if (!(c == '{' || c == '}')) { // skip braces at line start - do { // scan patterns - if (csdigit(c)) - num[i] = c - '0'; - else { - buf[i++] = c; - num[i] = 0; - } - c = hpf_getc(fp); - } while (i < WORD_MAX && c != EOF && !csspace(c) - && c != '%' && c != '{' && c != '}'); - } - if (!traditional) { - if (i >= 9 && !strncmp(buf + i - 9, "\\patterns", 9)) { - while (csspace(c)) - c = hpf_getc(fp); - if (c == '{') { - if (have_patterns || have_hyphenation) - error("`{' not allowed inside of \\patterns or \\hyphenation"); - else { - have_patterns = 1; - have_keyword = 1; - } - c = hpf_getc(fp); - continue; - } - } - else if (i >= 12 && !strncmp(buf + i - 12, "\\hyphenation", 12)) { - while (csspace(c)) - c = hpf_getc(fp); - if (c == '{') { - if (have_patterns || have_hyphenation) - error("`{' not allowed inside of \\patterns or \\hyphenation"); - else { - have_hyphenation = 1; - have_keyword = 1; - } - c = hpf_getc(fp); - continue; - } - } - else if (strstr(buf, "\\endinput")) { - if (have_patterns || have_hyphenation) - error("found \\endinput inside of %1 group", - have_patterns ? "\\patterns" : "\\hyphenation"); - break; - } - else if (c == '}') { - if (have_patterns) { - have_patterns = 0; - if (i > 0) - final_pattern = 1; - } - else if (have_hyphenation) { - have_hyphenation = 0; - if (i > 0) - final_hyphenation = 1; - } - c = hpf_getc(fp); - } - else if (c == '{') // skipped if not starting \patterns - c = hpf_getc(fp); // or \hyphenation - } - if (i > 0) { - if (have_patterns || final_pattern || traditional) { - for (int j = 0; j < i; j++) - buf[j] = hpf_code_table[(unsigned char)buf[j]]; - insert_pattern(buf, i, num); - final_pattern = 0; - } - else if (have_hyphenation || final_hyphenation) { - insert_hyphenation(ex, buf, i); - final_hyphenation = 0; - } - } - } - fclose(fp); - a_delete path; - return; -} - -void hyphenate(hyphen_list *h, unsigned flags) -{ - if (!current_language) - return; - while (h) { - while (h && h->hyphenation_code == 0) - h = h->next; - int len = 0; - char hbuf[WORD_MAX+2]; - char *buf = hbuf + 1; - hyphen_list *tem; - for (tem = h; tem && len < WORD_MAX; tem = tem->next) { - if (tem->hyphenation_code != 0) - buf[len++] = tem->hyphenation_code; - else - break; - } - hyphen_list *nexth = tem; - if (len > 2) { - buf[len] = 0; - unsigned char *pos - = (unsigned char *)current_language->exceptions.lookup(buf); - if (pos != 0) { - int j = 0; - int i = 1; - for (tem = h; tem != 0; tem = tem->next, i++) - if (pos[j] == i) { - tem->hyphen = 1; - j++; - } - } - else { - hbuf[0] = hbuf[len+1] = '.'; - int num[WORD_MAX+3]; - current_language->patterns.hyphenate(hbuf, len+2, num); - int i; - num[2] = 0; - if (flags & 8) - num[3] = 0; - if (flags & 4) - --len; - for (i = 2, tem = h; i < len && tem; tem = tem->next, i++) - if (num[i] & 1) - tem->hyphen = 1; - } - } - h = nexth; - } -} - -static void do_hyphenation_patterns_file(int append) -{ - symbol name = get_long_name(1); - if (!name.is_null()) { - if (!current_language) - error("no current hyphenation language"); - else - current_language->patterns.read_patterns_file( - name.contents(), append, - current_language->exceptions); - } - skip_line(); -} - -static void hyphenation_patterns_file() -{ - do_hyphenation_patterns_file(0); -} - -static void hyphenation_patterns_file_append() -{ - do_hyphenation_patterns_file(1); -} - -class hyphenation_language_reg : public reg { -public: - const char *get_string(); -}; - -const char *hyphenation_language_reg::get_string() -{ - return current_language ? current_language->name.contents() : ""; -} - -void init_hyphen_requests() -{ - init_request("hw", hyphen_word); - init_request("hla", set_hyphenation_language); - init_request("hpf", hyphenation_patterns_file); - init_request("hpfa", hyphenation_patterns_file_append); - number_reg_dictionary.define(".hla", new hyphenation_language_reg); -} diff --git a/contrib/groff/src/roff/troff/input.cc b/contrib/groff/src/roff/troff/input.cc deleted file mode 100644 index 7a90e4b..0000000 --- a/contrib/groff/src/roff/troff/input.cc +++ /dev/null @@ -1,7665 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "reg.h" -#include "token.h" -#include "div.h" -#include "charinfo.h" -#include "stringclass.h" -#include "font.h" -#include "macropath.h" -#include "defs.h" -#include "input.h" - -// Needed for getpid() and isatty() -#include "posix.h" - -#include "nonposix.h" - -#ifdef NEED_DECLARATION_PUTENV -extern "C" { - int putenv(const char *); -} -#endif /* NEED_DECLARATION_PUTENV */ - -#define MACRO_PREFIX "tmac." -#define MACRO_POSTFIX ".tmac" -#define INITIAL_STARTUP_FILE "troffrc" -#define FINAL_STARTUP_FILE "troffrc-end" -#define DEFAULT_INPUT_STACK_LIMIT 1000 - -#ifndef DEFAULT_WARNING_MASK -// warnings that are enabled by default -#define DEFAULT_WARNING_MASK \ - (WARN_CHAR|WARN_NUMBER|WARN_BREAK|WARN_SPACE|WARN_FONT) -#endif - -// initial size of buffer for reading names; expanded as necessary -#define ABUF_SIZE 16 - -extern "C" const char *Version_string; - -#ifdef COLUMN -void init_column_requests(); -#endif /* COLUMN */ - -static node *read_draw_node(); -void handle_first_page_transition(); -static void push_token(const token &); -void copy_file(); -#ifdef COLUMN -void vjustify(); -#endif /* COLUMN */ -void transparent_file(); -void process_input_stack(); - -const char *program_name = 0; -token tok; -int break_flag = 0; -int color_flag = 1; // colors are on by default -static int backtrace_flag = 0; -#ifndef POPEN_MISSING -char *pipe_command = 0; -#endif -charinfo *charset_table[256]; -unsigned char hpf_code_table[256]; - -static int warning_mask = DEFAULT_WARNING_MASK; -static int inhibit_errors = 0; -static int ignoring = 0; - -static void enable_warning(const char *); -static void disable_warning(const char *); - -static int escape_char = '\\'; -static symbol end_macro_name; -static symbol blank_line_macro_name; -static int compatible_flag = 0; -int ascii_output_flag = 0; -int suppress_output_flag = 0; -int is_html = 0; -int begin_level = 0; // number of nested .begin requests - -int have_input = 0; // whether \f, \H, \R, \s, or \S has - // been processed in token::next() -int tcommand_flag = 0; -int safer_flag = 1; // safer by default - -int have_string_arg = 0; // whether we have \*[foo bar...] - -double spread_limit = -3.0 - 1.0; // negative means deactivated - -double warn_scale; -char warn_scaling_indicator; - -search_path *mac_path = &safer_macro_path; - -static int get_copy(node**, int = 0); -static void copy_mode_error(const char *, - const errarg & = empty_errarg, - const errarg & = empty_errarg, - const errarg & = empty_errarg); - -enum read_mode { ALLOW_EMPTY, WITH_ARGS, NO_ARGS }; -static symbol read_escape_name(read_mode mode = NO_ARGS); -static symbol read_long_escape_name(read_mode mode = NO_ARGS); -static void interpolate_string(symbol); -static void interpolate_string_with_args(symbol); -static void interpolate_macro(symbol); -static void interpolate_number_format(symbol); -static void interpolate_environment_variable(symbol); - -static void interpolate_arg(symbol); -static request_or_macro *lookup_request(symbol); -static int get_delim_number(units *, int); -static int get_delim_number(units *, int, units); -static int get_line_arg(units *res, int si, charinfo **cp); -static int read_size(int *); -static symbol get_delim_name(); -static void init_registers(); -static void trapping_blank_line(); - -struct input_iterator; -input_iterator *make_temp_iterator(const char *); -const char *input_char_description(int); - - -void set_escape_char() -{ - if (has_arg()) { - if (tok.ch() == 0) { - error("bad escape character"); - escape_char = '\\'; - } - else - escape_char = tok.ch(); - } - else - escape_char = '\\'; - skip_line(); -} - -void escape_off() -{ - escape_char = 0; - skip_line(); -} - -static int saved_escape_char = '\\'; - -void save_escape_char() -{ - saved_escape_char = escape_char; - skip_line(); -} - -void restore_escape_char() -{ - escape_char = saved_escape_char; - skip_line(); -} - -class input_iterator { -public: - input_iterator(); - virtual ~input_iterator() {} - int get(node **); - friend class input_stack; -protected: - const unsigned char *ptr; - const unsigned char *eptr; - input_iterator *next; -private: - virtual int fill(node **); - virtual int peek(); - virtual int has_args() { return 0; } - virtual int nargs() { return 0; } - virtual input_iterator *get_arg(int) { return 0; } - virtual int get_location(int, const char **, int *) { return 0; } - virtual void backtrace() {} - virtual int set_location(const char *, int) { return 0; } - virtual int next_file(FILE *, const char *) { return 0; } - virtual void shift(int) {} - virtual int is_boundary() {return 0; } - virtual int internal_level() { return 0; } - virtual int is_file() { return 0; } - virtual int is_macro() { return 0; } - virtual void save_compatible_flag(int) {} - virtual int get_compatible_flag() { return 0; } -}; - -input_iterator::input_iterator() -: ptr(0), eptr(0) -{ -} - -int input_iterator::fill(node **) -{ - return EOF; -} - -int input_iterator::peek() -{ - return EOF; -} - -inline int input_iterator::get(node **p) -{ - return ptr < eptr ? *ptr++ : fill(p); -} - -class input_boundary : public input_iterator { -public: - int is_boundary() { return 1; } -}; - -class input_return_boundary : public input_iterator { -public: - int is_boundary() { return 2; } -}; - -class file_iterator : public input_iterator { - FILE *fp; - int lineno; - const char *filename; - int popened; - int newline_flag; - int seen_escape; - enum { BUF_SIZE = 512 }; - unsigned char buf[BUF_SIZE]; - void close(); -public: - file_iterator(FILE *, const char *, int = 0); - ~file_iterator(); - int fill(node **); - int peek(); - int get_location(int, const char **, int *); - void backtrace(); - int set_location(const char *, int); - int next_file(FILE *, const char *); - int is_file(); -}; - -file_iterator::file_iterator(FILE *f, const char *fn, int po) -: fp(f), lineno(1), filename(fn), popened(po), - newline_flag(0), seen_escape(0) -{ - if ((font::use_charnames_in_special) && (fn != 0)) { - if (!the_output) - init_output(); - the_output->put_filename(fn); - } -} - -file_iterator::~file_iterator() -{ - close(); -} - -void file_iterator::close() -{ - if (fp == stdin) - clearerr(stdin); -#ifndef POPEN_MISSING - else if (popened) - pclose(fp); -#endif /* not POPEN_MISSING */ - else - fclose(fp); -} - -int file_iterator::is_file() -{ - return 1; -} - -int file_iterator::next_file(FILE *f, const char *s) -{ - close(); - filename = s; - fp = f; - lineno = 1; - newline_flag = 0; - seen_escape = 0; - popened = 0; - ptr = 0; - eptr = 0; - return 1; -} - -int file_iterator::fill(node **) -{ - if (newline_flag) - lineno++; - newline_flag = 0; - unsigned char *p = buf; - ptr = p; - unsigned char *e = p + BUF_SIZE; - while (p < e) { - int c = getc(fp); - if (c == EOF) - break; - if (invalid_input_char(c)) - warning(WARN_INPUT, "invalid input character code %1", int(c)); - else { - *p++ = c; - if (c == '\n') { - seen_escape = 0; - newline_flag = 1; - break; - } - seen_escape = (c == '\\'); - } - } - if (p > buf) { - eptr = p; - return *ptr++; - } - else { - eptr = p; - return EOF; - } -} - -int file_iterator::peek() -{ - int c = getc(fp); - while (invalid_input_char(c)) { - warning(WARN_INPUT, "invalid input character code %1", int(c)); - c = getc(fp); - } - if (c != EOF) - ungetc(c, fp); - return c; -} - -int file_iterator::get_location(int /*allow_macro*/, - const char **filenamep, int *linenop) -{ - *linenop = lineno; - if (filename != 0 && strcmp(filename, "-") == 0) - *filenamep = ""; - else - *filenamep = filename; - return 1; -} - -void file_iterator::backtrace() -{ - errprint("%1:%2: backtrace: %3 `%1'\n", filename, lineno, - popened ? "process" : "file"); -} - -int file_iterator::set_location(const char *f, int ln) -{ - if (f) { - filename = f; - if (!the_output) - init_output(); - the_output->put_filename(f); - } - lineno = ln; - return 1; -} - -input_iterator nil_iterator; - -class input_stack { -public: - static int get(node **); - static int peek(); - static void push(input_iterator *); - static input_iterator *get_arg(int); - static int nargs(); - static int get_location(int, const char **, int *); - static int set_location(const char *, int); - static void backtrace(); - static void backtrace_all(); - static void next_file(FILE *, const char *); - static void end_file(); - static void shift(int n); - static void add_boundary(); - static void add_return_boundary(); - static int is_return_boundary(); - static void remove_boundary(); - static int get_level(); - static void clear(); - static void pop_macro(); - static void save_compatible_flag(int); - static int get_compatible_flag(); - - static int limit; -private: - static input_iterator *top; - static int level; - - static int finish_get(node **); - static int finish_peek(); -}; - -input_iterator *input_stack::top = &nil_iterator; -int input_stack::level = 0; -int input_stack::limit = DEFAULT_INPUT_STACK_LIMIT; - -inline int input_stack::get_level() -{ - return level + top->internal_level(); -} - -inline int input_stack::get(node **np) -{ - return (top->ptr < top->eptr) ? *top->ptr++ : finish_get(np); -} - -int input_stack::finish_get(node **np) -{ - for (;;) { - int c = top->fill(np); - if (c != EOF || top->is_boundary()) - return c; - if (top == &nil_iterator) - break; - input_iterator *tem = top; - top = top->next; - level--; - delete tem; - if (top->ptr < top->eptr) - return *top->ptr++; - } - assert(level == 0); - return EOF; -} - -inline int input_stack::peek() -{ - return (top->ptr < top->eptr) ? *top->ptr : finish_peek(); -} - -int input_stack::finish_peek() -{ - for (;;) { - int c = top->peek(); - if (c != EOF || top->is_boundary()) - return c; - if (top == &nil_iterator) - break; - input_iterator *tem = top; - top = top->next; - level--; - delete tem; - if (top->ptr < top->eptr) - return *top->ptr; - } - assert(level == 0); - return EOF; -} - -void input_stack::add_boundary() -{ - push(new input_boundary); -} - -void input_stack::add_return_boundary() -{ - push(new input_return_boundary); -} - -int input_stack::is_return_boundary() -{ - return top->is_boundary() == 2; -} - -void input_stack::remove_boundary() -{ - assert(top->is_boundary()); - input_iterator *temp = top->next; - delete top; - top = temp; - level--; -} - -void input_stack::push(input_iterator *in) -{ - if (in == 0) - return; - if (++level > limit && limit > 0) - fatal("input stack limit exceeded (probable infinite loop)"); - in->next = top; - top = in; -} - -input_iterator *input_stack::get_arg(int i) -{ - input_iterator *p; - for (p = top; p != 0; p = p->next) - if (p->has_args()) - return p->get_arg(i); - return 0; -} - -void input_stack::shift(int n) -{ - for (input_iterator *p = top; p; p = p->next) - if (p->has_args()) { - p->shift(n); - return; - } -} - -int input_stack::nargs() -{ - for (input_iterator *p =top; p != 0; p = p->next) - if (p->has_args()) - return p->nargs(); - return 0; -} - -int input_stack::get_location(int allow_macro, const char **filenamep, int *linenop) -{ - for (input_iterator *p = top; p; p = p->next) - if (p->get_location(allow_macro, filenamep, linenop)) - return 1; - return 0; -} - -void input_stack::backtrace() -{ - const char *f; - int n; - // only backtrace down to (not including) the topmost file - for (input_iterator *p = top; - p && !p->get_location(0, &f, &n); - p = p->next) - p->backtrace(); -} - -void input_stack::backtrace_all() -{ - for (input_iterator *p = top; p; p = p->next) - p->backtrace(); -} - -int input_stack::set_location(const char *filename, int lineno) -{ - for (input_iterator *p = top; p; p = p->next) - if (p->set_location(filename, lineno)) - return 1; - return 0; -} - -void input_stack::next_file(FILE *fp, const char *s) -{ - input_iterator **pp; - for (pp = ⊤ *pp != &nil_iterator; pp = &(*pp)->next) - if ((*pp)->next_file(fp, s)) - return; - if (++level > limit && limit > 0) - fatal("input stack limit exceeded"); - *pp = new file_iterator(fp, s); - (*pp)->next = &nil_iterator; -} - -void input_stack::end_file() -{ - for (input_iterator **pp = ⊤ *pp != &nil_iterator; pp = &(*pp)->next) - if ((*pp)->is_file()) { - input_iterator *tem = *pp; - *pp = (*pp)->next; - delete tem; - level--; - return; - } -} - -void input_stack::clear() -{ - int nboundaries = 0; - while (top != &nil_iterator) { - if (top->is_boundary()) - nboundaries++; - input_iterator *tem = top; - top = top->next; - level--; - delete tem; - } - // Keep while_request happy. - for (; nboundaries > 0; --nboundaries) - add_return_boundary(); -} - -void input_stack::pop_macro() -{ - int nboundaries = 0; - int is_macro = 0; - do { - if (top->next == &nil_iterator) - break; - if (top->is_boundary()) - nboundaries++; - is_macro = top->is_macro(); - input_iterator *tem = top; - top = top->next; - level--; - delete tem; - } while (!is_macro); - // Keep while_request happy. - for (; nboundaries > 0; --nboundaries) - add_return_boundary(); -} - -inline void input_stack::save_compatible_flag(int f) -{ - top->save_compatible_flag(f); -} - -inline int input_stack::get_compatible_flag() -{ - return top->get_compatible_flag(); -} - -void backtrace_request() -{ - input_stack::backtrace_all(); - fflush(stderr); - skip_line(); -} - -void next_file() -{ - symbol nm = get_long_name(0); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (nm.is_null()) - input_stack::end_file(); - else { - errno = 0; - FILE *fp = fopen(nm.contents(), "r"); - if (!fp) - error("can't open `%1': %2", nm.contents(), strerror(errno)); - else - input_stack::next_file(fp, nm.contents()); - } - tok.next(); -} - -void shift() -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - input_stack::shift(n); - skip_line(); -} - -static int get_char_for_escape_name(int allow_space = 0) -{ - int c = get_copy(0); - switch (c) { - case EOF: - copy_mode_error("end of input in escape name"); - return '\0'; - default: - if (!invalid_input_char(c)) - break; - // fall through - case '\n': - if (c == '\n') - input_stack::push(make_temp_iterator("\n")); - // fall through - case ' ': - if (c == ' ' && allow_space) - break; - // fall through - case '\t': - case '\001': - case '\b': - copy_mode_error("%1 is not allowed in an escape name", - input_char_description(c)); - return '\0'; - } - return c; -} - -static symbol read_two_char_escape_name() -{ - char buf[3]; - buf[0] = get_char_for_escape_name(); - if (buf[0] != '\0') { - buf[1] = get_char_for_escape_name(); - if (buf[1] == '\0') - buf[0] = 0; - else - buf[2] = 0; - } - return symbol(buf); -} - -static symbol read_long_escape_name(read_mode mode) -{ - int start_level = input_stack::get_level(); - char abuf[ABUF_SIZE]; - char *buf = abuf; - int buf_size = ABUF_SIZE; - int i = 0; - int c; - int have_char = 0; - for (;;) { - c = get_char_for_escape_name(have_char && mode == WITH_ARGS); - if (c == 0) { - if (buf != abuf) - a_delete buf; - return NULL_SYMBOL; - } - have_char = 1; - if (mode == WITH_ARGS && c == ' ') - break; - if (i + 2 > buf_size) { - if (buf == abuf) { - buf = new char[ABUF_SIZE*2]; - memcpy(buf, abuf, buf_size); - buf_size = ABUF_SIZE*2; - } - else { - char *old_buf = buf; - buf = new char[buf_size*2]; - memcpy(buf, old_buf, buf_size); - buf_size *= 2; - a_delete old_buf; - } - } - if (c == ']' && input_stack::get_level() == start_level) - break; - buf[i++] = c; - } - buf[i] = 0; - if (c == ' ') - have_string_arg = 1; - if (buf == abuf) { - if (i == 0) { - if (mode != ALLOW_EMPTY) - copy_mode_error("empty escape name"); - return EMPTY_SYMBOL; - } - return symbol(abuf); - } - else { - symbol s(buf); - a_delete buf; - return s; - } -} - -static symbol read_escape_name(read_mode mode) -{ - int c = get_char_for_escape_name(); - if (c == 0) - return NULL_SYMBOL; - if (c == '(') - return read_two_char_escape_name(); - if (c == '[' && !compatible_flag) - return read_long_escape_name(mode); - char buf[2]; - buf[0] = c; - buf[1] = '\0'; - return symbol(buf); -} - -static symbol read_increment_and_escape_name(int *incp) -{ - int c = get_char_for_escape_name(); - switch (c) { - case 0: - *incp = 0; - return NULL_SYMBOL; - case '(': - *incp = 0; - return read_two_char_escape_name(); - case '+': - *incp = 1; - return read_escape_name(); - case '-': - *incp = -1; - return read_escape_name(); - case '[': - if (!compatible_flag) { - *incp = 0; - return read_long_escape_name(); - } - break; - } - *incp = 0; - char buf[2]; - buf[0] = c; - buf[1] = '\0'; - return symbol(buf); -} - -static int get_copy(node **nd, int defining) -{ - for (;;) { - int c = input_stack::get(nd); - if (c == ESCAPE_NEWLINE) { - if (defining) - return c; - do { - c = input_stack::get(nd); - } while (c == ESCAPE_NEWLINE); - } - if (c != escape_char || escape_char <= 0) - return c; - c = input_stack::peek(); - switch(c) { - case 0: - return escape_char; - case '"': - (void)input_stack::get(0); - while ((c = input_stack::get(0)) != '\n' && c != EOF) - ; - return c; - case '#': // Like \" but newline is ignored. - (void)input_stack::get(0); - while ((c = input_stack::get(0)) != '\n') - if (c == EOF) - return EOF; - break; - case '$': - { - (void)input_stack::get(0); - symbol s = read_escape_name(); - if (!(s.is_null() || s.is_empty())) - interpolate_arg(s); - break; - } - case '*': - { - (void)input_stack::get(0); - symbol s = read_escape_name(WITH_ARGS); - if (!(s.is_null() || s.is_empty())) { - if (have_string_arg) { - have_string_arg = 0; - interpolate_string_with_args(s); - } - else - interpolate_string(s); - } - break; - } - case 'a': - (void)input_stack::get(0); - return '\001'; - case 'e': - (void)input_stack::get(0); - return ESCAPE_e; - case 'E': - (void)input_stack::get(0); - return ESCAPE_E; - case 'n': - { - (void)input_stack::get(0); - int inc; - symbol s = read_increment_and_escape_name(&inc); - if (!(s.is_null() || s.is_empty())) - interpolate_number_reg(s, inc); - break; - } - case 'g': - { - (void)input_stack::get(0); - symbol s = read_escape_name(); - if (!(s.is_null() || s.is_empty())) - interpolate_number_format(s); - break; - } - case 't': - (void)input_stack::get(0); - return '\t'; - case 'V': - { - (void)input_stack::get(0); - symbol s = read_escape_name(); - if (!(s.is_null() || s.is_empty())) - interpolate_environment_variable(s); - break; - } - case '\n': - (void)input_stack::get(0); - if (defining) - return ESCAPE_NEWLINE; - break; - case ' ': - (void)input_stack::get(0); - return ESCAPE_SPACE; - case '~': - (void)input_stack::get(0); - return ESCAPE_TILDE; - case ':': - (void)input_stack::get(0); - return ESCAPE_COLON; - case '|': - (void)input_stack::get(0); - return ESCAPE_BAR; - case '^': - (void)input_stack::get(0); - return ESCAPE_CIRCUMFLEX; - case '{': - (void)input_stack::get(0); - return ESCAPE_LEFT_BRACE; - case '}': - (void)input_stack::get(0); - return ESCAPE_RIGHT_BRACE; - case '`': - (void)input_stack::get(0); - return ESCAPE_LEFT_QUOTE; - case '\'': - (void)input_stack::get(0); - return ESCAPE_RIGHT_QUOTE; - case '-': - (void)input_stack::get(0); - return ESCAPE_HYPHEN; - case '_': - (void)input_stack::get(0); - return ESCAPE_UNDERSCORE; - case 'c': - (void)input_stack::get(0); - return ESCAPE_c; - case '!': - (void)input_stack::get(0); - return ESCAPE_BANG; - case '?': - (void)input_stack::get(0); - return ESCAPE_QUESTION; - case '&': - (void)input_stack::get(0); - return ESCAPE_AMPERSAND; - case ')': - (void)input_stack::get(0); - return ESCAPE_RIGHT_PARENTHESIS; - case '.': - (void)input_stack::get(0); - return c; - case '%': - (void)input_stack::get(0); - return ESCAPE_PERCENT; - default: - if (c == escape_char) { - (void)input_stack::get(0); - return c; - } - else - return escape_char; - } - } -} - -class non_interpreted_char_node : public node { - unsigned char c; -public: - non_interpreted_char_node(unsigned char); - node *copy(); - int interpret(macro *); - int same(node *); - const char *type(); - int force_tprint(); -}; - -int non_interpreted_char_node::same(node *nd) -{ - return c == ((non_interpreted_char_node *)nd)->c; -} - -const char *non_interpreted_char_node::type() -{ - return "non_interpreted_char_node"; -} - -int non_interpreted_char_node::force_tprint() -{ - return 0; -} - -non_interpreted_char_node::non_interpreted_char_node(unsigned char n) : c(n) -{ - assert(n != 0); -} - -node *non_interpreted_char_node::copy() -{ - return new non_interpreted_char_node(c); -} - -int non_interpreted_char_node::interpret(macro *mac) -{ - mac->append(c); - return 1; -} - -static void do_width(); -static node *do_non_interpreted(); -static node *do_special(); -static node *do_suppress(symbol nm); -static void do_register(); - -dictionary color_dictionary(501); -static symbol default_symbol("default"); - -static color *lookup_color(symbol nm) -{ - assert(!nm.is_null()); - if (nm == default_symbol) - return &default_color; - color *c = (color *)color_dictionary.lookup(nm); - if (c == 0) - warning(WARN_COLOR, "`%1' not defined", nm.contents()); - return c; -} - -void do_glyph_color(symbol nm) -{ - if (nm.is_null()) - return; - if (nm.is_empty()) - curenv->set_glyph_color(curenv->get_prev_glyph_color()); - else { - color *tem = lookup_color(nm); - if (tem) - curenv->set_glyph_color(tem); - else - (void)color_dictionary.lookup(nm, new color); - } -} - -void do_fill_color(symbol nm) -{ - if (nm.is_null()) - return; - if (nm.is_empty()) - curenv->set_fill_color(curenv->get_prev_fill_color()); - else { - color *tem = lookup_color(nm); - if (tem) - curenv->set_fill_color(tem); - else - (void)color_dictionary.lookup(nm, new color); - } -} - -static unsigned int get_color_element(const char *scheme, const char *col) -{ - units val; - if (!get_number(&val, 'f')) { - warning(WARN_COLOR, "%1 in %2 definition set to 0", col, scheme); - tok.next(); - return 0; - } - if (val < 0) { - warning(WARN_RANGE, "%1 cannot be negative: set to 0", col); - return 0; - } - if (val > color::MAX_COLOR_VAL+1) { - warning(WARN_RANGE, "%1 cannot be greater than 1", col); - // we change 0x10000 to 0xffff - return color::MAX_COLOR_VAL; - } - return (unsigned int)val; -} - -static color *read_rgb() -{ - symbol component = get_long_name(0); - if (component.is_null()) { - warning(WARN_COLOR, "missing rgb color values"); - return 0; - } - const char *s = component.contents(); - color *col = new color; - if (*s == '#') { - if (!col->read_rgb(s)) { - warning(WARN_COLOR, "expecting rgb color definition not `%1'", s); - delete col; - return 0; - } - } - else { - input_stack::push(make_temp_iterator(" ")); - input_stack::push(make_temp_iterator(s)); - tok.next(); - unsigned int r = get_color_element("rgb color", "red component"); - unsigned int g = get_color_element("rgb color", "green component"); - unsigned int b = get_color_element("rgb color", "blue component"); - col->set_rgb(r, g, b); - } - return col; -} - -static color *read_cmy() -{ - symbol component = get_long_name(0); - if (component.is_null()) { - warning(WARN_COLOR, "missing cmy color values"); - return 0; - } - const char *s = component.contents(); - color *col = new color; - if (*s == '#') { - if (!col->read_cmy(s)) { - warning(WARN_COLOR, "expecting cmy color definition not `%1'", s); - delete col; - return 0; - } - } - else { - input_stack::push(make_temp_iterator(" ")); - input_stack::push(make_temp_iterator(s)); - tok.next(); - unsigned int c = get_color_element("cmy color", "cyan component"); - unsigned int m = get_color_element("cmy color", "magenta component"); - unsigned int y = get_color_element("cmy color", "yellow component"); - col->set_cmy(c, m, y); - } - return col; -} - -static color *read_cmyk() -{ - symbol component = get_long_name(0); - if (component.is_null()) { - warning(WARN_COLOR, "missing cmyk color values"); - return 0; - } - const char *s = component.contents(); - color *col = new color; - if (*s == '#') { - if (!col->read_cmyk(s)) { - warning(WARN_COLOR, "`expecting a cmyk color definition not `%1'", s); - delete col; - return 0; - } - } - else { - input_stack::push(make_temp_iterator(" ")); - input_stack::push(make_temp_iterator(s)); - tok.next(); - unsigned int c = get_color_element("cmyk color", "cyan component"); - unsigned int m = get_color_element("cmyk color", "magenta component"); - unsigned int y = get_color_element("cmyk color", "yellow component"); - unsigned int k = get_color_element("cmyk color", "black component"); - col->set_cmyk(c, m, y, k); - } - return col; -} - -static color *read_gray() -{ - symbol component = get_long_name(0); - if (component.is_null()) { - warning(WARN_COLOR, "missing gray values"); - return 0; - } - const char *s = component.contents(); - color *col = new color; - if (*s == '#') { - if (!col->read_gray(s)) { - warning(WARN_COLOR, "`expecting a gray definition not `%1'", s); - delete col; - return 0; - } - } - else { - input_stack::push(make_temp_iterator("\n")); - input_stack::push(make_temp_iterator(s)); - tok.next(); - unsigned int g = get_color_element("gray", "gray value"); - col->set_gray(g); - } - return col; -} - -static void activate_color() -{ - int n; - if (has_arg() && get_integer(&n)) - color_flag = n != 0; - else - color_flag = 1; - skip_line(); -} - -static void define_color() -{ - symbol color_name = get_long_name(1); - if (color_name.is_null()) { - skip_line(); - return; - } - if (color_name == default_symbol) { - warning(WARN_COLOR, "default color can't be redefined"); - skip_line(); - return; - } - symbol style = get_long_name(1); - if (style.is_null()) { - skip_line(); - return; - } - color *col; - if (strcmp(style.contents(), "rgb") == 0) - col = read_rgb(); - else if (strcmp(style.contents(), "cmyk") == 0) - col = read_cmyk(); - else if (strcmp(style.contents(), "gray") == 0) - col = read_gray(); - else if (strcmp(style.contents(), "grey") == 0) - col = read_gray(); - else if (strcmp(style.contents(), "cmy") == 0) - col = read_cmy(); - else { - warning(WARN_COLOR, - "unknown color space `%1'; use rgb, cmyk, gray or cmy", - style.contents()); - skip_line(); - return; - } - if (col) - (void)color_dictionary.lookup(color_name, col); - skip_line(); -} - -static node *do_overstrike() -{ - token start; - overstrike_node *on = new overstrike_node; - int start_level = input_stack::get_level(); - start.next(); - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - charinfo *ci = tok.get_char(1); - if (ci) { - node *n = curenv->make_char_node(ci); - if (n) - on->overstrike(n); - } - } - return on; -} - -static node *do_bracket() -{ - token start; - bracket_node *bn = new bracket_node; - start.next(); - int start_level = input_stack::get_level(); - for (;;) { - tok.next(); - if (tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok.newline()) { - warning(WARN_DELIM, "missing closing delimiter"); - input_stack::push(make_temp_iterator("\n")); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - charinfo *ci = tok.get_char(1); - if (ci) { - node *n = curenv->make_char_node(ci); - if (n) - bn->bracket(n); - } - } - return bn; -} - -static int do_name_test() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - int bad_char = 0; - int some_char = 0; - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - if (!tok.ch()) - bad_char = 1; - some_char = 1; - } - return some_char && !bad_char; -} - -static int do_expr_test() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - if (!start.delimiter(1)) - return 0; - tok.next(); - // disable all warning and error messages temporarily - int saved_warning_mask = warning_mask; - int saved_inhibit_errors = inhibit_errors; - warning_mask = 0; - inhibit_errors = 1; - int dummy; - int result = get_number_rigidly(&dummy, 'u'); - warning_mask = saved_warning_mask; - inhibit_errors = saved_inhibit_errors; - if (tok == start && input_stack::get_level() == start_level) - return result; - // ignore everything up to the delimiter in case we aren't right there - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok == start && input_stack::get_level() == start_level) - break; - } - return 0; -} - -#if 0 -static node *do_zero_width() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - environment env(curenv); - environment *oldenv = curenv; - curenv = &env; - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - error("missing closing delimiter"); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - tok.process(); - } - curenv = oldenv; - node *rev = env.extract_output_line(); - node *n = 0; - while (rev) { - node *tem = rev; - rev = rev->next; - tem->next = n; - n = tem; - } - return new zero_width_node(n); -} - -#else - -// It's undesirable for \Z to change environments, because then -// \n(.w won't work as expected. - -static node *do_zero_width() -{ - node *rev = new dummy_node; - token start; - start.next(); - int start_level = input_stack::get_level(); - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - if (!tok.add_to_node_list(&rev)) - error("invalid token in argument to \\Z"); - } - node *n = 0; - while (rev) { - node *tem = rev; - rev = rev->next; - tem->next = n; - n = tem; - } - return new zero_width_node(n); -} - -#endif - -token_node *node::get_token_node() -{ - return 0; -} - -class token_node : public node { -public: - token tk; - token_node(const token &t); - node *copy(); - token_node *get_token_node(); - int same(node *); - const char *type(); - int force_tprint(); -}; - -token_node::token_node(const token &t) : tk(t) -{ -} - -node *token_node::copy() -{ - return new token_node(tk); -} - -token_node *token_node::get_token_node() -{ - return this; -} - -int token_node::same(node *nd) -{ - return tk == ((token_node *)nd)->tk; -} - -const char *token_node::type() -{ - return "token_node"; -} - -int token_node::force_tprint() -{ - return 0; -} - -token::token() : nd(0), type(TOKEN_EMPTY) -{ -} - -token::~token() -{ - delete nd; -} - -token::token(const token &t) -: nm(t.nm), c(t.c), val(t.val), dim(t.dim), type(t.type) -{ - // Use two statements to work around bug in SGI C++. - node *tem = t.nd; - nd = tem ? tem->copy() : 0; -} - -void token::operator=(const token &t) -{ - delete nd; - nm = t.nm; - // Use two statements to work around bug in SGI C++. - node *tem = t.nd; - nd = tem ? tem->copy() : 0; - c = t.c; - val = t.val; - dim = t.dim; - type = t.type; -} - -void token::skip() -{ - while (space()) - next(); -} - -int has_arg() -{ - while (tok.space()) - tok.next(); - return !tok.newline(); -} - -void token::make_space() -{ - type = TOKEN_SPACE; -} - -void token::make_newline() -{ - type = TOKEN_NEWLINE; -} - -void token::next() -{ - if (nd) { - delete nd; - nd = 0; - } - units x; - for (;;) { - node *n; - int cc = input_stack::get(&n); - if (cc != escape_char || escape_char == 0) { - handle_normal_char: - switch(cc) { - case COMPATIBLE_SAVE: - input_stack::save_compatible_flag(compatible_flag); - compatible_flag = 0; - continue; - case COMPATIBLE_RESTORE: - compatible_flag = input_stack::get_compatible_flag(); - continue; - case EOF: - type = TOKEN_EOF; - return; - case TRANSPARENT_FILE_REQUEST: - case TITLE_REQUEST: - case COPY_FILE_REQUEST: -#ifdef COLUMN - case VJUSTIFY_REQUEST: -#endif /* COLUMN */ - type = TOKEN_REQUEST; - c = cc; - return; - case BEGIN_TRAP: - type = TOKEN_BEGIN_TRAP; - return; - case END_TRAP: - type = TOKEN_END_TRAP; - return; - case LAST_PAGE_EJECTOR: - seen_last_page_ejector = 1; - // fall through - case PAGE_EJECTOR: - type = TOKEN_PAGE_EJECTOR; - return; - case ESCAPE_PERCENT: - ESCAPE_PERCENT: - type = TOKEN_HYPHEN_INDICATOR; - return; - case ESCAPE_SPACE: - ESCAPE_SPACE: - type = TOKEN_UNSTRETCHABLE_SPACE; - return; - case ESCAPE_TILDE: - ESCAPE_TILDE: - type = TOKEN_STRETCHABLE_SPACE; - return; - case ESCAPE_COLON: - ESCAPE_COLON: - type = TOKEN_ZERO_WIDTH_BREAK; - return; - case ESCAPE_e: - ESCAPE_e: - type = TOKEN_ESCAPE; - return; - case ESCAPE_E: - goto handle_escape_char; - case ESCAPE_BAR: - ESCAPE_BAR: - type = TOKEN_NODE; - nd = new hmotion_node(curenv->get_narrow_space_width(), - curenv->get_fill_color()); - return; - case ESCAPE_CIRCUMFLEX: - ESCAPE_CIRCUMFLEX: - type = TOKEN_NODE; - nd = new hmotion_node(curenv->get_half_narrow_space_width(), - curenv->get_fill_color()); - return; - case ESCAPE_NEWLINE: - break; - case ESCAPE_LEFT_BRACE: - ESCAPE_LEFT_BRACE: - type = TOKEN_LEFT_BRACE; - return; - case ESCAPE_RIGHT_BRACE: - ESCAPE_RIGHT_BRACE: - type = TOKEN_RIGHT_BRACE; - return; - case ESCAPE_LEFT_QUOTE: - ESCAPE_LEFT_QUOTE: - type = TOKEN_SPECIAL; - nm = symbol("ga"); - return; - case ESCAPE_RIGHT_QUOTE: - ESCAPE_RIGHT_QUOTE: - type = TOKEN_SPECIAL; - nm = symbol("aa"); - return; - case ESCAPE_HYPHEN: - ESCAPE_HYPHEN: - type = TOKEN_SPECIAL; - nm = symbol("-"); - return; - case ESCAPE_UNDERSCORE: - ESCAPE_UNDERSCORE: - type = TOKEN_SPECIAL; - nm = symbol("ul"); - return; - case ESCAPE_c: - ESCAPE_c: - type = TOKEN_INTERRUPT; - return; - case ESCAPE_BANG: - ESCAPE_BANG: - type = TOKEN_TRANSPARENT; - return; - case ESCAPE_QUESTION: - ESCAPE_QUESTION: - nd = do_non_interpreted(); - if (nd) { - type = TOKEN_NODE; - return; - } - break; - case ESCAPE_AMPERSAND: - ESCAPE_AMPERSAND: - type = TOKEN_DUMMY; - return; - case ESCAPE_RIGHT_PARENTHESIS: - ESCAPE_RIGHT_PARENTHESIS: - type = TOKEN_TRANSPARENT_DUMMY; - return; - case '\b': - type = TOKEN_BACKSPACE; - return; - case ' ': - type = TOKEN_SPACE; - return; - case '\t': - type = TOKEN_TAB; - return; - case '\n': - type = TOKEN_NEWLINE; - return; - case '\001': - type = TOKEN_LEADER; - return; - case 0: - { - assert(n != 0); - token_node *tn = n->get_token_node(); - if (tn) { - *this = tn->tk; - delete tn; - } - else { - nd = n; - type = TOKEN_NODE; - } - } - return; - default: - type = TOKEN_CHAR; - c = cc; - return; - } - } - else { - handle_escape_char: - cc = input_stack::get(0); - switch(cc) { - case '(': - nm = read_two_char_escape_name(); - type = TOKEN_SPECIAL; - return; - case EOF: - type = TOKEN_EOF; - error("end of input after escape character"); - return; - case '`': - goto ESCAPE_LEFT_QUOTE; - case '\'': - goto ESCAPE_RIGHT_QUOTE; - case '-': - goto ESCAPE_HYPHEN; - case '_': - goto ESCAPE_UNDERSCORE; - case '%': - goto ESCAPE_PERCENT; - case ' ': - goto ESCAPE_SPACE; - case '0': - nd = new hmotion_node(curenv->get_digit_width(), - curenv->get_fill_color()); - type = TOKEN_NODE; - return; - case '|': - goto ESCAPE_BAR; - case '^': - goto ESCAPE_CIRCUMFLEX; - case '/': - type = TOKEN_ITALIC_CORRECTION; - return; - case ',': - type = TOKEN_NODE; - nd = new left_italic_corrected_node; - return; - case '&': - goto ESCAPE_AMPERSAND; - case ')': - goto ESCAPE_RIGHT_PARENTHESIS; - case '!': - goto ESCAPE_BANG; - case '?': - goto ESCAPE_QUESTION; - case '~': - goto ESCAPE_TILDE; - case ':': - goto ESCAPE_COLON; - case '"': - while ((cc = input_stack::get(0)) != '\n' && cc != EOF) - ; - if (cc == '\n') - type = TOKEN_NEWLINE; - else - type = TOKEN_EOF; - return; - case '#': // Like \" but newline is ignored. - while ((cc = input_stack::get(0)) != '\n') - if (cc == EOF) { - type = TOKEN_EOF; - return; - } - break; - case '$': - { - symbol nm = read_escape_name(); - if (!(nm.is_null() || nm.is_empty())) - interpolate_arg(nm); - break; - } - case '*': - { - symbol nm = read_escape_name(WITH_ARGS); - if (!(nm.is_null() || nm.is_empty())) { - if (have_string_arg) { - have_string_arg = 0; - interpolate_string_with_args(nm); - } - else - interpolate_string(nm); - } - break; - } - case 'a': - nd = new non_interpreted_char_node('\001'); - type = TOKEN_NODE; - return; - case 'A': - c = '0' + do_name_test(); - type = TOKEN_CHAR; - return; - case 'b': - nd = do_bracket(); - type = TOKEN_NODE; - return; - case 'B': - c = '0' + do_expr_test(); - type = TOKEN_CHAR; - return; - case 'c': - goto ESCAPE_c; - case 'C': - nm = get_delim_name(); - if (nm.is_null()) - break; - type = TOKEN_SPECIAL; - return; - case 'd': - type = TOKEN_NODE; - nd = new vmotion_node(curenv->get_size() / 2, - curenv->get_fill_color()); - return; - case 'D': - nd = read_draw_node(); - if (!nd) - break; - type = TOKEN_NODE; - return; - case 'e': - goto ESCAPE_e; - case 'E': - goto handle_escape_char; - case 'f': - { - symbol s = read_escape_name(ALLOW_EMPTY); - if (s.is_null()) - break; - const char *p; - for (p = s.contents(); *p != '\0'; p++) - if (!csdigit(*p)) - break; - if (*p || s.is_empty()) - curenv->set_font(s); - else - curenv->set_font(atoi(s.contents())); - if (!compatible_flag) - have_input = 1; - break; - } - case 'F': - { - symbol s = read_escape_name(ALLOW_EMPTY); - if (s.is_null()) - break; - curenv->set_family(s); - break; - } - case 'g': - { - symbol s = read_escape_name(); - if (!(s.is_null() || s.is_empty())) - interpolate_number_format(s); - break; - } - case 'h': - if (!get_delim_number(&x, 'm')) - break; - type = TOKEN_NODE; - nd = new hmotion_node(x, curenv->get_fill_color()); - return; - case 'H': - // don't take height increments relative to previous height if - // in compatibility mode - if (!compatible_flag && curenv->get_char_height()) - { - if (get_delim_number(&x, 'z', curenv->get_char_height())) - curenv->set_char_height(x); - } - else - { - if (get_delim_number(&x, 'z', curenv->get_requested_point_size())) - curenv->set_char_height(x); - } - if (!compatible_flag) - have_input = 1; - break; - case 'k': - nm = read_escape_name(); - if (nm.is_null() || nm.is_empty()) - break; - type = TOKEN_MARK_INPUT; - return; - case 'l': - case 'L': - { - charinfo *s = 0; - if (!get_line_arg(&x, (cc == 'l' ? 'm': 'v'), &s)) - break; - if (s == 0) - s = get_charinfo(cc == 'l' ? "ru" : "br"); - type = TOKEN_NODE; - node *n = curenv->make_char_node(s); - if (cc == 'l') - nd = new hline_node(x, n); - else - nd = new vline_node(x, n); - return; - } - case 'm': - do_glyph_color(read_escape_name(ALLOW_EMPTY)); - if (!compatible_flag) - have_input = 1; - break; - case 'M': - do_fill_color(read_escape_name(ALLOW_EMPTY)); - if (!compatible_flag) - have_input = 1; - break; - case 'n': - { - int inc; - symbol nm = read_increment_and_escape_name(&inc); - if (!(nm.is_null() || nm.is_empty())) - interpolate_number_reg(nm, inc); - break; - } - case 'N': - if (!get_delim_number(&val, 0)) - break; - type = TOKEN_NUMBERED_CHAR; - return; - case 'o': - nd = do_overstrike(); - type = TOKEN_NODE; - return; - case 'O': - nd = do_suppress(read_escape_name()); - if (!nd) - break; - type = TOKEN_NODE; - return; - case 'p': - type = TOKEN_SPREAD; - return; - case 'r': - type = TOKEN_NODE; - nd = new vmotion_node(-curenv->get_size(), curenv->get_fill_color()); - return; - case 'R': - do_register(); - if (!compatible_flag) - have_input = 1; - break; - case 's': - if (read_size(&x)) - curenv->set_size(x); - if (!compatible_flag) - have_input = 1; - break; - case 'S': - if (get_delim_number(&x, 0)) - curenv->set_char_slant(x); - if (!compatible_flag) - have_input = 1; - break; - case 't': - type = TOKEN_NODE; - nd = new non_interpreted_char_node('\t'); - return; - case 'u': - type = TOKEN_NODE; - nd = new vmotion_node(-curenv->get_size() / 2, - curenv->get_fill_color()); - return; - case 'v': - if (!get_delim_number(&x, 'v')) - break; - type = TOKEN_NODE; - nd = new vmotion_node(x, curenv->get_fill_color()); - return; - case 'V': - { - symbol nm = read_escape_name(); - if (!(nm.is_null() || nm.is_empty())) - interpolate_environment_variable(nm); - break; - } - case 'w': - do_width(); - break; - case 'x': - if (!get_delim_number(&x, 'v')) - break; - type = TOKEN_NODE; - nd = new extra_size_node(x); - return; - case 'X': - nd = do_special(); - if (!nd) - break; - type = TOKEN_NODE; - return; - case 'Y': - { - symbol s = read_escape_name(); - if (s.is_null() || s.is_empty()) - break; - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) { - error("can't transparently throughput a request"); - break; - } - nd = new special_node(*m); - type = TOKEN_NODE; - return; - } - case 'z': - { - next(); - if (type == TOKEN_NODE) - nd = new zero_width_node(nd); - else { - charinfo *ci = get_char(1); - if (ci == 0) - break; - node *gn = curenv->make_char_node(ci); - if (gn == 0) - break; - nd = new zero_width_node(gn); - type = TOKEN_NODE; - } - return; - } - case 'Z': - nd = do_zero_width(); - if (nd == 0) - break; - type = TOKEN_NODE; - return; - case '{': - goto ESCAPE_LEFT_BRACE; - case '}': - goto ESCAPE_RIGHT_BRACE; - case '\n': - break; - case '[': - if (!compatible_flag) { - nm = read_long_escape_name(); - if (nm.is_null() || nm.is_empty()) - break; - type = TOKEN_SPECIAL; - return; - } - goto handle_normal_char; - default: - if (cc != escape_char && cc != '.') - warning(WARN_ESCAPE, "escape character ignored before %1", - input_char_description(cc)); - goto handle_normal_char; - } - } - } -} - -int token::operator==(const token &t) -{ - if (type != t.type) - return 0; - switch(type) { - case TOKEN_CHAR: - return c == t.c; - case TOKEN_SPECIAL: - return nm == t.nm; - case TOKEN_NUMBERED_CHAR: - return val == t.val; - default: - return 1; - } -} - -int token::operator!=(const token &t) -{ - return !(*this == t); -} - -// is token a suitable delimiter (like ')? - -int token::delimiter(int err) -{ - switch(type) { - case TOKEN_CHAR: - switch(c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case '/': - case '*': - case '%': - case '<': - case '>': - case '=': - case '&': - case ':': - case '(': - case ')': - case '.': - if (err) - error("cannot use character `%1' as a starting delimiter", char(c)); - return 0; - default: - return 1; - } - case TOKEN_NODE: - case TOKEN_SPACE: - case TOKEN_STRETCHABLE_SPACE: - case TOKEN_UNSTRETCHABLE_SPACE: - case TOKEN_TAB: - case TOKEN_NEWLINE: - if (err) - error("cannot use %1 as a starting delimiter", description()); - return 0; - default: - return 1; - } -} - -const char *token::description() -{ - static char buf[4]; - switch (type) { - case TOKEN_BACKSPACE: - return "a backspace character"; - case TOKEN_CHAR: - buf[0] = '`'; - buf[1] = c; - buf[2] = '\''; - buf[3] = '\0'; - return buf; - case TOKEN_DUMMY: - return "`\\&'"; - case TOKEN_ESCAPE: - return "`\\e'"; - case TOKEN_HYPHEN_INDICATOR: - return "`\\%'"; - case TOKEN_INTERRUPT: - return "`\\c'"; - case TOKEN_ITALIC_CORRECTION: - return "`\\/'"; - case TOKEN_LEADER: - return "a leader character"; - case TOKEN_LEFT_BRACE: - return "`\\{'"; - case TOKEN_MARK_INPUT: - return "`\\k'"; - case TOKEN_NEWLINE: - return "newline"; - case TOKEN_NODE: - return "a node"; - case TOKEN_NUMBERED_CHAR: - return "`\\N'"; - case TOKEN_RIGHT_BRACE: - return "`\\}'"; - case TOKEN_SPACE: - return "a space"; - case TOKEN_SPECIAL: - return "a special character"; - case TOKEN_SPREAD: - return "`\\p'"; - case TOKEN_STRETCHABLE_SPACE: - return "`\\~'"; - case TOKEN_UNSTRETCHABLE_SPACE: - return "`\\ '"; - case TOKEN_TAB: - return "a tab character"; - case TOKEN_TRANSPARENT: - return "`\\!'"; - case TOKEN_TRANSPARENT_DUMMY: - return "`\\)'"; - case TOKEN_ZERO_WIDTH_BREAK: - return "`\\:'"; - case TOKEN_EOF: - return "end of input"; - default: - break; - } - return "a magic token"; -} - -void skip_line() -{ - while (!tok.newline()) - if (tok.eof()) - return; - else - tok.next(); - tok.next(); -} - -void compatible() -{ - int n; - if (has_arg() && get_integer(&n)) - compatible_flag = n != 0; - else - compatible_flag = 1; - skip_line(); -} - -static void empty_name_warning(int required) -{ - if (tok.newline() || tok.eof()) { - if (required) - warning(WARN_MISSING, "missing name"); - } - else if (tok.right_brace() || tok.tab()) { - const char *start = tok.description(); - do { - tok.next(); - } while (tok.space() || tok.right_brace() || tok.tab()); - if (!tok.newline() && !tok.eof()) - error("%1 is not allowed before an argument", start); - else if (required) - warning(WARN_MISSING, "missing name"); - } - else if (required) - error("name expected (got %1)", tok.description()); - else - error("name expected (got %1): treated as missing", tok.description()); -} - -static void non_empty_name_warning() -{ - if (!tok.newline() && !tok.eof() && !tok.space() && !tok.tab() - && !tok.right_brace() - // We don't want to give a warning for .el\{ - && !tok.left_brace()) - error("%1 is not allowed in a name", tok.description()); -} - -symbol get_name(int required) -{ - if (compatible_flag) { - char buf[3]; - tok.skip(); - if ((buf[0] = tok.ch()) != 0) { - tok.next(); - if ((buf[1] = tok.ch()) != 0) { - buf[2] = 0; - tok.make_space(); - } - else - non_empty_name_warning(); - return symbol(buf); - } - else { - empty_name_warning(required); - return NULL_SYMBOL; - } - } - else - return get_long_name(required); -} - -symbol get_long_name(int required) -{ - while (tok.space()) - tok.next(); - char abuf[ABUF_SIZE]; - char *buf = abuf; - int buf_size = ABUF_SIZE; - int i = 0; - for (;;) { - if (i + 1 > buf_size) { - if (buf == abuf) { - buf = new char[ABUF_SIZE*2]; - memcpy(buf, abuf, buf_size); - buf_size = ABUF_SIZE*2; - } - else { - char *old_buf = buf; - buf = new char[buf_size*2]; - memcpy(buf, old_buf, buf_size); - buf_size *= 2; - a_delete old_buf; - } - } - if ((buf[i] = tok.ch()) == 0) - break; - i++; - tok.next(); - } - if (i == 0) { - empty_name_warning(required); - return NULL_SYMBOL; - } - non_empty_name_warning(); - if (buf == abuf) - return symbol(buf); - else { - symbol s(buf); - a_delete buf; - return s; - } -} - -void exit_troff() -{ - exit_started = 1; - topdiv->set_last_page(); - if (!end_macro_name.is_null()) { - spring_trap(end_macro_name); - tok.next(); - process_input_stack(); - } - curenv->final_break(); - tok.next(); - process_input_stack(); - end_diversions(); - if (topdiv->get_page_length() > 0) { - done_end_macro = 1; - topdiv->set_ejecting(); - static unsigned char buf[2] = { LAST_PAGE_EJECTOR, '\0' }; - input_stack::push(make_temp_iterator((char *)buf)); - topdiv->space(topdiv->get_page_length(), 1); - tok.next(); - process_input_stack(); - seen_last_page_ejector = 1; // should be set already - topdiv->set_ejecting(); - push_page_ejector(); - topdiv->space(topdiv->get_page_length(), 1); - tok.next(); - process_input_stack(); - } - // This will only happen if a trap-invoked macro starts a diversion, - // or if vertical position traps have been disabled. - cleanup_and_exit(0); -} - -// This implements .ex. The input stack must be cleared before calling -// exit_troff(). - -void exit_request() -{ - input_stack::clear(); - if (exit_started) - tok.next(); - else - exit_troff(); -} - -void return_macro_request() -{ - input_stack::pop_macro(); - tok.next(); -} - -void end_macro() -{ - end_macro_name = get_name(); - skip_line(); -} - -void blank_line_macro() -{ - blank_line_macro_name = get_name(); - skip_line(); -} - -static void trapping_blank_line() -{ - if (!blank_line_macro_name.is_null()) - spring_trap(blank_line_macro_name); - else - blank_line(); -} - -void do_request() -{ - int old_compatible_flag = compatible_flag; - compatible_flag = 0; - symbol nm = get_name(); - if (nm.is_null()) - skip_line(); - else - interpolate_macro(nm); - compatible_flag = old_compatible_flag; -} - -inline int possibly_handle_first_page_transition() -{ - if (topdiv->before_first_page && curdiv == topdiv && !curenv->is_dummy()) { - handle_first_page_transition(); - return 1; - } - else - return 0; -} - -static int transparent_translate(int cc) -{ - if (!invalid_input_char(cc)) { - charinfo *ci = charset_table[cc]; - switch (ci->get_special_translation(1)) { - case charinfo::TRANSLATE_SPACE: - return ' '; - case charinfo::TRANSLATE_STRETCHABLE_SPACE: - return ESCAPE_TILDE; - case charinfo::TRANSLATE_DUMMY: - return ESCAPE_AMPERSAND; - case charinfo::TRANSLATE_HYPHEN_INDICATOR: - return ESCAPE_PERCENT; - } - // This is really ugly. - ci = ci->get_translation(1); - if (ci) { - int c = ci->get_ascii_code(); - if (c != '\0') - return c; - error("can't translate %1 to special character `%2'" - " in transparent throughput", - input_char_description(cc), - ci->nm.contents()); - } - } - return cc; -} - -class int_stack { - struct int_stack_element { - int n; - int_stack_element *next; - } *top; -public: - int_stack(); - ~int_stack(); - void push(int); - int is_empty(); - int pop(); -}; - -int_stack::int_stack() -{ - top = 0; -} - -int_stack::~int_stack() -{ - while (top != 0) { - int_stack_element *temp = top; - top = top->next; - delete temp; - } -} - -int int_stack::is_empty() -{ - return top == 0; -} - -void int_stack::push(int n) -{ - int_stack_element *p = new int_stack_element; - p->next = top; - p->n = n; - top = p; -} - -int int_stack::pop() -{ - assert(top != 0); - int_stack_element *p = top; - top = top->next; - int n = p->n; - delete p; - return n; -} - -int node::reread(int *) -{ - return 0; -} - -int diverted_space_node::reread(int *bolp) -{ - if (curenv->get_fill()) - trapping_blank_line(); - else - curdiv->space(n); - *bolp = 1; - return 1; -} - -int diverted_copy_file_node::reread(int *bolp) -{ - curdiv->copy_file(filename.contents()); - *bolp = 1; - return 1; -} - -int word_space_node::reread(int *bolp) -{ - if (unformat) { - for (width_list *w = orig_width; w; w = w->next) - curenv->space(w->width, w->sentence_width); - unformat = 0; - return 1; - } - return 0; -} - -int unbreakable_space_node::reread(int *) -{ - return 0; -} - -int hmotion_node::reread(int *bolp) -{ - if (unformat && was_tab) { - curenv->handle_tab(0); - unformat = 0; - return 1; - } - return 0; -} - -void process_input_stack() -{ - int_stack trap_bol_stack; - int bol = 1; - for (;;) { - int suppress_next = 0; - switch (tok.type) { - case token::TOKEN_CHAR: - { - unsigned char ch = tok.c; - if (bol && !have_input - && (ch == curenv->control_char - || ch == curenv->no_break_control_char)) { - break_flag = ch == curenv->control_char; - // skip tabs as well as spaces here - do { - tok.next(); - } while (tok.white_space()); - symbol nm = get_name(); - if (nm.is_null()) - skip_line(); - else - interpolate_macro(nm); - suppress_next = 1; - have_input = 0; - } - else { - if (possibly_handle_first_page_transition()) - ; - else { - for (;;) { - curenv->add_char(charset_table[ch]); - tok.next(); - if (tok.type != token::TOKEN_CHAR) - break; - ch = tok.c; - } - suppress_next = 1; - bol = 0; - } - } - break; - } - case token::TOKEN_TRANSPARENT: - { - if (bol) { - if (possibly_handle_first_page_transition()) - ; - else { - int cc; - do { - node *n; - cc = get_copy(&n); - if (cc != EOF) - if (cc != '\0') - curdiv->transparent_output(transparent_translate(cc)); - else - curdiv->transparent_output(n); - } while (cc != '\n' && cc != EOF); - if (cc == EOF) - curdiv->transparent_output('\n'); - } - } - break; - } - case token::TOKEN_NEWLINE: - { - if (bol && !have_input - && !curenv->get_prev_line_interrupted()) - trapping_blank_line(); - else { - curenv->newline(); - bol = 1; - have_input = 0; - } - break; - } - case token::TOKEN_REQUEST: - { - int request_code = tok.c; - tok.next(); - switch (request_code) { - case TITLE_REQUEST: - title(); - break; - case COPY_FILE_REQUEST: - copy_file(); - break; - case TRANSPARENT_FILE_REQUEST: - transparent_file(); - break; -#ifdef COLUMN - case VJUSTIFY_REQUEST: - vjustify(); - break; -#endif /* COLUMN */ - default: - assert(0); - break; - } - suppress_next = 1; - have_input = 0; - break; - } - case token::TOKEN_SPACE: - { - if (possibly_handle_first_page_transition()) - ; - else if (bol && !curenv->get_prev_line_interrupted()) { - int nspaces = 0; - // save space_width now so that it isn't changed by \f or \s - // which we wouldn't notice here - hunits space_width = curenv->get_space_width(); - do { - nspaces += tok.nspaces(); - tok.next(); - } while (tok.space()); - if (tok.newline()) - trapping_blank_line(); - else { - push_token(tok); - curenv->do_break(); - curenv->add_node(new hmotion_node(space_width * nspaces, - curenv->get_fill_color())); - bol = 0; - } - } - else { - curenv->space(); - bol = 0; - } - break; - } - case token::TOKEN_EOF: - return; - case token::TOKEN_NODE: - { - if (possibly_handle_first_page_transition()) - ; - else if (tok.nd->reread(&bol)) { - delete tok.nd; - tok.nd = 0; - } - else { - curenv->add_node(tok.nd); - tok.nd = 0; - bol = 0; - curenv->possibly_break_line(1); - } - break; - } - case token::TOKEN_PAGE_EJECTOR: - { - continue_page_eject(); - // I think we just want to preserve bol. - // bol = 1; - break; - } - case token::TOKEN_BEGIN_TRAP: - { - trap_bol_stack.push(bol); - bol = 1; - have_input = 0; - break; - } - case token::TOKEN_END_TRAP: - { - if (trap_bol_stack.is_empty()) - error("spurious end trap token detected!"); - else - bol = trap_bol_stack.pop(); - - /* I'm not totally happy about this. But I can't think of any other - way to do it. Doing an output_pending_lines() whenever a - TOKEN_END_TRAP is detected doesn't work: for example, - - .wh -1i x - .de x - 'bp - .. - .wh -.5i y - .de y - .tl ''-%-'' - .. - .br - .ll .5i - .sp |\n(.pu-1i-.5v - a\%very\%very\%long\%word - - will print all but the first lines from the word immediately - after the footer, rather than on the next page. */ - - if (trap_bol_stack.is_empty()) - curenv->output_pending_lines(); - break; - } - default: - { - bol = 0; - tok.process(); - break; - } - } - if (!suppress_next) - tok.next(); - trap_sprung_flag = 0; - } -} - -#ifdef WIDOW_CONTROL - -void flush_pending_lines() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - curenv->output_pending_lines(); - tok.next(); -} - -#endif /* WIDOW_CONTROL */ - -request_or_macro::request_or_macro() -{ -} - -macro *request_or_macro::to_macro() -{ - return 0; -} - -request::request(REQUEST_FUNCP pp) : p(pp) -{ -} - -void request::invoke(symbol) -{ - (*p)(); -} - -struct char_block { - enum { SIZE = 128 }; - unsigned char s[SIZE]; - char_block *next; - char_block(); -}; - -char_block::char_block() -: next(0) -{ -} - -class char_list { -public: - char_list(); - ~char_list(); - void append(unsigned char); - void set(unsigned char, int); - unsigned char get(int); - int length(); -private: - unsigned char *ptr; - int len; - char_block *head; - char_block *tail; - friend class macro_header; - friend class string_iterator; -}; - -char_list::char_list() -: ptr(0), len(0), head(0), tail(0) -{ -} - -char_list::~char_list() -{ - while (head != 0) { - char_block *tem = head; - head = head->next; - delete tem; - } -} - -int char_list::length() -{ - return len; -} - -void char_list::append(unsigned char c) -{ - if (tail == 0) { - head = tail = new char_block; - ptr = tail->s; - } - else { - if (ptr >= tail->s + char_block::SIZE) { - tail->next = new char_block; - tail = tail->next; - ptr = tail->s; - } - } - *ptr++ = c; - len++; -} - -void char_list::set(unsigned char c, int offset) -{ - assert(len > offset); - // optimization for access at the end - int boundary = len - len % char_block::SIZE; - if (offset >= boundary) { - *(tail->s + offset - boundary) = c; - return; - } - char_block *tem = head; - int l = 0; - for (;;) { - l += char_block::SIZE; - if (l > offset) { - *(tem->s + offset % char_block::SIZE) = c; - return; - } - tem = tem->next; - } -} - -unsigned char char_list::get(int offset) -{ - assert(len > offset); - // optimization for access at the end - int boundary = len - len % char_block::SIZE; - if (offset >= boundary) - return *(tail->s + offset - boundary); - char_block *tem = head; - int l = 0; - for (;;) { - l += char_block::SIZE; - if (l > offset) - return *(tem->s + offset % char_block::SIZE); - tem = tem->next; - } -} - -class node_list { - node *head; - node *tail; -public: - node_list(); - ~node_list(); - void append(node *); - int length(); - node *extract(); - - friend class macro_header; - friend class string_iterator; -}; - -void node_list::append(node *n) -{ - if (head == 0) { - n->next = 0; - head = tail = n; - } - else { - n->next = 0; - tail = tail->next = n; - } -} - -int node_list::length() -{ - int total = 0; - for (node *n = head; n != 0; n = n->next) - ++total; - return total; -} - -node_list::node_list() -{ - head = tail = 0; -} - -node *node_list::extract() -{ - node *temp = head; - head = tail = 0; - return temp; -} - -node_list::~node_list() -{ - delete_node_list(head); -} - -struct macro_header { -public: - int count; - char_list cl; - node_list nl; - macro_header() { count = 1; } - macro_header *copy(int); -}; - -macro::~macro() -{ - if (p != 0 && --(p->count) <= 0) - delete p; -} - -macro::macro() -{ - if (!input_stack::get_location(1, &filename, &lineno)) { - filename = 0; - lineno = 0; - } - len = 0; - empty_macro = 1; - p = 0; -} - -macro::macro(const macro &m) -: p(m.p), filename(m.filename), lineno(m.lineno), len(m.len), - empty_macro(m.empty_macro) -{ - if (p != 0) - p->count++; -} - -macro ¯o::operator=(const macro &m) -{ - // don't assign object - if (m.p != 0) - m.p->count++; - if (p != 0 && --(p->count) <= 0) - delete p; - p = m.p; - filename = m.filename; - lineno = m.lineno; - len = m.len; - empty_macro = m.empty_macro; - return *this; -} - -void macro::append(unsigned char c) -{ - assert(c != 0); - if (p == 0) - p = new macro_header; - if (p->cl.length() != len) { - macro_header *tem = p->copy(len); - if (--(p->count) <= 0) - delete p; - p = tem; - } - p->cl.append(c); - ++len; - if (c != COMPATIBLE_SAVE && c != COMPATIBLE_RESTORE) - empty_macro = 0; -} - -void macro::set(unsigned char c, int offset) -{ - assert(p != 0); - assert(c != 0); - p->cl.set(c, offset); -} - -unsigned char macro::get(int offset) -{ - assert(p != 0); - return p->cl.get(offset); -} - -int macro::length() -{ - return len; -} - -void macro::append_str(const char *s) -{ - int i = 0; - - if (s) { - while (s[i] != (char)0) { - append(s[i]); - i++; - } - } -} - -void macro::append(node *n) -{ - assert(n != 0); - if (p == 0) - p = new macro_header; - if (p->cl.length() != len) { - macro_header *tem = p->copy(len); - if (--(p->count) <= 0) - delete p; - p = tem; - } - p->cl.append(0); - p->nl.append(n); - ++len; - empty_macro = 0; -} - -void macro::append_unsigned(unsigned int i) -{ - unsigned int j = i / 10; - if (j != 0) - append_unsigned(j); - append(((unsigned char)(((int)'0') + i % 10))); -} - -void macro::append_int(int i) -{ - if (i < 0) { - append('-'); - i = -i; - } - append_unsigned((unsigned int)i); -} - -void macro::print_size() -{ - errprint("%1", len); -} - -// make a copy of the first n bytes - -macro_header *macro_header::copy(int n) -{ - macro_header *p = new macro_header; - char_block *bp = cl.head; - unsigned char *ptr = bp->s; - node *nd = nl.head; - while (--n >= 0) { - if (ptr >= bp->s + char_block::SIZE) { - bp = bp->next; - ptr = bp->s; - } - int c = *ptr++; - p->cl.append(c); - if (c == 0) { - p->nl.append(nd->copy()); - nd = nd->next; - } - } - return p; -} - -void print_macros() -{ - object_dictionary_iterator iter(request_dictionary); - request_or_macro *rm; - symbol s; - while (iter.get(&s, (object **)&rm)) { - assert(!s.is_null()); - macro *m = rm->to_macro(); - if (m) { - errprint("%1\t", s.contents()); - m->print_size(); - errprint("\n"); - } - } - fflush(stderr); - skip_line(); -} - -class string_iterator : public input_iterator { - macro mac; - const char *how_invoked; - int newline_flag; - int lineno; - char_block *bp; - int count; // of characters remaining - node *nd; - int saved_compatible_flag; -protected: - symbol nm; - string_iterator(); -public: - string_iterator(const macro &m, const char *p = 0, symbol s = NULL_SYMBOL); - int fill(node **); - int peek(); - int get_location(int, const char **, int *); - void backtrace(); - void save_compatible_flag(int f) { saved_compatible_flag = f; } - int get_compatible_flag() { return saved_compatible_flag; } -}; - -string_iterator::string_iterator(const macro &m, const char *p, symbol s) -: mac(m), how_invoked(p), - newline_flag(0), lineno(1), nm(s) -{ - count = mac.len; - if (count != 0) { - bp = mac.p->cl.head; - nd = mac.p->nl.head; - ptr = eptr = bp->s; - } - else { - bp = 0; - nd = 0; - ptr = eptr = 0; - } -} - -string_iterator::string_iterator() -{ - bp = 0; - nd = 0; - ptr = eptr = 0; - newline_flag = 0; - how_invoked = 0; - lineno = 1; - count = 0; -} - -int string_iterator::fill(node **np) -{ - if (newline_flag) - lineno++; - newline_flag = 0; - if (count <= 0) - return EOF; - const unsigned char *p = eptr; - if (p >= bp->s + char_block::SIZE) { - bp = bp->next; - p = bp->s; - } - if (*p == '\0') { - if (np) - *np = nd->copy(); - nd = nd->next; - eptr = ptr = p + 1; - count--; - return 0; - } - const unsigned char *e = bp->s + char_block::SIZE; - if (e - p > count) - e = p + count; - ptr = p; - while (p < e) { - unsigned char c = *p; - if (c == '\n' || c == ESCAPE_NEWLINE) { - newline_flag = 1; - p++; - break; - } - if (c == '\0') - break; - p++; - } - eptr = p; - count -= p - ptr; - return *ptr++; -} - -int string_iterator::peek() -{ - if (count <= 0) - return EOF; - const unsigned char *p = eptr; - if (p >= bp->s + char_block::SIZE) { - p = bp->next->s; - } - return *p; -} - -int string_iterator::get_location(int allow_macro, - const char **filep, int *linep) -{ - if (!allow_macro) - return 0; - if (mac.filename == 0) - return 0; - *filep = mac.filename; - *linep = mac.lineno + lineno - 1; - return 1; -} - -void string_iterator::backtrace() -{ - if (mac.filename) { - errprint("%1:%2: backtrace", mac.filename, mac.lineno + lineno - 1); - if (how_invoked) { - if (!nm.is_null()) - errprint(": %1 `%2'\n", how_invoked, nm.contents()); - else - errprint(": %1\n", how_invoked); - } - else - errprint("\n"); - } -} - -class temp_iterator : public input_iterator { - unsigned char *base; - temp_iterator(const char *, int len); -public: - ~temp_iterator(); - friend input_iterator *make_temp_iterator(const char *); -}; - -#ifdef __GNUG__ -inline -#endif -temp_iterator::temp_iterator(const char *s, int len) -{ - base = new unsigned char[len]; - memcpy(base, s, len); - ptr = base; - eptr = base + len; -} - -temp_iterator::~temp_iterator() -{ - a_delete base; -} - -class small_temp_iterator : public input_iterator { -private: - small_temp_iterator(const char *, int); - ~small_temp_iterator(); - enum { BLOCK = 16 }; - static small_temp_iterator *free_list; - void *operator new(size_t); - void operator delete(void *); - enum { SIZE = 12 }; - unsigned char buf[SIZE]; - friend input_iterator *make_temp_iterator(const char *); -}; - -small_temp_iterator *small_temp_iterator::free_list = 0; - -void *small_temp_iterator::operator new(size_t n) -{ - assert(n == sizeof(small_temp_iterator)); - if (!free_list) { - free_list = - (small_temp_iterator *)new char[sizeof(small_temp_iterator)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - small_temp_iterator *p = free_list; - free_list = (small_temp_iterator *)(free_list->next); - p->next = 0; - return p; -} - -#ifdef __GNUG__ -inline -#endif -void small_temp_iterator::operator delete(void *p) -{ - if (p) { - ((small_temp_iterator *)p)->next = free_list; - free_list = (small_temp_iterator *)p; - } -} - -small_temp_iterator::~small_temp_iterator() -{ -} - -#ifdef __GNUG__ -inline -#endif -small_temp_iterator::small_temp_iterator(const char *s, int len) -{ - for (int i = 0; i < len; i++) - buf[i] = s[i]; - ptr = buf; - eptr = buf + len; -} - -input_iterator *make_temp_iterator(const char *s) -{ - if (s == 0) - return new small_temp_iterator(s, 0); - else { - int n = strlen(s); - if (n <= small_temp_iterator::SIZE) - return new small_temp_iterator(s, n); - else - return new temp_iterator(s, n); - } -} - -// this is used when macros with arguments are interpolated - -struct arg_list { - macro mac; - arg_list *next; - arg_list(const macro &); - ~arg_list(); -}; - -arg_list::arg_list(const macro &m) : mac(m), next(0) -{ -} - -arg_list::~arg_list() -{ -} - -class macro_iterator : public string_iterator { - arg_list *args; - int argc; -public: - macro_iterator(symbol, macro &, const char *how_invoked = "macro"); - macro_iterator(); - ~macro_iterator(); - int has_args() { return 1; } - input_iterator *get_arg(int i); - int nargs() { return argc; } - void add_arg(const macro &m); - void shift(int n); - int is_macro() { return 1; } -}; - -input_iterator *macro_iterator::get_arg(int i) -{ - if (i == 0) - return make_temp_iterator(nm.contents()); - if (i > 0 && i <= argc) { - arg_list *p = args; - for (int j = 1; j < i; j++) { - assert(p != 0); - p = p->next; - } - return new string_iterator(p->mac); - } - else - return 0; -} - -void macro_iterator::add_arg(const macro &m) -{ - arg_list **p; - for (p = &args; *p; p = &((*p)->next)) - ; - *p = new arg_list(m); - ++argc; -} - -void macro_iterator::shift(int n) -{ - while (n > 0 && argc > 0) { - arg_list *tem = args; - args = args->next; - delete tem; - --argc; - --n; - } -} - -// This gets used by eg .if '\?xxx\?''. - -int operator==(const macro &m1, const macro &m2) -{ - if (m1.len != m2.len) - return 0; - string_iterator iter1(m1); - string_iterator iter2(m2); - int n = m1.len; - while (--n >= 0) { - node *nd1 = 0; - int c1 = iter1.get(&nd1); - assert(c1 != EOF); - node *nd2 = 0; - int c2 = iter2.get(&nd2); - assert(c2 != EOF); - if (c1 != c2) { - if (c1 == 0) - delete nd1; - else if (c2 == 0) - delete nd2; - return 0; - } - if (c1 == 0) { - assert(nd1 != 0); - assert(nd2 != 0); - int are_same = nd1->type() == nd2->type() && nd1->same(nd2); - delete nd1; - delete nd2; - if (!are_same) - return 0; - } - } - return 1; -} - -static void interpolate_macro(symbol nm) -{ - request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm); - if (p == 0) { - int warned = 0; - const char *s = nm.contents(); - if (strlen(s) > 2) { - request_or_macro *r; - char buf[3]; - buf[0] = s[0]; - buf[1] = s[1]; - buf[2] = '\0'; - r = (request_or_macro *)request_dictionary.lookup(symbol(buf)); - if (r) { - macro *m = r->to_macro(); - if (!m || !m->empty()) - warned = warning(WARN_SPACE, - "`%1' not defined (probable missing space after `%2')", - nm.contents(), buf); - } - } - if (!warned) { - warning(WARN_MAC, "`%1' not defined", nm.contents()); - p = new macro; - request_dictionary.define(nm, p); - } - } - if (p) - p->invoke(nm); - else { - skip_line(); - return; - } -} - -static void decode_args(macro_iterator *mi) -{ - if (!tok.newline() && !tok.eof()) { - node *n; - int c = get_copy(&n); - for (;;) { - while (c == ' ') - c = get_copy(&n); - if (c == '\n' || c == EOF) - break; - macro arg; - int quote_input_level = 0; - int done_tab_warning = 0; - if (c == '\"') { - quote_input_level = input_stack::get_level(); - c = get_copy(&n); - } - while (c != EOF && c != '\n' && !(c == ' ' && quote_input_level == 0)) { - if (quote_input_level > 0 && c == '\"' - && (compatible_flag - || input_stack::get_level() == quote_input_level)) { - c = get_copy(&n); - if (c == '"') { - arg.append(c); - c = get_copy(&n); - } - else - break; - } - else { - if (c == 0) - arg.append(n); - else { - if (c == '\t' && quote_input_level == 0 && !done_tab_warning) { - warning(WARN_TAB, "tab character in unquoted macro argument"); - done_tab_warning = 1; - } - arg.append(c); - } - c = get_copy(&n); - } - } - mi->add_arg(arg); - } - } -} - -static void decode_string_args(macro_iterator *mi) -{ - node *n; - int c = get_copy(&n); - for (;;) { - while (c == ' ') - c = get_copy(&n); - if (c == '\n' || c == EOF) { - error("missing `]'"); - break; - } - if (c == ']') - break; - macro arg; - int quote_input_level = 0; - int done_tab_warning = 0; - if (c == '\"') { - quote_input_level = input_stack::get_level(); - c = get_copy(&n); - } - while (c != EOF && c != '\n' - && !(c == ']' && quote_input_level == 0) - && !(c == ' ' && quote_input_level == 0)) { - if (quote_input_level > 0 && c == '\"' - && input_stack::get_level() == quote_input_level) { - c = get_copy(&n); - if (c == '"') { - arg.append(c); - c = get_copy(&n); - } - else - break; - } - else { - if (c == 0) - arg.append(n); - else { - if (c == '\t' && quote_input_level == 0 && !done_tab_warning) { - warning(WARN_TAB, "tab character in unquoted string argument"); - done_tab_warning = 1; - } - arg.append(c); - } - c = get_copy(&n); - } - } - mi->add_arg(arg); - } -} - -void macro::invoke(symbol nm) -{ - macro_iterator *mi = new macro_iterator(nm, *this); - decode_args(mi); - input_stack::push(mi); - tok.next(); -} - -macro *macro::to_macro() -{ - return this; -} - -int macro::empty() -{ - return empty_macro == 1; -} - -macro_iterator::macro_iterator(symbol s, macro &m, const char *how_invoked) -: string_iterator(m, how_invoked, s), args(0), argc(0) -{ -} - -macro_iterator::macro_iterator() : args(0), argc(0) -{ -} - -macro_iterator::~macro_iterator() -{ - while (args != 0) { - arg_list *tem = args; - args = args->next; - delete tem; - } -} - -int trap_sprung_flag = 0; -int postpone_traps_flag = 0; -symbol postponed_trap; - -void spring_trap(symbol nm) -{ - assert(!nm.is_null()); - trap_sprung_flag = 1; - if (postpone_traps_flag) { - postponed_trap = nm; - return; - } - static char buf[2] = { BEGIN_TRAP, 0 }; - static char buf2[2] = { END_TRAP, '\0' }; - input_stack::push(make_temp_iterator(buf2)); - request_or_macro *p = lookup_request(nm); - macro *m = p->to_macro(); - if (m) - input_stack::push(new macro_iterator(nm, *m, "trap-invoked macro")); - else - error("you can't invoke a request with a trap"); - input_stack::push(make_temp_iterator(buf)); -} - -void postpone_traps() -{ - postpone_traps_flag = 1; -} - -int unpostpone_traps() -{ - postpone_traps_flag = 0; - if (!postponed_trap.is_null()) { - spring_trap(postponed_trap); - postponed_trap = NULL_SYMBOL; - return 1; - } - else - return 0; -} - -void read_request() -{ - macro_iterator *mi = new macro_iterator; - int reading_from_terminal = isatty(fileno(stdin)); - int had_prompt = 0; - if (!tok.newline() && !tok.eof()) { - int c = get_copy(0); - while (c == ' ') - c = get_copy(0); - while (c != EOF && c != '\n' && c != ' ') { - if (!invalid_input_char(c)) { - if (reading_from_terminal) - fputc(c, stderr); - had_prompt = 1; - } - c = get_copy(0); - } - if (c == ' ') { - tok.make_space(); - decode_args(mi); - } - } - if (reading_from_terminal) { - fputc(had_prompt ? ':' : '\a', stderr); - fflush(stderr); - } - input_stack::push(mi); - macro mac; - int nl = 0; - int c; - while ((c = getchar()) != EOF) { - if (invalid_input_char(c)) - warning(WARN_INPUT, "invalid input character code %1", int(c)); - else { - if (c == '\n') { - if (nl) - break; - else - nl = 1; - } - else - nl = 0; - mac.append(c); - } - } - if (reading_from_terminal) - clearerr(stdin); - input_stack::push(new string_iterator(mac)); - tok.next(); -} - -enum define_mode { DEFINE_NORMAL, DEFINE_APPEND, DEFINE_IGNORE }; -enum calling_mode { CALLING_NORMAL, CALLING_INDIRECT, CALLING_DISABLE_COMP }; - -void do_define_string(define_mode mode, calling_mode calling) -{ - symbol nm; - node *n; - int c; - nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - if (tok.newline()) - c = '\n'; - else if (tok.tab()) - c = '\t'; - else if (!tok.space()) { - error("bad string definition"); - skip_line(); - return; - } - else - c = get_copy(&n); - while (c == ' ') - c = get_copy(&n); - if (c == '"') - c = get_copy(&n); - macro mac; - request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); - macro *mm = rm ? rm->to_macro() : 0; - if (mode == DEFINE_APPEND && mm) - mac = *mm; - if (calling == CALLING_DISABLE_COMP) - mac.append(COMPATIBLE_SAVE); - while (c != '\n' && c != EOF) { - if (c == 0) - mac.append(n); - else - mac.append((unsigned char)c); - c = get_copy(&n); - } - if (!mm) { - mm = new macro; - request_dictionary.define(nm, mm); - } - if (calling == CALLING_DISABLE_COMP) - mac.append(COMPATIBLE_RESTORE); - *mm = mac; - tok.next(); -} - -void define_string() -{ - do_define_string(DEFINE_NORMAL, CALLING_NORMAL); -} - -void define_nocomp_string() -{ - do_define_string(DEFINE_NORMAL, CALLING_DISABLE_COMP); -} - -void append_string() -{ - do_define_string(DEFINE_APPEND, CALLING_NORMAL); -} - -void append_nocomp_string() -{ - do_define_string(DEFINE_APPEND, CALLING_DISABLE_COMP); -} - -void do_define_character(int fallback) -{ - node *n; - int c; - tok.skip(); - charinfo *ci = tok.get_char(1); - if (ci == 0) { - skip_line(); - return; - } - tok.next(); - if (tok.newline()) - c = '\n'; - else if (tok.tab()) - c = '\t'; - else if (!tok.space()) { - error("bad character definition"); - skip_line(); - return; - } - else - c = get_copy(&n); - while (c == ' ' || c == '\t') - c = get_copy(&n); - if (c == '"') - c = get_copy(&n); - macro *m = new macro; - while (c != '\n' && c != EOF) { - if (c == 0) - m->append(n); - else - m->append((unsigned char)c); - c = get_copy(&n); - } - m = ci->set_macro(m, fallback); - if (m) - delete m; - tok.next(); -} - -void define_character() -{ - do_define_character(0); -} - -void define_fallback_character() -{ - do_define_character(1); -} - -static void remove_character() -{ - tok.skip(); - while (!tok.newline() && !tok.eof()) { - if (!tok.space() && !tok.tab()) { - charinfo *ci = tok.get_char(1); - if (!ci) - break; - macro *m = ci->set_macro(0); - if (m) - delete m; - } - tok.next(); - } - skip_line(); -} - -static void interpolate_string(symbol nm) -{ - request_or_macro *p = lookup_request(nm); - macro *m = p->to_macro(); - if (!m) - error("you can only invoke a string or macro using \\*"); - else { - string_iterator *si = new string_iterator(*m, "string", nm); - input_stack::push(si); - } -} - -static void interpolate_string_with_args(symbol s) -{ - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("you can only invoke a string or macro using \\*"); - else { - macro_iterator *mi = new macro_iterator(s, *m); - decode_string_args(mi); - input_stack::push(mi); - } -} - -/* This class is used for the implementation of \$@. It is used for -each of the closing double quotes. It artificially increases the -input level by 2, so that the closing double quote will appear to have -the same input level as the opening quote. */ - -class end_quote_iterator : public input_iterator { - unsigned char buf[1]; -public: - end_quote_iterator(); - ~end_quote_iterator() { } - int internal_level() { return 2; } -}; - -end_quote_iterator::end_quote_iterator() -{ - buf[0] = '"'; - ptr = buf; - eptr = buf + 1; -} - -static void interpolate_arg(symbol nm) -{ - const char *s = nm.contents(); - if (!s || *s == '\0') - copy_mode_error("missing argument name"); - else if (s[1] == 0 && csdigit(s[0])) - input_stack::push(input_stack::get_arg(s[0] - '0')); - else if (s[0] == '*' && s[1] == '\0') { - for (int i = input_stack::nargs(); i > 0; i--) { - input_stack::push(input_stack::get_arg(i)); - if (i != 1) - input_stack::push(make_temp_iterator(" ")); - } - } - else if (s[0] == '@' && s[1] == '\0') { - for (int i = input_stack::nargs(); i > 0; i--) { - input_stack::push(new end_quote_iterator); - input_stack::push(input_stack::get_arg(i)); - input_stack::push(make_temp_iterator(i == 1 ? "\"" : " \"")); - } - } - else { - const char *p; - for (p = s; *p && csdigit(*p); p++) - ; - if (*p) - copy_mode_error("bad argument name `%1'", s); - else - input_stack::push(input_stack::get_arg(atoi(s))); - } -} - -void handle_first_page_transition() -{ - push_token(tok); - topdiv->begin_page(); -} - -// We push back a token by wrapping it up in a token_node, and -// wrapping that up in a string_iterator. - -static void push_token(const token &t) -{ - macro m; - m.append(new token_node(t)); - input_stack::push(new string_iterator(m)); -} - -void push_page_ejector() -{ - static char buf[2] = { PAGE_EJECTOR, '\0' }; - input_stack::push(make_temp_iterator(buf)); -} - -void handle_initial_request(unsigned char code) -{ - char buf[2]; - buf[0] = code; - buf[1] = '\0'; - macro mac; - mac.append(new token_node(tok)); - input_stack::push(new string_iterator(mac)); - input_stack::push(make_temp_iterator(buf)); - topdiv->begin_page(); - tok.next(); -} - -void handle_initial_title() -{ - handle_initial_request(TITLE_REQUEST); -} - -// this should be local to define_macro, but cfront 1.2 doesn't support that -static symbol dot_symbol("."); - -void do_define_macro(define_mode mode, calling_mode calling) -{ - symbol nm, term; - if (calling == CALLING_INDIRECT) { - symbol temp1 = get_name(1); - if (temp1.is_null()) { - skip_line(); - return; - } - symbol temp2 = get_name(); - input_stack::push(make_temp_iterator("\n")); - if (!temp2.is_null()) { - interpolate_string(temp2); - input_stack::push(make_temp_iterator(" ")); - } - interpolate_string(temp1); - input_stack::push(make_temp_iterator(" ")); - tok.next(); - } - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - } - term = get_name(); // the request that terminates the definition - if (term.is_null()) - term = dot_symbol; - while (!tok.newline() && !tok.eof()) - tok.next(); - const char *start_filename; - int start_lineno; - int have_start_location = input_stack::get_location(0, &start_filename, - &start_lineno); - node *n; - // doing this here makes the line numbers come out right - int c = get_copy(&n, 1); - macro mac; - macro *mm = 0; - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - request_or_macro *rm = - (request_or_macro *)request_dictionary.lookup(nm); - if (rm) - mm = rm->to_macro(); - if (mm && mode == DEFINE_APPEND) - mac = *mm; - } - int bol = 1; - if (calling == CALLING_DISABLE_COMP) - mac.append(COMPATIBLE_SAVE); - for (;;) { - while (c == ESCAPE_NEWLINE) { - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) - mac.append(c); - c = get_copy(&n, 1); - } - if (bol && c == '.') { - const char *s = term.contents(); - int d = 0; - // see if it matches term - int i = 0; - if (s[0] != 0) { - while ((d = get_copy(&n)) == ' ' || d == '\t') - ; - if ((unsigned char)s[0] == d) { - for (i = 1; s[i] != 0; i++) { - d = get_copy(&n); - if ((unsigned char)s[i] != d) - break; - } - } - } - if (s[i] == 0 - && ((i == 2 && compatible_flag) - || (d = get_copy(&n)) == ' ' - || d == '\n')) { // we found it - if (d == '\n') - tok.make_newline(); - else - tok.make_space(); - if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { - if (!mm) { - mm = new macro; - request_dictionary.define(nm, mm); - } - if (calling == CALLING_DISABLE_COMP) - mac.append(COMPATIBLE_RESTORE); - *mm = mac; - } - if (term != dot_symbol) { - ignoring = 0; - interpolate_macro(term); - } - else - skip_line(); - return; - } - if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { - mac.append(c); - for (int j = 0; j < i; j++) - mac.append(s[j]); - } - c = d; - } - if (c == EOF) { - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - if (have_start_location) - error_with_file_and_line(start_filename, start_lineno, - "end of file while defining macro `%1'", - nm.contents()); - else - error("end of file while defining macro `%1'", nm.contents()); - } - else { - if (have_start_location) - error_with_file_and_line(start_filename, start_lineno, - "end of file while ignoring input lines"); - else - error("end of file while ignoring input lines"); - } - tok.next(); - return; - } - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - if (c == 0) - mac.append(n); - else - mac.append(c); - } - bol = (c == '\n'); - c = get_copy(&n, 1); - } -} - -void define_macro() -{ - do_define_macro(DEFINE_NORMAL, CALLING_NORMAL); -} - -void define_nocomp_macro() -{ - do_define_macro(DEFINE_NORMAL, CALLING_DISABLE_COMP); -} - -void define_indirect_macro() -{ - do_define_macro(DEFINE_NORMAL, CALLING_INDIRECT); -} - -void append_macro() -{ - do_define_macro(DEFINE_APPEND, CALLING_NORMAL); -} - -void append_indirect_macro() -{ - do_define_macro(DEFINE_APPEND, CALLING_INDIRECT); -} - -void append_nocomp_macro() -{ - do_define_macro(DEFINE_APPEND, CALLING_DISABLE_COMP); -} - -void ignore() -{ - ignoring = 1; - do_define_macro(DEFINE_IGNORE, CALLING_NORMAL); - ignoring = 0; -} - -void remove_macro() -{ - for (;;) { - symbol s = get_name(); - if (s.is_null()) - break; - request_dictionary.remove(s); - } - skip_line(); -} - -void rename_macro() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) - request_dictionary.rename(s1, s2); - } - skip_line(); -} - -void alias_macro() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) { - if (!request_dictionary.alias(s1, s2)) - warning(WARN_MAC, "`%1' not defined", s2.contents()); - } - } - skip_line(); -} - -void chop_macro() -{ - symbol s = get_name(1); - if (!s.is_null()) { - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot chop request"); - else if (m->empty()) - error("cannot chop empty macro"); - else { - int have_restore = 0; - // we have to check for additional save/restore pairs which could be - // there due to empty am1 requests. - for (;;) { - if (m->get(m->len - 1) != COMPATIBLE_RESTORE) - break; - have_restore = 1; - m->len -= 1; - if (m->get(m->len - 1) != COMPATIBLE_SAVE) - break; - have_restore = 0; - m->len -= 1; - if (m->len == 0) - break; - } - if (m->len == 0) - error("cannot chop empty macro"); - else { - if (have_restore) - m->set(COMPATIBLE_RESTORE, m->len - 1); - else - m->len -= 1; - } - } - } - skip_line(); -} - -void substring_request() -{ - int start; // 0, 1, ..., n-1 or -1, -2, ... - symbol s = get_name(1); - if (!s.is_null() && get_integer(&start)) { - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot apply `substring' on a request"); - else { - int end = -1; - if (!has_arg() || get_integer(&end)) { - int real_length = 0; // 1, 2, ..., n - string_iterator iter1(*m); - for (int l = 0; l < m->len; l++) { - int c = iter1.get(0); - if (c == COMPATIBLE_SAVE || c == COMPATIBLE_RESTORE) - continue; - if (c == EOF) - break; - real_length++; - } - if (start < 0) - start += real_length; - if (end < 0) - end += real_length; - if (start > end) { - int tem = start; - start = end; - end = tem; - } - if (start >= real_length || end < 0) { - warning(WARN_RANGE, - "start and end index of substring out of range"); - m->len = 0; - if (m->p) { - if (--(m->p->count) <= 0) - delete m->p; - m->p = 0; - } - skip_line(); - return; - } - if (start < 0) { - warning(WARN_RANGE, - "start index of substring out of range, set to 0"); - start = 0; - } - if (end >= real_length) { - warning(WARN_RANGE, - "end index of substring out of range, set to string length"); - end = real_length - 1; - } - // now extract the substring - string_iterator iter(*m); - int i; - for (i = 0; i < start; i++) { - int c = iter.get(0); - while (c == COMPATIBLE_SAVE || c == COMPATIBLE_RESTORE) - c = iter.get(0); - if (c == EOF) - break; - } - macro mac; - for (; i <= end; i++) { - node *nd; - int c = iter.get(&nd); - while (c == COMPATIBLE_SAVE || c == COMPATIBLE_RESTORE) - c = iter.get(0); - if (c == EOF) - break; - if (c == 0) - mac.append(nd); - else - mac.append((unsigned char)c); - } - *m = mac; - } - } - } - skip_line(); -} - -void length_request() -{ - symbol ret; - ret = get_name(1); - if (ret.is_null()) { - skip_line(); - return; - } - int c; - node *n; - if (tok.newline()) - c = '\n'; - else if (tok.tab()) - c = '\t'; - else if (!tok.space()) { - error("bad string definition"); - skip_line(); - return; - } - else - c = get_copy(&n); - while (c == ' ') - c = get_copy(&n); - if (c == '"') - c = get_copy(&n); - int len = 0; - while (c != '\n' && c != EOF) { - ++len; - c = get_copy(&n); - } - reg *r = (reg*)number_reg_dictionary.lookup(ret); - if (r) - r->set_value(len); - else - set_number_reg(ret, len); - tok.next(); -} - -void asciify_macro() -{ - symbol s = get_name(1); - if (!s.is_null()) { - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot asciify request"); - else { - macro am; - string_iterator iter(*m); - for (;;) { - node *nd; - int c = iter.get(&nd); - if (c == EOF) - break; - if (c != 0) - am.append(c); - else - nd->asciify(&am); - } - *m = am; - } - } - skip_line(); -} - -void unformat_macro() -{ - symbol s = get_name(1); - if (!s.is_null()) { - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot unformat request"); - else { - macro am; - string_iterator iter(*m); - for (;;) { - node *nd; - int c = iter.get(&nd); - if (c == EOF) - break; - if (c != 0) - am.append(c); - else { - if (nd->set_unformat_flag()) - am.append(nd); - } - } - *m = am; - } - } - skip_line(); -} - -static void interpolate_environment_variable(symbol nm) -{ - const char *s = getenv(nm.contents()); - if (s && *s) - input_stack::push(make_temp_iterator(s)); -} - -void interpolate_number_reg(symbol nm, int inc) -{ - reg *r = lookup_number_reg(nm); - if (inc < 0) - r->decrement(); - else if (inc > 0) - r->increment(); - input_stack::push(make_temp_iterator(r->get_string())); -} - -static void interpolate_number_format(symbol nm) -{ - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r) - input_stack::push(make_temp_iterator(r->get_format())); -} - -static int get_delim_number(units *n, int si, int prev_value) -{ - token start; - start.next(); - if (start.delimiter(1)) { - tok.next(); - if (get_number(n, si, prev_value)) { - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - return 1; - } - } - return 0; -} - -static int get_delim_number(units *n, int si) -{ - token start; - start.next(); - if (start.delimiter(1)) { - tok.next(); - if (get_number(n, si)) { - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - return 1; - } - } - return 0; -} - -static int get_line_arg(units *n, int si, charinfo **cp) -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - if (!start.delimiter(1)) - return 0; - tok.next(); - if (get_number(n, si)) { - if (tok.dummy() || tok.transparent_dummy()) - tok.next(); - if (!(start == tok && input_stack::get_level() == start_level)) { - *cp = tok.get_char(1); - tok.next(); - } - if (!(start == tok && input_stack::get_level() == start_level)) - warning(WARN_DELIM, "closing delimiter does not match"); - return 1; - } - return 0; -} - -static int read_size(int *x) -{ - tok.next(); - int c = tok.ch(); - int inc = 0; - if (c == '-') { - inc = -1; - tok.next(); - c = tok.ch(); - } - else if (c == '+') { - inc = 1; - tok.next(); - c = tok.ch(); - } - int val; - int bad = 0; - if (c == '(') { - tok.next(); - c = tok.ch(); - if (!inc) { - // allow an increment either before or after the left parenthesis - if (c == '-') { - inc = -1; - tok.next(); - c = tok.ch(); - } - else if (c == '+') { - inc = 1; - tok.next(); - c = tok.ch(); - } - } - if (!csdigit(c)) - bad = 1; - else { - val = c - '0'; - tok.next(); - c = tok.ch(); - if (!csdigit(c)) - bad = 1; - else { - val = val*10 + (c - '0'); - val *= sizescale; - } - } - } - else if (csdigit(c)) { - val = c - '0'; - if (!inc && c != '0' && c < '4') { - tok.next(); - c = tok.ch(); - if (!csdigit(c)) - bad = 1; - else - val = val*10 + (c - '0'); - } - val *= sizescale; - } - else if (!tok.delimiter(1)) - return 0; - else { - token start(tok); - tok.next(); - if (!(inc - ? get_number(&val, 'z') - : get_number(&val, 'z', curenv->get_requested_point_size()))) - return 0; - if (!(start.ch() == '[' && tok.ch() == ']') && start != tok) { - if (start.ch() == '[') - error("missing `]'"); - else - error("missing closing delimiter"); - return 0; - } - } - if (!bad) { - switch (inc) { - case 0: - if (val == 0) { - // special case -- \s[0] and \s0 means to revert to previous size - *x = 0; - return 1; - } - *x = val; - break; - case 1: - *x = curenv->get_requested_point_size() + val; - break; - case -1: - *x = curenv->get_requested_point_size() - val; - break; - default: - assert(0); - } - if (*x <= 0) { - warning(WARN_RANGE, - "\\s request results in non-positive point size; set to 1"); - *x = 1; - } - return 1; - } - else { - error("bad digit in point size"); - return 0; - } -} - -static symbol get_delim_name() -{ - token start; - start.next(); - if (start.eof()) { - error("end of input at start of delimited name"); - return NULL_SYMBOL; - } - if (start.newline()) { - error("can't delimit name with a newline"); - return NULL_SYMBOL; - } - int start_level = input_stack::get_level(); - char abuf[ABUF_SIZE]; - char *buf = abuf; - int buf_size = ABUF_SIZE; - int i = 0; - for (;;) { - if (i + 1 > buf_size) { - if (buf == abuf) { - buf = new char[ABUF_SIZE*2]; - memcpy(buf, abuf, buf_size); - buf_size = ABUF_SIZE*2; - } - else { - char *old_buf = buf; - buf = new char[buf_size*2]; - memcpy(buf, old_buf, buf_size); - buf_size *= 2; - a_delete old_buf; - } - } - tok.next(); - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - if ((buf[i] = tok.ch()) == 0) { - error("missing delimiter (got %1)", tok.description()); - if (buf != abuf) - a_delete buf; - return NULL_SYMBOL; - } - i++; - } - buf[i] = '\0'; - if (buf == abuf) { - if (i == 0) { - error("empty delimited name"); - return NULL_SYMBOL; - } - else - return symbol(buf); - } - else { - symbol s(buf); - a_delete buf; - return s; - } -} - -// Implement \R - -static void do_register() -{ - token start; - start.next(); - if (!start.delimiter(1)) - return; - tok.next(); - symbol nm = get_long_name(1); - if (nm.is_null()) - return; - while (tok.space()) - tok.next(); - reg *r = (reg *)number_reg_dictionary.lookup(nm); - int prev_value; - if (!r || !r->get_value(&prev_value)) - prev_value = 0; - int val; - if (!get_number(&val, 'u', prev_value)) - return; - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - if (r) - r->set_value(val); - else - set_number_reg(nm, val); -} - -// this implements the \w escape sequence - -static void do_width() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - environment env(curenv); - environment *oldenv = curenv; - curenv = &env; - for (;;) { - tok.next(); - if (tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok.newline()) { - warning(WARN_DELIM, "missing closing delimiter"); - input_stack::push(make_temp_iterator("\n")); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - tok.process(); - } - env.wrap_up_tab(); - units x = env.get_input_line_position().to_units(); - input_stack::push(make_temp_iterator(i_to_a(x))); - env.width_registers(); - curenv = oldenv; -} - -charinfo *page_character; - -void set_page_character() -{ - page_character = get_optional_char(); - skip_line(); -} - -static const symbol percent_symbol("%"); - -void read_title_parts(node **part, hunits *part_width) -{ - tok.skip(); - if (tok.newline() || tok.eof()) - return; - token start(tok); - int start_level = input_stack::get_level(); - tok.next(); - for (int i = 0; i < 3; i++) { - while (!tok.newline() && !tok.eof()) { - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) { - tok.next(); - break; - } - if (page_character != 0 && tok.get_char() == page_character) - interpolate_number_reg(percent_symbol, 0); - else - tok.process(); - tok.next(); - } - curenv->wrap_up_tab(); - part_width[i] = curenv->get_input_line_position(); - part[i] = curenv->extract_output_line(); - } - while (!tok.newline() && !tok.eof()) - tok.next(); -} - -class non_interpreted_node : public node { - macro mac; -public: - non_interpreted_node(const macro &); - int interpret(macro *); - node *copy(); - int same(node *); - const char *type(); - int force_tprint(); -}; - -non_interpreted_node::non_interpreted_node(const macro &m) : mac(m) -{ -} - -int non_interpreted_node::same(node *nd) -{ - return mac == ((non_interpreted_node *)nd)->mac; -} - -const char *non_interpreted_node::type() -{ - return "non_interpreted_node"; -} - -int non_interpreted_node::force_tprint() -{ - return 0; -} - -node *non_interpreted_node::copy() -{ - return new non_interpreted_node(mac); -} - -int non_interpreted_node::interpret(macro *m) -{ - string_iterator si(mac); - node *n; - for (;;) { - int c = si.get(&n); - if (c == EOF) - break; - if (c == 0) - m->append(n); - else - m->append(c); - } - return 1; -} - -static node *do_non_interpreted() -{ - node *n; - int c; - macro mac; - while ((c = get_copy(&n)) != ESCAPE_QUESTION && c != EOF && c != '\n') - if (c == 0) - mac.append(n); - else - mac.append(c); - if (c == EOF || c == '\n') { - error("missing \\?"); - return 0; - } - return new non_interpreted_node(mac); -} - -static void encode_char(macro *mac, char c) -{ - if (c == '\0') { - if ((font::use_charnames_in_special) && tok.special()) { - charinfo *ci = tok.get_char(1); - const char *s = ci->get_symbol()->contents(); - if (s[0] != (char)0) { - mac->append('\\'); - mac->append('('); - int i = 0; - while (s[i] != (char)0) { - mac->append(s[i]); - i++; - } - mac->append('\\'); - mac->append(')'); - } - } - else if (tok.stretchable_space() - || tok.unstretchable_space()) - mac->append(' '); - else if (!(tok.hyphen_indicator() - || tok.dummy() - || tok.transparent_dummy() - || tok.zero_width_break())) - error("%1 is invalid within \\X", tok.description()); - } - else { - if ((font::use_charnames_in_special) && (c == '\\')) { - /* - * add escape escape sequence - */ - mac->append(c); - } - mac->append(c); - } -} - -node *do_special() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - macro mac; - for (tok.next(); - tok != start || input_stack::get_level() != start_level; - tok.next()) { - if (tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - return 0; - } - if (tok.newline()) { - input_stack::push(make_temp_iterator("\n")); - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - unsigned char c; - if (tok.space()) - c = ' '; - else if (tok.tab()) - c = '\t'; - else if (tok.leader()) - c = '\001'; - else if (tok.backspace()) - c = '\b'; - else - c = tok.ch(); - encode_char(&mac, c); - } - return new special_node(mac); -} - -void output_request() -{ - if (!tok.newline() && !tok.eof()) { - int c; - for (;;) { - c = get_copy(0); - if (c == '"') { - c = get_copy(0); - break; - } - if (c != ' ' && c != '\t') - break; - } - for (; c != '\n' && c != EOF; c = get_copy(0)) - topdiv->transparent_output(c); - topdiv->transparent_output('\n'); - } - tok.next(); -} - -extern int image_no; // from node.cc - -static node *do_suppress(symbol nm) -{ - if (nm.is_null() || nm.is_empty()) { - error("expecting an argument to escape \\O"); - return 0; - } - const char *s = nm.contents(); - switch (*s) { - case '0': - if (begin_level == 0) - // suppress generation of glyphs - return new suppress_node(0, 0); - break; - case '1': - if (begin_level == 0) - // enable generation of glyphs - return new suppress_node(1, 0); - break; - case '2': - if (begin_level == 0) - return new suppress_node(1, 1); - break; - case '3': - begin_level++; - break; - case '4': - begin_level--; - break; - case '5': - { - s++; // move over '5' - char position = *s; - if (*s == (char)0) { - error("missing position and filename in \\O"); - return 0; - } - if (!(position == 'l' - || position == 'r' - || position == 'c' - || position == 'i')) { - error("l, r, c, or i position expected (got %1 in \\O)", position); - return 0; - } - s++; // onto image name - if (s == (char *)0) { - error("missing image name for \\O"); - return 0; - } - image_no++; - if (begin_level == 0) - return new suppress_node(symbol(s), position, image_no); - } - break; - default: - error("`%1' is an invalid argument to \\O", *s); - } - return 0; -} - -void special_node::tprint(troff_output_file *out) -{ - tprint_start(out); - string_iterator iter(mac); - for (;;) { - int c = iter.get(0); - if (c == EOF) - break; - for (const char *s = ::asciify(c); *s; s++) - tprint_char(out, *s); - } - tprint_end(out); -} - -int get_file_line(const char **filename, int *lineno) -{ - return input_stack::get_location(0, filename, lineno); -} - -void line_file() -{ - int n; - if (get_integer(&n)) { - const char *filename = 0; - if (has_arg()) { - symbol s = get_long_name(); - filename = s.contents(); - } - (void)input_stack::set_location(filename, n-1); - } - skip_line(); -} - -static int nroff_mode = 0; - -static void nroff_request() -{ - nroff_mode = 1; - skip_line(); -} - -static void troff_request() -{ - nroff_mode = 0; - skip_line(); -} - -static void skip_alternative() -{ - int level = 0; - // ensure that ``.if 0\{'' works as expected - if (tok.left_brace()) - level++; - int c; - for (;;) { - c = input_stack::get(0); - if (c == EOF) - break; - if (c == ESCAPE_LEFT_BRACE) - ++level; - else if (c == ESCAPE_RIGHT_BRACE) - --level; - else if (c == escape_char && escape_char > 0) - switch(input_stack::get(0)) { - case '{': - ++level; - break; - case '}': - --level; - break; - case '"': - while ((c = input_stack::get(0)) != '\n' && c != EOF) - ; - } - /* - Note that the level can properly be < 0, eg - - .if 1 \{\ - .if 0 \{\ - .\}\} - - So don't give an error message in this case. - */ - if (level <= 0 && c == '\n') - break; - } - tok.next(); -} - -static void begin_alternative() -{ - while (tok.space() || tok.left_brace()) - tok.next(); -} - -void nop_request() -{ - while (tok.space()) - tok.next(); -} - -static int_stack if_else_stack; - -int do_if_request() -{ - int invert = 0; - while (tok.space()) - tok.next(); - while (tok.ch() == '!') { - tok.next(); - invert = !invert; - } - int result; - unsigned char c = tok.ch(); - if (c == 't') { - tok.next(); - result = !nroff_mode; - } - else if (c == 'n') { - tok.next(); - result = nroff_mode; - } - else if (c == 'v') { - tok.next(); - result = 0; - } - else if (c == 'o') { - result = (topdiv->get_page_number() & 1); - tok.next(); - } - else if (c == 'e') { - result = !(topdiv->get_page_number() & 1); - tok.next(); - } - else if (c == 'd' || c == 'r') { - tok.next(); - symbol nm = get_name(1); - if (nm.is_null()) { - skip_alternative(); - return 0; - } - result = (c == 'd' - ? request_dictionary.lookup(nm) != 0 - : number_reg_dictionary.lookup(nm) != 0); - } - else if (c == 'm') { - tok.next(); - symbol nm = get_long_name(1); - if (nm.is_null()) { - skip_alternative(); - return 0; - } - result = (nm == default_symbol - || color_dictionary.lookup(nm) != 0); - } - else if (c == 'c') { - tok.next(); - tok.skip(); - charinfo *ci = tok.get_char(1); - if (ci == 0) { - skip_alternative(); - return 0; - } - result = character_exists(ci, curenv); - tok.next(); - } - else if (tok.space()) - result = 0; - else if (tok.delimiter()) { - token delim = tok; - int delim_level = input_stack::get_level(); - environment env1(curenv); - environment env2(curenv); - environment *oldenv = curenv; - curenv = &env1; - for (int i = 0; i < 2; i++) { - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - tok.next(); - curenv = oldenv; - return 0; - } - if (tok == delim - && (compatible_flag || input_stack::get_level() == delim_level)) - break; - tok.process(); - } - curenv = &env2; - } - node *n1 = env1.extract_output_line(); - node *n2 = env2.extract_output_line(); - result = same_node_list(n1, n2); - delete_node_list(n1); - delete_node_list(n2); - curenv = oldenv; - tok.next(); - } - else { - units n; - if (!get_number(&n, 'u')) { - skip_alternative(); - return 0; - } - else - result = n > 0; - } - if (invert) - result = !result; - if (result) - begin_alternative(); - else - skip_alternative(); - return result; -} - -void if_else_request() -{ - if_else_stack.push(do_if_request()); -} - -void if_request() -{ - do_if_request(); -} - -void else_request() -{ - if (if_else_stack.is_empty()) { - warning(WARN_EL, "unbalanced .el request"); - skip_alternative(); - } - else { - if (if_else_stack.pop()) - skip_alternative(); - else - begin_alternative(); - } -} - -static int while_depth = 0; -static int while_break_flag = 0; - -void while_request() -{ - macro mac; - int escaped = 0; - int level = 0; - mac.append(new token_node(tok)); - for (;;) { - node *n; - int c = input_stack::get(&n); - if (c == EOF) - break; - if (c == 0) { - escaped = 0; - mac.append(n); - } - else if (escaped) { - if (c == '{') - level += 1; - else if (c == '}') - level -= 1; - escaped = 0; - mac.append(c); - } - else { - if (c == ESCAPE_LEFT_BRACE) - level += 1; - else if (c == ESCAPE_RIGHT_BRACE) - level -= 1; - else if (c == escape_char) - escaped = 1; - mac.append(c); - if (c == '\n' && level <= 0) - break; - } - } - if (level != 0) - error("unbalanced \\{ \\}"); - else { - while_depth++; - input_stack::add_boundary(); - for (;;) { - input_stack::push(new string_iterator(mac, "while loop")); - tok.next(); - if (!do_if_request()) { - while (input_stack::get(0) != EOF) - ; - break; - } - process_input_stack(); - if (while_break_flag || input_stack::is_return_boundary()) { - while_break_flag = 0; - break; - } - } - input_stack::remove_boundary(); - while_depth--; - } - tok.next(); -} - -void while_break_request() -{ - if (!while_depth) { - error("no while loop"); - skip_line(); - } - else { - while_break_flag = 1; - while (input_stack::get(0) != EOF) - ; - tok.next(); - } -} - -void while_continue_request() -{ - if (!while_depth) { - error("no while loop"); - skip_line(); - } - else { - while (input_stack::get(0) != EOF) - ; - tok.next(); - } -} - -// .so - -void source() -{ - symbol nm = get_long_name(1); - if (nm.is_null()) - skip_line(); - else { - while (!tok.newline() && !tok.eof()) - tok.next(); - errno = 0; - FILE *fp = fopen(nm.contents(), "r"); - if (fp) - input_stack::push(new file_iterator(fp, nm.contents())); - else - error("can't open `%1': %2", nm.contents(), strerror(errno)); - tok.next(); - } -} - -// like .so but use popen() - -void pipe_source() -{ - if (safer_flag) { - error(".pso request not allowed in safer mode"); - skip_line(); - } - else { -#ifdef POPEN_MISSING - error("pipes not available on this system"); - skip_line(); -#else /* not POPEN_MISSING */ - if (tok.newline() || tok.eof()) - error("missing command"); - else { - int c; - while ((c = get_copy(0)) == ' ' || c == '\t') - ; - int buf_size = 24; - char *buf = new char[buf_size]; - int buf_used = 0; - for (; c != '\n' && c != EOF; c = get_copy(0)) { - const char *s = asciify(c); - int slen = strlen(s); - if (buf_used + slen + 1> buf_size) { - char *old_buf = buf; - int old_buf_size = buf_size; - buf_size *= 2; - buf = new char[buf_size]; - memcpy(buf, old_buf, old_buf_size); - a_delete old_buf; - } - strcpy(buf + buf_used, s); - buf_used += slen; - } - buf[buf_used] = '\0'; - errno = 0; - FILE *fp = popen(buf, POPEN_RT); - if (fp) - input_stack::push(new file_iterator(fp, symbol(buf).contents(), 1)); - else - error("can't open pipe to process `%1': %2", buf, strerror(errno)); - a_delete buf; - } - tok.next(); -#endif /* not POPEN_MISSING */ - } -} - -// .psbb - -static int llx_reg_contents = 0; -static int lly_reg_contents = 0; -static int urx_reg_contents = 0; -static int ury_reg_contents = 0; - -struct bounding_box { - int llx, lly, urx, ury; -}; - -/* Parse the argument to a %%BoundingBox comment. Return 1 if it -contains 4 numbers, 2 if it contains (atend), 0 otherwise. */ - -int parse_bounding_box(char *p, bounding_box *bb) -{ - if (sscanf(p, "%d %d %d %d", - &bb->llx, &bb->lly, &bb->urx, &bb->ury) == 4) - return 1; - else { - /* The Document Structuring Conventions say that the numbers - should be integers. Unfortunately some broken applications - get this wrong. */ - double x1, x2, x3, x4; - if (sscanf(p, "%lf %lf %lf %lf", &x1, &x2, &x3, &x4) == 4) { - bb->llx = (int)x1; - bb->lly = (int)x2; - bb->urx = (int)x3; - bb->ury = (int)x4; - return 1; - } - else { - for (; *p == ' ' || *p == '\t'; p++) - ; - if (strncmp(p, "(atend)", 7) == 0) { - return 2; - } - } - } - bb->llx = bb->lly = bb->urx = bb->ury = 0; - return 0; -} - -// This version is taken from psrm.cc - -#define PS_LINE_MAX 255 -cset white_space("\n\r \t"); - -int ps_get_line(char *buf, FILE *fp, const char* filename) -{ - int c = getc(fp); - if (c == EOF) { - buf[0] = '\0'; - return 0; - } - int i = 0; - int err = 0; - while (c != '\r' && c != '\n' && c != EOF) { - if ((c < 0x1b && !white_space(c)) || c == 0x7f) - error("invalid input character code %1 in `%2'", int(c), filename); - else if (i < PS_LINE_MAX) - buf[i++] = c; - else if (!err) { - err = 1; - error("PostScript file `%1' is non-conforming " - "because length of line exceeds 255", filename); - } - c = getc(fp); - } - buf[i++] = '\n'; - buf[i] = '\0'; - if (c == '\r') { - c = getc(fp); - if (c != EOF && c != '\n') - ungetc(c, fp); - } - return 1; -} - -inline void assign_registers(int llx, int lly, int urx, int ury) -{ - llx_reg_contents = llx; - lly_reg_contents = lly; - urx_reg_contents = urx; - ury_reg_contents = ury; -} - -void do_ps_file(FILE *fp, const char* filename) -{ - bounding_box bb; - int bb_at_end = 0; - char buf[PS_LINE_MAX]; - llx_reg_contents = lly_reg_contents = - urx_reg_contents = ury_reg_contents = 0; - if (!ps_get_line(buf, fp, filename)) { - error("`%1' is empty", filename); - return; - } - if (strncmp("%!PS-Adobe-", buf, 11) != 0) { - error("`%1' is not conforming to the Document Structuring Conventions", - filename); - return; - } - while (ps_get_line(buf, fp, filename) != 0) { - if (buf[0] != '%' || buf[1] != '%' - || strncmp(buf + 2, "EndComments", 11) == 0) - break; - if (strncmp(buf + 2, "BoundingBox:", 12) == 0) { - int res = parse_bounding_box(buf + 14, &bb); - if (res == 1) { - assign_registers(bb.llx, bb.lly, bb.urx, bb.ury); - return; - } - else if (res == 2) { - bb_at_end = 1; - break; - } - else { - error("the arguments to the %%%%BoundingBox comment in `%1' are bad", - filename); - return; - } - } - } - if (bb_at_end) { - long offset; - int last_try = 0; - /* in the trailer, the last BoundingBox comment is significant */ - for (offset = 512; !last_try; offset *= 2) { - int had_trailer = 0; - int got_bb = 0; - if (offset > 32768 || fseek(fp, -offset, 2) == -1) { - last_try = 1; - if (fseek(fp, 0L, 0) == -1) - break; - } - while (ps_get_line(buf, fp, filename) != 0) { - if (buf[0] == '%' && buf[1] == '%') { - if (!had_trailer) { - if (strncmp(buf + 2, "Trailer", 7) == 0) - had_trailer = 1; - } - else { - if (strncmp(buf + 2, "BoundingBox:", 12) == 0) { - int res = parse_bounding_box(buf + 14, &bb); - if (res == 1) - got_bb = 1; - else if (res == 2) { - error("`(atend)' not allowed in trailer of `%1'", filename); - return; - } - else { - error("the arguments to the %%%%BoundingBox comment in `%1' are bad", - filename); - return; - } - } - } - } - } - if (got_bb) { - assign_registers(bb.llx, bb.lly, bb.urx, bb.ury); - return; - } - } - } - error("%%%%BoundingBox comment not found in `%1'", filename); -} - -void ps_bbox_request() -{ - symbol nm = get_long_name(1); - if (nm.is_null()) - skip_line(); - else { - while (!tok.newline() && !tok.eof()) - tok.next(); - errno = 0; - // PS files might contain non-printable characters, such as ^Z - // and CRs not followed by an LF, so open them in binary mode. - FILE *fp = fopen(nm.contents(), FOPEN_RB); - if (fp) { - do_ps_file(fp, nm.contents()); - fclose(fp); - } - else - error("can't open `%1': %2", nm.contents(), strerror(errno)); - tok.next(); - } -} - -const char *asciify(int c) -{ - static char buf[3]; - buf[0] = escape_char == '\0' ? '\\' : escape_char; - buf[1] = buf[2] = '\0'; - switch (c) { - case ESCAPE_QUESTION: - buf[1] = '?'; - break; - case ESCAPE_AMPERSAND: - buf[1] = '&'; - break; - case ESCAPE_RIGHT_PARENTHESIS: - buf[1] = ')'; - break; - case ESCAPE_UNDERSCORE: - buf[1] = '_'; - break; - case ESCAPE_BAR: - buf[1] = '|'; - break; - case ESCAPE_CIRCUMFLEX: - buf[1] = '^'; - break; - case ESCAPE_LEFT_BRACE: - buf[1] = '{'; - break; - case ESCAPE_RIGHT_BRACE: - buf[1] = '}'; - break; - case ESCAPE_LEFT_QUOTE: - buf[1] = '`'; - break; - case ESCAPE_RIGHT_QUOTE: - buf[1] = '\''; - break; - case ESCAPE_HYPHEN: - buf[1] = '-'; - break; - case ESCAPE_BANG: - buf[1] = '!'; - break; - case ESCAPE_c: - buf[1] = 'c'; - break; - case ESCAPE_e: - buf[1] = 'e'; - break; - case ESCAPE_E: - buf[1] = 'E'; - break; - case ESCAPE_PERCENT: - buf[1] = '%'; - break; - case ESCAPE_SPACE: - buf[1] = ' '; - break; - case ESCAPE_TILDE: - buf[1] = '~'; - break; - case ESCAPE_COLON: - buf[1] = ':'; - break; - case COMPATIBLE_SAVE: - case COMPATIBLE_RESTORE: - buf[0] = '\0'; - break; - default: - if (invalid_input_char(c)) - buf[0] = '\0'; - else - buf[0] = c; - break; - } - return buf; -} - -const char *input_char_description(int c) -{ - switch (c) { - case '\n': - return "a newline character"; - case '\b': - return "a backspace character"; - case '\001': - return "a leader character"; - case '\t': - return "a tab character"; - case ' ': - return "a space character"; - case '\0': - return "a node"; - } - static char buf[sizeof("magic character code ") + 1 + INT_DIGITS]; - if (invalid_input_char(c)) { - const char *s = asciify(c); - if (*s) { - buf[0] = '`'; - strcpy(buf + 1, s); - strcat(buf, "'"); - return buf; - } - sprintf(buf, "magic character code %d", c); - return buf; - } - if (csprint(c)) { - buf[0] = '`'; - buf[1] = c; - buf[2] = '\''; - return buf; - } - sprintf(buf, "character code %d", c); - return buf; -} - -// .tm, .tm1, and .tmc - -void do_terminal(int newline, int string_like) -{ - if (!tok.newline() && !tok.eof()) { - int c; - for (;;) { - c = get_copy(0); - if (string_like && c == '"') { - c = get_copy(0); - break; - } - if (c != ' ' && c != '\t') - break; - } - for (; c != '\n' && c != EOF; c = get_copy(0)) - fputs(asciify(c), stderr); - } - if (newline) - fputc('\n', stderr); - fflush(stderr); - tok.next(); -} - -void terminal() -{ - do_terminal(1, 0); -} - -void terminal1() -{ - do_terminal(1, 1); -} - -void terminal_continue() -{ - do_terminal(0, 1); -} - -dictionary stream_dictionary(20); - -void do_open(int append) -{ - symbol stream = get_name(1); - if (!stream.is_null()) { - symbol filename = get_long_name(1); - if (!filename.is_null()) { - errno = 0; - FILE *fp = fopen(filename.contents(), append ? "a" : "w"); - if (!fp) { - error("can't open `%1' for %2: %3", - filename.contents(), - append ? "appending" : "writing", - strerror(errno)); - fp = (FILE *)stream_dictionary.remove(stream); - } - else - fp = (FILE *)stream_dictionary.lookup(stream, fp); - if (fp) - fclose(fp); - } - } - skip_line(); -} - -void open_request() -{ - if (safer_flag) { - error(".open request not allowed in safer mode"); - skip_line(); - } - else - do_open(0); -} - -void opena_request() -{ - if (safer_flag) { - error(".opena request not allowed in safer mode"); - skip_line(); - } - else - do_open(1); -} - -void close_request() -{ - symbol stream = get_name(1); - if (!stream.is_null()) { - FILE *fp = (FILE *)stream_dictionary.remove(stream); - if (!fp) - error("no stream named `%1'", stream.contents()); - else - fclose(fp); - } - skip_line(); -} - -// .write and .writec - -void do_write_request(int newline) -{ - symbol stream = get_name(1); - if (stream.is_null()) { - skip_line(); - return; - } - FILE *fp = (FILE *)stream_dictionary.lookup(stream); - if (!fp) { - error("no stream named `%1'", stream.contents()); - skip_line(); - return; - } - int c; - while ((c = get_copy(0)) == ' ') - ; - if (c == '"') - c = get_copy(0); - for (; c != '\n' && c != EOF; c = get_copy(0)) - fputs(asciify(c), fp); - if (newline) - fputc('\n', fp); - fflush(fp); - tok.next(); -} - -void write_request() -{ - do_write_request(1); -} - -void write_request_continue() -{ - do_write_request(0); -} - -void write_macro_request() -{ - symbol stream = get_name(1); - if (stream.is_null()) { - skip_line(); - return; - } - FILE *fp = (FILE *)stream_dictionary.lookup(stream); - if (!fp) { - error("no stream named `%1'", stream.contents()); - skip_line(); - return; - } - symbol s = get_name(1); - if (s.is_null()) { - skip_line(); - return; - } - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot write request"); - else { - string_iterator iter(*m); - for (;;) { - int c = iter.get(0); - if (c == EOF) - break; - fputs(asciify(c), fp); - } - fflush(fp); - } - skip_line(); -} - -void warnscale_request() -{ - if (has_arg()) { - char c = tok.ch(); - if (c == 'u') - warn_scale = 1.0; - else if (c == 'i') - warn_scale = (double)units_per_inch; - else if (c == 'c') - warn_scale = (double)units_per_inch / 2.54; - else if (c == 'p') - warn_scale = (double)units_per_inch / 72.0; - else if (c == 'P') - warn_scale = (double)units_per_inch / 6.0; - else { - warning(WARN_SCALE, - "invalid scaling indicator `%1', using `i' instead", c); - c = 'i'; - } - warn_scaling_indicator = c; - } - skip_line(); -} - -void spreadwarn_request() -{ - hunits n; - if (has_arg() && get_hunits(&n, 'm')) { - if (n < 0) - n = 0; - hunits em = curenv->get_size(); - spread_limit = (double)n.to_units() - / (em.is_zero() ? hresolution : em.to_units()); - } - else - spread_limit = -spread_limit - 1; // no arg toggles on/off without - // changing value; we mirror at - // -0.5 to make zero a valid value - skip_line(); -} - -static void init_charset_table() -{ - char buf[16]; - strcpy(buf, "char"); - for (int i = 0; i < 256; i++) { - strcpy(buf + 4, i_to_a(i)); - charset_table[i] = get_charinfo(symbol(buf)); - charset_table[i]->set_ascii_code(i); - if (csalpha(i)) - charset_table[i]->set_hyphenation_code(cmlower(i)); - } - charset_table['.']->set_flags(charinfo::ENDS_SENTENCE); - charset_table['?']->set_flags(charinfo::ENDS_SENTENCE); - charset_table['!']->set_flags(charinfo::ENDS_SENTENCE); - charset_table['-']->set_flags(charinfo::BREAK_AFTER); - charset_table['"']->set_flags(charinfo::TRANSPARENT); - charset_table['\'']->set_flags(charinfo::TRANSPARENT); - charset_table[')']->set_flags(charinfo::TRANSPARENT); - charset_table[']']->set_flags(charinfo::TRANSPARENT); - charset_table['*']->set_flags(charinfo::TRANSPARENT); - get_charinfo(symbol("dg"))->set_flags(charinfo::TRANSPARENT); - get_charinfo(symbol("rq"))->set_flags(charinfo::TRANSPARENT); - get_charinfo(symbol("em"))->set_flags(charinfo::BREAK_AFTER); - get_charinfo(symbol("ul"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("rn"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("radicalex"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("ru"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("br"))->set_flags(charinfo::OVERLAPS_VERTICALLY); - page_character = charset_table['%']; -} - -static void init_hpf_code_table() -{ - for (int i = 0; i < 256; i++) - hpf_code_table[i] = i; -} - -static void do_translate(int translate_transparent, int translate_input) -{ - tok.skip(); - while (!tok.newline() && !tok.eof()) { - if (tok.space()) { - // This is a really bizarre troff feature. - tok.next(); - translate_space_to_dummy = tok.dummy(); - if (tok.newline() || tok.eof()) - break; - tok.next(); - continue; - } - charinfo *ci1 = tok.get_char(1); - if (ci1 == 0) - break; - tok.next(); - if (tok.newline() || tok.eof()) { - ci1->set_special_translation(charinfo::TRANSLATE_SPACE, - translate_transparent); - break; - } - if (tok.space()) - ci1->set_special_translation(charinfo::TRANSLATE_SPACE, - translate_transparent); - else if (tok.stretchable_space()) - ci1->set_special_translation(charinfo::TRANSLATE_STRETCHABLE_SPACE, - translate_transparent); - else if (tok.dummy()) - ci1->set_special_translation(charinfo::TRANSLATE_DUMMY, - translate_transparent); - else if (tok.hyphen_indicator()) - ci1->set_special_translation(charinfo::TRANSLATE_HYPHEN_INDICATOR, - translate_transparent); - else { - charinfo *ci2 = tok.get_char(1); - if (ci2 == 0) - break; - if (ci1 == ci2) - ci1->set_translation(0, translate_transparent, translate_input); - else - ci1->set_translation(ci2, translate_transparent, translate_input); - } - tok.next(); - } - skip_line(); -} - -void translate() -{ - do_translate(1, 0); -} - -void translate_no_transparent() -{ - do_translate(0, 0); -} - -void translate_input() -{ - do_translate(1, 1); -} - -void char_flags() -{ - int flags; - if (get_integer(&flags)) - while (has_arg()) { - charinfo *ci = tok.get_char(1); - if (ci) { - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - ci->set_flags(flags); - } - tok.next(); - } - skip_line(); -} - -void hyphenation_code() -{ - tok.skip(); - while (!tok.newline() && !tok.eof()) { - charinfo *ci = tok.get_char(1); - if (ci == 0) - break; - tok.next(); - tok.skip(); - unsigned char c = tok.ch(); - if (c == 0) { - error("hyphenation code must be ordinary character"); - break; - } - if (csdigit(c)) { - error("hyphenation code cannot be digit"); - break; - } - ci->set_hyphenation_code(c); - if (ci->get_translation() - && ci->get_translation()->get_translation_input()) - ci->get_translation()->set_hyphenation_code(c); - tok.next(); - tok.skip(); - } - skip_line(); -} - -void hyphenation_patterns_file_code() -{ - tok.skip(); - while (!tok.newline() && !tok.eof()) { - int n1, n2; - if (get_integer(&n1) && (0 <= n1 && n1 <= 255)) { - if (!has_arg()) { - error("missing output hyphenation code"); - break; - } - if (get_integer(&n2) && (0 <= n2 && n2 <= 255)) { - hpf_code_table[n1] = n2; - tok.skip(); - } - else { - error("output hyphenation code must be integer in the range 0..255"); - break; - } - } - else { - error("input hyphenation code must be integer in the range 0..255"); - break; - } - } - skip_line(); -} - -charinfo *token::get_char(int required) -{ - if (type == TOKEN_CHAR) - return charset_table[c]; - if (type == TOKEN_SPECIAL) - return get_charinfo(nm); - if (type == TOKEN_NUMBERED_CHAR) - return get_charinfo_by_number(val); - if (type == TOKEN_ESCAPE) { - if (escape_char != 0) - return charset_table[escape_char]; - else { - error("`\\e' used while no current escape character"); - return 0; - } - } - if (required) { - if (type == TOKEN_EOF || type == TOKEN_NEWLINE) - warning(WARN_MISSING, "missing normal or special character"); - else - error("normal or special character expected (got %1)", description()); - } - return 0; -} - -charinfo *get_optional_char() -{ - while (tok.space()) - tok.next(); - charinfo *ci = tok.get_char(); - if (!ci) - check_missing_character(); - else - tok.next(); - return ci; -} - -void check_missing_character() -{ - if (!tok.newline() && !tok.eof() && !tok.right_brace() && !tok.tab()) - error("normal or special character expected (got %1): " - "treated as missing", - tok.description()); -} - -// this is for \Z - -int token::add_to_node_list(node **pp) -{ - hunits w; - int s; - node *n = 0; - switch (type) { - case TOKEN_CHAR: - *pp = (*pp)->add_char(charset_table[c], curenv, &w, &s); - break; - case TOKEN_DUMMY: - n = new dummy_node; - break; - case TOKEN_ESCAPE: - if (escape_char != 0) - *pp = (*pp)->add_char(charset_table[escape_char], curenv, &w, &s); - break; - case TOKEN_HYPHEN_INDICATOR: - *pp = (*pp)->add_discretionary_hyphen(); - break; - case TOKEN_ITALIC_CORRECTION: - *pp = (*pp)->add_italic_correction(&w); - break; - case TOKEN_LEFT_BRACE: - break; - case TOKEN_MARK_INPUT: - set_number_reg(nm, curenv->get_input_line_position().to_units()); - break; - case TOKEN_NODE: - n = nd; - nd = 0; - break; - case TOKEN_NUMBERED_CHAR: - *pp = (*pp)->add_char(get_charinfo_by_number(val), curenv, &w, &s); - break; - case TOKEN_RIGHT_BRACE: - break; - case TOKEN_SPACE: - n = new hmotion_node(curenv->get_space_width(), - curenv->get_fill_color()); - break; - case TOKEN_SPECIAL: - *pp = (*pp)->add_char(get_charinfo(nm), curenv, &w, &s); - break; - case TOKEN_STRETCHABLE_SPACE: - n = new unbreakable_space_node(curenv->get_space_width(), - curenv->get_fill_color()); - break; - case TOKEN_UNSTRETCHABLE_SPACE: - n = new space_char_hmotion_node(curenv->get_space_width(), - curenv->get_fill_color()); - break; - case TOKEN_TRANSPARENT_DUMMY: - n = new transparent_dummy_node; - break; - case TOKEN_ZERO_WIDTH_BREAK: - n = new space_node(H0, curenv->get_fill_color()); - n->freeze_space(); - n->is_escape_colon(); - break; - default: - return 0; - } - if (n) { - n->next = *pp; - *pp = n; - } - return 1; -} - -void token::process() -{ - if (possibly_handle_first_page_transition()) - return; - switch (type) { - case TOKEN_BACKSPACE: - curenv->add_node(new hmotion_node(-curenv->get_space_width(), - curenv->get_fill_color())); - break; - case TOKEN_CHAR: - curenv->add_char(charset_table[c]); - break; - case TOKEN_DUMMY: - curenv->add_node(new dummy_node); - break; - case TOKEN_EMPTY: - assert(0); - break; - case TOKEN_EOF: - assert(0); - break; - case TOKEN_ESCAPE: - if (escape_char != 0) - curenv->add_char(charset_table[escape_char]); - break; - case TOKEN_BEGIN_TRAP: - case TOKEN_END_TRAP: - case TOKEN_PAGE_EJECTOR: - // these are all handled in process_input_stack() - break; - case TOKEN_HYPHEN_INDICATOR: - curenv->add_hyphen_indicator(); - break; - case TOKEN_INTERRUPT: - curenv->interrupt(); - break; - case TOKEN_ITALIC_CORRECTION: - curenv->add_italic_correction(); - break; - case TOKEN_LEADER: - curenv->handle_tab(1); - break; - case TOKEN_LEFT_BRACE: - break; - case TOKEN_MARK_INPUT: - set_number_reg(nm, curenv->get_input_line_position().to_units()); - break; - case TOKEN_NEWLINE: - curenv->newline(); - break; - case TOKEN_NODE: - curenv->add_node(nd); - nd = 0; - break; - case TOKEN_NUMBERED_CHAR: - curenv->add_char(get_charinfo_by_number(val)); - break; - case TOKEN_REQUEST: - // handled in process_input_stack() - break; - case TOKEN_RIGHT_BRACE: - break; - case TOKEN_SPACE: - curenv->space(); - break; - case TOKEN_SPECIAL: - curenv->add_char(get_charinfo(nm)); - break; - case TOKEN_SPREAD: - curenv->spread(); - break; - case TOKEN_STRETCHABLE_SPACE: - curenv->add_node(new unbreakable_space_node(curenv->get_space_width(), - curenv->get_fill_color())); - break; - case TOKEN_UNSTRETCHABLE_SPACE: - curenv->add_node(new space_char_hmotion_node(curenv->get_space_width(), - curenv->get_fill_color())); - break; - case TOKEN_TAB: - curenv->handle_tab(0); - break; - case TOKEN_TRANSPARENT: - break; - case TOKEN_TRANSPARENT_DUMMY: - curenv->add_node(new transparent_dummy_node); - break; - case TOKEN_ZERO_WIDTH_BREAK: - { - node *tmp = new space_node(H0, curenv->get_fill_color()); - tmp->freeze_space(); - tmp->is_escape_colon(); - curenv->add_node(tmp); - break; - } - default: - assert(0); - } -} - -class nargs_reg : public reg { -public: - const char *get_string(); -}; - -const char *nargs_reg::get_string() -{ - return i_to_a(input_stack::nargs()); -} - -class lineno_reg : public reg { -public: - const char *get_string(); -}; - -const char *lineno_reg::get_string() -{ - int line; - const char *file; - if (!input_stack::get_location(0, &file, &line)) - line = 0; - return i_to_a(line); -} - -class writable_lineno_reg : public general_reg { -public: - writable_lineno_reg(); - void set_value(units); - int get_value(units *); -}; - -writable_lineno_reg::writable_lineno_reg() -{ -} - -int writable_lineno_reg::get_value(units *res) -{ - int line; - const char *file; - if (!input_stack::get_location(0, &file, &line)) - return 0; - *res = line; - return 1; -} - -void writable_lineno_reg::set_value(units n) -{ - input_stack::set_location(0, n); -} - -class filename_reg : public reg { -public: - const char *get_string(); -}; - -const char *filename_reg::get_string() -{ - int line; - const char *file; - if (input_stack::get_location(0, &file, &line)) - return file; - else - return 0; -} - -class constant_reg : public reg { - const char *s; -public: - constant_reg(const char *); - const char *get_string(); -}; - -constant_reg::constant_reg(const char *p) : s(p) -{ -} - -const char *constant_reg::get_string() -{ - return s; -} - -constant_int_reg::constant_int_reg(int *q) : p(q) -{ -} - -const char *constant_int_reg::get_string() -{ - return i_to_a(*p); -} - -void abort_request() -{ - int c; - if (tok.eof()) - c = EOF; - else if (tok.newline()) - c = '\n'; - else { - while ((c = get_copy(0)) == ' ') - ; - } - if (c == EOF || c == '\n') - fputs("User Abort.", stderr); - else { - for (; c != '\n' && c != EOF; c = get_copy(0)) - fputs(asciify(c), stderr); - } - fputc('\n', stderr); - cleanup_and_exit(1); -} - -char *read_string() -{ - int len = 256; - char *s = new char[len]; - int c; - while ((c = get_copy(0)) == ' ') - ; - int i = 0; - while (c != '\n' && c != EOF) { - if (!invalid_input_char(c)) { - if (i + 2 > len) { - char *tem = s; - s = new char[len*2]; - memcpy(s, tem, len); - len *= 2; - a_delete tem; - } - s[i++] = c; - } - c = get_copy(0); - } - s[i] = '\0'; - tok.next(); - if (i == 0) { - a_delete s; - return 0; - } - return s; -} - -void pipe_output() -{ - if (safer_flag) { - error(".pi request not allowed in safer mode"); - skip_line(); - } - else { -#ifdef POPEN_MISSING - error("pipes not available on this system"); - skip_line(); -#else /* not POPEN_MISSING */ - if (the_output) { - error("can't pipe: output already started"); - skip_line(); - } - else { - char *pc; - if ((pc = read_string()) == 0) - error("can't pipe to empty command"); - if (pipe_command) { - char *s = new char[strlen(pipe_command) + strlen(pc) + 1 + 1]; - strcpy(s, pipe_command); - strcat(s, "|"); - strcat(s, pc); - a_delete pipe_command; - a_delete pc; - pipe_command = s; - } - else - pipe_command = pc; - } -#endif /* not POPEN_MISSING */ - } -} - -static int system_status; - -void system_request() -{ - if (safer_flag) { - error(".sy request not allowed in safer mode"); - skip_line(); - } - else { - char *command = read_string(); - if (!command) - error("empty command"); - else { - system_status = system(command); - a_delete command; - } - } -} - -void copy_file() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_request(COPY_FILE_REQUEST); - return; - } - symbol filename = get_long_name(1); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (!filename.is_null()) - curdiv->copy_file(filename.contents()); - tok.next(); -} - -#ifdef COLUMN - -void vjustify() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_request(VJUSTIFY_REQUEST); - return; - } - symbol type = get_long_name(1); - if (!type.is_null()) - curdiv->vjustify(type); - skip_line(); -} - -#endif /* COLUMN */ - -void transparent_file() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_request(TRANSPARENT_FILE_REQUEST); - return; - } - symbol filename = get_long_name(1); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (!filename.is_null()) { - errno = 0; - FILE *fp = fopen(filename.contents(), "r"); - if (!fp) - error("can't open `%1': %2", filename.contents(), strerror(errno)); - else { - int bol = 1; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - if (invalid_input_char(c)) - warning(WARN_INPUT, "invalid input character code %1", int(c)); - else { - curdiv->transparent_output(c); - bol = c == '\n'; - } - } - if (!bol) - curdiv->transparent_output('\n'); - fclose(fp); - } - } - tok.next(); -} - -class page_range { - int first; - int last; -public: - page_range *next; - page_range(int, int, page_range *); - int contains(int n); -}; - -page_range::page_range(int i, int j, page_range *p) -: first(i), last(j), next(p) -{ -} - -int page_range::contains(int n) -{ - return n >= first && (last <= 0 || n <= last); -} - -page_range *output_page_list = 0; - -int in_output_page_list(int n) -{ - if (!output_page_list) - return 1; - for (page_range *p = output_page_list; p; p = p->next) - if (p->contains(n)) - return 1; - return 0; -} - -static void parse_output_page_list(char *p) -{ - for (;;) { - int i; - if (*p == '-') - i = 1; - else if (csdigit(*p)) { - i = 0; - do - i = i*10 + *p++ - '0'; - while (csdigit(*p)); - } - else - break; - int j; - if (*p == '-') { - p++; - j = 0; - if (csdigit(*p)) { - do - j = j*10 + *p++ - '0'; - while (csdigit(*p)); - } - } - else - j = i; - if (j == 0) - last_page_number = -1; - else if (last_page_number >= 0 && j > last_page_number) - last_page_number = j; - output_page_list = new page_range(i, j, output_page_list); - if (*p != ',') - break; - ++p; - } - if (*p != '\0') { - error("bad output page list"); - output_page_list = 0; - } -} - -static FILE *open_mac_file(const char *mac, char **path) -{ - // Try first FOOBAR.tmac, then tmac.FOOBAR - char *s1 = new char[strlen(mac)+strlen(MACRO_POSTFIX)+1]; - strcpy(s1, mac); - strcat(s1, MACRO_POSTFIX); - FILE *fp = mac_path->open_file(s1, path); - a_delete s1; - if (!fp) { - char *s2 = new char[strlen(mac)+strlen(MACRO_PREFIX)+1]; - strcpy(s2, MACRO_PREFIX); - strcat(s2, mac); - fp = mac_path->open_file(s2, path); - a_delete s2; - } - return fp; -} - -static void process_macro_file(const char *mac) -{ - char *path; - FILE *fp = open_mac_file(mac, &path); - if (!fp) - fatal("can't find macro file %1", mac); - const char *s = symbol(path).contents(); - a_delete path; - input_stack::push(new file_iterator(fp, s)); - tok.next(); - process_input_stack(); -} - -static void process_startup_file(char *filename) -{ - char *path; - search_path *orig_mac_path = mac_path; - mac_path = &config_macro_path; - FILE *fp = mac_path->open_file(filename, &path); - if (fp) { - input_stack::push(new file_iterator(fp, symbol(path).contents())); - a_delete path; - tok.next(); - process_input_stack(); - } - mac_path = orig_mac_path; -} - -void macro_source() -{ - symbol nm = get_long_name(1); - if (nm.is_null()) - skip_line(); - else { - while (!tok.newline() && !tok.eof()) - tok.next(); - char *path; - FILE *fp = mac_path->open_file(nm.contents(), &path); - // .mso doesn't (and cannot) go through open_mac_file, so we - // need to do it here manually: If we have tmac.FOOBAR, try - // FOOBAR.tmac and vice versa - if (!fp) { - const char *fn = nm.contents(); - if (strncasecmp(fn, MACRO_PREFIX, sizeof(MACRO_PREFIX) - 1) == 0) { - char *s = new char[strlen(fn) + sizeof(MACRO_POSTFIX)]; - strcpy(s, fn + sizeof(MACRO_PREFIX) - 1); - strcat(s, MACRO_POSTFIX); - fp = mac_path->open_file(s, &path); - a_delete s; - } - if (!fp) { - if (strncasecmp(fn + strlen(fn) - sizeof(MACRO_POSTFIX) + 1, - MACRO_POSTFIX, sizeof(MACRO_POSTFIX) - 1) == 0) { - char *s = new char[strlen(fn) + sizeof(MACRO_PREFIX)]; - strcpy(s, MACRO_PREFIX); - strncat(s, fn, strlen(fn) - sizeof(MACRO_POSTFIX) + 1); - fp = mac_path->open_file(s, &path); - a_delete s; - } - } - } - if (fp) { - input_stack::push(new file_iterator(fp, symbol(path).contents())); - a_delete path; - } - else - error("can't find macro file `%1'", nm.contents()); - tok.next(); - } -} - -static void process_input_file(const char *name) -{ - FILE *fp; - if (strcmp(name, "-") == 0) { - clearerr(stdin); - fp = stdin; - } - else { - errno = 0; - fp = fopen(name, "r"); - if (!fp) - fatal("can't open `%1': %2", name, strerror(errno)); - } - input_stack::push(new file_iterator(fp, name)); - tok.next(); - process_input_stack(); -} - -// make sure the_input is empty before calling this - -static int evaluate_expression(const char *expr, units *res) -{ - input_stack::push(make_temp_iterator(expr)); - tok.next(); - int success = get_number(res, 'u'); - while (input_stack::get(0) != EOF) - ; - return success; -} - -static void do_register_assignment(const char *s) -{ - const char *p = strchr(s, '='); - if (!p) { - char buf[2]; - buf[0] = s[0]; - buf[1] = 0; - units n; - if (evaluate_expression(s + 1, &n)) - set_number_reg(buf, n); - } - else { - char *buf = new char[p - s + 1]; - memcpy(buf, s, p - s); - buf[p - s] = 0; - units n; - if (evaluate_expression(p + 1, &n)) - set_number_reg(buf, n); - a_delete buf; - } -} - -static void set_string(const char *name, const char *value) -{ - macro *m = new macro; - for (const char *p = value; *p; p++) - if (!invalid_input_char((unsigned char)*p)) - m->append(*p); - request_dictionary.define(name, m); -} - -static void do_string_assignment(const char *s) -{ - const char *p = strchr(s, '='); - if (!p) { - char buf[2]; - buf[0] = s[0]; - buf[1] = 0; - set_string(buf, s + 1); - } - else { - char *buf = new char[p - s + 1]; - memcpy(buf, s, p - s); - buf[p - s] = 0; - set_string(buf, p + 1); - a_delete buf; - } -} - -struct string_list { - const char *s; - string_list *next; - string_list(const char *ss) : s(ss), next(0) {} -}; - -#if 0 -static void prepend_string(const char *s, string_list **p) -{ - string_list *l = new string_list(s); - l->next = *p; - *p = l; -} -#endif - -static void add_string(const char *s, string_list **p) -{ - while (*p) - p = &((*p)->next); - *p = new string_list(s); -} - -void usage(FILE *stream, const char *prog) -{ - fprintf(stream, -"usage: %s -abcivzCERU -wname -Wname -dcs -ffam -mname -nnum -olist\n" -" -rcn -Tname -Fdir -Mdir [files...]\n", - prog); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int c; - string_list *macros = 0; - string_list *register_assignments = 0; - string_list *string_assignments = 0; - int iflag = 0; - int tflag = 0; - int fflag = 0; - int nflag = 0; - int no_rc = 0; // don't process troffrc and troffrc-end - int next_page_number; - opterr = 0; - hresolution = vresolution = 1; - // restore $PATH if called from groff - char* groff_path = getenv("GROFF_PATH__"); - if (groff_path) { - string e = "PATH"; - e += '='; - if (*groff_path) - e += groff_path; - e += '\0'; - if (putenv(strsave(e.contents()))) - fatal("putenv failed"); - } - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { 0, 0, 0, 0 } - }; - while ((c = getopt_long(argc, argv, "abcivw:W:zCEf:m:n:o:r:d:F:M:T:tqs:RU", - long_options, 0)) - != EOF) - switch(c) { - case 'v': - { - printf("GNU troff (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'T': - device = optarg; - tflag = 1; - is_html = (strcmp(device, "html") == 0); - break; - case 'C': - compatible_flag = 1; - // fall through - case 'c': - color_flag = 0; - break; - case 'M': - macro_path.command_line_dir(optarg); - safer_macro_path.command_line_dir(optarg); - config_macro_path.command_line_dir(optarg); - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'm': - add_string(optarg, ¯os); - break; - case 'E': - inhibit_errors = 1; - break; - case 'R': - no_rc = 1; - break; - case 'w': - enable_warning(optarg); - break; - case 'W': - disable_warning(optarg); - break; - case 'i': - iflag = 1; - break; - case 'b': - backtrace_flag = 1; - break; - case 'a': - ascii_output_flag = 1; - break; - case 'z': - suppress_output_flag = 1; - break; - case 'n': - if (sscanf(optarg, "%d", &next_page_number) == 1) - nflag++; - else - error("bad page number"); - break; - case 'o': - parse_output_page_list(optarg); - break; - case 'd': - if (*optarg == '\0') - error("`-d' requires non-empty argument"); - else - add_string(optarg, &string_assignments); - break; - case 'r': - if (*optarg == '\0') - error("`-r' requires non-empty argument"); - else - add_string(optarg, ®ister_assignments); - break; - case 'f': - default_family = symbol(optarg); - fflag = 1; - break; - case 'q': - case 's': - case 't': - // silently ignore these - break; - case 'U': - safer_flag = 0; // unsafe behaviour - break; - case CHAR_MAX + 1: // --help - usage(stdout, argv[0]); - exit(0); - break; - case '?': - usage(stderr, argv[0]); - exit(1); - break; // never reached - default: - assert(0); - } - if (!safer_flag) - mac_path = ¯o_path; - set_string(".T", device); - init_charset_table(); - init_hpf_code_table(); - if (!font::load_desc()) - fatal("sorry, I can't continue"); - units_per_inch = font::res; - hresolution = font::hor; - vresolution = font::vert; - sizescale = font::sizescale; - tcommand_flag = font::tcommand; - warn_scale = (double)units_per_inch; - warn_scaling_indicator = 'i'; - if (!fflag && font::family != 0 && *font::family != '\0') - default_family = symbol(font::family); - font_size::init_size_table(font::sizes); - int i; - int j = 1; - if (font::style_table) { - for (i = 0; font::style_table[i]; i++) - mount_style(j++, symbol(font::style_table[i])); - } - for (i = 0; font::font_name_table[i]; i++, j++) - // In the DESC file a font name of 0 (zero) means leave this - // position empty. - if (strcmp(font::font_name_table[i], "0") != 0) - mount_font(j, symbol(font::font_name_table[i])); - curdiv = topdiv = new top_level_diversion; - if (nflag) - topdiv->set_next_page_number(next_page_number); - init_input_requests(); - init_env_requests(); - init_div_requests(); -#ifdef COLUMN - init_column_requests(); -#endif /* COLUMN */ - init_node_requests(); - number_reg_dictionary.define(".T", new constant_reg(tflag ? "1" : "0")); - init_registers(); - init_reg_requests(); - init_hyphen_requests(); - init_environments(); - while (string_assignments) { - do_string_assignment(string_assignments->s); - string_list *tem = string_assignments; - string_assignments = string_assignments->next; - delete tem; - } - while (register_assignments) { - do_register_assignment(register_assignments->s); - string_list *tem = register_assignments; - register_assignments = register_assignments->next; - delete tem; - } - if (!no_rc) - process_startup_file(INITIAL_STARTUP_FILE); - while (macros) { - process_macro_file(macros->s); - string_list *tem = macros; - macros = macros->next; - delete tem; - } - if (!no_rc) - process_startup_file(FINAL_STARTUP_FILE); - for (i = optind; i < argc; i++) - process_input_file(argv[i]); - if (optind >= argc || iflag) - process_input_file("-"); - exit_troff(); - return 0; // not reached -} - -void warn_request() -{ - int n; - if (has_arg() && get_integer(&n)) { - if (n & ~WARN_TOTAL) { - warning(WARN_RANGE, "warning mask must be between 0 and %1", WARN_TOTAL); - n &= WARN_TOTAL; - } - warning_mask = n; - } - else - warning_mask = WARN_TOTAL; - skip_line(); -} - -static void init_registers() -{ -#ifdef LONG_FOR_TIME_T - long -#else /* not LONG_FOR_TIME_T */ - time_t -#endif /* not LONG_FOR_TIME_T */ - t = time(0); - // Use struct here to work around misfeature in old versions of g++. - struct tm *tt = localtime(&t); - set_number_reg("seconds", int(tt->tm_sec)); - set_number_reg("minutes", int(tt->tm_min)); - set_number_reg("hours", int(tt->tm_hour)); - set_number_reg("dw", int(tt->tm_wday + 1)); - set_number_reg("dy", int(tt->tm_mday)); - set_number_reg("mo", int(tt->tm_mon + 1)); - set_number_reg("year", int(1900 + tt->tm_year)); - set_number_reg("yr", int(tt->tm_year)); - set_number_reg("$$", getpid()); - number_reg_dictionary.define(".A", - new constant_reg(ascii_output_flag - ? "1" - : "0")); -} - -/* - * registers associated with \O - */ - -static int output_reg_minx_contents = -1; -static int output_reg_miny_contents = -1; -static int output_reg_maxx_contents = -1; -static int output_reg_maxy_contents = -1; - -void check_output_limits(int x, int y) -{ - if ((output_reg_minx_contents == -1) || (x < output_reg_minx_contents)) - output_reg_minx_contents = x; - if (x > output_reg_maxx_contents) - output_reg_maxx_contents = x; - if ((output_reg_miny_contents == -1) || (y < output_reg_miny_contents)) - output_reg_miny_contents = y; - if (y > output_reg_maxy_contents) - output_reg_maxy_contents = y; -} - -void reset_output_registers(int miny) -{ - // fprintf(stderr, "reset_output_registers\n"); - output_reg_minx_contents = -1; - output_reg_miny_contents = -1; - output_reg_maxx_contents = -1; - output_reg_maxy_contents = -1; -} - -void get_output_registers(int *minx, int *miny, int *maxx, int *maxy) -{ - *minx = output_reg_minx_contents; - *miny = output_reg_miny_contents; - *maxx = output_reg_maxx_contents; - *maxy = output_reg_maxy_contents; -} - -void init_input_requests() -{ - init_request("ab", abort_request); - init_request("als", alias_macro); - init_request("am", append_macro); - init_request("am1", append_nocomp_macro); - init_request("ami", append_indirect_macro); - init_request("as", append_string); - init_request("as1", append_nocomp_string); - init_request("asciify", asciify_macro); - init_request("backtrace", backtrace_request); - init_request("blm", blank_line_macro); - init_request("break", while_break_request); - init_request("cf", copy_file); - init_request("cflags", char_flags); - init_request("char", define_character); - init_request("chop", chop_macro); - init_request("close", close_request); - init_request("color", activate_color); - init_request("continue", while_continue_request); - init_request("cp", compatible); - init_request("de", define_macro); - init_request("de1", define_nocomp_macro); - init_request("defcolor", define_color); - init_request("dei", define_indirect_macro); - init_request("do", do_request); - init_request("ds", define_string); - init_request("ds1", define_nocomp_string); - init_request("ec", set_escape_char); - init_request("ecr", restore_escape_char); - init_request("ecs", save_escape_char); - init_request("el", else_request); - init_request("em", end_macro); - init_request("eo", escape_off); - init_request("ex", exit_request); - init_request("fchar", define_fallback_character); -#ifdef WIDOW_CONTROL - init_request("fpl", flush_pending_lines); -#endif /* WIDOW_CONTROL */ - init_request("hcode", hyphenation_code); - init_request("hpfcode", hyphenation_patterns_file_code); - init_request("ie", if_else_request); - init_request("if", if_request); - init_request("ig", ignore); - init_request("length", length_request); - init_request("lf", line_file); - init_request("mso", macro_source); - init_request("nop", nop_request); - init_request("nx", next_file); - init_request("open", open_request); - init_request("opena", opena_request); - init_request("output", output_request); - init_request("pc", set_page_character); - init_request("pi", pipe_output); - init_request("pm", print_macros); - init_request("psbb", ps_bbox_request); -#ifndef POPEN_MISSING - init_request("pso", pipe_source); -#endif /* not POPEN_MISSING */ - init_request("rchar", remove_character); - init_request("rd", read_request); - init_request("return", return_macro_request); - init_request("rm", remove_macro); - init_request("rn", rename_macro); - init_request("shift", shift); - init_request("so", source); - init_request("spreadwarn", spreadwarn_request); - init_request("substring", substring_request); - init_request("sy", system_request); - init_request("tm", terminal); - init_request("tm1", terminal1); - init_request("tmc", terminal_continue); - init_request("tr", translate); - init_request("trf", transparent_file); - init_request("trin", translate_input); - init_request("trnt", translate_no_transparent); - init_request("unformat", unformat_macro); - init_request("warn", warn_request); - init_request("while", while_request); - init_request("write", write_request); - init_request("writec", write_request_continue); - init_request("writem", write_macro_request); - init_request("nroff", nroff_request); - init_request("troff", troff_request); -#ifdef COLUMN - init_request("vj", vjustify); -#endif /* COLUMN */ - init_request("warnscale", warnscale_request); - number_reg_dictionary.define(".$", new nargs_reg); - number_reg_dictionary.define(".C", new constant_int_reg(&compatible_flag)); - number_reg_dictionary.define(".F", new filename_reg); - number_reg_dictionary.define(".H", new constant_int_reg(&hresolution)); - number_reg_dictionary.define(".R", new constant_reg("10000")); - number_reg_dictionary.define(".V", new constant_int_reg(&vresolution)); - extern const char *revision; - number_reg_dictionary.define(".Y", new constant_reg(revision)); - number_reg_dictionary.define(".c", new lineno_reg); - number_reg_dictionary.define(".g", new constant_reg("1")); - number_reg_dictionary.define(".color", new constant_int_reg(&color_flag)); - number_reg_dictionary.define(".warn", new constant_int_reg(&warning_mask)); - extern const char *major_version; - number_reg_dictionary.define(".x", new constant_reg(major_version)); - extern const char *minor_version; - number_reg_dictionary.define(".y", new constant_reg(minor_version)); - number_reg_dictionary.define("c.", new writable_lineno_reg); - number_reg_dictionary.define("llx", new variable_reg(&llx_reg_contents)); - number_reg_dictionary.define("lly", new variable_reg(&lly_reg_contents)); - number_reg_dictionary.define("opmaxx", - new variable_reg(&output_reg_maxx_contents)); - number_reg_dictionary.define("opmaxy", - new variable_reg(&output_reg_maxy_contents)); - number_reg_dictionary.define("opminx", - new variable_reg(&output_reg_minx_contents)); - number_reg_dictionary.define("opminy", - new variable_reg(&output_reg_miny_contents)); - number_reg_dictionary.define("slimit", - new variable_reg(&input_stack::limit)); - number_reg_dictionary.define("systat", new variable_reg(&system_status)); - number_reg_dictionary.define("urx", new variable_reg(&urx_reg_contents)); - number_reg_dictionary.define("ury", new variable_reg(&ury_reg_contents)); -} - -object_dictionary request_dictionary(501); - -void init_request(const char *s, REQUEST_FUNCP f) -{ - request_dictionary.define(s, new request(f)); -} - -static request_or_macro *lookup_request(symbol nm) -{ - assert(!nm.is_null()); - request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm); - if (p == 0) { - warning(WARN_MAC, "`%1' not defined", nm.contents()); - p = new macro; - request_dictionary.define(nm, p); - } - return p; -} - -node *charinfo_to_node_list(charinfo *ci, const environment *envp) -{ - // Don't interpret character definitions in compatible mode. - int old_compatible_flag = compatible_flag; - compatible_flag = 0; - int old_escape_char = escape_char; - escape_char = '\\'; - macro *mac = ci->set_macro(0); - assert(mac != 0); - environment *oldenv = curenv; - environment env(envp); - curenv = &env; - curenv->set_composite(); - token old_tok = tok; - input_stack::add_boundary(); - string_iterator *si = - new string_iterator(*mac, "composite character", ci->nm); - input_stack::push(si); - // we don't use process_input_stack, because we don't want to recognise - // requests - for (;;) { - tok.next(); - if (tok.eof()) - break; - if (tok.newline()) { - error("composite character mustn't contain newline"); - while (!tok.eof()) - tok.next(); - break; - } - else - tok.process(); - } - node *n = curenv->extract_output_line(); - input_stack::remove_boundary(); - ci->set_macro(mac); - tok = old_tok; - curenv = oldenv; - compatible_flag = old_compatible_flag; - escape_char = old_escape_char; - return n; -} - -static node *read_draw_node() -{ - token start; - start.next(); - if (!start.delimiter(1)){ - do { - tok.next(); - } while (tok != start && !tok.newline() && !tok.eof()); - } - else { - tok.next(); - if (tok == start) - error("missing argument"); - else { - unsigned char type = tok.ch(); - tok.next(); - int maxpoints = 10; - hvpair *point = new hvpair[maxpoints]; - int npoints = 0; - int no_last_v = 0; - int err = 0; - int i; - for (i = 0; tok != start; i++) { - if (i == maxpoints) { - hvpair *oldpoint = point; - point = new hvpair[maxpoints*2]; - for (int j = 0; j < maxpoints; j++) - point[j] = oldpoint[j]; - maxpoints *= 2; - a_delete oldpoint; - } - if (!get_hunits(&point[i].h, - type == 'f' || type == 't' ? 'u' : 'm')) { - err = 1; - break; - } - ++npoints; - tok.skip(); - point[i].v = V0; - if (tok == start) { - no_last_v = 1; - break; - } - if (!get_vunits(&point[i].v, 'v')) { - err = 1; - break; - } - tok.skip(); - } - while (tok != start && !tok.newline() && !tok.eof()) - tok.next(); - if (!err) { - switch (type) { - case 'l': - if (npoints != 1 || no_last_v) { - error("two arguments needed for line"); - npoints = 1; - } - break; - case 'c': - if (npoints != 1 || !no_last_v) { - error("one argument needed for circle"); - npoints = 1; - point[0].v = V0; - } - break; - case 'e': - if (npoints != 1 || no_last_v) { - error("two arguments needed for ellipse"); - npoints = 1; - } - break; - case 'a': - if (npoints != 2 || no_last_v) { - error("four arguments needed for arc"); - npoints = 2; - } - break; - case '~': - if (no_last_v) - error("even number of arguments needed for spline"); - break; - case 'f': - if (npoints != 1 || !no_last_v) { - error("one argument needed for gray shade"); - npoints = 1; - point[0].v = V0; - } - default: - // silently pass it through - break; - } - draw_node *dn = new draw_node(type, point, npoints, - curenv->get_font_size(), - curenv->get_glyph_color(), - curenv->get_fill_color()); - a_delete point; - return dn; - } - else { - a_delete point; - } - } - } - return 0; -} - -static struct { - const char *name; - int mask; -} warning_table[] = { - { "char", WARN_CHAR }, - { "range", WARN_RANGE }, - { "break", WARN_BREAK }, - { "delim", WARN_DELIM }, - { "el", WARN_EL }, - { "scale", WARN_SCALE }, - { "number", WARN_NUMBER }, - { "syntax", WARN_SYNTAX }, - { "tab", WARN_TAB }, - { "right-brace", WARN_RIGHT_BRACE }, - { "missing", WARN_MISSING }, - { "input", WARN_INPUT }, - { "escape", WARN_ESCAPE }, - { "space", WARN_SPACE }, - { "font", WARN_FONT }, - { "di", WARN_DI }, - { "mac", WARN_MAC }, - { "reg", WARN_REG }, - { "ig", WARN_IG }, - { "color", WARN_COLOR }, - { "all", WARN_TOTAL & ~(WARN_DI | WARN_MAC | WARN_REG) }, - { "w", WARN_TOTAL }, - { "default", DEFAULT_WARNING_MASK }, -}; - -static int lookup_warning(const char *name) -{ - for (unsigned int i = 0; - i < sizeof(warning_table)/sizeof(warning_table[0]); - i++) - if (strcmp(name, warning_table[i].name) == 0) - return warning_table[i].mask; - return 0; -} - -static void enable_warning(const char *name) -{ - int mask = lookup_warning(name); - if (mask) - warning_mask |= mask; - else - error("unknown warning `%1'", name); -} - -static void disable_warning(const char *name) -{ - int mask = lookup_warning(name); - if (mask) - warning_mask &= ~mask; - else - error("unknown warning `%1'", name); -} - -static void copy_mode_error(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - if (ignoring) { - static const char prefix[] = "(in ignored input) "; - char *s = new char[sizeof(prefix) + strlen(format)]; - strcpy(s, prefix); - strcat(s, format); - warning(WARN_IG, s, arg1, arg2, arg3); - a_delete s; - } - else - error(format, arg1, arg2, arg3); -} - -enum error_type { WARNING, OUTPUT_WARNING, ERROR, FATAL }; - -static void do_error(error_type type, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - const char *filename; - int lineno; - if (inhibit_errors && type < FATAL) - return; - if (backtrace_flag) - input_stack::backtrace(); - if (!get_file_line(&filename, &lineno)) - filename = 0; - if (filename) - errprint("%1:%2: ", filename, lineno); - else if (program_name) - fprintf(stderr, "%s: ", program_name); - switch (type) { - case FATAL: - fputs("fatal error: ", stderr); - break; - case ERROR: - break; - case WARNING: - fputs("warning: ", stderr); - break; - case OUTPUT_WARNING: - double fromtop = topdiv->get_vertical_position().to_units() / warn_scale; - fprintf(stderr, "warning [p %d, %.1f%c", - topdiv->get_page_number(), fromtop, warn_scaling_indicator); - if (topdiv != curdiv) { - double fromtop1 = curdiv->get_vertical_position().to_units() - / warn_scale; - fprintf(stderr, ", div `%s', %.1f%c", - curdiv->get_diversion_name(), fromtop1, warn_scaling_indicator); - } - fprintf(stderr, "]: "); - break; - } - errprint(format, arg1, arg2, arg3); - fputc('\n', stderr); - fflush(stderr); - if (type == FATAL) - cleanup_and_exit(1); -} - -int warning(warning_type t, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - if ((t & warning_mask) != 0) { - do_error(WARNING, format, arg1, arg2, arg3); - return 1; - } - else - return 0; -} - -int output_warning(warning_type t, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - if ((t & warning_mask) != 0) { - do_error(OUTPUT_WARNING, format, arg1, arg2, arg3); - return 1; - } - else - return 0; -} - -void error(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error(ERROR, format, arg1, arg2, arg3); -} - -void fatal(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error(FATAL, format, arg1, arg2, arg3); -} - -void fatal_with_file_and_line(const char *filename, int lineno, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - fprintf(stderr, "%s:%d: fatal error: ", filename, lineno); - errprint(format, arg1, arg2, arg3); - fputc('\n', stderr); - fflush(stderr); - cleanup_and_exit(1); -} - -void error_with_file_and_line(const char *filename, int lineno, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - fprintf(stderr, "%s:%d: error: ", filename, lineno); - errprint(format, arg1, arg2, arg3); - fputc('\n', stderr); - fflush(stderr); -} - -dictionary charinfo_dictionary(501); - -charinfo *get_charinfo(symbol nm) -{ - void *p = charinfo_dictionary.lookup(nm); - if (p != 0) - return (charinfo *)p; - charinfo *cp = new charinfo(nm); - (void)charinfo_dictionary.lookup(nm, cp); - return cp; -} - -int charinfo::next_index = 0; - -charinfo::charinfo(symbol s) -: translation(0), mac(0), special_translation(TRANSLATE_NONE), - hyphenation_code(0), flags(0), ascii_code(0), asciify_code(0), - not_found(0), transparent_translate(1), translate_input(0), - fallback(0), nm(s) -{ - index = next_index++; -} - -void charinfo::set_hyphenation_code(unsigned char c) -{ - hyphenation_code = c; -} - -void charinfo::set_translation(charinfo *ci, int tt, int ti) -{ - translation = ci; - if (ci && ti) { - if (hyphenation_code != 0) - ci->set_hyphenation_code(hyphenation_code); - if (asciify_code != 0) - ci->set_asciify_code(asciify_code); - else if (ascii_code != 0) - ci->set_asciify_code(ascii_code); - ci->set_translation_input(); - } - special_translation = TRANSLATE_NONE; - transparent_translate = tt; -} - -void charinfo::set_special_translation(int c, int tt) -{ - special_translation = c; - translation = 0; - transparent_translate = tt; -} - -void charinfo::set_ascii_code(unsigned char c) -{ - ascii_code = c; -} - -void charinfo::set_asciify_code(unsigned char c) -{ - asciify_code = c; -} - -macro *charinfo::set_macro(macro *m, int f) -{ - macro *tem = mac; - mac = m; - fallback = f; - return tem; -} - -void charinfo::set_number(int n) -{ - number = n; - flags |= NUMBERED; -} - -int charinfo::get_number() -{ - assert(flags & NUMBERED); - return number; -} - -symbol UNNAMED_SYMBOL("---"); - -// For numbered characters not between 0 and 255, we make a symbol out -// of the number and store them in this dictionary. - -dictionary numbered_charinfo_dictionary(11); - -charinfo *get_charinfo_by_number(int n) -{ - static charinfo *number_table[256]; - - if (n >= 0 && n < 256) { - charinfo *ci = number_table[n]; - if (!ci) { - ci = new charinfo(UNNAMED_SYMBOL); - ci->set_number(n); - number_table[n] = ci; - } - return ci; - } - else { - symbol ns(i_to_a(n)); - charinfo *ci = (charinfo *)numbered_charinfo_dictionary.lookup(ns); - if (!ci) { - ci = new charinfo(UNNAMED_SYMBOL); - ci->set_number(n); - numbered_charinfo_dictionary.lookup(ns, ci); - } - return ci; - } -} - -int font::name_to_index(const char *nm) -{ - charinfo *ci; - if (nm[1] == 0) - ci = charset_table[nm[0] & 0xff]; - else if (nm[0] == '\\' && nm[2] == 0) - ci = get_charinfo(symbol(nm + 1)); - else - ci = get_charinfo(symbol(nm)); - if (ci == 0) - return -1; - else - return ci->get_index(); -} - -int font::number_to_index(int n) -{ - return get_charinfo_by_number(n)->get_index(); -} diff --git a/contrib/groff/src/roff/troff/node.cc b/contrib/groff/src/roff/troff/node.cc deleted file mode 100644 index 58a3cd8..0000000 --- a/contrib/groff/src/roff/troff/node.cc +++ /dev/null @@ -1,5888 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002 - 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 "troff.h" - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "charinfo.h" -#include "font.h" -#include "reg.h" -#include "input.h" -#include "div.h" -#include "geometry.h" - -#include "nonposix.h" - -#ifdef _POSIX_VERSION - -#include - -#else /* not _POSIX_VERSION */ - -/* traditional Unix */ - -#define WIFEXITED(s) (((s) & 0377) == 0) -#define WEXITSTATUS(s) (((s) >> 8) & 0377) -#define WTERMSIG(s) ((s) & 0177) -#define WIFSTOPPED(s) (((s) & 0377) == 0177) -#define WSTOPSIG(s) (((s) >> 8) & 0377) -#define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177)) - -#endif /* not _POSIX_VERSION */ - -/* - * how many boundaries of images have been written? Useful for - * debugging grohtml - */ - -int image_no = 0; -static int suppress_start_page = 0; - -#define STORE_WIDTH 1 - -symbol HYPHEN_SYMBOL("hy"); - -// Character used when a hyphen is inserted at a line break. -static charinfo *soft_hyphen_char; - -enum constant_space_type { - CONSTANT_SPACE_NONE, - CONSTANT_SPACE_RELATIVE, - CONSTANT_SPACE_ABSOLUTE - }; - -struct special_font_list { - int n; - special_font_list *next; -}; - -special_font_list *global_special_fonts; -static int global_ligature_mode = 1; -static int global_kern_mode = 1; - -class track_kerning_function { - int non_zero; - units min_size; - hunits min_amount; - units max_size; - hunits max_amount; -public: - track_kerning_function(); - track_kerning_function(units, hunits, units, hunits); - int operator==(const track_kerning_function &); - int operator!=(const track_kerning_function &); - hunits compute(int point_size); -}; - -// embolden fontno when this is the current font - -struct conditional_bold { - conditional_bold *next; - int fontno; - hunits offset; - conditional_bold(int, hunits, conditional_bold * = 0); -}; - -struct tfont; - -class font_info { - tfont *last_tfont; - int number; - font_size last_size; - int last_height; - int last_slant; - symbol internal_name; - symbol external_name; - font *fm; - char is_bold; - hunits bold_offset; - track_kerning_function track_kern; - constant_space_type is_constant_spaced; - units constant_space; - int last_ligature_mode; - int last_kern_mode; - conditional_bold *cond_bold_list; - void flush(); -public: - special_font_list *sf; - font_info(symbol nm, int n, symbol enm, font *f); - int contains(charinfo *); - void set_bold(hunits); - void unbold(); - void set_conditional_bold(int, hunits); - void conditional_unbold(int); - void set_track_kern(track_kerning_function &); - void set_constant_space(constant_space_type, units = 0); - int is_named(symbol); - symbol get_name(); - tfont *get_tfont(font_size, int, int, int); - hunits get_space_width(font_size, int); - hunits get_narrow_space_width(font_size); - hunits get_half_narrow_space_width(font_size); - int get_bold(hunits *); - int is_special(); - int is_style(); - friend symbol get_font_name(int, environment *); -}; - -class tfont_spec { -protected: - symbol name; - int input_position; - font *fm; - font_size size; - char is_bold; - char is_constant_spaced; - int ligature_mode; - int kern_mode; - hunits bold_offset; - hunits track_kern; // add this to the width - hunits constant_space_width; - int height; - int slant; -public: - tfont_spec(symbol nm, int pos, font *, font_size, int, int); - tfont_spec(const tfont_spec &spec) { *this = spec; } - tfont_spec plain(); - int operator==(const tfont_spec &); - friend tfont *font_info::get_tfont(font_size fs, int, int, int); -}; - -class tfont : public tfont_spec { - static tfont *tfont_list; - tfont *next; - tfont *plain_version; -public: - tfont(tfont_spec &); - int contains(charinfo *); - hunits get_width(charinfo *c); - int get_bold(hunits *); - int get_constant_space(hunits *); - hunits get_track_kern(); - tfont *get_plain(); - font_size get_size(); - symbol get_name(); - charinfo *get_lig(charinfo *c1, charinfo *c2); - int get_kern(charinfo *c1, charinfo *c2, hunits *res); - int get_input_position(); - int get_character_type(charinfo *); - int get_height(); - int get_slant(); - vunits get_char_height(charinfo *); - vunits get_char_depth(charinfo *); - hunits get_char_skew(charinfo *); - hunits get_italic_correction(charinfo *); - hunits get_left_italic_correction(charinfo *); - hunits get_subscript_correction(charinfo *); - friend tfont *make_tfont(tfont_spec &); -}; - -inline int env_definite_font(environment *env) -{ - return env->get_family()->make_definite(env->get_font()); -} - -/* font_info functions */ - -static font_info **font_table = 0; -static int font_table_size = 0; - -font_info::font_info(symbol nm, int n, symbol enm, font *f) -: last_tfont(0), number(n), last_size(0), - internal_name(nm), external_name(enm), fm(f), - is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1), - last_kern_mode(1), cond_bold_list(0), sf(0) -{ -} - -inline int font_info::contains(charinfo *ci) -{ - return fm != 0 && fm->contains(ci->get_index()); -} - -inline int font_info::is_special() -{ - return fm != 0 && fm->is_special(); -} - -inline int font_info::is_style() -{ - return fm == 0; -} - -tfont *make_tfont(tfont_spec &spec) -{ - for (tfont *p = tfont::tfont_list; p; p = p->next) - if (*p == spec) - return p; - return new tfont(spec); -} - -// this is the current_font, fontno is where we found the character, -// presumably a special font - -tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno) -{ - if (last_tfont == 0 || fs != last_size - || height != last_height || slant != last_slant - || global_ligature_mode != last_ligature_mode - || global_kern_mode != last_kern_mode - || fontno != number) { - font_info *f = font_table[fontno]; - tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant); - for (conditional_bold *p = cond_bold_list; p; p = p->next) - if (p->fontno == fontno) { - spec.is_bold = 1; - spec.bold_offset = p->offset; - break; - } - if (!spec.is_bold && is_bold) { - spec.is_bold = 1; - spec.bold_offset = bold_offset; - } - spec.track_kern = track_kern.compute(fs.to_scaled_points()); - spec.ligature_mode = global_ligature_mode; - spec.kern_mode = global_kern_mode; - switch (is_constant_spaced) { - case CONSTANT_SPACE_NONE: - break; - case CONSTANT_SPACE_ABSOLUTE: - spec.is_constant_spaced = 1; - spec.constant_space_width = constant_space; - break; - case CONSTANT_SPACE_RELATIVE: - spec.is_constant_spaced = 1; - spec.constant_space_width - = scale(constant_space*fs.to_scaled_points(), - units_per_inch, - 36*72*sizescale); - break; - default: - assert(0); - } - if (fontno != number) - return make_tfont(spec); - last_tfont = make_tfont(spec); - last_size = fs; - last_height = height; - last_slant = slant; - last_ligature_mode = global_ligature_mode; - last_kern_mode = global_kern_mode; - } - return last_tfont; -} - -int font_info::get_bold(hunits *res) -{ - if (is_bold) { - *res = bold_offset; - return 1; - } - else - return 0; -} - -void font_info::unbold() -{ - if (is_bold) { - is_bold = 0; - flush(); - } -} - -void font_info::set_bold(hunits offset) -{ - if (!is_bold || offset != bold_offset) { - is_bold = 1; - bold_offset = offset; - flush(); - } -} - -void font_info::set_conditional_bold(int fontno, hunits offset) -{ - for (conditional_bold *p = cond_bold_list; p; p = p->next) - if (p->fontno == fontno) { - if (offset != p->offset) { - p->offset = offset; - flush(); - } - return; - } - cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list); -} - -conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x) -: next(x), fontno(f), offset(h) -{ -} - -void font_info::conditional_unbold(int fontno) -{ - for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next) - if ((*p)->fontno == fontno) { - conditional_bold *tem = *p; - *p = (*p)->next; - delete tem; - flush(); - return; - } -} - -void font_info::set_constant_space(constant_space_type type, units x) -{ - if (type != is_constant_spaced - || (type != CONSTANT_SPACE_NONE && x != constant_space)) { - flush(); - is_constant_spaced = type; - constant_space = x; - } -} - -void font_info::set_track_kern(track_kerning_function &tk) -{ - if (track_kern != tk) { - track_kern = tk; - flush(); - } -} - -void font_info::flush() -{ - last_tfont = 0; -} - -int font_info::is_named(symbol s) -{ - return internal_name == s; -} - -symbol font_info::get_name() -{ - return internal_name; -} - -symbol get_font_name(int fontno, environment *env) -{ - symbol f = font_table[fontno]->get_name(); - if (font_table[fontno]->is_style()) { - return concat(env->get_family()->nm, f); - } - return f; -} - -hunits font_info::get_space_width(font_size fs, int space_size) -{ - if (is_constant_spaced == CONSTANT_SPACE_NONE) - return scale(hunits(fm->get_space_width(fs.to_scaled_points())), - space_size, 12); - else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE) - return constant_space; - else - return scale(constant_space*fs.to_scaled_points(), - units_per_inch, 36*72*sizescale); -} - -hunits font_info::get_narrow_space_width(font_size fs) -{ - charinfo *ci = get_charinfo(symbol("|")); - if (fm->contains(ci->get_index())) - return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); - else - return hunits(fs.to_units()/6); -} - -hunits font_info::get_half_narrow_space_width(font_size fs) -{ - charinfo *ci = get_charinfo(symbol("^")); - if (fm->contains(ci->get_index())) - return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); - else - return hunits(fs.to_units()/12); -} - -/* tfont */ - -tfont_spec::tfont_spec(symbol nm, int n, font *f, - font_size s, int h, int sl) -: name(nm), input_position(n), fm(f), size(s), - is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1), - height(h), slant(sl) -{ - if (height == size.to_scaled_points()) - height = 0; -} - -int tfont_spec::operator==(const tfont_spec &spec) -{ - if (fm == spec.fm - && size == spec.size - && input_position == spec.input_position - && name == spec.name - && height == spec.height - && slant == spec.slant - && (is_bold - ? (spec.is_bold && bold_offset == spec.bold_offset) - : !spec.is_bold) - && track_kern == spec.track_kern - && (is_constant_spaced - ? (spec.is_constant_spaced - && constant_space_width == spec.constant_space_width) - : !spec.is_constant_spaced) - && ligature_mode == spec.ligature_mode - && kern_mode == spec.kern_mode) - return 1; - else - return 0; -} - -tfont_spec tfont_spec::plain() -{ - return tfont_spec(name, input_position, fm, size, height, slant); -} - -hunits tfont::get_width(charinfo *c) -{ - if (is_constant_spaced) - return constant_space_width; - else if (is_bold) - return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) - + track_kern + bold_offset); - else - return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) - + track_kern); -} - -vunits tfont::get_char_height(charinfo *c) -{ - vunits v = fm->get_height(c->get_index(), size.to_scaled_points()); - if (height != 0 && height != size.to_scaled_points()) - return scale(v, height, size.to_scaled_points()); - else - return v; -} - -vunits tfont::get_char_depth(charinfo *c) -{ - vunits v = fm->get_depth(c->get_index(), size.to_scaled_points()); - if (height != 0 && height != size.to_scaled_points()) - return scale(v, height, size.to_scaled_points()); - else - return v; -} - -hunits tfont::get_char_skew(charinfo *c) -{ - return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant)); -} - -hunits tfont::get_italic_correction(charinfo *c) -{ - return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points())); -} - -hunits tfont::get_left_italic_correction(charinfo *c) -{ - return hunits(fm->get_left_italic_correction(c->get_index(), - size.to_scaled_points())); -} - -hunits tfont::get_subscript_correction(charinfo *c) -{ - return hunits(fm->get_subscript_correction(c->get_index(), - size.to_scaled_points())); -} - -inline int tfont::get_input_position() -{ - return input_position; -} - -inline int tfont::contains(charinfo *ci) -{ - return fm->contains(ci->get_index()); -} - -inline int tfont::get_character_type(charinfo *ci) -{ - return fm->get_character_type(ci->get_index()); -} - -inline int tfont::get_bold(hunits *res) -{ - if (is_bold) { - *res = bold_offset; - return 1; - } - else - return 0; -} - -inline int tfont::get_constant_space(hunits *res) -{ - if (is_constant_spaced) { - *res = constant_space_width; - return 1; - } - else - return 0; -} - -inline hunits tfont::get_track_kern() -{ - return track_kern; -} - -inline tfont *tfont::get_plain() -{ - return plain_version; -} - -inline font_size tfont::get_size() -{ - return size; -} - -inline symbol tfont::get_name() -{ - return name; -} - -inline int tfont::get_height() -{ - return height; -} - -inline int tfont::get_slant() -{ - return slant; -} - -symbol SYMBOL_ff("ff"); -symbol SYMBOL_fi("fi"); -symbol SYMBOL_fl("fl"); -symbol SYMBOL_Fi("Fi"); -symbol SYMBOL_Fl("Fl"); - -charinfo *tfont::get_lig(charinfo *c1, charinfo *c2) -{ - if (ligature_mode == 0) - return 0; - charinfo *ci = 0; - if (c1->get_ascii_code() == 'f') { - switch (c2->get_ascii_code()) { - case 'f': - if (fm->has_ligature(font::LIG_ff)) - ci = get_charinfo(SYMBOL_ff); - break; - case 'i': - if (fm->has_ligature(font::LIG_fi)) - ci = get_charinfo(SYMBOL_fi); - break; - case 'l': - if (fm->has_ligature(font::LIG_fl)) - ci = get_charinfo(SYMBOL_fl); - break; - } - } - else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) { - switch (c2->get_ascii_code()) { - case 'i': - if (fm->has_ligature(font::LIG_ffi)) - ci = get_charinfo(SYMBOL_Fi); - break; - case 'l': - if (fm->has_ligature(font::LIG_ffl)) - ci = get_charinfo(SYMBOL_Fl); - break; - } - } - if (ci != 0 && fm->contains(ci->get_index())) - return ci; - return 0; -} - -inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res) -{ - if (kern_mode == 0) - return 0; - else { - int n = fm->get_kern(c1->get_index(), - c2->get_index(), - size.to_scaled_points()); - if (n) { - *res = hunits(n); - return 1; - } - else - return 0; - } -} - -tfont *tfont::tfont_list = 0; - -tfont::tfont(tfont_spec &spec) : tfont_spec(spec) -{ - next = tfont_list; - tfont_list = this; - tfont_spec plain_spec = plain(); - tfont *p; - for (p = tfont_list; p; p = p->next) - if (*p == plain_spec) { - plain_version = p; - break; - } - if (!p) - plain_version = new tfont(plain_spec); -} - -/* output_file */ - -class real_output_file : public output_file { -#ifndef POPEN_MISSING - int piped; -#endif - int printing; // decision via optional page list - int output_on; // \O[0] or \O[1] escape calls - virtual void really_transparent_char(unsigned char) = 0; - virtual void really_print_line(hunits x, vunits y, node *n, - vunits before, vunits after, hunits width) = 0; - virtual void really_begin_page(int pageno, vunits page_length) = 0; - virtual void really_copy_file(hunits x, vunits y, const char *filename); - virtual void really_put_filename(const char *filename); - virtual void really_on(); - virtual void really_off(); -protected: - FILE *fp; -public: - real_output_file(); - ~real_output_file(); - void flush(); - void transparent_char(unsigned char); - void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width); - void begin_page(int pageno, vunits page_length); - void put_filename(const char *filename); - void on(); - void off(); - int is_on(); - int is_printing(); - void copy_file(hunits x, vunits y, const char *filename); -}; - -class suppress_output_file : public real_output_file { -public: - suppress_output_file(); - void really_transparent_char(unsigned char); - void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width); - void really_begin_page(int pageno, vunits page_length); -}; - -class ascii_output_file : public real_output_file { -public: - ascii_output_file(); - void really_transparent_char(unsigned char); - void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width); - void really_begin_page(int pageno, vunits page_length); - void outc(unsigned char c); - void outs(const char *s); -}; - -void ascii_output_file::outc(unsigned char c) -{ - fputc(c, fp); -} - -void ascii_output_file::outs(const char *s) -{ - fputc('<', fp); - if (s) - fputs(s, fp); - fputc('>', fp); -} - -struct hvpair; - -class troff_output_file : public real_output_file { - units hpos; - units vpos; - units output_vpos; - units output_hpos; - int force_motion; - int current_size; - int current_slant; - int current_height; - tfont *current_tfont; - color *current_fill_color; - color *current_glyph_color; - int current_font_number; - symbol *font_position; - int nfont_positions; - enum { TBUF_SIZE = 256 }; - char tbuf[TBUF_SIZE]; - int tbuf_len; - int tbuf_kern; - int begun_page; - void do_motion(); - void put(char c); - void put(unsigned char c); - void put(int i); - void put(unsigned int i); - void put(const char *s); - void set_font(tfont *tf); - void flush_tbuf(); -public: - troff_output_file(); - ~troff_output_file(); - void trailer(vunits page_length); - void put_char(charinfo *, tfont *, color *, color *); - void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits); - void right(hunits); - void down(vunits); - void moveto(hunits, vunits); - void start_special(tfont *, color *, color *, int = 0); - void start_special(); - void special_char(unsigned char c); - void end_special(); - void word_marker(); - void really_transparent_char(unsigned char c); - void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width); - void really_begin_page(int pageno, vunits page_length); - void really_copy_file(hunits x, vunits y, const char *filename); - void really_put_filename(const char *filename); - void really_on(); - void really_off(); - void draw(char, hvpair *, int, font_size, color *, color *); - void determine_line_limits (char code, hvpair *point, int npoints); - void check_charinfo(tfont *tf, charinfo *ci); - void glyph_color(color *c); - void fill_color(color *c); - int get_hpos() { return hpos; } - int get_vpos() { return vpos; } -}; - -static void put_string(const char *s, FILE *fp) -{ - for (; *s != '\0'; ++s) - putc(*s, fp); -} - -inline void troff_output_file::put(char c) -{ - putc(c, fp); -} - -inline void troff_output_file::put(unsigned char c) -{ - putc(c, fp); -} - -inline void troff_output_file::put(const char *s) -{ - put_string(s, fp); -} - -inline void troff_output_file::put(int i) -{ - put_string(i_to_a(i), fp); -} - -inline void troff_output_file::put(unsigned int i) -{ - put_string(ui_to_a(i), fp); -} - -void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol, - int no_init_string) -{ - flush_tbuf(); - do_motion(); - if (tf != current_tfont) - set_font(tf); - glyph_color(gcol); - fill_color(fcol); - if (!no_init_string) - put("x X "); -} - -void troff_output_file::start_special() -{ - flush_tbuf(); - do_motion(); - put("x X "); -} - -void troff_output_file::special_char(unsigned char c) -{ - put(c); - if (c == '\n') - put('+'); -} - -void troff_output_file::end_special() -{ - put('\n'); -} - -inline void troff_output_file::moveto(hunits h, vunits v) -{ - hpos = h.to_units(); - vpos = v.to_units(); -} - -void troff_output_file::really_print_line(hunits x, vunits y, node *n, - vunits before, vunits after, hunits width) -{ - moveto(x, y); - while (n != 0) { - n->tprint(this); - n = n->next; - } - flush_tbuf(); - // This ensures that transparent throughput will have a more predictable - // position. - do_motion(); - force_motion = 1; - hpos = 0; - put('n'); - put(before.to_units()); - put(' '); - put(after.to_units()); - put('\n'); -} - -inline void troff_output_file::word_marker() -{ - flush_tbuf(); - if (is_on()) - put('w'); -} - -inline void troff_output_file::right(hunits n) -{ - hpos += n.to_units(); -} - -inline void troff_output_file::down(vunits n) -{ - vpos += n.to_units(); -} - -void troff_output_file::do_motion() -{ - if (force_motion) { - put('V'); - put(vpos); - put('\n'); - put('H'); - put(hpos); - put('\n'); - } - else { - if (hpos != output_hpos) { - units n = hpos - output_hpos; - if (n > 0 && n < hpos) { - put('h'); - put(n); - } - else { - put('H'); - put(hpos); - } - put('\n'); - } - if (vpos != output_vpos) { - units n = vpos - output_vpos; - if (n > 0 && n < vpos) { - put('v'); - put(n); - } - else { - put('V'); - put(vpos); - } - put('\n'); - } - } - output_vpos = vpos; - output_hpos = hpos; - force_motion = 0; -} - -void troff_output_file::flush_tbuf() -{ - if (!is_on()) { - tbuf_len = 0; - return; - } - - if (tbuf_len == 0) - return; - if (tbuf_kern == 0) - put('t'); - else { - put('u'); - put(tbuf_kern); - put(' '); - } - check_output_limits(hpos, vpos); - check_output_limits(hpos, vpos - current_size); - - for (int i = 0; i < tbuf_len; i++) - put(tbuf[i]); - put('\n'); - tbuf_len = 0; -} - -void troff_output_file::check_charinfo(tfont *tf, charinfo *ci) -{ - if (!is_on()) - return; - - int height = tf->get_char_height(ci).to_units(); - int width = tf->get_width(ci).to_units() - + tf->get_italic_correction(ci).to_units(); - int depth = tf->get_char_depth(ci).to_units(); - check_output_limits(output_hpos, output_vpos - height); - check_output_limits(output_hpos + width, output_vpos + depth); -} - -void troff_output_file::put_char_width(charinfo *ci, tfont *tf, - color *gcol, color *fcol, - hunits w, hunits k) -{ - int kk = k.to_units(); - if (!is_on()) { - flush_tbuf(); - hpos += w.to_units() + kk; - return; - } - if (tf != current_tfont) { - flush_tbuf(); - set_font(tf); - } - char c = ci->get_ascii_code(); - if (c == '\0') { - flush_tbuf(); - do_motion(); - glyph_color(gcol); - fill_color(fcol); - check_charinfo(tf, ci); - if (ci->numbered()) { - put('N'); - put(ci->get_number()); - } - else { - put('C'); - const char *s = ci->nm.contents(); - if (s[1] == 0) { - put('\\'); - put(s[0]); - } - else - put(s); - } - put('\n'); - hpos += w.to_units() + kk; - } - else if (tcommand_flag) { - if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos - && (!gcol || gcol == current_glyph_color) - && (!fcol || fcol == current_fill_color) - && kk == tbuf_kern - && tbuf_len < TBUF_SIZE) { - check_charinfo(tf, ci); - tbuf[tbuf_len++] = c; - output_hpos += w.to_units() + kk; - hpos = output_hpos; - return; - } - flush_tbuf(); - do_motion(); - glyph_color(gcol); - fill_color(fcol); - check_charinfo(tf, ci); - tbuf[tbuf_len++] = c; - output_hpos += w.to_units() + kk; - tbuf_kern = kk; - hpos = output_hpos; - } - else { - // flush_tbuf(); - int n = hpos - output_hpos; - check_charinfo(tf, ci); - // check_output_limits(output_hpos, output_vpos); - if (vpos == output_vpos - && (!gcol || gcol == current_glyph_color) - && (!fcol || fcol == current_fill_color) - && n > 0 && n < 100 && !force_motion) { - put(char(n/10 + '0')); - put(char(n%10 + '0')); - put(c); - output_hpos = hpos; - } - else { - do_motion(); - put('c'); - put(c); - } - hpos += w.to_units() + kk; - } -} - -void troff_output_file::put_char(charinfo *ci, tfont *tf, - color *gcol, color *fcol) -{ - flush_tbuf(); - if (!is_on()) - return; - if (tf != current_tfont) - set_font(tf); - char c = ci->get_ascii_code(); - if (c == '\0') { - do_motion(); - glyph_color(gcol); - fill_color(fcol); - if (ci->numbered()) { - put('N'); - put(ci->get_number()); - } - else { - put('C'); - const char *s = ci->nm.contents(); - if (s[1] == 0) { - put('\\'); - put(s[0]); - } - else - put(s); - } - put('\n'); - } - else { - int n = hpos - output_hpos; - if (vpos == output_vpos - && (!gcol || gcol == current_glyph_color) - && (!fcol || fcol == current_fill_color) - && n > 0 && n < 100) { - put(char(n/10 + '0')); - put(char(n%10 + '0')); - put(c); - output_hpos = hpos; - } - else { - do_motion(); - glyph_color(gcol); - fill_color(fcol); - put('c'); - put(c); - } - } -} - -void troff_output_file::set_font(tfont *tf) -{ - if (current_tfont == tf) - return; - int n = tf->get_input_position(); - symbol nm = tf->get_name(); - if (n >= nfont_positions || font_position[n] != nm) { - put("x font "); - put(n); - put(' '); - put(nm.contents()); - put('\n'); - if (n >= nfont_positions) { - int old_nfont_positions = nfont_positions; - symbol *old_font_position = font_position; - nfont_positions *= 3; - nfont_positions /= 2; - if (nfont_positions <= n) - nfont_positions = n + 10; - font_position = new symbol[nfont_positions]; - memcpy(font_position, old_font_position, - old_nfont_positions*sizeof(symbol)); - a_delete old_font_position; - } - font_position[n] = nm; - } - if (current_font_number != n) { - put('f'); - put(n); - put('\n'); - current_font_number = n; - } - int size = tf->get_size().to_scaled_points(); - if (current_size != size) { - put('s'); - put(size); - put('\n'); - current_size = size; - } - int slant = tf->get_slant(); - if (current_slant != slant) { - put("x Slant "); - put(slant); - put('\n'); - current_slant = slant; - } - int height = tf->get_height(); - if (current_height != height) { - put("x Height "); - put(height == 0 ? current_size : height); - put('\n'); - current_height = height; - } - current_tfont = tf; -} - -void troff_output_file::fill_color(color *col) -{ - if (!col || current_fill_color == col || !color_flag) - return; - flush_tbuf(); - put("DF"); - unsigned int components[4]; - color_scheme cs; - cs = col->get_components(components); - switch (cs) { - case DEFAULT: - put('d'); - break; - case RGB: - put("r "); - put(Red); - put(' '); - put(Green); - put(' '); - put(Blue); - break; - case CMY: - put("c "); - put(Cyan); - put(' '); - put(Magenta); - put(' '); - put(Yellow); - break; - case CMYK: - put("k "); - put(Cyan); - put(' '); - put(Magenta); - put(' '); - put(Yellow); - put(' '); - put(Black); - break; - case GRAY: - put("g "); - put(Gray); - break; - } - put('\n'); - current_fill_color = col; -} - -void troff_output_file::glyph_color(color *col) -{ - if (!col || current_glyph_color == col || !color_flag) - return; - flush_tbuf(); - put("m"); - unsigned int components[4]; - color_scheme cs; - cs = col->get_components(components); - switch (cs) { - case DEFAULT: - put('d'); - break; - case RGB: - put("r "); - put(Red); - put(' '); - put(Green); - put(' '); - put(Blue); - break; - case CMY: - put("c "); - put(Cyan); - put(' '); - put(Magenta); - put(' '); - put(Yellow); - break; - case CMYK: - put("k "); - put(Cyan); - put(' '); - put(Magenta); - put(' '); - put(Yellow); - put(' '); - put(Black); - break; - case GRAY: - put("g "); - put(Gray); - break; - } - put('\n'); - current_glyph_color = col; -} - -// determine_line_limits - works out the smallest box which will contain -// the entity, code, built from the point array. -void troff_output_file::determine_line_limits(char code, hvpair *point, - int npoints) -{ - int i, x, y; - - if (!is_on()) - return; - - switch (code) { - case 'c': - case 'C': - // only the h field is used when defining a circle - check_output_limits(output_hpos, - output_vpos - point[0].h.to_units()/2); - check_output_limits(output_hpos + point[0].h.to_units(), - output_vpos + point[0].h.to_units()/2); - break; - case 'E': - case 'e': - check_output_limits(output_hpos, - output_vpos - point[0].v.to_units()/2); - check_output_limits(output_hpos + point[0].h.to_units(), - output_vpos + point[0].v.to_units()/2); - break; - case 'P': - case 'p': - x = output_hpos; - y = output_vpos; - check_output_limits(x, y); - for (i = 0; i < npoints; i++) { - x += point[i].h.to_units(); - y += point[i].v.to_units(); - check_output_limits(x, y); - } - break; - case 't': - x = output_hpos; - y = output_vpos; - for (i = 0; i < npoints; i++) { - x += point[i].h.to_units(); - y += point[i].v.to_units(); - check_output_limits(x, y); - } - break; - case 'a': - double c[2]; - int p[4]; - int minx, miny, maxx, maxy; - x = output_hpos; - y = output_vpos; - p[0] = point[0].h.to_units(); - p[1] = point[0].v.to_units(); - p[2] = point[1].h.to_units(); - p[3] = point[1].v.to_units(); - if (adjust_arc_center(p, c)) { - check_output_arc_limits(x, y, - p[0], p[1], p[2], p[3], - c[0], c[1], - &minx, &maxx, &miny, &maxy); - check_output_limits(minx, miny); - check_output_limits(maxx, maxy); - break; - } - // fall through - case 'l': - x = output_hpos; - y = output_vpos; - check_output_limits(x, y); - for (i = 0; i < npoints; i++) { - x += point[i].h.to_units(); - y += point[i].v.to_units(); - check_output_limits(x, y); - } - break; - default: - x = output_hpos; - y = output_vpos; - for (i = 0; i < npoints; i++) { - x += point[i].h.to_units(); - y += point[i].v.to_units(); - check_output_limits(x, y); - } - } -} - -void troff_output_file::draw(char code, hvpair *point, int npoints, - font_size fsize, color *gcol, color *fcol) -{ - int i; - flush_tbuf(); - do_motion(); - glyph_color(gcol); - fill_color(fcol); - if (is_on()) { - int size = fsize.to_scaled_points(); - if (current_size != size) { - put('s'); - put(size); - put('\n'); - current_size = size; - current_tfont = 0; - } - put('D'); - put(code); - if (code == 'c') { - put(' '); - put(point[0].h.to_units()); - } - else - for (i = 0; i < npoints; i++) { - put(' '); - put(point[i].h.to_units()); - put(' '); - put(point[i].v.to_units()); - } - determine_line_limits(code, point, npoints); - } - - for (i = 0; i < npoints; i++) - output_hpos += point[i].h.to_units(); - hpos = output_hpos; - if (code != 'e') { - for (i = 0; i < npoints; i++) - output_vpos += point[i].v.to_units(); - vpos = output_vpos; - } - if (is_on()) - put('\n'); -} - -void troff_output_file::really_on() -{ - flush_tbuf(); - force_motion = 1; - do_motion(); -} - -void troff_output_file::really_off() -{ - flush_tbuf(); -} - -void troff_output_file::really_put_filename(const char *filename) -{ - flush_tbuf(); - put("F "); - put(filename); - put('\n'); -} - -void troff_output_file::really_begin_page(int pageno, vunits page_length) -{ - flush_tbuf(); - if (begun_page) { - if (page_length > V0) { - put('V'); - put(page_length.to_units()); - put('\n'); - } - } - else - begun_page = 1; - current_tfont = 0; - current_font_number = -1; - current_size = 0; - // current_height = 0; - // current_slant = 0; - hpos = 0; - vpos = 0; - output_hpos = 0; - output_vpos = 0; - force_motion = 1; - for (int i = 0; i < nfont_positions; i++) - font_position[i] = NULL_SYMBOL; - put('p'); - put(pageno); - put('\n'); -} - -void troff_output_file::really_copy_file(hunits x, vunits y, const char *filename) -{ - moveto(x, y); - flush_tbuf(); - do_motion(); - errno = 0; - FILE *ifp = fopen(filename, "r"); - if (ifp == 0) - error("can't open `%1': %2", filename, strerror(errno)); - else { - int c; - while ((c = getc(ifp)) != EOF) - put(char(c)); - fclose(ifp); - } - force_motion = 1; - current_size = 0; - current_tfont = 0; - current_font_number = -1; - for (int i = 0; i < nfont_positions; i++) - font_position[i] = NULL_SYMBOL; -} - -void troff_output_file::really_transparent_char(unsigned char c) -{ - put(c); -} - -troff_output_file::~troff_output_file() -{ - a_delete font_position; -} - -void troff_output_file::trailer(vunits page_length) -{ - flush_tbuf(); - if (page_length > V0) { - put("x trailer\n"); - put('V'); - put(page_length.to_units()); - put('\n'); - } - put("x stop\n"); -} - -troff_output_file::troff_output_file() -: current_slant(0), current_height(0), nfont_positions(10), tbuf_len(0), - begun_page(0) -{ - font_position = new symbol[nfont_positions]; - put("x T "); - put(device); - put('\n'); - put("x res "); - put(units_per_inch); - put(' '); - put(hresolution); - put(' '); - put(vresolution); - put('\n'); - put("x init\n"); -} - -/* output_file */ - -output_file *the_output = 0; - -output_file::output_file() -{ -} - -output_file::~output_file() -{ -} - -void output_file::trailer(vunits) -{ -} - -void output_file::put_filename(const char *filename) -{ -} - -void output_file::on() -{ -} - -void output_file::off() -{ -} - -real_output_file::real_output_file() -: printing(0), output_on(1) -{ -#ifndef POPEN_MISSING - if (pipe_command) { - if ((fp = popen(pipe_command, POPEN_WT)) != 0) { - piped = 1; - return; - } - error("pipe open failed: %1", strerror(errno)); - } - piped = 0; -#endif /* not POPEN_MISSING */ - fp = stdout; -} - -real_output_file::~real_output_file() -{ - if (!fp) - return; - // To avoid looping, set fp to 0 before calling fatal(). - if (ferror(fp) || fflush(fp) < 0) { - fp = 0; - fatal("error writing output file"); - } -#ifndef POPEN_MISSING - if (piped) { - int result = pclose(fp); - fp = 0; - if (result < 0) - fatal("pclose failed"); - if (!WIFEXITED(result)) - error("output process `%1' got fatal signal %2", - pipe_command, - WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result)); - else { - int exit_status = WEXITSTATUS(result); - if (exit_status != 0) - error("output process `%1' exited with status %2", - pipe_command, exit_status); - } - } - else -#endif /* not POPEN MISSING */ - if (fclose(fp) < 0) { - fp = 0; - fatal("error closing output file"); - } -} - -void real_output_file::flush() -{ - if (fflush(fp) < 0) - fatal("error writing output file"); -} - -int real_output_file::is_printing() -{ - return printing; -} - -void real_output_file::begin_page(int pageno, vunits page_length) -{ - printing = in_output_page_list(pageno); - if (printing) - really_begin_page(pageno, page_length); -} - -void real_output_file::copy_file(hunits x, vunits y, const char *filename) -{ - if (printing && output_on) - really_copy_file(x, y, filename); - check_output_limits(x.to_units(), y.to_units()); -} - -void real_output_file::transparent_char(unsigned char c) -{ - if (printing && output_on) - really_transparent_char(c); -} - -void real_output_file::print_line(hunits x, vunits y, node *n, - vunits before, vunits after, hunits width) -{ - if (printing) - really_print_line(x, y, n, before, after, width); - delete_node_list(n); -} - -void real_output_file::really_copy_file(hunits, vunits, const char *) -{ - // do nothing -} - -void real_output_file::put_filename(const char *filename) -{ - really_put_filename(filename); -} - -void real_output_file::really_put_filename(const char *filename) -{ -} - -void real_output_file::on() -{ - really_on(); - if (output_on == 0) - output_on = 1; -} - -void real_output_file::off() -{ - really_off(); - output_on = 0; -} - -int real_output_file::is_on() -{ - return output_on; -} - -void real_output_file::really_on() -{ -} - -void real_output_file::really_off() -{ -} - -/* ascii_output_file */ - -void ascii_output_file::really_transparent_char(unsigned char c) -{ - putc(c, fp); -} - -void ascii_output_file::really_print_line(hunits, vunits, node *n, vunits, vunits, hunits width) -{ - while (n != 0) { - n->ascii_print(this); - n = n->next; - } - fputc('\n', fp); -} - -void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/) -{ - fputs("\n", fp); -} - -ascii_output_file::ascii_output_file() -{ -} - -/* suppress_output_file */ - -suppress_output_file::suppress_output_file() -{ -} - -void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits) -{ -} - -void suppress_output_file::really_begin_page(int, vunits) -{ -} - -void suppress_output_file::really_transparent_char(unsigned char) -{ -} - -/* glyphs, ligatures, kerns, discretionary breaks */ - -class charinfo_node : public node { -protected: - charinfo *ci; -public: - charinfo_node(charinfo *, node * = 0); - int ends_sentence(); - int overlaps_vertically(); - int overlaps_horizontally(); -}; - -charinfo_node::charinfo_node(charinfo *c, node *x) -: node(x), ci(c) -{ -} - -int charinfo_node::ends_sentence() -{ - if (ci->ends_sentence()) - return 1; - else if (ci->transparent()) - return 2; - else - return 0; -} - -int charinfo_node::overlaps_horizontally() -{ - return ci->overlaps_horizontally(); -} - -int charinfo_node::overlaps_vertically() -{ - return ci->overlaps_vertically(); -} - -class glyph_node : public charinfo_node { - static glyph_node *free_list; -protected: - tfont *tf; - color *gcol; - color *fcol; /* this is needed for grotty */ -#ifdef STORE_WIDTH - hunits wid; - glyph_node(charinfo *, tfont *, color *, color *, hunits, node * = 0); -#endif -public: - void *operator new(size_t); - void operator delete(void *); - glyph_node(charinfo *, tfont *, color *, color *, node * = 0); - ~glyph_node() {} - node *copy(); - node *merge_glyph_node(glyph_node *); - node *merge_self(node *); - hunits width(); - node *last_char_node(); - units size(); - void vertical_extent(vunits *, vunits *); - hunits subscript_correction(); - hunits italic_correction(); - hunits left_italic_correction(); - hunits skew(); - hyphenation_type get_hyphenation_type(); - tfont *get_tfont(); - color *get_glyph_color(); - color *get_fill_color(); - void tprint(troff_output_file *); - void zero_width_tprint(troff_output_file *); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - node *add_self(node *, hyphen_list **); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int character_type(); - int same(node *); - const char *type(); - int force_tprint(); -}; - -glyph_node *glyph_node::free_list = 0; - -class ligature_node : public glyph_node { - node *n1; - node *n2; -#ifdef STORE_WIDTH - ligature_node(charinfo *, tfont *, color *, color *, hunits, - node *, node *, node * = 0); -#endif -public: - void *operator new(size_t); - void operator delete(void *); - ligature_node(charinfo *, tfont *, color *, color *, - node *, node *, node * = 0); - ~ligature_node(); - node *copy(); - node *add_self(node *, hyphen_list **); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int same(node *); - const char *type(); - int force_tprint(); -}; - -class kern_pair_node : public node { - hunits amount; - node *n1; - node *n2; -public: - kern_pair_node(hunits n, node *first, node *second, node *x = 0); - ~kern_pair_node(); - node *copy(); - node *merge_glyph_node(glyph_node *); - node *add_self(node *, hyphen_list **); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - node *add_discretionary_hyphen(); - hunits width(); - node *last_char_node(); - hunits italic_correction(); - hunits subscript_correction(); - void tprint(troff_output_file *); - hyphenation_type get_hyphenation_type(); - int ends_sentence(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int same(node *); - const char *type(); - int force_tprint(); - void vertical_extent(vunits *, vunits *); -}; - -class dbreak_node : public node { - node *none; - node *pre; - node *post; -public: - dbreak_node(node *n, node *p, node *x = 0); - ~dbreak_node(); - node *copy(); - node *merge_glyph_node(glyph_node *); - node *add_discretionary_hyphen(); - hunits width(); - node *last_char_node(); - hunits italic_correction(); - hunits subscript_correction(); - void tprint(troff_output_file *); - breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0, - int is_inner = 0); - int nbreaks(); - int ends_sentence(); - void split(int, node **, node **); - hyphenation_type get_hyphenation_type(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int same(node *); - const char *type(); - int force_tprint(); -}; - -void *glyph_node::operator new(size_t n) -{ - assert(n == sizeof(glyph_node)); - if (!free_list) { - const int BLOCK = 1024; - free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - glyph_node *p = free_list; - free_list = (glyph_node *)(free_list->next); - p->next = 0; - return p; -} - -void *ligature_node::operator new(size_t n) -{ - return new char[n]; -} - -void glyph_node::operator delete(void *p) -{ - if (p) { - ((glyph_node *)p)->next = free_list; - free_list = (glyph_node *)p; - } -} - -void ligature_node::operator delete(void *p) -{ - delete[] (char *)p; -} - -glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc, node *x) -: charinfo_node(c, x), tf(t), gcol(gc), fcol(fc) -{ -#ifdef STORE_WIDTH - wid = tf->get_width(ci); -#endif -} - -#ifdef STORE_WIDTH -glyph_node::glyph_node(charinfo *c, tfont *t, - color *gc, color *fc, hunits w, node *x) -: charinfo_node(c, x), tf(t), gcol(gc), fcol(fc), wid(w) -{ -} -#endif - -node *glyph_node::copy() -{ -#ifdef STORE_WIDTH - return new glyph_node(ci, tf, gcol, fcol, wid); -#else - return new glyph_node(ci, tf, gcol, fcol); -#endif -} - -node *glyph_node::merge_self(node *nd) -{ - return nd->merge_glyph_node(this); -} - -int glyph_node::character_type() -{ - return tf->get_character_type(ci); -} - -node *glyph_node::add_self(node *n, hyphen_list **p) -{ - assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); - next = 0; - node *nn; - if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) { - next = n; - nn = this; - } - if ((*p)->hyphen) - nn = nn->add_discretionary_hyphen(); - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return nn; -} - -units glyph_node::size() -{ - return tf->get_size().to_units(); -} - -hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(ci->get_hyphenation_code(), tail); -} - -tfont *node::get_tfont() -{ - return 0; -} - -tfont *glyph_node::get_tfont() -{ - return tf; -} - -color *node::get_glyph_color() -{ - return 0; -} - -color *glyph_node::get_glyph_color() -{ - return gcol; -} - -color *node::get_fill_color() -{ - return 0; -} - -color *glyph_node::get_fill_color() -{ - return fcol; -} - -node *node::merge_glyph_node(glyph_node * /*gn*/) -{ - return 0; -} - -node *glyph_node::merge_glyph_node(glyph_node *gn) -{ - if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) { - charinfo *lig; - if ((lig = tf->get_lig(ci, gn->ci)) != 0) { - node *next1 = next; - next = 0; - return new ligature_node(lig, tf, gcol, fcol, this, gn, next1); - } - hunits kern; - if (tf->get_kern(ci, gn->ci, &kern)) { - node *next1 = next; - next = 0; - return new kern_pair_node(kern, this, gn, next1); - } - } - return 0; -} - -#ifdef STORE_WIDTH -inline -#endif -hunits glyph_node::width() -{ -#ifdef STORE_WIDTH - return wid; -#else - return tf->get_width(ci); -#endif -} - -node *glyph_node::last_char_node() -{ - return this; -} - -void glyph_node::vertical_extent(vunits *min, vunits *max) -{ - *min = -tf->get_char_height(ci); - *max = tf->get_char_depth(ci); -} - -hunits glyph_node::skew() -{ - return tf->get_char_skew(ci); -} - -hunits glyph_node::subscript_correction() -{ - return tf->get_subscript_correction(ci); -} - -hunits glyph_node::italic_correction() -{ - return tf->get_italic_correction(ci); -} - -hunits glyph_node::left_italic_correction() -{ - return tf->get_left_italic_correction(ci); -} - -hyphenation_type glyph_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -void glyph_node::ascii_print(ascii_output_file *ascii) -{ - unsigned char c = ci->get_ascii_code(); - if (c != 0) - ascii->outc(c); - else - ascii->outs(ci->nm.contents()); -} - -ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc, - node *gn1, node *gn2, node *x) -: glyph_node(c, t, gc, fc, x), n1(gn1), n2(gn2) -{ -} - -#ifdef STORE_WIDTH -ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc, - hunits w, node *gn1, node *gn2, node *x) -: glyph_node(c, t, gc, fc, w, x), n1(gn1), n2(gn2) -{ -} -#endif - -ligature_node::~ligature_node() -{ - delete n1; - delete n2; -} - -node *ligature_node::copy() -{ -#ifdef STORE_WIDTH - return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy()); -#else - return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy()); -#endif -} - -void ligature_node::ascii_print(ascii_output_file *ascii) -{ - n1->ascii_print(ascii); - n2->ascii_print(ascii); -} - -hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail) -{ - return n1->get_hyphen_list(n2->get_hyphen_list(tail)); -} - -node *ligature_node::add_self(node *n, hyphen_list **p) -{ - n = n1->add_self(n, p); - n = n2->add_self(n, p); - n1 = n2 = 0; - delete this; - return n; -} - -kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x) -: node(x), amount(n), n1(first), n2(second) -{ -} - -dbreak_node::dbreak_node(node *n, node *p, node *x) -: node(x), none(n), pre(p), post(0) -{ -} - -node *dbreak_node::merge_glyph_node(glyph_node *gn) -{ - glyph_node *gn2 = (glyph_node *)gn->copy(); - node *new_none = none ? none->merge_glyph_node(gn) : 0; - node *new_post = post ? post->merge_glyph_node(gn2) : 0; - if (new_none == 0 && new_post == 0) { - delete gn2; - return 0; - } - if (new_none != 0) - none = new_none; - else { - gn->next = none; - none = gn; - } - if (new_post != 0) - post = new_post; - else { - gn2->next = post; - post = gn2; - } - return this; -} - -node *kern_pair_node::merge_glyph_node(glyph_node *gn) -{ - node *nd = n2->merge_glyph_node(gn); - if (nd == 0) - return 0; - n2 = nd; - nd = n2->merge_self(n1); - if (nd) { - nd->next = next; - n1 = 0; - n2 = 0; - delete this; - return nd; - } - return this; -} - -hunits kern_pair_node::italic_correction() -{ - return n2->italic_correction(); -} - -hunits kern_pair_node::subscript_correction() -{ - return n2->subscript_correction(); -} - -void kern_pair_node::vertical_extent(vunits *min, vunits *max) -{ - n1->vertical_extent(min, max); - vunits min2, max2; - n2->vertical_extent(&min2, &max2); - if (min2 < *min) - *min = min2; - if (max2 > *max) - *max = max2; -} - -node *kern_pair_node::add_discretionary_hyphen() -{ - tfont *tf = n2->get_tfont(); - if (tf) { - if (tf->contains(soft_hyphen_char)) { - color *gcol = n2->get_glyph_color(); - color *fcol = n2->get_fill_color(); - node *next1 = next; - next = 0; - node *n = copy(); - glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol); - node *nn = n->merge_glyph_node(gn); - if (nn == 0) { - gn->next = n; - nn = gn; - } - return new dbreak_node(this, nn, next1); - } - } - return this; -} - -kern_pair_node::~kern_pair_node() -{ - if (n1 != 0) - delete n1; - if (n2 != 0) - delete n2; -} - -dbreak_node::~dbreak_node() -{ - delete_node_list(pre); - delete_node_list(post); - delete_node_list(none); -} - -node *kern_pair_node::copy() -{ - return new kern_pair_node(amount, n1->copy(), n2->copy()); -} - -node *copy_node_list(node *n) -{ - node *p = 0; - while (n != 0) { - node *nn = n->copy(); - nn->next = p; - p = nn; - n = n->next; - } - while (p != 0) { - node *pp = p->next; - p->next = n; - n = p; - p = pp; - } - return n; -} - -void delete_node_list(node *n) -{ - while (n != 0) { - node *tem = n; - n = n->next; - delete tem; - } -} - -node *dbreak_node::copy() -{ - dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre)); - p->post = copy_node_list(post); - return p; -} - -hyphen_list *node::get_hyphen_list(hyphen_list *tail) -{ - return tail; -} - -hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail) -{ - return n1->get_hyphen_list(n2->get_hyphen_list(tail)); -} - -class hyphen_inhibitor_node : public node { -public: - hyphen_inhibitor_node(node *nd = 0); - node *copy(); - int same(node *); - const char *type(); - int force_tprint(); - hyphenation_type get_hyphenation_type(); -}; - -hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd) -{ -} - -node *hyphen_inhibitor_node::copy() -{ - return new hyphen_inhibitor_node; -} - -int hyphen_inhibitor_node::same(node *) -{ - return 1; -} - -const char *hyphen_inhibitor_node::type() -{ - return "hyphen_inhibitor_node"; -} - -int hyphen_inhibitor_node::force_tprint() -{ - return 0; -} - -hyphenation_type hyphen_inhibitor_node::get_hyphenation_type() -{ - return HYPHEN_INHIBIT; -} - -/* add_discretionary_hyphen methods */ - -node *dbreak_node::add_discretionary_hyphen() -{ - if (post) - post = post->add_discretionary_hyphen(); - if (none) - none = none->add_discretionary_hyphen(); - return this; -} - -node *node::add_discretionary_hyphen() -{ - tfont *tf = get_tfont(); - if (!tf) - return new hyphen_inhibitor_node(this); - if (tf->contains(soft_hyphen_char)) { - color *gcol = get_glyph_color(); - color *fcol = get_fill_color(); - node *next1 = next; - next = 0; - node *n = copy(); - glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol); - node *n1 = n->merge_glyph_node(gn); - if (n1 == 0) { - gn->next = n; - n1 = gn; - } - return new dbreak_node(this, n1, next1); - } - return this; -} - -node *node::merge_self(node *) -{ - return 0; -} - -node *node::add_self(node *n, hyphen_list ** /*p*/) -{ - next = n; - return this; -} - -node *kern_pair_node::add_self(node *n, hyphen_list **p) -{ - n = n1->add_self(n, p); - n = n2->add_self(n, p); - n1 = n2 = 0; - delete this; - return n; -} - -hunits node::width() -{ - return H0; -} - -node *node::last_char_node() -{ - return 0; -} - -int node::force_tprint() -{ - return 0; -} - -hunits hmotion_node::width() -{ - return n; -} - -units node::size() -{ - return points_to_units(10); -} - -hunits kern_pair_node::width() -{ - return n1->width() + n2->width() + amount; -} - -node *kern_pair_node::last_char_node() -{ - node *nd = n2->last_char_node(); - if (nd) - return nd; - return n1->last_char_node(); -} - -hunits dbreak_node::width() -{ - hunits x = H0; - for (node *n = none; n != 0; n = n->next) - x += n->width(); - return x; -} - -node *dbreak_node::last_char_node() -{ - for (node *n = none; n; n = n->next) { - node *last = n->last_char_node(); - if (last) - return last; - } - return 0; -} - -hunits dbreak_node::italic_correction() -{ - return none ? none->italic_correction() : H0; -} - -hunits dbreak_node::subscript_correction() -{ - return none ? none->subscript_correction() : H0; -} - -class italic_corrected_node : public node { - node *n; - hunits x; -public: - italic_corrected_node(node *, hunits, node * = 0); - ~italic_corrected_node(); - node *copy(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - hunits width(); - node *last_char_node(); - void vertical_extent(vunits *, vunits *); - int ends_sentence(); - int overlaps_horizontally(); - int overlaps_vertically(); - int same(node *); - hyphenation_type get_hyphenation_type(); - tfont *get_tfont(); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - int character_type(); - void tprint(troff_output_file *); - hunits subscript_correction(); - hunits skew(); - node *add_self(node *, hyphen_list **); - const char *type(); - int force_tprint(); -}; - -node *node::add_italic_correction(hunits *width) -{ - hunits ic = italic_correction(); - if (ic.is_zero()) - return this; - else { - node *next1 = next; - next = 0; - *width += ic; - return new italic_corrected_node(this, ic, next1); - } -} - -italic_corrected_node::italic_corrected_node(node *nn, hunits xx, node *p) -: node(p), n(nn), x(xx) -{ - assert(n != 0); -} - -italic_corrected_node::~italic_corrected_node() -{ - delete n; -} - -node *italic_corrected_node::copy() -{ - return new italic_corrected_node(n->copy(), x); -} - -hunits italic_corrected_node::width() -{ - return n->width() + x; -} - -void italic_corrected_node::vertical_extent(vunits *min, vunits *max) -{ - n->vertical_extent(min, max); -} - -void italic_corrected_node::tprint(troff_output_file *out) -{ - n->tprint(out); - out->right(x); -} - -hunits italic_corrected_node::skew() -{ - return n->skew() - x/2; -} - -hunits italic_corrected_node::subscript_correction() -{ - return n->subscript_correction() - x; -} - -void italic_corrected_node::ascii_print(ascii_output_file *out) -{ - n->ascii_print(out); -} - -int italic_corrected_node::ends_sentence() -{ - return n->ends_sentence(); -} - -int italic_corrected_node::overlaps_horizontally() -{ - return n->overlaps_horizontally(); -} - -int italic_corrected_node::overlaps_vertically() -{ - return n->overlaps_vertically(); -} - -node *italic_corrected_node::last_char_node() -{ - return n->last_char_node(); -} - -tfont *italic_corrected_node::get_tfont() -{ - return n->get_tfont(); -} - -hyphenation_type italic_corrected_node::get_hyphenation_type() -{ - return n->get_hyphenation_type(); -} - -node *italic_corrected_node::add_self(node *nd, hyphen_list **p) -{ - nd = n->add_self(nd, p); - hunits not_interested; - nd = nd->add_italic_correction(¬_interested); - n = 0; - delete this; - return nd; -} - -hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail) -{ - return n->get_hyphen_list(tail); -} - -int italic_corrected_node::character_type() -{ - return n->character_type(); -} - -class break_char_node : public node { - node *ch; - char break_code; - color *col; -public: - break_char_node(node *, int, color *, node * = 0); - ~break_char_node(); - node *copy(); - hunits width(); - vunits vertical_width(); - node *last_char_node(); - int character_type(); - int ends_sentence(); - node *add_self(node *, hyphen_list **); - hyphen_list *get_hyphen_list(hyphen_list *s = 0); - void tprint(troff_output_file *); - void zero_width_tprint(troff_output_file *); - void ascii_print(ascii_output_file *); - void asciify(macro *); - hyphenation_type get_hyphenation_type(); - int overlaps_vertically(); - int overlaps_horizontally(); - units size(); - tfont *get_tfont(); - int same(node *); - const char *type(); - int force_tprint(); -}; - -break_char_node::break_char_node(node *n, int bc, color *c, node *x) -: node(x), ch(n), break_code(bc), col(c) -{ -} - -break_char_node::~break_char_node() -{ - delete ch; -} - -node *break_char_node::copy() -{ - return new break_char_node(ch->copy(), break_code, col); -} - -hunits break_char_node::width() -{ - return ch->width(); -} - -vunits break_char_node::vertical_width() -{ - return ch->vertical_width(); -} - -node *break_char_node::last_char_node() -{ - return ch->last_char_node(); -} - -int break_char_node::character_type() -{ - return ch->character_type(); -} - -int break_char_node::ends_sentence() -{ - return ch->ends_sentence(); -} - -node *break_char_node::add_self(node *n, hyphen_list **p) -{ - assert((*p)->hyphenation_code == 0); - if ((*p)->breakable && (break_code & 1)) { - n = new space_node(H0, col, n); - n->freeze_space(); - } - next = n; - n = this; - if ((*p)->breakable && (break_code & 2)) { - n = new space_node(H0, col, n); - n->freeze_space(); - } - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return n; -} - -hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(0, tail); -} - -hyphenation_type break_char_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -void break_char_node::ascii_print(ascii_output_file *ascii) -{ - ch->ascii_print(ascii); -} - -int break_char_node::overlaps_vertically() -{ - return ch->overlaps_vertically(); -} - -int break_char_node::overlaps_horizontally() -{ - return ch->overlaps_horizontally(); -} - -units break_char_node::size() -{ - return ch->size(); -} - -tfont *break_char_node::get_tfont() -{ - return ch->get_tfont(); -} - -node *extra_size_node::copy() -{ - return new extra_size_node(n); -} - -node *vertical_size_node::copy() -{ - return new vertical_size_node(n); -} - -node *hmotion_node::copy() -{ - return new hmotion_node(n, was_tab, unformat, col); -} - -node *space_char_hmotion_node::copy() -{ - return new space_char_hmotion_node(n, col); -} - -node *vmotion_node::copy() -{ - return new vmotion_node(n, col); -} - -node *dummy_node::copy() -{ - return new dummy_node; -} - -node *transparent_dummy_node::copy() -{ - return new transparent_dummy_node; -} - -hline_node::~hline_node() -{ - if (n) - delete n; -} - -node *hline_node::copy() -{ - return new hline_node(x, n ? n->copy() : 0); -} - -hunits hline_node::width() -{ - return x < H0 ? H0 : x; -} - -vline_node::~vline_node() -{ - if (n) - delete n; -} - -node *vline_node::copy() -{ - return new vline_node(x, n ? n->copy() : 0); -} - -hunits vline_node::width() -{ - return n == 0 ? H0 : n->width(); -} - -zero_width_node::zero_width_node(node *nd) : n(nd) -{ -} - -zero_width_node::~zero_width_node() -{ - delete_node_list(n); -} - -node *zero_width_node::copy() -{ - return new zero_width_node(copy_node_list(n)); -} - -int node_list_character_type(node *p) -{ - int t = 0; - for (; p; p = p->next) - t |= p->character_type(); - return t; -} - -int zero_width_node::character_type() -{ - return node_list_character_type(n); -} - -void node_list_vertical_extent(node *p, vunits *min, vunits *max) -{ - *min = V0; - *max = V0; - vunits cur_vpos = V0; - vunits v1, v2; - for (; p; p = p->next) { - p->vertical_extent(&v1, &v2); - v1 += cur_vpos; - if (v1 < *min) - *min = v1; - v2 += cur_vpos; - if (v2 > *max) - *max = v2; - cur_vpos += p->vertical_width(); - } -} - -void zero_width_node::vertical_extent(vunits *min, vunits *max) -{ - node_list_vertical_extent(n, min, max); -} - -overstrike_node::overstrike_node() : list(0), max_width(H0) -{ -} - -overstrike_node::~overstrike_node() -{ - delete_node_list(list); -} - -node *overstrike_node::copy() -{ - overstrike_node *on = new overstrike_node; - for (node *tem = list; tem; tem = tem->next) - on->overstrike(tem->copy()); - return on; -} - -void overstrike_node::overstrike(node *n) -{ - if (n == 0) - return; - hunits w = n->width(); - if (w > max_width) - max_width = w; - node **p; - for (p = &list; *p; p = &(*p)->next) - ; - n->next = 0; - *p = n; -} - -hunits overstrike_node::width() -{ - return max_width; -} - -bracket_node::bracket_node() : list(0), max_width(H0) -{ -} - -bracket_node::~bracket_node() -{ - delete_node_list(list); -} - -node *bracket_node::copy() -{ - bracket_node *on = new bracket_node; - node *last = 0; - node *tem; - if (list) - list->last = 0; - for (tem = list; tem; tem = tem->next) { - if (tem->next) - tem->next->last = tem; - last = tem; - } - for (tem = last; tem; tem = tem->last) - on->bracket(tem->copy()); - return on; -} - -void bracket_node::bracket(node *n) -{ - if (n == 0) - return; - hunits w = n->width(); - if (w > max_width) - max_width = w; - n->next = list; - list = n; -} - -hunits bracket_node::width() -{ - return max_width; -} - -int node::nspaces() -{ - return 0; -} - -int node::merge_space(hunits, hunits, hunits) -{ - return 0; -} - -#if 0 -space_node *space_node::free_list = 0; - -void *space_node::operator new(size_t n) -{ - assert(n == sizeof(space_node)); - if (!free_list) { - free_list = (space_node *)new char[sizeof(space_node)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - space_node *p = free_list; - free_list = (space_node *)(free_list->next); - p->next = 0; - return p; -} - -inline void space_node::operator delete(void *p) -{ - if (p) { - ((space_node *)p)->next = free_list; - free_list = (space_node *)p; - } -} -#endif - -space_node::space_node(hunits nn, color *c, node *p) -: node(p), n(nn), set(0), was_escape_colon(0), col(c) -{ -} - -space_node::space_node(hunits nn, int s, int flag, color *c, node *p) -: node(p), n(nn), set(s), was_escape_colon(flag), col(c) -{ -} - -#if 0 -space_node::~space_node() -{ -} -#endif - -node *space_node::copy() -{ - return new space_node(n, set, was_escape_colon, col); -} - -int space_node::force_tprint() -{ - return 0; -} - -int space_node::nspaces() -{ - return set ? 0 : 1; -} - -int space_node::merge_space(hunits h, hunits, hunits) -{ - n += h; - return 1; -} - -hunits space_node::width() -{ - return n; -} - -void node::spread_space(int*, hunits*) -{ -} - -void space_node::spread_space(int *nspaces, hunits *desired_space) -{ - if (!set) { - assert(*nspaces > 0); - if (*nspaces == 1) { - n += *desired_space; - *desired_space = H0; - } - else { - hunits extra = *desired_space / *nspaces; - *desired_space -= extra; - n += extra; - } - *nspaces -= 1; - set = 1; - } -} - -void node::freeze_space() -{ -} - -void space_node::freeze_space() -{ - set = 1; -} - -void node::is_escape_colon() -{ -} - -void space_node::is_escape_colon() -{ - was_escape_colon = 1; -} - -diverted_space_node::diverted_space_node(vunits d, node *p) -: node(p), n(d) -{ -} - -node *diverted_space_node::copy() -{ - return new diverted_space_node(n); -} - -diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p) -: node(p), filename(s) -{ -} - -node *diverted_copy_file_node::copy() -{ - return new diverted_copy_file_node(filename); -} - -int node::ends_sentence() -{ - return 0; -} - -int kern_pair_node::ends_sentence() -{ - switch (n2->ends_sentence()) { - case 0: - return 0; - case 1: - return 1; - case 2: - break; - default: - assert(0); - } - return n1->ends_sentence(); -} - -int node_list_ends_sentence(node *n) -{ - for (; n != 0; n = n->next) - switch (n->ends_sentence()) { - case 0: - return 0; - case 1: - return 1; - case 2: - break; - default: - assert(0); - } - return 2; -} - -int dbreak_node::ends_sentence() -{ - return node_list_ends_sentence(none); -} - -int node::overlaps_horizontally() -{ - return 0; -} - -int node::overlaps_vertically() -{ - return 0; -} - -int node::discardable() -{ - return 0; -} - -int space_node::discardable() -{ - return set ? 0 : 1; -} - -vunits node::vertical_width() -{ - return V0; -} - -vunits vline_node::vertical_width() -{ - return x; -} - -vunits vmotion_node::vertical_width() -{ - return n; -} - -int node::set_unformat_flag() -{ - return 1; -} - -int node::character_type() -{ - return 0; -} - -hunits node::subscript_correction() -{ - return H0; -} - -hunits node::italic_correction() -{ - return H0; -} - -hunits node::left_italic_correction() -{ - return H0; -} - -hunits node::skew() -{ - return H0; -} - -/* vertical_extent methods */ - -void node::vertical_extent(vunits *min, vunits *max) -{ - vunits v = vertical_width(); - if (v < V0) { - *min = v; - *max = V0; - } - else { - *max = v; - *min = V0; - } -} - -void vline_node::vertical_extent(vunits *min, vunits *max) -{ - if (n == 0) - node::vertical_extent(min, max); - else { - vunits cmin, cmax; - n->vertical_extent(&cmin, &cmax); - vunits h = n->size(); - if (x < V0) { - if (-x < h) { - *min = x; - *max = V0; - } - else { - // we print the first character and then move up, so - *max = cmax; - // we print the last character and then move up h - *min = cmin + h; - if (*min > V0) - *min = V0; - *min += x; - } - } - else { - if (x < h) { - *max = x; - *min = V0; - } - else { - // we move down by h and then print the first character, so - *min = cmin + h; - if (*min > V0) - *min = V0; - *max = x + cmax; - } - } - } -} - -/* ascii_print methods */ - -static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n) -{ - if (n == 0) - return; - ascii_print_reverse_node_list(ascii, n->next); - n->ascii_print(ascii); -} - -void dbreak_node::ascii_print(ascii_output_file *ascii) -{ - ascii_print_reverse_node_list(ascii, none); -} - -void kern_pair_node::ascii_print(ascii_output_file *ascii) -{ - n1->ascii_print(ascii); - n2->ascii_print(ascii); -} - -void node::ascii_print(ascii_output_file *) -{ -} - -void space_node::ascii_print(ascii_output_file *ascii) -{ - if (!n.is_zero()) - ascii->outc(' '); -} - -void hmotion_node::ascii_print(ascii_output_file *ascii) -{ - // this is pretty arbitrary - if (n >= points_to_units(2)) - ascii->outc(' '); -} - -void space_char_hmotion_node::ascii_print(ascii_output_file *ascii) -{ - ascii->outc(' '); -} - -/* asciify methods */ - -void node::asciify(macro *m) -{ - m->append(this); -} - -void glyph_node::asciify(macro *m) -{ - unsigned char c = ci->get_asciify_code(); - if (c == 0) - c = ci->get_ascii_code(); - if (c != 0) { - m->append(c); - delete this; - } - else - m->append(this); -} - -void kern_pair_node::asciify(macro *m) -{ - n1->asciify(m); - n2->asciify(m); - n1 = n2 = 0; - delete this; -} - -static void asciify_reverse_node_list(macro *m, node *n) -{ - if (n == 0) - return; - asciify_reverse_node_list(m, n->next); - n->asciify(m); -} - -void dbreak_node::asciify(macro *m) -{ - asciify_reverse_node_list(m, none); - none = 0; - delete this; -} - -void ligature_node::asciify(macro *m) -{ - n1->asciify(m); - n2->asciify(m); - n1 = n2 = 0; - delete this; -} - -void break_char_node::asciify(macro *m) -{ - ch->asciify(m); - ch = 0; - delete this; -} - -void italic_corrected_node::asciify(macro *m) -{ - n->asciify(m); - n = 0; - delete this; -} - -void left_italic_corrected_node::asciify(macro *m) -{ - if (n) { - n->asciify(m); - n = 0; - } - delete this; -} - -void hmotion_node::asciify(macro *m) -{ - if (was_tab) { - m->append('\t'); - delete this; - } - else - m->append(this); -} - -space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c, - node *next) -: hmotion_node(i, c, next) -{ -} - -void space_char_hmotion_node::asciify(macro *m) -{ - m->append(ESCAPE_SPACE); - delete this; -} - -void space_node::asciify(macro *m) -{ - if (was_escape_colon) { - m->append(ESCAPE_COLON); - delete this; - } - else - m->append(this); -} - -void word_space_node::asciify(macro *m) -{ - for (width_list *w = orig_width; w; w = w->next) - m->append(' '); - delete this; -} - -void unbreakable_space_node::asciify(macro *m) -{ - m->append(ESCAPE_TILDE); - delete this; -} - -void line_start_node::asciify(macro *) -{ - delete this; -} - -void vertical_size_node::asciify(macro *) -{ - delete this; -} - -breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/, - breakpoint *rest, int /*is_inner*/) -{ - return rest; -} - -int node::nbreaks() -{ - return 0; -} - -breakpoint *space_node::get_breakpoints(hunits width, int ns, - breakpoint *rest, int is_inner) -{ - if (next->discardable()) - return rest; - breakpoint *bp = new breakpoint; - bp->next = rest; - bp->width = width; - bp->nspaces = ns; - bp->hyphenated = 0; - if (is_inner) { - assert(rest != 0); - bp->index = rest->index + 1; - bp->nd = rest->nd; - } - else { - bp->nd = this; - bp->index = 0; - } - return bp; -} - -int space_node::nbreaks() -{ - if (next->discardable()) - return 0; - else - return 1; -} - -static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp, - int ns, breakpoint *rest) -{ - if (p != 0) { - rest = p->get_breakpoints(*widthp, - ns, - node_list_get_breakpoints(p->next, widthp, ns, - rest), - 1); - *widthp += p->width(); - } - return rest; -} - -breakpoint *dbreak_node::get_breakpoints(hunits width, int ns, - breakpoint *rest, int is_inner) -{ - breakpoint *bp = new breakpoint; - bp->next = rest; - bp->width = width; - for (node *tem = pre; tem != 0; tem = tem->next) - bp->width += tem->width(); - bp->nspaces = ns; - bp->hyphenated = 1; - if (is_inner) { - assert(rest != 0); - bp->index = rest->index + 1; - bp->nd = rest->nd; - } - else { - bp->nd = this; - bp->index = 0; - } - return node_list_get_breakpoints(none, &width, ns, bp); -} - -int dbreak_node::nbreaks() -{ - int i = 1; - for (node *tem = none; tem != 0; tem = tem->next) - i += tem->nbreaks(); - return i; -} - -void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/) -{ - assert(0); -} - -void space_node::split(int where, node **pre, node **post) -{ - assert(where == 0); - *pre = next; - *post = 0; - delete this; -} - -static void node_list_split(node *p, int *wherep, node **prep, node **postp) -{ - if (p == 0) - return; - int nb = p->nbreaks(); - node_list_split(p->next, wherep, prep, postp); - if (*wherep < 0) { - p->next = *postp; - *postp = p; - } - else if (*wherep < nb) { - p->next = *prep; - p->split(*wherep, prep, postp); - } - else { - p->next = *prep; - *prep = p; - } - *wherep -= nb; -} - -void dbreak_node::split(int where, node **prep, node **postp) -{ - assert(where >= 0); - if (where == 0) { - *postp = post; - post = 0; - if (pre == 0) - *prep = next; - else { - node *tem; - for (tem = pre; tem->next != 0; tem = tem->next) - ; - tem->next = next; - *prep = pre; - } - pre = 0; - delete this; - } - else { - *prep = next; - where -= 1; - node_list_split(none, &where, prep, postp); - none = 0; - delete this; - } -} - -hyphenation_type node::get_hyphenation_type() -{ - return HYPHEN_BOUNDARY; -} - -hyphenation_type dbreak_node::get_hyphenation_type() -{ - return HYPHEN_INHIBIT; -} - -hyphenation_type kern_pair_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type dummy_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type transparent_dummy_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type hmotion_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type space_char_hmotion_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type overstrike_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type space_node::get_hyphenation_type() -{ - if (was_escape_colon) - return HYPHEN_MIDDLE; - return HYPHEN_BOUNDARY; -} - -hyphenation_type unbreakable_space_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -int node::interpret(macro *) -{ - return 0; -} - -special_node::special_node(const macro &m, int n) -: mac(m), no_init_string(n) -{ - font_size fs = curenv->get_font_size(); - int char_height = curenv->get_char_height(); - int char_slant = curenv->get_char_slant(); - int fontno = env_definite_font(curenv); - tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno); - if (curenv->is_composite()) - tf = tf->get_plain(); - gcol = curenv->get_glyph_color(); - fcol = curenv->get_fill_color(); -} - -special_node::special_node(const macro &m, tfont *t, - color *gc, color *fc, int n) -: mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n) -{ -} - -int special_node::same(node *n) -{ - return mac == ((special_node *)n)->mac - && tf == ((special_node *)n)->tf - && gcol == ((special_node *)n)->gcol - && fcol == ((special_node *)n)->fcol - && no_init_string == ((special_node *)n)->no_init_string; -} - -const char *special_node::type() -{ - return "special_node"; -} - -int special_node::ends_sentence() -{ - return 2; -} - -int special_node::force_tprint() -{ - return 0; -} - -node *special_node::copy() -{ - return new special_node(mac, tf, gcol, fcol, no_init_string); -} - -void special_node::tprint_start(troff_output_file *out) -{ - out->start_special(tf, gcol, fcol, no_init_string); -} - -void special_node::tprint_char(troff_output_file *out, unsigned char c) -{ - out->special_char(c); -} - -void special_node::tprint_end(troff_output_file *out) -{ - out->end_special(); -} - -tfont *special_node::get_tfont() -{ - return tf; -} - -/* suppress_node */ - -suppress_node::suppress_node(int on_or_off, int issue_limits) -: is_on(on_or_off), emit_limits(issue_limits), - filename(0), position(0), image_id(0) -{ -} - -suppress_node::suppress_node(symbol f, char p, int id) -: is_on(2), emit_limits(0), filename(f), position(p), image_id(id) -{ -} - -suppress_node::suppress_node(int issue_limits, int on_or_off, - symbol f, char p, int id) -: is_on(on_or_off), emit_limits(issue_limits), - filename(f), position(p), image_id(id) -{ -} - -int suppress_node::same(node *n) -{ - return ((is_on == ((suppress_node *)n)->is_on) - && (emit_limits == ((suppress_node *)n)->emit_limits) - && (filename == ((suppress_node *)n)->filename) - && (position == ((suppress_node *)n)->position) - && (image_id == ((suppress_node *)n)->image_id)); -} - -const char *suppress_node::type() -{ - return "suppress_node"; -} - -node *suppress_node::copy() -{ - return new suppress_node(emit_limits, is_on, filename, position, image_id); -} - -int get_reg_int(const char *p) -{ - reg *r = (reg *)number_reg_dictionary.lookup(p); - units prev_value; - if (r && (r->get_value(&prev_value))) - return (int)prev_value; - else - warning(WARN_REG, "number register `%1' not defined", p); - return 0; -} - -const char *get_reg_str(const char *p) -{ - reg *r = (reg *)number_reg_dictionary.lookup(p); - if (r) - return r->get_string(); - else - warning(WARN_REG, "register `%1' not defined", p); - return 0; -} - -void suppress_node::put(troff_output_file *out, const char *s) -{ - int i = 0; - while (s[i] != (char)0) { - out->special_char(s[i]); - i++; - } -} - -/* - * We need to remember the start of the image and its name. - */ - -static char last_position = 0; -static const char *last_image_filename = 0; -static int last_image_id = 0; - -inline int min(int a, int b) -{ - return a < b ? a : b; -} - -/* - * tprint - if (is_on == 2) - * remember current position (l, r, c, i) and filename - * else - * if (emit_limits) - * if (html) - * emit image tag - * else - * emit postscript bounds for image - * else - * if (suppress boolean differs from current state) - * alter state - * reset registers - * record current page - * set low water mark. - */ - -void suppress_node::tprint(troff_output_file *out) -{ - int current_page = topdiv->get_page_number(); - // firstly check to see whether this suppress node contains - // an image filename & position. - if (is_on == 2) { - // remember position and filename - last_position = position; - last_image_filename = strdup(filename.contents()); - last_image_id = image_id; - // printf("start of image and page = %d\n", current_page); - } - else { - // now check whether the suppress node requires us to issue limits. - if (emit_limits) { - char name[8192]; - // remember that the filename will contain a %d in which the - // last_image_id is placed - sprintf(name, last_image_filename, last_image_id); - if (is_html) { - switch (last_position) { - case 'c': - out->start_special(); - put(out, "html-tag:.centered-image"); - break; - case 'r': - out->start_special(); - put(out, "html-tag:.right-image"); - break; - case 'l': - out->start_special(); - put(out, "html-tag:.left-image"); - break; - case 'i': - ; - default: - ; - } - out->end_special(); - out->start_special(); - put(out, "html-tag:.auto-image "); - put(out, name); - out->end_special(); - } - else { - // postscript (or other device) - if (suppress_start_page > 0 && current_page != suppress_start_page) - error("suppression limit registers span more than one page;\n" - "image description %1 will be wrong", image_no); - // if (topdiv->get_page_number() != suppress_start_page) - // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n", - // topdiv->get_page_number(), suppress_start_page); - - // remember that the filename will contain a %d in which the - // image_no is placed - fprintf(stderr, - "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n", - topdiv->get_page_number(), - get_reg_int("opminx"), get_reg_int("opminy"), - get_reg_int("opmaxx"), get_reg_int("opmaxy"), - // page offset + line length - get_reg_int(".o") + get_reg_int(".l"), - name, hresolution, vresolution, get_reg_str(".F")); - fflush(stderr); - } - } - else { - if (is_on) { - out->on(); - // lastly we reset the output registers - reset_output_registers(out->get_vpos()); - } - else - out->off(); - suppress_start_page = current_page; - } - } -} - -int suppress_node::force_tprint() -{ - return is_on; -} - -hunits suppress_node::width() -{ - return H0; -} - -/* composite_node */ - -class composite_node : public charinfo_node { - node *n; - tfont *tf; -public: - composite_node(node *, charinfo *, tfont *, node * = 0); - ~composite_node(); - node *copy(); - hunits width(); - node *last_char_node(); - units size(); - void tprint(troff_output_file *); - hyphenation_type get_hyphenation_type(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - hyphen_list *get_hyphen_list(hyphen_list *tail); - node *add_self(node *, hyphen_list **); - tfont *get_tfont(); - int same(node *); - const char *type(); - int force_tprint(); - void vertical_extent(vunits *, vunits *); - vunits vertical_width(); -}; - -composite_node::composite_node(node *p, charinfo *c, tfont *t, node *x) -: charinfo_node(c, x), n(p), tf(t) -{ -} - -composite_node::~composite_node() -{ - delete_node_list(n); -} - -node *composite_node::copy() -{ - return new composite_node(copy_node_list(n), ci, tf); -} - -hunits composite_node::width() -{ - hunits x; - if (tf->get_constant_space(&x)) - return x; - x = H0; - for (node *tem = n; tem; tem = tem->next) - x += tem->width(); - hunits offset; - if (tf->get_bold(&offset)) - x += offset; - x += tf->get_track_kern(); - return x; -} - -node *composite_node::last_char_node() -{ - return this; -} - -vunits composite_node::vertical_width() -{ - vunits v = V0; - for (node *tem = n; tem; tem = tem->next) - v += tem->vertical_width(); - return v; -} - -units composite_node::size() -{ - return tf->get_size().to_units(); -} - -hyphenation_type composite_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -void composite_node::asciify(macro *m) -{ - unsigned char c = ci->get_asciify_code(); - if (c == 0) - c = ci->get_ascii_code(); - if (c != 0) { - m->append(c); - delete this; - } - else - m->append(this); -} - -void composite_node::ascii_print(ascii_output_file *ascii) -{ - unsigned char c = ci->get_ascii_code(); - if (c != 0) - ascii->outc(c); - else - ascii->outs(ci->nm.contents()); - -} - -hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(ci->get_hyphenation_code(), tail); -} - -node *composite_node::add_self(node *nn, hyphen_list **p) -{ - assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); - next = nn; - nn = this; - if ((*p)->hyphen) - nn = nn->add_discretionary_hyphen(); - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return nn; -} - -tfont *composite_node::get_tfont() -{ - return tf; -} - -node *reverse_node_list(node *n) -{ - node *r = 0; - while (n) { - node *tem = n; - n = n->next; - tem->next = r; - r = tem; - } - return r; -} - -void composite_node::vertical_extent(vunits *min, vunits *max) -{ - n = reverse_node_list(n); - node_list_vertical_extent(n, min, max); - n = reverse_node_list(n); -} - -width_list::width_list(hunits w, hunits s) -: width(w), sentence_width(s), next(0) -{ -} - -width_list::width_list(width_list *w) -: width(w->width), sentence_width(w->sentence_width), next(0) -{ -} - -word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x) -: space_node(d, c, x), orig_width(w), unformat(0) -{ -} - -word_space_node::word_space_node(hunits d, int s, color *c, width_list *w, - int flag, node *x) -: space_node(d, s, 0, c, x), orig_width(w), unformat(flag) -{ -} - -word_space_node::~word_space_node() -{ - width_list *w = orig_width; - while (w != 0) { - width_list *tmp = w; - w = w->next; - delete tmp; - } -} - -node *word_space_node::copy() -{ - assert(orig_width != 0); - width_list *w_old_curr = orig_width; - width_list *w_new_curr = new width_list(w_old_curr); - width_list *w_new = w_new_curr; - w_old_curr = w_old_curr->next; - while (w_old_curr != 0) { - w_new_curr->next = new width_list(w_old_curr); - w_new_curr = w_new_curr->next; - w_old_curr = w_old_curr->next; - } - return new word_space_node(n, set, col, w_new, unformat); -} - -int word_space_node::set_unformat_flag() -{ - unformat = 1; - return 1; -} - -void word_space_node::tprint(troff_output_file *out) -{ - out->fill_color(col); - out->word_marker(); - out->right(n); -} - -int word_space_node::merge_space(hunits h, hunits sw, hunits ssw) -{ - n += h; - assert(orig_width != 0); - width_list *w = orig_width; - for (; w->next; w = w->next) - ; - w->next = new width_list(sw, ssw); - return 1; -} - -unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x) -: word_space_node(d, c, 0, x) -{ -} - -unbreakable_space_node::unbreakable_space_node(hunits d, int s, - color *c, node *x) -: word_space_node(d, s, c, 0, 0, x) -{ -} - -node *unbreakable_space_node::copy() -{ - return new unbreakable_space_node(n, set, col); -} - -int unbreakable_space_node::force_tprint() -{ - return 0; -} - -breakpoint *unbreakable_space_node::get_breakpoints(hunits, int, - breakpoint *rest, int) -{ - return rest; -} - -int unbreakable_space_node::nbreaks() -{ - return 0; -} - -void unbreakable_space_node::split(int, node **, node **) -{ - assert(0); -} - -int unbreakable_space_node::merge_space(hunits, hunits, hunits) -{ - return 0; -} - -hvpair::hvpair() -{ -} - -draw_node::draw_node(char c, hvpair *p, int np, font_size s, - color *gc, color *fc) -: npoints(np), sz(s), gcol(gc), fcol(fc), code(c) -{ - point = new hvpair[npoints]; - for (int i = 0; i < npoints; i++) - point[i] = p[i]; -} - -int draw_node::same(node *n) -{ - draw_node *nd = (draw_node *)n; - if (code != nd->code || npoints != nd->npoints || sz != nd->sz - || gcol != nd->gcol || fcol != nd->fcol) - return 0; - for (int i = 0; i < npoints; i++) - if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v) - return 0; - return 1; -} - -const char *draw_node::type() -{ - return "draw_node"; -} - -int draw_node::force_tprint() -{ - return 0; -} - -draw_node::~draw_node() -{ - if (point) - a_delete point; -} - -hunits draw_node::width() -{ - hunits x = H0; - for (int i = 0; i < npoints; i++) - x += point[i].h; - return x; -} - -vunits draw_node::vertical_width() -{ - if (code == 'e') - return V0; - vunits x = V0; - for (int i = 0; i < npoints; i++) - x += point[i].v; - return x; -} - -node *draw_node::copy() -{ - return new draw_node(code, point, npoints, sz, gcol, fcol); -} - -void draw_node::tprint(troff_output_file *out) -{ - out->draw(code, point, npoints, sz, gcol, fcol); -} - -/* tprint methods */ - -void glyph_node::tprint(troff_output_file *out) -{ - tfont *ptf = tf->get_plain(); - if (ptf == tf) - out->put_char_width(ci, ptf, gcol, fcol, width(), H0); - else { - hunits offset; - int bold = tf->get_bold(&offset); - hunits w = ptf->get_width(ci); - hunits k = H0; - hunits x; - int cs = tf->get_constant_space(&x); - if (cs) { - x -= w; - if (bold) - x -= offset; - hunits x2 = x/2; - out->right(x2); - k = x - x2; - } - else - k = tf->get_track_kern(); - if (bold) { - out->put_char(ci, ptf, gcol, fcol); - out->right(offset); - } - out->put_char_width(ci, ptf, gcol, fcol, w, k); - } -} - -void glyph_node::zero_width_tprint(troff_output_file *out) -{ - tfont *ptf = tf->get_plain(); - hunits offset; - int bold = tf->get_bold(&offset); - hunits x; - int cs = tf->get_constant_space(&x); - if (cs) { - x -= ptf->get_width(ci); - if (bold) - x -= offset; - x = x/2; - out->right(x); - } - out->put_char(ci, ptf, gcol, fcol); - if (bold) { - out->right(offset); - out->put_char(ci, ptf, gcol, fcol); - out->right(-offset); - } - if (cs) - out->right(-x); -} - -void break_char_node::tprint(troff_output_file *t) -{ - ch->tprint(t); -} - -void break_char_node::zero_width_tprint(troff_output_file *t) -{ - ch->zero_width_tprint(t); -} - -void hline_node::tprint(troff_output_file *out) -{ - if (x < H0) { - out->right(x); - x = -x; - } - if (n == 0) { - out->right(x); - return; - } - hunits w = n->width(); - if (w <= H0) { - error("horizontal line drawing character must have positive width"); - out->right(x); - return; - } - int i = int(x/w); - if (i == 0) { - hunits xx = x - w; - hunits xx2 = xx/2; - out->right(xx2); - if (out->is_on()) - n->tprint(out); - out->right(xx - xx2); - } - else { - hunits rem = x - w*i; - if (rem > H0) - if (n->overlaps_horizontally()) { - if (out->is_on()) - n->tprint(out); - out->right(rem - w); - } - else - out->right(rem); - while (--i >= 0) - if (out->is_on()) - n->tprint(out); - } -} - -void vline_node::tprint(troff_output_file *out) -{ - if (n == 0) { - out->down(x); - return; - } - vunits h = n->size(); - int overlaps = n->overlaps_vertically(); - vunits y = x; - if (y < V0) { - y = -y; - int i = y / h; - vunits rem = y - i*h; - if (i == 0) { - out->right(n->width()); - out->down(-rem); - } - else { - while (--i > 0) { - n->zero_width_tprint(out); - out->down(-h); - } - if (overlaps) { - n->zero_width_tprint(out); - out->down(-rem); - if (out->is_on()) - n->tprint(out); - out->down(-h); - } - else { - if (out->is_on()) - n->tprint(out); - out->down(-h - rem); - } - } - } - else { - int i = y / h; - vunits rem = y - i*h; - if (i == 0) { - out->down(rem); - out->right(n->width()); - } - else { - out->down(h); - if (overlaps) - n->zero_width_tprint(out); - out->down(rem); - while (--i > 0) { - n->zero_width_tprint(out); - out->down(h); - } - if (out->is_on()) - n->tprint(out); - } - } -} - -void zero_width_node::tprint(troff_output_file *out) -{ - if (!n) - return; - if (!n->next) { - n->zero_width_tprint(out); - return; - } - int hpos = out->get_hpos(); - int vpos = out->get_vpos(); - node *tem = n; - while (tem) { - tem->tprint(out); - tem = tem->next; - } - out->moveto(hpos, vpos); -} - -void overstrike_node::tprint(troff_output_file *out) -{ - hunits pos = H0; - for (node *tem = list; tem; tem = tem->next) { - hunits x = (max_width - tem->width())/2; - out->right(x - pos); - pos = x; - tem->zero_width_tprint(out); - } - out->right(max_width - pos); -} - -void bracket_node::tprint(troff_output_file *out) -{ - if (list == 0) - return; - int npieces = 0; - node *tem; - for (tem = list; tem; tem = tem->next) - ++npieces; - vunits h = list->size(); - vunits totalh = h*npieces; - vunits y = (totalh - h)/2; - out->down(y); - for (tem = list; tem; tem = tem->next) { - tem->zero_width_tprint(out); - out->down(-h); - } - out->right(max_width); - out->down(totalh - y); -} - -void node::tprint(troff_output_file *) -{ -} - -void node::zero_width_tprint(troff_output_file *out) -{ - int hpos = out->get_hpos(); - int vpos = out->get_vpos(); - tprint(out); - out->moveto(hpos, vpos); -} - -void space_node::tprint(troff_output_file *out) -{ - out->fill_color(col); - out->right(n); -} - -void hmotion_node::tprint(troff_output_file *out) -{ - out->fill_color(col); - out->right(n); -} - -void vmotion_node::tprint(troff_output_file *out) -{ - out->fill_color(col); - out->down(n); -} - -void kern_pair_node::tprint(troff_output_file *out) -{ - n1->tprint(out); - out->right(amount); - n2->tprint(out); -} - -static void tprint_reverse_node_list(troff_output_file *out, node *n) -{ - if (n == 0) - return; - tprint_reverse_node_list(out, n->next); - n->tprint(out); -} - -void dbreak_node::tprint(troff_output_file *out) -{ - tprint_reverse_node_list(out, none); -} - -void composite_node::tprint(troff_output_file *out) -{ - hunits bold_offset; - int is_bold = tf->get_bold(&bold_offset); - hunits track_kern = tf->get_track_kern(); - hunits constant_space; - int is_constant_spaced = tf->get_constant_space(&constant_space); - hunits x = H0; - if (is_constant_spaced) { - x = constant_space; - for (node *tem = n; tem; tem = tem->next) - x -= tem->width(); - if (is_bold) - x -= bold_offset; - hunits x2 = x/2; - out->right(x2); - x -= x2; - } - if (is_bold) { - int hpos = out->get_hpos(); - int vpos = out->get_vpos(); - tprint_reverse_node_list(out, n); - out->moveto(hpos, vpos); - out->right(bold_offset); - } - tprint_reverse_node_list(out, n); - if (is_constant_spaced) - out->right(x); - else - out->right(track_kern); -} - -node *make_composite_node(charinfo *s, environment *env) -{ - int fontno = env_definite_font(env); - if (fontno < 0) { - error("no current font"); - return 0; - } - assert(fontno < font_table_size && font_table[fontno] != 0); - node *n = charinfo_to_node_list(s, env); - font_size fs = env->get_font_size(); - int char_height = env->get_char_height(); - int char_slant = env->get_char_slant(); - tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, - fontno); - if (env->is_composite()) - tf = tf->get_plain(); - return new composite_node(n, s, tf); -} - -node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0) -{ - int fontno = env_definite_font(env); - if (fontno < 0) { - error("no current font"); - return 0; - } - assert(fontno < font_table_size && font_table[fontno] != 0); - int fn = fontno; - int found = font_table[fontno]->contains(s); - if (!found) { - if (s->is_fallback()) - return make_composite_node(s, env); - if (s->numbered()) { - if (!no_error_message) - warning(WARN_CHAR, "can't find numbered character %1", - s->get_number()); - return 0; - } - special_font_list *sf = font_table[fontno]->sf; - while (sf != 0 && !found) { - fn = sf->n; - if (font_table[fn]) - found = font_table[fn]->contains(s); - sf = sf->next; - } - if (!found) { - sf = global_special_fonts; - while (sf != 0 && !found) { - fn = sf->n; - if (font_table[fn]) - found = font_table[fn]->contains(s); - sf = sf->next; - } - } - if (!found -#if 0 - && global_special_fonts == 0 && font_table[fontno]->sf == 0 -#endif - ) { - for (fn = 0; fn < font_table_size; fn++) - if (font_table[fn] - && font_table[fn]->is_special() - && font_table[fn]->contains(s)) { - found = 1; - break; - } - } - if (!found) { - if (!no_error_message && s->first_time_not_found()) { - unsigned char input_code = s->get_ascii_code(); - if (input_code != 0) { - if (csgraph(input_code)) - warning(WARN_CHAR, "can't find character `%1'", input_code); - else - warning(WARN_CHAR, "can't find character with input code %1", - int(input_code)); - } - else if (s->nm.contents()) - warning(WARN_CHAR, "can't find special character `%1'", - s->nm.contents()); - } - return 0; - } - } - font_size fs = env->get_font_size(); - int char_height = env->get_char_height(); - int char_slant = env->get_char_slant(); - tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn); - if (env->is_composite()) - tf = tf->get_plain(); - color *gcol = env->get_glyph_color(); - color *fcol = env->get_fill_color(); - return new glyph_node(s, tf, gcol, fcol); -} - -node *make_node(charinfo *ci, environment *env) -{ - switch (ci->get_special_translation()) { - case charinfo::TRANSLATE_SPACE: - return new space_char_hmotion_node(env->get_space_width(), - env->get_fill_color()); - case charinfo::TRANSLATE_STRETCHABLE_SPACE: - return new unbreakable_space_node(env->get_space_width(), - env->get_fill_color()); - case charinfo::TRANSLATE_DUMMY: - return new dummy_node; - case charinfo::TRANSLATE_HYPHEN_INDICATOR: - error("translation to \\% ignored in this context"); - break; - } - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - macro *mac = ci->get_macro(); - if (mac && !ci->is_fallback()) - return make_composite_node(ci, env); - else - return make_glyph_node(ci, env); -} - -int character_exists(charinfo *ci, environment *env) -{ - if (ci->get_special_translation() != charinfo::TRANSLATE_NONE) - return 1; - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - if (ci->get_macro()) - return 1; - node *nd = make_glyph_node(ci, env, 1); - if (nd) { - delete nd; - return 1; - } - return 0; -} - -node *node::add_char(charinfo *ci, environment *env, - hunits *widthp, int *spacep) -{ - node *res; - switch (ci->get_special_translation()) { - case charinfo::TRANSLATE_SPACE: - res = new space_char_hmotion_node(env->get_space_width(), - env->get_fill_color(), this); - *widthp += res->width(); - return res; - case charinfo::TRANSLATE_STRETCHABLE_SPACE: - res = new unbreakable_space_node(env->get_space_width(), - env->get_fill_color(), this); - res->freeze_space(); - *widthp += res->width(); - *spacep += res->nspaces(); - return res; - case charinfo::TRANSLATE_DUMMY: - return new dummy_node(this); - case charinfo::TRANSLATE_HYPHEN_INDICATOR: - return add_discretionary_hyphen(); - } - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - macro *mac = ci->get_macro(); - if (mac && !ci->is_fallback()) { - res = make_composite_node(ci, env); - if (res) { - res->next = this; - *widthp += res->width(); - } - else - return this; - } - else { - node *gn = make_glyph_node(ci, env); - if (gn == 0) - return this; - else { - hunits old_width = width(); - node *p = gn->merge_self(this); - if (p == 0) { - *widthp += gn->width(); - gn->next = this; - res = gn; - } - else { - *widthp += p->width() - old_width; - res = p; - } - } - } - int break_code = 0; - if (ci->can_break_before()) - break_code = 1; - if (ci->can_break_after()) - break_code |= 2; - if (break_code) { - node *next1 = res->next; - res->next = 0; - res = new break_char_node(res, break_code, env->get_fill_color(), next1); - } - return res; -} - -#ifdef __GNUG__ -inline -#endif -int same_node(node *n1, node *n2) -{ - if (n1 != 0) { - if (n2 != 0) - return n1->type() == n2->type() && n1->same(n2); - else - return 0; - } - else - return n2 == 0; -} - -int same_node_list(node *n1, node *n2) -{ - while (n1 && n2) { - if (n1->type() != n2->type() || !n1->same(n2)) - return 0; - n1 = n1->next; - n2 = n2->next; - } - return !n1 && !n2; -} - -int extra_size_node::same(node *nd) -{ - return n == ((extra_size_node *)nd)->n; -} - -const char *extra_size_node::type() -{ - return "extra_size_node"; -} - -int extra_size_node::force_tprint() -{ - return 0; -} - -int vertical_size_node::same(node *nd) -{ - return n == ((vertical_size_node *)nd)->n; -} - -const char *vertical_size_node::type() -{ - return "vertical_size_node"; -} - -int vertical_size_node::set_unformat_flag() -{ - return 0; -} - -int vertical_size_node::force_tprint() -{ - return 0; -} - -int hmotion_node::same(node *nd) -{ - return n == ((hmotion_node *)nd)->n - && col == ((hmotion_node *)nd)->col; -} - -const char *hmotion_node::type() -{ - return "hmotion_node"; -} - -int hmotion_node::set_unformat_flag() -{ - unformat = 1; - return 1; -} - -int hmotion_node::force_tprint() -{ - return 0; -} - -node *hmotion_node::add_self(node *n, hyphen_list **p) -{ - next = n; - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return this; -} - -hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(0, tail); -} - -int space_char_hmotion_node::same(node *nd) -{ - return n == ((space_char_hmotion_node *)nd)->n - && col == ((space_char_hmotion_node *)nd)->col; -} - -const char *space_char_hmotion_node::type() -{ - return "space_char_hmotion_node"; -} - -int space_char_hmotion_node::force_tprint() -{ - return 0; -} - -node *space_char_hmotion_node::add_self(node *n, hyphen_list **p) -{ - next = n; - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return this; -} - -hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(0, tail); -} - -int vmotion_node::same(node *nd) -{ - return n == ((vmotion_node *)nd)->n - && col == ((vmotion_node *)nd)->col; -} - -const char *vmotion_node::type() -{ - return "vmotion_node"; -} - -int vmotion_node::force_tprint() -{ - return 0; -} - -int hline_node::same(node *nd) -{ - return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n); -} - -const char *hline_node::type() -{ - return "hline_node"; -} - -int hline_node::force_tprint() -{ - return 0; -} - -int vline_node::same(node *nd) -{ - return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n); -} - -const char *vline_node::type() -{ - return "vline_node"; -} - -int vline_node::force_tprint() -{ - return 0; -} - -int dummy_node::same(node * /*nd*/) -{ - return 1; -} - -const char *dummy_node::type() -{ - return "dummy_node"; -} - -int dummy_node::force_tprint() -{ - return 0; -} - -int transparent_dummy_node::same(node * /*nd*/) -{ - return 1; -} - -const char *transparent_dummy_node::type() -{ - return "transparent_dummy_node"; -} - -int transparent_dummy_node::force_tprint() -{ - return 0; -} - -int transparent_dummy_node::ends_sentence() -{ - return 2; -} - -int zero_width_node::same(node *nd) -{ - return same_node_list(n, ((zero_width_node *)nd)->n); -} - -const char *zero_width_node::type() -{ - return "zero_width_node"; -} - -int zero_width_node::force_tprint() -{ - return 0; -} - -int italic_corrected_node::same(node *nd) -{ - return (x == ((italic_corrected_node *)nd)->x - && same_node(n, ((italic_corrected_node *)nd)->n)); -} - -const char *italic_corrected_node::type() -{ - return "italic_corrected_node"; -} - -int italic_corrected_node::force_tprint() -{ - return 0; -} - -left_italic_corrected_node::left_italic_corrected_node(node *x) -: node(x), n(0) -{ -} - -left_italic_corrected_node::~left_italic_corrected_node() -{ - delete n; -} - -node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn) -{ - if (n == 0) { - hunits lic = gn->left_italic_correction(); - if (!lic.is_zero()) { - x = lic; - n = gn; - return this; - } - } - else { - node *nd = n->merge_glyph_node(gn); - if (nd) { - n = nd; - x = n->left_italic_correction(); - return this; - } - } - return 0; -} - -node *left_italic_corrected_node::copy() -{ - left_italic_corrected_node *nd = new left_italic_corrected_node; - if (n) { - nd->n = n->copy(); - nd->x = x; - } - return nd; -} - -void left_italic_corrected_node::tprint(troff_output_file *out) -{ - if (n) { - out->right(x); - n->tprint(out); - } -} - -const char *left_italic_corrected_node::type() -{ - return "left_italic_corrected_node"; -} - -int left_italic_corrected_node::force_tprint() -{ - return 0; -} - -int left_italic_corrected_node::same(node *nd) -{ - return (x == ((left_italic_corrected_node *)nd)->x - && same_node(n, ((left_italic_corrected_node *)nd)->n)); -} - -void left_italic_corrected_node::ascii_print(ascii_output_file *out) -{ - if (n) - n->ascii_print(out); -} - -hunits left_italic_corrected_node::width() -{ - return n ? n->width() + x : H0; -} - -void left_italic_corrected_node::vertical_extent(vunits *min, vunits *max) -{ - if (n) - n->vertical_extent(min, max); - else - node::vertical_extent(min, max); -} - -hunits left_italic_corrected_node::skew() -{ - return n ? n->skew() + x/2 : H0; -} - -hunits left_italic_corrected_node::subscript_correction() -{ - return n ? n->subscript_correction() : H0; -} - -hunits left_italic_corrected_node::italic_correction() -{ - return n ? n->italic_correction() : H0; -} - -int left_italic_corrected_node::ends_sentence() -{ - return n ? n->ends_sentence() : 0; -} - -int left_italic_corrected_node::overlaps_horizontally() -{ - return n ? n->overlaps_horizontally() : 0; -} - -int left_italic_corrected_node::overlaps_vertically() -{ - return n ? n->overlaps_vertically() : 0; -} - -node *left_italic_corrected_node::last_char_node() -{ - return n ? n->last_char_node() : 0; -} - -tfont *left_italic_corrected_node::get_tfont() -{ - return n ? n->get_tfont() : 0; -} - -hyphenation_type left_italic_corrected_node::get_hyphenation_type() -{ - if (n) - return n->get_hyphenation_type(); - else - return HYPHEN_MIDDLE; -} - -hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail) -{ - return n ? n->get_hyphen_list(tail) : tail; -} - -node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p) -{ - if (n) { - nd = new left_italic_corrected_node(nd); - nd = n->add_self(nd, p); - n = 0; - delete this; - } - return nd; -} - -int left_italic_corrected_node::character_type() -{ - return n ? n->character_type() : 0; -} - -int overstrike_node::same(node *nd) -{ - return same_node_list(list, ((overstrike_node *)nd)->list); -} - -const char *overstrike_node::type() -{ - return "overstrike_node"; -} - -int overstrike_node::force_tprint() -{ - return 0; -} - -node *overstrike_node::add_self(node *n, hyphen_list **p) -{ - next = n; - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return this; -} - -hyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(0, tail); -} - -int bracket_node::same(node *nd) -{ - return same_node_list(list, ((bracket_node *)nd)->list); -} - -const char *bracket_node::type() -{ - return "bracket_node"; -} - -int bracket_node::force_tprint() -{ - return 0; -} - -int composite_node::same(node *nd) -{ - return ci == ((composite_node *)nd)->ci - && same_node_list(n, ((composite_node *)nd)->n); -} - -const char *composite_node::type() -{ - return "composite_node"; -} - -int composite_node::force_tprint() -{ - return 0; -} - -int glyph_node::same(node *nd) -{ - return ci == ((glyph_node *)nd)->ci - && tf == ((glyph_node *)nd)->tf - && gcol == ((glyph_node *)nd)->gcol - && fcol == ((glyph_node *)nd)->fcol; -} - -const char *glyph_node::type() -{ - return "glyph_node"; -} - -int glyph_node::force_tprint() -{ - return 0; -} - -int ligature_node::same(node *nd) -{ - return (same_node(n1, ((ligature_node *)nd)->n1) - && same_node(n2, ((ligature_node *)nd)->n2) - && glyph_node::same(nd)); -} - -const char *ligature_node::type() -{ - return "ligature_node"; -} - -int ligature_node::force_tprint() -{ - return 0; -} - -int kern_pair_node::same(node *nd) -{ - return (amount == ((kern_pair_node *)nd)->amount - && same_node(n1, ((kern_pair_node *)nd)->n1) - && same_node(n2, ((kern_pair_node *)nd)->n2)); -} - -const char *kern_pair_node::type() -{ - return "kern_pair_node"; -} - -int kern_pair_node::force_tprint() -{ - return 0; -} - -int dbreak_node::same(node *nd) -{ - return (same_node_list(none, ((dbreak_node *)nd)->none) - && same_node_list(pre, ((dbreak_node *)nd)->pre) - && same_node_list(post, ((dbreak_node *)nd)->post)); -} - -const char *dbreak_node::type() -{ - return "dbreak_node"; -} - -int dbreak_node::force_tprint() -{ - return 0; -} - -int break_char_node::same(node *nd) -{ - return break_code == ((break_char_node *)nd)->break_code - && col == ((break_char_node *)nd)->col - && same_node(ch, ((break_char_node *)nd)->ch); -} - -const char *break_char_node::type() -{ - return "break_char_node"; -} - -int break_char_node::force_tprint() -{ - return 0; -} - -int line_start_node::same(node * /*nd*/) -{ - return 1; -} - -const char *line_start_node::type() -{ - return "line_start_node"; -} - -int line_start_node::force_tprint() -{ - return 0; -} - -int space_node::same(node *nd) -{ - return n == ((space_node *)nd)->n - && set == ((space_node *)nd)->set - && col == ((space_node *)nd)->col; -} - -const char *space_node::type() -{ - return "space_node"; -} - -int word_space_node::same(node *nd) -{ - return n == ((word_space_node *)nd)->n - && set == ((word_space_node *)nd)->set - && col == ((word_space_node *)nd)->col; -} - -const char *word_space_node::type() -{ - return "word_space_node"; -} - -int word_space_node::force_tprint() -{ - return 0; -} - -int unbreakable_space_node::same(node *nd) -{ - return n == ((unbreakable_space_node *)nd)->n - && set == ((unbreakable_space_node *)nd)->set - && col == ((unbreakable_space_node *)nd)->col; -} - -const char *unbreakable_space_node::type() -{ - return "unbreakable_space_node"; -} - -node *unbreakable_space_node::add_self(node *n, hyphen_list **p) -{ - next = n; - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return this; -} - -hyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(0, tail); -} - -int diverted_space_node::same(node *nd) -{ - return n == ((diverted_space_node *)nd)->n; -} - -const char *diverted_space_node::type() -{ - return "diverted_space_node"; -} - -int diverted_space_node::force_tprint() -{ - return 0; -} - -int diverted_copy_file_node::same(node *nd) -{ - return filename == ((diverted_copy_file_node *)nd)->filename; -} - -const char *diverted_copy_file_node::type() -{ - return "diverted_copy_file_node"; -} - -int diverted_copy_file_node::force_tprint() -{ - return 0; -} - -// Grow the font_table so that its size is > n. - -static void grow_font_table(int n) -{ - assert(n >= font_table_size); - font_info **old_font_table = font_table; - int old_font_table_size = font_table_size; - font_table_size = font_table_size ? (font_table_size*3)/2 : 10; - if (font_table_size <= n) - font_table_size = n + 10; - font_table = new font_info *[font_table_size]; - if (old_font_table_size) - memcpy(font_table, old_font_table, - old_font_table_size*sizeof(font_info *)); - a_delete old_font_table; - for (int i = old_font_table_size; i < font_table_size; i++) - font_table[i] = 0; -} - -dictionary font_translation_dictionary(17); - -static symbol get_font_translation(symbol nm) -{ - void *p = font_translation_dictionary.lookup(nm); - return p ? symbol((char *)p) : nm; -} - -dictionary font_dictionary(50); - -static int mount_font_no_translate(int n, symbol name, symbol external_name) -{ - assert(n >= 0); - // We store the address of this char in font_dictionary to indicate - // that we've previously tried to mount the font and failed. - static char a_char; - font *fm = 0; - void *p = font_dictionary.lookup(external_name); - if (p == 0) { - int not_found; - fm = font::load_font(external_name.contents(), ¬_found); - if (!fm) { - if (not_found) - warning(WARN_FONT, "can't find font `%1'", external_name.contents()); - font_dictionary.lookup(external_name, &a_char); - return 0; - } - font_dictionary.lookup(name, fm); - } - else if (p == &a_char) { -#if 0 - error("invalid font `%1'", external_name.contents()); -#endif - return 0; - } - else - fm = (font*)p; - if (n >= font_table_size) { - if (n - font_table_size > 1000) { - error("font position too much larger than first unused position"); - return 0; - } - grow_font_table(n); - } - else if (font_table[n] != 0) - delete font_table[n]; - font_table[n] = new font_info(name, n, external_name, fm); - font_family::invalidate_fontno(n); - return 1; -} - -int mount_font(int n, symbol name, symbol external_name) -{ - assert(n >= 0); - name = get_font_translation(name); - if (external_name.is_null()) - external_name = name; - else - external_name = get_font_translation(external_name); - return mount_font_no_translate(n, name, external_name); -} - -void mount_style(int n, symbol name) -{ - assert(n >= 0); - if (n >= font_table_size) { - if (n - font_table_size > 1000) { - error("font position too much larger than first unused position"); - return; - } - grow_font_table(n); - } - else if (font_table[n] != 0) - delete font_table[n]; - font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0); - font_family::invalidate_fontno(n); -} - -/* global functions */ - -void font_translate() -{ - symbol from = get_name(1); - if (!from.is_null()) { - symbol to = get_name(); - if (to.is_null() || from == to) - font_translation_dictionary.remove(from); - else - font_translation_dictionary.lookup(from, (void *)to.contents()); - } - skip_line(); -} - -void font_position() -{ - int n; - if (get_integer(&n)) { - if (n < 0) - error("negative font position"); - else { - symbol internal_name = get_name(1); - if (!internal_name.is_null()) { - symbol external_name = get_long_name(0); - mount_font(n, internal_name, external_name); // ignore error - } - } - } - skip_line(); -} - -font_family::font_family(symbol s) -: map_size(10), nm(s) -{ - map = new int[map_size]; - for (int i = 0; i < map_size; i++) - map[i] = -1; -} - -font_family::~font_family() -{ - a_delete map; -} - -int font_family::make_definite(int i) -{ - if (i >= 0) { - if (i < map_size && map[i] >= 0) - return map[i]; - else { - if (i < font_table_size && font_table[i] != 0) { - if (i >= map_size) { - int old_map_size = map_size; - int *old_map = map; - map_size *= 3; - map_size /= 2; - if (i >= map_size) - map_size = i + 10; - map = new int[map_size]; - memcpy(map, old_map, old_map_size*sizeof(int)); - a_delete old_map; - for (int j = old_map_size; j < map_size; j++) - map[j] = -1; - } - if (font_table[i]->is_style()) { - symbol sty = font_table[i]->get_name(); - symbol f = concat(nm, sty); - int n; - // don't use symbol_fontno, because that might return a style - // and because we don't want to translate the name - for (n = 0; n < font_table_size; n++) - if (font_table[n] != 0 && font_table[n]->is_named(f) - && !font_table[n]->is_style()) - break; - if (n >= font_table_size) { - n = next_available_font_position(); - if (!mount_font_no_translate(n, f, f)) - return -1; - } - return map[i] = n; - } - else - return map[i] = i; - } - else - return -1; - } - } - else - return -1; -} - -dictionary family_dictionary(5); - -font_family *lookup_family(symbol nm) -{ - font_family *f = (font_family *)family_dictionary.lookup(nm); - if (!f) { - f = new font_family(nm); - (void)family_dictionary.lookup(nm, f); - } - return f; -} - -void font_family::invalidate_fontno(int n) -{ - assert(n >= 0 && n < font_table_size); - dictionary_iterator iter(family_dictionary); - symbol nm; - font_family *fam; - while (iter.get(&nm, (void **)&fam)) { - int map_size = fam->map_size; - if (n < map_size) - fam->map[n] = -1; - for (int i = 0; i < map_size; i++) - if (fam->map[i] == n) - fam->map[i] = -1; - } -} - -void style() -{ - int n; - if (get_integer(&n)) { - if (n < 0) - error("negative font position"); - else { - symbol internal_name = get_name(1); - if (!internal_name.is_null()) - mount_style(n, internal_name); - } - } - skip_line(); -} - -static int get_fontno() -{ - int n; - tok.skip(); - if (tok.delimiter()) { - symbol s = get_name(1); - if (!s.is_null()) { - n = symbol_fontno(s); - if (n < 0) { - n = next_available_font_position(); - if (!mount_font(n, s)) - return -1; - } - return curenv->get_family()->make_definite(n); - } - } - else if (get_integer(&n)) { - if (n < 0 || n >= font_table_size || font_table[n] == 0) - error("bad font number"); - else - return curenv->get_family()->make_definite(n); - } - return -1; -} - -static int underline_fontno = 2; - -void underline_font() -{ - int n = get_fontno(); - if (n >= 0) - underline_fontno = n; - skip_line(); -} - -int get_underline_fontno() -{ - return underline_fontno; -} - -static void read_special_fonts(special_font_list **sp) -{ - special_font_list *s = *sp; - *sp = 0; - while (s != 0) { - special_font_list *tem = s; - s = s->next; - delete tem; - } - special_font_list **p = sp; - while (has_arg()) { - int i = get_fontno(); - if (i >= 0) { - special_font_list *tem = new special_font_list; - tem->n = i; - tem->next = 0; - *p = tem; - p = &(tem->next); - } - } -} - -void font_special_request() -{ - int n = get_fontno(); - if (n >= 0) - read_special_fonts(&font_table[n]->sf); - skip_line(); -} - -void special_request() -{ - read_special_fonts(&global_special_fonts); - skip_line(); -} - -int next_available_font_position() -{ - int i; - for (i = 1; i < font_table_size && font_table[i] != 0; i++) - ; - return i; -} - -int symbol_fontno(symbol s) -{ - s = get_font_translation(s); - for (int i = 0; i < font_table_size; i++) - if (font_table[i] != 0 && font_table[i]->is_named(s)) - return i; - return -1; -} - -int is_good_fontno(int n) -{ - return n >= 0 && n < font_table_size && font_table[n] != 0; -} - -int get_bold_fontno(int n) -{ - if (n >= 0 && n < font_table_size && font_table[n] != 0) { - hunits offset; - if (font_table[n]->get_bold(&offset)) - return offset.to_units() + 1; - else - return 0; - } - else - return 0; -} - -hunits env_digit_width(environment *env) -{ - node *n = make_glyph_node(charset_table['0'], env); - if (n) { - hunits x = n->width(); - delete n; - return x; - } - else - return H0; -} - -hunits env_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return scale(fs.to_units()/3, env->get_space_size(), 12); - else - return font_table[fn]->get_space_width(fs, env->get_space_size()); -} - -hunits env_sentence_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return scale(fs.to_units()/3, env->get_sentence_space_size(), 12); - else - return font_table[fn]->get_space_width(fs, env->get_sentence_space_size()); -} - -hunits env_half_narrow_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return 0; - else - return font_table[fn]->get_half_narrow_space_width(fs); -} - -hunits env_narrow_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return 0; - else - return font_table[fn]->get_narrow_space_width(fs); -} - -void bold_font() -{ - int n = get_fontno(); - if (n >= 0) { - if (has_arg()) { - if (tok.delimiter()) { - int f = get_fontno(); - if (f >= 0) { - units offset; - if (has_arg() && get_number(&offset, 'u') && offset >= 1) - font_table[f]->set_conditional_bold(n, hunits(offset - 1)); - else - font_table[f]->conditional_unbold(n); - } - } - else { - units offset; - if (get_number(&offset, 'u') && offset >= 1) - font_table[n]->set_bold(hunits(offset - 1)); - else - font_table[n]->unbold(); - } - } - else - font_table[n]->unbold(); - } - skip_line(); -} - -track_kerning_function::track_kerning_function() : non_zero(0) -{ -} - -track_kerning_function::track_kerning_function(int min_s, hunits min_a, - int max_s, hunits max_a) -: non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s), - max_amount(max_a) -{ -} - -int track_kerning_function::operator==(const track_kerning_function &tk) -{ - if (non_zero) - return (tk.non_zero - && min_size == tk.min_size - && min_amount == tk.min_amount - && max_size == tk.max_size - && max_amount == tk.max_amount); - else - return !tk.non_zero; -} - -int track_kerning_function::operator!=(const track_kerning_function &tk) -{ - if (non_zero) - return (!tk.non_zero - || min_size != tk.min_size - || min_amount != tk.min_amount - || max_size != tk.max_size - || max_amount != tk.max_amount); - else - return tk.non_zero; -} - -hunits track_kerning_function::compute(int size) -{ - if (non_zero) { - if (max_size <= min_size) - return min_amount; - else if (size <= min_size) - return min_amount; - else if (size >= max_size) - return max_amount; - else - return (scale(max_amount, size - min_size, max_size - min_size) - + scale(min_amount, max_size - size, max_size - min_size)); - } - else - return H0; -} - -void track_kern() -{ - int n = get_fontno(); - if (n >= 0) { - int min_s, max_s; - hunits min_a, max_a; - if (has_arg() - && get_number(&min_s, 'z') - && get_hunits(&min_a, 'p') - && get_number(&max_s, 'z') - && get_hunits(&max_a, 'p')) { - track_kerning_function tk(min_s, min_a, max_s, max_a); - font_table[n]->set_track_kern(tk); - } - else { - track_kerning_function tk; - font_table[n]->set_track_kern(tk); - } - } - skip_line(); -} - -void constant_space() -{ - int n = get_fontno(); - if (n >= 0) { - int x, y; - if (!has_arg() || !get_integer(&x)) - font_table[n]->set_constant_space(CONSTANT_SPACE_NONE); - else { - if (!has_arg() || !get_number(&y, 'z')) - font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x); - else - font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE, - scale(y*x, - units_per_inch, - 36*72*sizescale)); - } - } - skip_line(); -} - -void ligature() -{ - int lig; - if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2) - global_ligature_mode = lig; - else - global_ligature_mode = 1; - skip_line(); -} - -void kern_request() -{ - int k; - if (has_arg() && get_integer(&k)) - global_kern_mode = k != 0; - else - global_kern_mode = 1; - skip_line(); -} - -void set_soft_hyphen_char() -{ - soft_hyphen_char = get_optional_char(); - if (!soft_hyphen_char) - soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); - skip_line(); -} - -void init_output() -{ - if (suppress_output_flag) - the_output = new suppress_output_file; - else if (ascii_output_flag) - the_output = new ascii_output_file; - else - the_output = new troff_output_file; -} - -class next_available_font_position_reg : public reg { -public: - const char *get_string(); -}; - -const char *next_available_font_position_reg::get_string() -{ - return i_to_a(next_available_font_position()); -} - -class printing_reg : public reg { -public: - const char *get_string(); -}; - -const char *printing_reg::get_string() -{ - if (the_output) - return the_output->is_printing() ? "1" : "0"; - else - return "0"; -} - -void init_node_requests() -{ - init_request("fp", font_position); - init_request("sty", style); - init_request("cs", constant_space); - init_request("bd", bold_font); - init_request("uf", underline_font); - init_request("lg", ligature); - init_request("kern", kern_request); - init_request("tkf", track_kern); - init_request("special", special_request); - init_request("fspecial", font_special_request); - init_request("ftr", font_translate); - init_request("shc", set_soft_hyphen_char); - number_reg_dictionary.define(".fp", new next_available_font_position_reg); - number_reg_dictionary.define(".kern", - new constant_int_reg(&global_kern_mode)); - number_reg_dictionary.define(".lg", - new constant_int_reg(&global_ligature_mode)); - number_reg_dictionary.define(".P", new printing_reg); - soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); -} diff --git a/contrib/groff/src/roff/troff/number.cc b/contrib/groff/src/roff/troff/number.cc deleted file mode 100644 index 8fed342..0000000 --- a/contrib/groff/src/roff/troff/number.cc +++ /dev/null @@ -1,697 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002 - 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 "troff.h" -#include "symbol.h" -#include "hvunits.h" -#include "env.h" -#include "token.h" -#include "div.h" - -vunits V0; -hunits H0; - -int hresolution = 1; -int vresolution = 1; -int units_per_inch; -int sizescale; - -static int parse_expr(units *v, int scale_indicator, - int parenthesised, int rigid = 0); -static int start_number(); - -int get_vunits(vunits *res, unsigned char si) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, si, 0)) { - *res = vunits(x); - return 1; - } - else - return 0; -} - -int get_hunits(hunits *res, unsigned char si) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, si, 0)) { - *res = hunits(x); - return 1; - } - else - return 0; -} - -// for \B - -int get_number_rigidly(units *res, unsigned char si) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, si, 0, 1)) { - *res = x; - return 1; - } - else - return 0; -} - -int get_number(units *res, unsigned char si) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, si, 0)) { - *res = x; - return 1; - } - else - return 0; -} - -int get_integer(int *res) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, 0, 0)) { - *res = x; - return 1; - } - else - return 0; -} - -enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT }; - -static incr_number_result get_incr_number(units *res, unsigned char); - -int get_vunits(vunits *res, unsigned char si, vunits prev_value) -{ - units v; - switch (get_incr_number(&v, si)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + v; - break; - case DECREMENT: - *res = prev_value - v; - break; - default: - assert(0); - } - return 1; -} - -int get_hunits(hunits *res, unsigned char si, hunits prev_value) -{ - units v; - switch (get_incr_number(&v, si)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + v; - break; - case DECREMENT: - *res = prev_value - v; - break; - default: - assert(0); - } - return 1; -} - -int get_number(units *res, unsigned char si, units prev_value) -{ - units v; - switch (get_incr_number(&v, si)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + v; - break; - case DECREMENT: - *res = prev_value - v; - break; - default: - assert(0); - } - return 1; -} - -int get_integer(int *res, int prev_value) -{ - units v; - switch (get_incr_number(&v, 0)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + int(v); - break; - case DECREMENT: - *res = prev_value - int(v); - break; - default: - assert(0); - } - return 1; -} - - -static incr_number_result get_incr_number(units *res, unsigned char si) -{ - if (!start_number()) - return BAD; - incr_number_result result = ABSOLUTE; - if (tok.ch() == '+') { - tok.next(); - result = INCREMENT; - } - else if (tok.ch() == '-') { - tok.next(); - result = DECREMENT; - } - if (parse_expr(res, si, 0)) - return result; - else - return BAD; -} - -static int start_number() -{ - while (tok.space()) - tok.next(); - if (tok.newline()) { - warning(WARN_MISSING, "missing number"); - return 0; - } - if (tok.tab()) { - warning(WARN_TAB, "tab character where number expected"); - return 0; - } - if (tok.right_brace()) { - warning(WARN_RIGHT_BRACE, "`\\}' where number expected"); - return 0; - } - return 1; -} - -enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' }; - -#define SCALE_INDICATOR_CHARS "icfPmnpuvMsz" - -static int parse_term(units *v, int scale_indicator, - int parenthesised, int rigid); - -static int parse_expr(units *v, int scale_indicator, - int parenthesised, int rigid) -{ - int result = parse_term(v, scale_indicator, parenthesised, rigid); - while (result) { - if (parenthesised) - tok.skip(); - int op = tok.ch(); - switch (op) { - case '+': - case '-': - case '/': - case '*': - case '%': - case ':': - case '&': - tok.next(); - break; - case '>': - tok.next(); - if (tok.ch() == '=') { - tok.next(); - op = OP_GEQ; - } - else if (tok.ch() == '?') { - tok.next(); - op = OP_MAX; - } - break; - case '<': - tok.next(); - if (tok.ch() == '=') { - tok.next(); - op = OP_LEQ; - } - else if (tok.ch() == '?') { - tok.next(); - op = OP_MIN; - } - break; - case '=': - tok.next(); - if (tok.ch() == '=') - tok.next(); - break; - default: - return result; - } - units v2; - if (!parse_term(&v2, scale_indicator, parenthesised, rigid)) - return 0; - int overflow = 0; - switch (op) { - case '<': - *v = *v < v2; - break; - case '>': - *v = *v > v2; - break; - case OP_LEQ: - *v = *v <= v2; - break; - case OP_GEQ: - *v = *v >= v2; - break; - case OP_MIN: - if (*v > v2) - *v = v2; - break; - case OP_MAX: - if (*v < v2) - *v = v2; - break; - case '=': - *v = *v == v2; - break; - case '&': - *v = *v > 0 && v2 > 0; - break; - case ':': - *v = *v > 0 || v2 > 0; - break; - case '+': - if (v2 < 0) { - if (*v < INT_MIN - v2) - overflow = 1; - } - else if (v2 > 0) { - if (*v > INT_MAX - v2) - overflow = 1; - } - if (overflow) { - error("addition overflow"); - return 0; - } - *v += v2; - break; - case '-': - if (v2 < 0) { - if (*v > INT_MAX + v2) - overflow = 1; - } - else if (v2 > 0) { - if (*v < INT_MIN + v2) - overflow = 1; - } - if (overflow) { - error("subtraction overflow"); - return 0; - } - *v -= v2; - break; - case '*': - if (v2 < 0) { - if (*v > 0) { - if (*v > -(unsigned)INT_MIN / -(unsigned)v2) - overflow = 1; - } - else if (-(unsigned)*v > INT_MAX / -(unsigned)v2) - overflow = 1; - } - else if (v2 > 0) { - if (*v > 0) { - if (*v > INT_MAX / v2) - overflow = 1; - } - else if (-(unsigned)*v > -(unsigned)INT_MIN / v2) - overflow = 1; - } - if (overflow) { - error("multiplication overflow"); - return 0; - } - *v *= v2; - break; - case '/': - if (v2 == 0) { - error("division by zero"); - return 0; - } - *v /= v2; - break; - case '%': - if (v2 == 0) { - error("modulus by zero"); - return 0; - } - *v %= v2; - break; - default: - assert(0); - } - } - return result; -} - -static int parse_term(units *v, int scale_indicator, - int parenthesised, int rigid) -{ - int negative = 0; - for (;;) - if (parenthesised && tok.space()) - tok.next(); - else if (tok.ch() == '+') - tok.next(); - else if (tok.ch() == '-') { - tok.next(); - negative = !negative; - } - else - break; - unsigned char c = tok.ch(); - switch (c) { - case '|': - // | is not restricted to the outermost level - // tbl uses this - tok.next(); - if (!parse_term(v, scale_indicator, parenthesised, rigid)) - return 0; - int tem; - tem = (scale_indicator == 'v' - ? curdiv->get_vertical_position().to_units() - : curenv->get_input_line_position().to_units()); - if (tem >= 0) { - if (*v < INT_MIN + tem) { - error("numeric overflow"); - return 0; - } - } - else { - if (*v > INT_MAX + tem) { - error("numeric overflow"); - return 0; - } - } - *v -= tem; - if (negative) { - if (*v == INT_MIN) { - error("numeric overflow"); - return 0; - } - *v = -*v; - } - return 1; - case '(': - tok.next(); - c = tok.ch(); - if (c == ')') { - if (rigid) - return 0; - warning(WARN_SYNTAX, "empty parentheses"); - tok.next(); - *v = 0; - return 1; - } - else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { - tok.next(); - if (tok.ch() == ';') { - tok.next(); - scale_indicator = c; - } - else { - error("expected `;' after scale-indicator (got %1)", - tok.description()); - return 0; - } - } - else if (c == ';') { - scale_indicator = 0; - tok.next(); - } - if (!parse_expr(v, scale_indicator, 1, rigid)) - return 0; - tok.skip(); - if (tok.ch() != ')') { - if (rigid) - return 0; - warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description()); - } - else - tok.next(); - if (negative) { - if (*v == INT_MIN) { - error("numeric overflow"); - return 0; - } - *v = -*v; - } - return 1; - case '.': - *v = 0; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - *v = 0; - do { - if (*v > INT_MAX/10) { - error("numeric overflow"); - return 0; - } - *v *= 10; - if (*v > INT_MAX - (int(c) - '0')) { - error("numeric overflow"); - return 0; - } - *v += c - '0'; - tok.next(); - c = tok.ch(); - } while (csdigit(c)); - break; - case '/': - case '*': - case '%': - case ':': - case '&': - case '>': - case '<': - case '=': - warning(WARN_SYNTAX, "empty left operand"); - *v = 0; - return rigid ? 0 : 1; - default: - warning(WARN_NUMBER, "numeric expression expected (got %1)", - tok.description()); - return 0; - } - int divisor = 1; - if (tok.ch() == '.') { - tok.next(); - for (;;) { - c = tok.ch(); - if (!csdigit(c)) - break; - // we may multiply the divisor by 254 later on - if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) { - *v *= 10; - *v += c - '0'; - divisor *= 10; - } - tok.next(); - } - } - int si = scale_indicator; - int do_next = 0; - if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { - switch (scale_indicator) { - case 'z': - if (c != 'u' && c != 'z') { - warning(WARN_SCALE, - "only `z' and `u' scale indicators valid in this context"); - break; - } - si = c; - break; - case 0: - warning(WARN_SCALE, "scale indicator invalid in this context"); - break; - case 'u': - si = c; - break; - default: - if (c == 'z') { - warning(WARN_SCALE, "`z' scale indicator invalid in this context"); - break; - } - si = c; - break; - } - // Don't do tok.next() here because the next token might be \s, which - // would affect the interpretation of m. - do_next = 1; - } - switch (si) { - case 'i': - *v = scale(*v, units_per_inch, divisor); - break; - case 'c': - *v = scale(*v, units_per_inch*100, divisor*254); - break; - case 0: - case 'u': - if (divisor != 1) - *v /= divisor; - break; - case 'f': - *v = scale(*v, 65536, divisor); - break; - case 'p': - *v = scale(*v, units_per_inch, divisor*72); - break; - case 'P': - *v = scale(*v, units_per_inch, divisor*6); - break; - case 'm': - { - // Convert to hunits so that with -Tascii `m' behaves as in nroff. - hunits em = curenv->get_size(); - *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor); - } - break; - case 'M': - { - hunits em = curenv->get_size(); - *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100); - } - break; - case 'n': - { - // Convert to hunits so that with -Tascii `n' behaves as in nroff. - hunits en = curenv->get_size()/2; - *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor); - } - break; - case 'v': - *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor); - break; - case 's': - while (divisor > INT_MAX/(sizescale*72)) { - divisor /= 10; - *v /= 10; - } - *v = scale(*v, units_per_inch, divisor*sizescale*72); - break; - case 'z': - *v = scale(*v, sizescale, divisor); - break; - default: - assert(0); - } - if (do_next) - tok.next(); - if (negative) { - if (*v == INT_MIN) { - error("numeric overflow"); - return 0; - } - *v = -*v; - } - return 1; -} - -units scale(units n, units x, units y) -{ - assert(x >= 0 && y > 0); - if (x == 0) - return 0; - if (n >= 0) { - if (n <= INT_MAX/x) - return (n*x)/y; - } - else { - if (-(unsigned)n <= -(unsigned)INT_MIN/x) - return (n*x)/y; - } - double res = n*double(x)/double(y); - if (res > INT_MAX) { - error("numeric overflow"); - return INT_MAX; - } - else if (res < INT_MIN) { - error("numeric overflow"); - return INT_MIN; - } - return int(res); -} - -vunits::vunits(units x) -{ - // don't depend on the rounding direction for division of negative integers - if (vresolution == 1) - n = x; - else - n = (x < 0 - ? -((-x + vresolution/2 - 1)/vresolution) - : (x + vresolution/2 - 1)/vresolution); -} - -hunits::hunits(units x) -{ - // don't depend on the rounding direction for division of negative integers - if (hresolution == 1) - n = x; - else - n = (x < 0 - ? -((-x + hresolution/2 - 1)/hresolution) - : (x + hresolution/2 - 1)/hresolution); -} diff --git a/contrib/groff/src/roff/troff/reg.cc b/contrib/groff/src/roff/troff/reg.cc deleted file mode 100644 index 8ac20c9..0000000 --- a/contrib/groff/src/roff/troff/reg.cc +++ /dev/null @@ -1,474 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001 - 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 "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "token.h" -#include "request.h" -#include "reg.h" - -object_dictionary number_reg_dictionary(101); - -int reg::get_value(units * /*d*/) -{ - return 0; -} - -void reg::increment() -{ - error("can't increment read-only register"); -} - -void reg::decrement() -{ - error("can't decrement read-only register"); -} - -void reg::set_increment(units /*n*/) -{ - error("can't auto increment read-only register"); -} - -void reg::alter_format(char /*f*/, int /*w*/) -{ - error("can't alter format of read-only register"); -} - -const char *reg::get_format() -{ - return "0"; -} - -void reg::set_value(units /*n*/) -{ - error("can't write read-only register"); -} - -general_reg::general_reg() : format('1'), width(0), inc(0) -{ -} - -static char uppercase_array[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', -}; - -static char lowercase_array[] = { - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', -}; - -static const char *number_value_to_ascii(int value, char format, int width) -{ - static char buf[128]; // must be at least 21 - switch(format) { - case '1': - if (width <= 0) - return i_to_a(value); - else if (width > int(sizeof(buf) - 2)) - sprintf(buf, "%.*d", int(sizeof(buf) - 2), int(value)); - else - sprintf(buf, "%.*d", width, int(value)); - break; - case 'i': - case 'I': - { - char *p = buf; - // troff uses z and w to represent 10000 and 5000 in Roman - // numerals; I can find no historical basis for this usage - const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI"; - int n = int(value); - if (n >= 40000 || n <= -40000) { - error("magnitude of `%1' too big for i or I format", n); - return i_to_a(n); - } - if (n == 0) { - *p++ = '0'; - *p = 0; - break; - } - if (n < 0) { - *p++ = '-'; - n = -n; - } - while (n >= 10000) { - *p++ = s[0]; - n -= 10000; - } - for (int i = 1000; i > 0; i /= 10, s += 2) { - int m = n/i; - n -= m*i; - switch (m) { - case 3: - *p++ = s[2]; - /* falls through */ - case 2: - *p++ = s[2]; - /* falls through */ - case 1: - *p++ = s[2]; - break; - case 4: - *p++ = s[2]; - *p++ = s[1]; - break; - case 8: - *p++ = s[1]; - *p++ = s[2]; - *p++ = s[2]; - *p++ = s[2]; - break; - case 7: - *p++ = s[1]; - *p++ = s[2]; - *p++ = s[2]; - break; - case 6: - *p++ = s[1]; - *p++ = s[2]; - break; - case 5: - *p++ = s[1]; - break; - case 9: - *p++ = s[2]; - *p++ = s[0]; - } - } - *p = 0; - break; - } - case 'a': - case 'A': - { - int n = value; - char *p = buf; - if (n == 0) { - *p++ = '0'; - *p = 0; - } - else { - if (n < 0) { - n = -n; - *p++ = '-'; - } - // this is a bit tricky - while (n > 0) { - int d = n % 26; - if (d == 0) - d = 26; - n -= d; - n /= 26; - *p++ = format == 'a' ? lowercase_array[d - 1] : - uppercase_array[d - 1]; - } - *p-- = 0; - char *q = buf[0] == '-' ? buf + 1 : buf; - while (q < p) { - char temp = *q; - *q = *p; - *p = temp; - --p; - ++q; - } - } - break; - } - default: - assert(0); - break; - } - return buf; -} - -const char *general_reg::get_string() -{ - units n; - if (!get_value(&n)) - return ""; - return number_value_to_ascii(n, format, width); -} - - -void general_reg::increment() -{ - int n; - if (get_value(&n)) - set_value(n + inc); -} - -void general_reg::decrement() -{ - int n; - if (get_value(&n)) - set_value(n - inc); -} - -void general_reg::set_increment(units n) -{ - inc = n; -} - -void general_reg::alter_format(char f, int w) -{ - format = f; - width = w; -} - -static const char *number_format_to_ascii(char format, int width) -{ - static char buf[24]; - if (format == '1') { - if (width > 0) { - int n = width; - if (n > int(sizeof(buf)) - 1) - n = int(sizeof(buf)) - 1; - sprintf(buf, "%.*d", n, 0); - return buf; - } - else - return "0"; - } - else { - buf[0] = format; - buf[1] = '\0'; - return buf; - } -} - -const char *general_reg::get_format() -{ - return number_format_to_ascii(format, width); -} - -class number_reg : public general_reg { - units value; -public: - number_reg(); - int get_value(units *); - void set_value(units); -}; - -number_reg::number_reg() : value(0) -{ -} - -int number_reg::get_value(units *res) -{ - *res = value; - return 1; -} - -void number_reg::set_value(units n) -{ - value = n; -} - -variable_reg::variable_reg(units *p) : ptr(p) -{ -} - -void variable_reg::set_value(units n) -{ - *ptr = n; -} - -int variable_reg::get_value(units *res) -{ - *res = *ptr; - return 1; -} - -void define_number_reg() -{ - symbol nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - reg *r = (reg *)number_reg_dictionary.lookup(nm); - units v; - units prev_value; - if (!r || !r->get_value(&prev_value)) - prev_value = 0; - if (get_number(&v, 'u', prev_value)) { - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - r->set_value(v); - if (tok.space() && has_arg() && get_number(&v, 'u')) - r->set_increment(v); - } - skip_line(); -} - -#if 0 -void inline_define_reg() -{ - token start; - start.next(); - if (!start.delimiter(1)) - return; - tok.next(); - symbol nm = get_name(1); - if (nm.is_null()) - return; - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - units v; - units prev_value; - if (!r->get_value(&prev_value)) - prev_value = 0; - if (get_number(&v, 'u', prev_value)) { - r->set_value(v); - if (start != tok) { - if (get_number(&v, 'u')) { - r->set_increment(v); - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - } - } - } -} -#endif - -void set_number_reg(symbol nm, units n) -{ - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - r->set_value(n); -} - -reg *lookup_number_reg(symbol nm) -{ - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - warning(WARN_REG, "number register `%1' not defined", nm.contents()); - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - return r; -} - -void alter_format() -{ - symbol nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - tok.skip(); - char c = tok.ch(); - if (csdigit(c)) { - int n = 0; - do { - ++n; - tok.next(); - } while (csdigit(tok.ch())); - r->alter_format('1', n); - } - else if (c == 'i' || c == 'I' || c == 'a' || c == 'A') - r->alter_format(c); - else if (tok.newline() || tok.eof()) - warning(WARN_MISSING, "missing number register format"); - else - error("bad number register format (got %1)", tok.description()); - skip_line(); -} - -void remove_reg() -{ - for (;;) { - symbol s = get_name(); - if (s.is_null()) - break; - number_reg_dictionary.remove(s); - } - skip_line(); -} - -void alias_reg() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) { - if (!number_reg_dictionary.alias(s1, s2)) - warning(WARN_REG, "number register `%1' not defined", s2.contents()); - } - } - skip_line(); -} - -void rename_reg() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) - number_reg_dictionary.rename(s1, s2); - } - skip_line(); -} - -void print_number_regs() -{ - object_dictionary_iterator iter(number_reg_dictionary); - reg *r; - symbol s; - while (iter.get(&s, (object **)&r)) { - assert(!s.is_null()); - errprint("%1\t", s.contents()); - const char *p = r->get_string(); - if (p) - errprint(p); - errprint("\n"); - } - fflush(stderr); - skip_line(); -} - -void init_reg_requests() -{ - init_request("rr", remove_reg); - init_request("nr", define_number_reg); - init_request("af", alter_format); - init_request("aln", alias_reg); - init_request("rnn", rename_reg); - init_request("pnr", print_number_regs); -} diff --git a/contrib/groff/src/roff/troff/symbol.cc b/contrib/groff/src/roff/troff/symbol.cc deleted file mode 100644 index 09f4c98..0000000 --- a/contrib/groff/src/roff/troff/symbol.cc +++ /dev/null @@ -1,154 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992, 2002 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 "troff.h" -#include "symbol.h" - -const char **symbol::table = 0; -int symbol::table_used = 0; -int symbol::table_size = 0; -char *symbol::block = 0; -int symbol::block_size = 0; - -const symbol NULL_SYMBOL; -const symbol EMPTY_SYMBOL(""); - -#ifdef BLOCK_SIZE -#undef BLOCK_SIZE -#endif - -const int BLOCK_SIZE = 1024; -// the table will increase in size as necessary -// the size will be chosen from the following array -// add some more if you want -static const unsigned int table_sizes[] = { - 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, - 160001, 500009, 1000003, 1500007, 2000003, 0 -}; -const double FULL_MAX = 0.3; // don't let the table get more than this full - -static unsigned int hash_string(const char *p) -{ - // compute a hash code; this assumes 32-bit unsigned ints - // see p436 of Compilers by Aho, Sethi & Ullman - // give special treatment to two-character names - unsigned int hc = 0, g; - if (*p != 0) { - hc = *p++; - if (*p != 0) { - hc <<= 7; - hc += *p++; - for (; *p != 0; p++) { - hc <<= 4; - hc += *p; - if ((g = (hc & 0xf0000000)) == 0) { - hc ^= g >> 24; - hc ^= g; - } - } - } - } - return hc; -} - -// Tell compiler that a variable is intentionally unused. -inline void unused(void *) { } - -symbol::symbol(const char *p, int how) -{ - if (p == 0) { - s = 0; - return; - } - if (*p == 0) { - s = ""; - return; - } - if (table == 0) { - table_size = table_sizes[0]; - table = (const char **)new char*[table_size]; - for (int i = 0; i < table_size; i++) - table[i] = 0; - table_used = 0; - } - unsigned int hc = hash_string(p); - const char **pp; - for (pp = table + hc % table_size; - *pp != 0; - (pp == table ? pp = table + table_size - 1 : --pp)) - if (strcmp(p, *pp) == 0) { - s = *pp; - return; - } - if (how == MUST_ALREADY_EXIST) { - s = 0; - return; - } - if (table_used >= table_size - 1 || table_used >= table_size*FULL_MAX) { - const char **old_table = table; - unsigned int old_table_size = table_size; - int i; - for (i = 1; table_sizes[i] <= old_table_size; i++) - if (table_sizes[i] == 0) - fatal("too many symbols"); - table_size = table_sizes[i]; - table_used = 0; - table = (const char **)new char*[table_size]; - for (i = 0; i < table_size; i++) - table[i] = 0; - for (pp = old_table + old_table_size - 1; - pp >= old_table; - --pp) { - symbol temp(*pp, 1); /* insert it into the new table */ - unused(&temp); - } - a_delete old_table; - for (pp = table + hc % table_size; - *pp != 0; - (pp == table ? pp = table + table_size - 1 : --pp)) - ; - } - ++table_used; - if (how == DONT_STORE) { - s = *pp = p; - } - else { - int len = strlen(p)+1; - if (block == 0 || block_size < len) { - block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE; - block = new char [block_size]; - } - (void)strcpy(block, p); - s = *pp = block; - block += len; - block_size -= len; - } -} - -symbol concat(symbol s1, symbol s2) -{ - char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1]; - strcpy(buf, s1.contents()); - strcat(buf, s2.contents()); - symbol res(buf); - a_delete buf; - return res; -} diff --git a/contrib/groff/src/utils/addftinfo/addftinfo.cc b/contrib/groff/src/utils/addftinfo/addftinfo.cc deleted file mode 100644 index 931d836..0000000 --- a/contrib/groff/src/utils/addftinfo/addftinfo.cc +++ /dev/null @@ -1,218 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001 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 "lib.h" - -#include -#include -#include -#include -#include "errarg.h" -#include "error.h" -#include "stringclass.h" -#include "cset.h" -#include "guess.h" - -extern "C" const char *Version_string; - -static void usage(FILE *stream); -static void usage(); -static void version(); -static void convert_font(const font_params &, FILE *, FILE *); - -typedef int font_params::*param_t; - -static struct { - const char *name; - param_t par; -} param_table[] = { - { "x-height", &font_params::x_height }, - { "fig-height", &font_params::fig_height }, - { "asc-height", &font_params::asc_height }, - { "body-height", &font_params::body_height }, - { "cap-height", &font_params::cap_height }, - { "comma-depth", &font_params::comma_depth }, - { "desc-depth", &font_params::desc_depth }, - { "body-depth", &font_params::body_depth }, -}; - -// These are all in thousandths of an em. -// These values are correct for PostScript Times Roman. - -#define DEFAULT_X_HEIGHT 448 -#define DEFAULT_FIG_HEIGHT 676 -#define DEFAULT_ASC_HEIGHT 682 -#define DEFAULT_BODY_HEIGHT 676 -#define DEFAULT_CAP_HEIGHT 662 -#define DEFAULT_COMMA_DEPTH 143 -#define DEFAULT_DESC_DEPTH 217 -#define DEFAULT_BODY_DEPTH 177 - -int main(int argc, char **argv) -{ - program_name = argv[0]; - int i; - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-v") || !strcmp(argv[i],"--version")) - version(); - if (!strcmp(argv[i],"--help")) { - usage(stdout); - exit(0); - } - } - if (argc < 4) - usage(); - int resolution; - if (sscanf(argv[argc-3], "%d", &resolution) != 1) - usage(); - if (resolution <= 0) - fatal("resolution must be > 0"); - int unitwidth; - if (sscanf(argv[argc-2], "%d", &unitwidth) != 1) - usage(); - if (unitwidth <= 0) - fatal("unitwidth must be > 0"); - font_params param; - const char *font = argv[argc-1]; - param.italic = (font[0] != '\0' && strchr(font, '\0')[-1] == 'I'); - param.em = (resolution*unitwidth)/72; - param.x_height = DEFAULT_X_HEIGHT; - param.fig_height = DEFAULT_FIG_HEIGHT; - param.asc_height = DEFAULT_ASC_HEIGHT; - param.body_height = DEFAULT_BODY_HEIGHT; - param.cap_height = DEFAULT_CAP_HEIGHT; - param.comma_depth = DEFAULT_COMMA_DEPTH; - param.desc_depth = DEFAULT_DESC_DEPTH; - param.body_depth = DEFAULT_BODY_DEPTH; - for (i = 1; i < argc && argv[i][0] == '-'; i++) { - if (argv[i][1] == '-' && argv[i][2] == '\0') { - i++; - break; - } - if (i + 1 >= argc) - usage(); - size_t j; - for (j = 0;; j++) { - if (j >= sizeof(param_table)/sizeof(param_table[0])) - fatal("parameter `%1' not recognized", argv[i] + 1); - if (strcmp(param_table[j].name, argv[i] + 1) == 0) - break; - } - if (sscanf(argv[i+1], "%d", &(param.*(param_table[j].par))) != 1) - fatal("invalid argument `%1'", argv[i+1]); - i++; - } - if (argc - i != 3) - usage(); - errno = 0; - FILE *infp = fopen(font, "r"); - if (infp == 0) - fatal("can't open `%1': %2", font, strerror(errno)); - convert_font(param, infp, stdout); - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-v] [-param value] ... " - "resolution unitwidth font\n", - program_name); -} -static void usage() -{ - usage(stderr); - exit(1); -} - -static void version() -{ - printf("GNU addftinfo (groff) version %s\n", Version_string); - exit(0); -} - -static int get_line(FILE *fp, string *p) -{ - int c; - p->clear(); - while ((c = getc(fp)) != EOF) { - *p += char(c); - if (c == '\n') - break; - } - return p->length() > 0; -} - -static void convert_font(const font_params ¶m, FILE *infp, FILE *outfp) -{ - string s; - while (get_line(infp, &s)) { - put_string(s, outfp); - if (s.length() >= 8 - && strncmp(&s[0], "charset", 7)) - break; - } - while (get_line(infp, &s)) { - s += '\0'; - string name; - const char *p = s.contents(); - while (csspace(*p)) - p++; - while (*p != '\0' && !csspace(*p)) - name += *p++; - while (csspace(*p)) - p++; - for (const char *q = s.contents(); q < p; q++) - putc(*q, outfp); - char *next; - char_metric metric; - metric.width = (int)strtol(p, &next, 10); - if (next != p) { - printf("%d", metric.width); - p = next; - metric.type = (int)strtol(p, &next, 10); - if (next != p) { - name += '\0'; - guess(name.contents(), param, &metric); - if (metric.sk == 0) { - if (metric.left_ic == 0) { - if (metric.ic == 0) { - if (metric.depth == 0) { - if (metric.height != 0) - printf(",%d", metric.height); - } - else - printf(",%d,%d", metric.height, metric.depth); - } - else - printf(",%d,%d,%d", metric.height, metric.depth, metric.ic); - } - else - printf(",%d,%d,%d,%d", metric.height, metric.depth, metric.ic, - metric.left_ic); - } - else - printf(",%d,%d,%d,%d,%d", metric.height, metric.depth, metric.ic, - metric.left_ic, metric.sk); - } - } - fputs(p, outfp); - } -} - diff --git a/contrib/groff/src/utils/addftinfo/guess.cc b/contrib/groff/src/utils/addftinfo/guess.cc deleted file mode 100644 index dcfd4c9..0000000 --- a/contrib/groff/src/utils/addftinfo/guess.cc +++ /dev/null @@ -1,490 +0,0 @@ -// -*- 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 "guess.h" - -void guess(const char *s, const font_params ¶m, char_metric *metric) -{ - int &height = metric->height; - int &depth = metric->depth; - - metric->ic = 0; - metric->left_ic = 0; - metric->sk = 0; - height = 0; - depth = 0; - if (s[0] == '\0' || (s[1] != '\0' && s[2] != '\0')) - goto do_default; -#define HASH(c1, c2) (((unsigned char)(c1) << 8) | (unsigned char)(c2)) - switch (HASH(s[0], s[1])) { - default: - do_default: - if (metric->type & 01) - depth = param.desc_depth; - if (metric->type & 02) - height = param.asc_height; - else - height = param.x_height; - break; - case HASH('\\', '|'): - case HASH('\\', '^'): - case HASH('\\', '&'): - // these have zero height and depth - break; - case HASH('f', 0): - height = param.asc_height; - if (param.italic) - depth = param.desc_depth; - break; - case HASH('a', 0): - case HASH('c', 0): - case HASH('e', 0): - case HASH('m', 0): - case HASH('n', 0): - case HASH('o', 0): - case HASH('r', 0): - case HASH('s', 0): - case HASH('u', 0): - case HASH('v', 0): - case HASH('w', 0): - case HASH('x', 0): - case HASH('z', 0): - height = param.x_height; - break; - case HASH('i', 0): - height = param.x_height; - break; - case HASH('b', 0): - case HASH('d', 0): - case HASH('h', 0): - case HASH('k', 0): - case HASH('l', 0): - case HASH('F', 'i'): - case HASH('F', 'l'): - case HASH('f', 'f'): - case HASH('f', 'i'): - case HASH('f', 'l'): - height = param.asc_height; - break; - case HASH('t', 0): - height = param.asc_height; - break; - case HASH('g', 0): - case HASH('p', 0): - case HASH('q', 0): - case HASH('y', 0): - height = param.x_height; - depth = param.desc_depth; - break; - case HASH('j', 0): - height = param.x_height; - depth = param.desc_depth; - break; - case HASH('A', 0): - case HASH('B', 0): - case HASH('C', 0): - case HASH('D', 0): - case HASH('E', 0): - case HASH('F', 0): - case HASH('G', 0): - case HASH('H', 0): - case HASH('I', 0): - case HASH('J', 0): - case HASH('K', 0): - case HASH('L', 0): - case HASH('M', 0): - case HASH('N', 0): - case HASH('O', 0): - case HASH('P', 0): - case HASH('Q', 0): - case HASH('R', 0): - case HASH('S', 0): - case HASH('T', 0): - case HASH('U', 0): - case HASH('V', 0): - case HASH('W', 0): - case HASH('X', 0): - case HASH('Y', 0): - case HASH('Z', 0): - height = param.cap_height; - break; - case HASH('*', 'A'): - case HASH('*', 'B'): - case HASH('*', 'C'): - case HASH('*', 'D'): - case HASH('*', 'E'): - case HASH('*', 'F'): - case HASH('*', 'G'): - case HASH('*', 'H'): - case HASH('*', 'I'): - case HASH('*', 'K'): - case HASH('*', 'L'): - case HASH('*', 'M'): - case HASH('*', 'N'): - case HASH('*', 'O'): - case HASH('*', 'P'): - case HASH('*', 'Q'): - case HASH('*', 'R'): - case HASH('*', 'S'): - case HASH('*', 'T'): - case HASH('*', 'U'): - case HASH('*', 'W'): - case HASH('*', 'X'): - case HASH('*', 'Y'): - case HASH('*', 'Z'): - height = param.cap_height; - break; - case HASH('0', 0): - case HASH('1', 0): - case HASH('2', 0): - case HASH('3', 0): - case HASH('4', 0): - case HASH('5', 0): - case HASH('6', 0): - case HASH('7', 0): - case HASH('8', 0): - case HASH('9', 0): - case HASH('1', '2'): - case HASH('1', '4'): - case HASH('3', '4'): - height = param.fig_height; - break; - case HASH('(', 0): - case HASH(')', 0): - case HASH('[', 0): - case HASH(']', 0): - case HASH('{', 0): - case HASH('}', 0): - height = param.body_height; - depth = param.body_depth; - break; - case HASH('i', 's'): - height = (param.em*3)/4; - depth = param.em/4; - break; - case HASH('*', 'a'): - case HASH('*', 'e'): - case HASH('*', 'i'): - case HASH('*', 'k'): - case HASH('*', 'n'): - case HASH('*', 'o'): - case HASH('*', 'p'): - case HASH('*', 's'): - case HASH('*', 't'): - case HASH('*', 'u'): - case HASH('*', 'w'): - height = param.x_height; - break; - case HASH('*', 'd'): - case HASH('*', 'l'): - height = param.asc_height; - break; - case HASH('*', 'g'): - case HASH('*', 'h'): - case HASH('*', 'm'): - case HASH('*', 'r'): - case HASH('*', 'x'): - case HASH('*', 'y'): - height = param.x_height; - depth = param.desc_depth; - break; - case HASH('*', 'b'): - case HASH('*', 'c'): - case HASH('*', 'f'): - case HASH('*', 'q'): - case HASH('*', 'z'): - height = param.asc_height; - depth = param.desc_depth; - break; - case HASH('t', 's'): - height = param.x_height; - depth = param.desc_depth; - break; - case HASH('!', 0): - case HASH('?', 0): - case HASH('"', 0): - case HASH('#', 0): - case HASH('$', 0): - case HASH('%', 0): - case HASH('&', 0): - case HASH('*', 0): - case HASH('+', 0): - height = param.asc_height; - break; - case HASH('`', 0): - case HASH('\'', 0): - height = param.asc_height; - break; - case HASH('~', 0): - case HASH('^', 0): - case HASH('a', 'a'): - case HASH('g', 'a'): - height = param.asc_height; - break; - case HASH('r', 'u'): - case HASH('.', 0): - break; - case HASH(',', 0): - depth = param.comma_depth; - break; - case HASH('m', 'i'): - case HASH('-', 0): - case HASH('h', 'y'): - case HASH('e', 'm'): - height = param.x_height; - break; - case HASH(':', 0): - height = param.x_height; - break; - case HASH(';', 0): - height = param.x_height; - depth = param.comma_depth; - break; - case HASH('=', 0): - case HASH('e', 'q'): - height = param.x_height; - break; - case HASH('<', 0): - case HASH('>', 0): - case HASH('>', '='): - case HASH('<', '='): - case HASH('@', 0): - case HASH('/', 0): - case HASH('|', 0): - case HASH('\\', 0): - height = param.asc_height; - break; - case HASH('_', 0): - case HASH('u', 'l'): - case HASH('\\', '_'): - depth = param.em/4; - break; - case HASH('r', 'n'): - height = (param.em*3)/4; - break; - case HASH('s', 'r'): - height = (param.em*3)/4; - depth = param.em/4; - break; - case HASH('b', 'u'): - case HASH('s', 'q'): - case HASH('d', 'e'): - case HASH('d', 'g'): - case HASH('f', 'm'): - case HASH('c', 't'): - case HASH('r', 'g'): - case HASH('c', 'o'): - case HASH('p', 'l'): - case HASH('*', '*'): - case HASH('s', 'c'): - case HASH('s', 'l'): - case HASH('=', '='): - case HASH('~', '='): - case HASH('a', 'p'): - case HASH('!', '='): - case HASH('-', '>'): - case HASH('<', '-'): - case HASH('u', 'a'): - case HASH('d', 'a'): - case HASH('m', 'u'): - case HASH('d', 'i'): - case HASH('+', '-'): - case HASH('c', 'u'): - case HASH('c', 'a'): - case HASH('s', 'b'): - case HASH('s', 'p'): - case HASH('i', 'b'): - case HASH('i', 'p'): - case HASH('i', 'f'): - case HASH('p', 'd'): - case HASH('g', 'r'): - case HASH('n', 'o'): - case HASH('p', 't'): - case HASH('e', 's'): - case HASH('m', 'o'): - case HASH('b', 'r'): - case HASH('d', 'd'): - case HASH('r', 'h'): - case HASH('l', 'h'): - case HASH('o', 'r'): - case HASH('c', 'i'): - height = param.asc_height; - break; - case HASH('l', 't'): - case HASH('l', 'b'): - case HASH('r', 't'): - case HASH('r', 'b'): - case HASH('l', 'k'): - case HASH('r', 'k'): - case HASH('b', 'v'): - case HASH('l', 'f'): - case HASH('r', 'f'): - case HASH('l', 'c'): - case HASH('r', 'c'): - height = (param.em*3)/4; - depth = param.em/4; - break; -#if 0 - case HASH('%', '0'): - case HASH('-', '+'): - case HASH('-', 'D'): - case HASH('-', 'd'): - case HASH('-', 'd'): - case HASH('-', 'h'): - case HASH('.', 'i'): - case HASH('.', 'j'): - case HASH('/', 'L'): - case HASH('/', 'O'): - case HASH('/', 'l'): - case HASH('/', 'o'): - case HASH('=', '~'): - case HASH('A', 'E'): - case HASH('A', 'h'): - case HASH('A', 'N'): - case HASH('C', 's'): - case HASH('D', 'o'): - case HASH('F', 'c'): - case HASH('F', 'o'): - case HASH('I', 'J'): - case HASH('I', 'm'): - case HASH('O', 'E'): - case HASH('O', 'f'): - case HASH('O', 'K'): - case HASH('O', 'm'): - case HASH('O', 'R'): - case HASH('P', 'o'): - case HASH('R', 'e'): - case HASH('S', '1'): - case HASH('S', '2'): - case HASH('S', '3'): - case HASH('T', 'P'): - case HASH('T', 'p'): - case HASH('Y', 'e'): - case HASH('\\', '-'): - case HASH('a', '"'): - case HASH('a', '-'): - case HASH('a', '.'): - case HASH('a', '^'): - case HASH('a', 'b'): - case HASH('a', 'c'): - case HASH('a', 'd'): - case HASH('a', 'e'): - case HASH('a', 'h'): - case HASH('a', 'o'): - case HASH('a', 't'): - case HASH('a', '~'): - case HASH('b', 'a'): - case HASH('b', 'b'): - case HASH('b', 's'): - case HASH('c', '*'): - case HASH('c', '+'): - case HASH('f', '/'): - case HASH('f', 'a'): - case HASH('f', 'c'): - case HASH('f', 'o'): - case HASH('h', 'a'): - case HASH('h', 'o'): - case HASH('i', 'j'): - case HASH('l', 'A'): - case HASH('l', 'B'): - case HASH('l', 'C'): - case HASH('m', 'd'): - case HASH('n', 'c'): - case HASH('n', 'e'): - case HASH('n', 'm'): - case HASH('o', 'A'): - case HASH('o', 'a'): - case HASH('o', 'e'): - case HASH('o', 'q'): - case HASH('p', 'l'): - case HASH('p', 'p'): - case HASH('p', 's'): - case HASH('r', '!'): - case HASH('r', '?'): - case HASH('r', 'A'): - case HASH('r', 'B'): - case HASH('r', 'C'): - case HASH('r', 's'): - case HASH('s', 'h'): - case HASH('s', 's'): - case HASH('t', 'e'): - case HASH('t', 'f'): - case HASH('t', 'i'): - case HASH('t', 'm'): - case HASH('~', '~'): - case HASH('v', 'S'): - case HASH('v', 'Z'): - case HASH('v', 's'): - case HASH('v', 'z'): - case HASH('^', 'A'): - case HASH('^', 'E'): - case HASH('^', 'I'): - case HASH('^', 'O'): - case HASH('^', 'U'): - case HASH('^', 'a'): - case HASH('^', 'e'): - case HASH('^', 'i'): - case HASH('^', 'o'): - case HASH('^', 'u'): - case HASH('`', 'A'): - case HASH('`', 'E'): - case HASH('`', 'I'): - case HASH('`', 'O'): - case HASH('`', 'U'): - case HASH('`', 'a'): - case HASH('`', 'e'): - case HASH('`', 'i'): - case HASH('`', 'o'): - case HASH('`', 'u'): - case HASH('~', 'A'): - case HASH('~', 'N'): - case HASH('~', 'O'): - case HASH('~', 'a'): - case HASH('~', 'n'): - case HASH('~', 'o'): - case HASH('\'', 'A'): - case HASH('\'', 'C'): - case HASH('\'', 'E'): - case HASH('\'', 'I'): - case HASH('\'', 'O'): - case HASH('\'', 'U'): - case HASH('\'', 'a'): - case HASH('\'', 'c'): - case HASH('\'', 'e'): - case HASH('\'', 'i'): - case HASH('\'', 'o'): - case HASH('\'', 'u') - case HASH(':', 'A'): - case HASH(':', 'E'): - case HASH(':', 'I'): - case HASH(':', 'O'): - case HASH(':', 'U'): - case HASH(':', 'Y'): - case HASH(':', 'a'): - case HASH(':', 'e'): - case HASH(':', 'i'): - case HASH(':', 'o'): - case HASH(':', 'u'): - case HASH(':', 'y'): - case HASH(',', 'C'): - case HASH(',', 'c'): -#endif - } -} diff --git a/contrib/groff/src/utils/hpftodit/hpftodit.cc b/contrib/groff/src/utils/hpftodit/hpftodit.cc deleted file mode 100644 index ecbc8a8..0000000 --- a/contrib/groff/src/utils/hpftodit/hpftodit.cc +++ /dev/null @@ -1,809 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1994, 2000, 2001 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. */ - -/* -TODO -put human readable font name in device file -devise new names for useful characters -use --- for unnamed characters -option to specify symbol sets to look in -make it work with TrueType fonts -put filename in error messages (or fix lib) -*/ - -#include "lib.h" - -#include -#include -#include -#include "assert.h" -#include "posix.h" -#include "errarg.h" -#include "error.h" -#include "cset.h" -#include "nonposix.h" - -extern "C" const char *Version_string; - -#define SIZEOF(v) (sizeof(v)/sizeof(v[0])) - -const int MULTIPLIER = 3; - -inline -int scale(int n) -{ - return n * MULTIPLIER; -} - -// tags in TFM file - -enum tag_type { - min_tag = 400, - type_tag = 400, - symbol_set_tag = 404, - msl_tag = 403, - inches_per_point_tag = 406, - design_units_per_em_tag = 408, - posture_tag = 409, - stroke_weight_tag = 411, - spacing_tag = 412, - slant_tag = 413, - appearance_width_tag = 414, - word_spacing_tag = 421, - x_height_tag = 424, - lower_ascent_tag = 427, - lower_descent_tag = 428, - width_tag = 433, - left_extent_tag = 435, - right_extent_tag = 436, - ascent_tag = 437, - descent_tag = 438, - pair_kern_tag = 439, - typeface_tag = 442, - max_tag = 443 - }; - -// types in TFM file - -enum { - ENUM_TYPE = 1, - BYTE_TYPE = 2, - USHORT_TYPE = 3, - FLOAT_TYPE = 5, - SIGNED_SHORT_TYPE = 17 - }; - - -typedef unsigned char byte; -typedef unsigned short uint16; -typedef short int16; -typedef unsigned int uint32; - -class File { -public: - File(const char *); - void skip(int n); - byte get_byte(); - uint16 get_uint16(); - uint32 get_uint32(); - void seek(uint32 n); -private: - unsigned char *buf_; - const unsigned char *ptr_; - const unsigned char *end_; -}; - -struct entry { - char present; - uint16 type; - uint32 count; - uint32 value; - entry() : present(0) { } -}; - -struct char_info { - uint16 msl; - uint16 width; - uint16 ascent; - int16 descent; - int16 left_extent; - uint16 right_extent; - uint16 symbol_set; - unsigned char code; -}; - -const uint16 NO_SYMBOL_SET = 0; - -struct name_list { - char *name; - name_list *next; - name_list(const char *s, name_list *p) : name(strsave(s)), next(p) { } - ~name_list() { a_delete name; } -}; - -struct symbol_set { - uint16 select; - uint16 index[256]; -}; - -#define SYMBOL_SET(n, c) ((n) * 32 + ((c) - 64)) - -uint16 text_symbol_sets[] = { - SYMBOL_SET(0, 'N'), // Latin 1 - SYMBOL_SET(6, 'J'), // Microsoft Publishing - SYMBOL_SET(2, 'N'), // Latin 2 - 0 - }; - -uint16 special_symbol_sets[] = { - SYMBOL_SET(8, 'M'), - SYMBOL_SET(5, 'M'), - SYMBOL_SET(15, 'U'), - 0 - }; - -entry tags[max_tag + 1 - min_tag]; - -char_info *char_table; -uint32 nchars; - -unsigned int msl_name_table_size = 0; -name_list **msl_name_table = 0; - -unsigned int n_symbol_sets; -symbol_set *symbol_set_table; - -static int special_flag = 0; -static int italic_flag = 0; -static int italic_sep; - -static void usage(FILE *stream); -static void usage(); -static const char *xbasename(const char *); -static void read_tags(File &); -static void check_type(); -static void check_units(File &); -static int read_map(const char *); -static void require_tag(tag_type); -static void dump_tags(File &f); -static void output_spacewidth(); -static void output_pclweight(); -static void output_pclproportional(); -static void read_and_output_pcltypeface(File &); -static void output_pclstyle(); -static void output_slant(); -static void output_ligatures(); -static void read_symbol_sets(File &); -static void read_and_output_kernpairs(File &); -static void output_charset(); -static void read_char_table(File &f); - -inline -entry &tag_info(tag_type t) -{ - return tags[t - min_tag]; -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - - int opt; - int debug_flag = 0; - - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "dsvi:", long_options, NULL)) != EOF) { - switch (opt) { - case 'd': - debug_flag = 1; - break; - case 's': - special_flag = 1; - break; - case 'i': - italic_flag = 1; - italic_sep = atoi(optarg); - break; - case 'v': - { - printf("GNU hpftodit (groff) version %s\n", Version_string); - exit(0); - } - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(); - break; - default: - assert(0); - } - } - if (argc - optind != 3) - usage(); - File f(argv[optind]); - if (!read_map(argv[optind + 1])) - exit(1); - current_filename = 0; - current_lineno = -1; // no line numbers - if (freopen(argv[optind + 2], "w", stdout) == 0) - fatal("cannot open `%1': %2", argv[optind + 2], strerror(errno)); - current_filename = argv[optind]; - printf("name %s\n", xbasename(argv[optind + 2])); - if (special_flag) - printf("special\n"); - read_tags(f); - check_type(); - check_units(f); - if (debug_flag) - dump_tags(f); - read_char_table(f); - output_spacewidth(); - output_slant(); - read_and_output_pcltypeface(f); - output_pclproportional(); - output_pclweight(); - output_pclstyle(); - read_symbol_sets(f); - output_ligatures(); - read_and_output_kernpairs(f); - output_charset(); - return 0; -} - -static -void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-s] [-i n] tfm_file map_file output_font\n", - program_name); -} -static -void usage() -{ - usage(stderr); - exit(1); -} - -File::File(const char *s) -{ - // We need to read the file in binary mode because hpftodit relies - // on byte counts. - int fd = open(s, O_RDONLY | O_BINARY); - if (fd < 0) - fatal("cannot open `%1': %2", s, strerror(errno)); - current_filename = s; - struct stat sb; - if (fstat(fd, &sb) < 0) - fatal("cannot stat: %1", strerror(errno)); - if (!S_ISREG(sb.st_mode)) - fatal("not a regular file"); - buf_ = new unsigned char[sb.st_size]; - long nread = read(fd, buf_, sb.st_size); - if (nread < 0) - fatal("read error: %1", strerror(errno)); - if (nread != sb.st_size) - fatal("read unexpected number of bytes"); - ptr_ = buf_; - end_ = buf_ + sb.st_size; -} - -void File::skip(int n) -{ - if (end_ - ptr_ < n) - fatal("unexpected end of file"); - ptr_ += n; -} - -void File::seek(uint32 n) -{ - if ((uint32)(end_ - buf_) < n) - fatal("unexpected end of file"); - ptr_ = buf_ + n; -} - -byte File::get_byte() -{ - if (ptr_ >= end_) - fatal("unexpected end of file"); - return *ptr_++; -} - -uint16 File::get_uint16() -{ - if (end_ - ptr_ < 2) - fatal("unexpected end of file"); - uint16 n = *ptr_++; - return n + (*ptr_++ << 8); -} - -uint32 File::get_uint32() -{ - if (end_ - ptr_ < 4) - fatal("unexpected end of file"); - uint32 n = *ptr_++; - for (int i = 0; i < 3; i++) - n += *ptr_++ << (i + 1)*8; - return n; -} - -static -void read_tags(File &f) -{ - if (f.get_byte() != 'I' || f.get_byte() != 'I') - fatal("not an Intel format TFM file"); - f.skip(6); - uint16 ntags = f.get_uint16(); - entry dummy; - for (uint16 i = 0; i < ntags; i++) { - uint16 tag = f.get_uint16(); - entry *p; - if (min_tag <= tag && tag <= max_tag) - p = tags + (tag - min_tag); - else - p = &dummy; - p->present = 1; - p->type = f.get_uint16(); - p->count = f.get_uint32(); - p->value = f.get_uint32(); - } -} - -static -void check_type() -{ - require_tag(type_tag); - if (tag_info(type_tag).value != 0) { - if (tag_info(type_tag).value == 2) - fatal("cannot handle TrueType tfm files"); - fatal("unknown type tag %1", int(tag_info(type_tag).value)); - } -} - -static -void check_units(File &f) -{ - require_tag(design_units_per_em_tag); - f.seek(tag_info(design_units_per_em_tag).value); - uint32 num = f.get_uint32(); - uint32 den = f.get_uint32(); - if (num != 8782 || den != 1) - fatal("design units per em != 8782/1"); - require_tag(inches_per_point_tag); - f.seek(tag_info(inches_per_point_tag).value); - num = f.get_uint32(); - den = f.get_uint32(); - if (num != 100 || den != 7231) - fatal("inches per point not 100/7231"); -} - -static -void require_tag(tag_type t) -{ - if (!tag_info(t).present) - fatal("tag %1 missing", int(t)); -} - -static -void output_spacewidth() -{ - require_tag(word_spacing_tag); - printf("spacewidth %d\n", scale(tag_info(word_spacing_tag).value)); -} - -static -void read_symbol_sets(File &f) -{ - uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count; - n_symbol_sets = symbol_set_dir_length/14; - symbol_set_table = new symbol_set[n_symbol_sets]; - unsigned int i; - for (i = 0; i < n_symbol_sets; i++) { - f.seek(tag_info(symbol_set_tag).value + i*14); - (void)f.get_uint32(); - uint32 off1 = f.get_uint32(); - uint32 off2 = f.get_uint32(); - (void)f.get_uint16(); // what's this for? - f.seek(off1); - unsigned int j; - uint16 kind = 0; - for (j = 0; j < off2 - off1; j++) { - unsigned char c = f.get_byte(); - if ('0' <= c && c <= '9') - kind = kind*10 + (c - '0'); - else if ('A' <= c && c <= 'Z') - kind = kind*32 + (c - 64); - } - symbol_set_table[i].select = kind; - for (j = 0; j < 256; j++) - symbol_set_table[i].index[j] = f.get_uint16(); - } - for (i = 0; i < nchars; i++) - char_table[i].symbol_set = NO_SYMBOL_SET; - - uint16 *symbol_set_selectors = (special_flag - ? special_symbol_sets - : text_symbol_sets); - for (i = 0; symbol_set_selectors[i] != 0; i++) { - unsigned int j; - for (j = 0; j < n_symbol_sets; j++) - if (symbol_set_table[j].select == symbol_set_selectors[i]) - break; - if (j < n_symbol_sets) { - for (int k = 0; k < 256; k++) { - uint16 index = symbol_set_table[j].index[k]; - if (index != 0xffff - && char_table[index].symbol_set == NO_SYMBOL_SET) { - char_table[index].symbol_set = symbol_set_table[j].select; - char_table[index].code = k; - } - } - } - } -} - -static -void read_char_table(File &f) -{ - require_tag(msl_tag); - nchars = tag_info(msl_tag).count; - char_table = new char_info[nchars]; - - f.seek(tag_info(msl_tag).value); - uint32 i; - for (i = 0; i < nchars; i++) - char_table[i].msl = f.get_uint16(); - - require_tag(width_tag); - f.seek(tag_info(width_tag).value); - for (i = 0; i < nchars; i++) - char_table[i].width = f.get_uint16(); - - require_tag(ascent_tag); - f.seek(tag_info(ascent_tag).value); - for (i = 0; i < nchars; i++) { - char_table[i].ascent = f.get_uint16(); - } - - require_tag(descent_tag); - f.seek(tag_info(descent_tag).value); - for (i = 0; i < nchars; i++) { - char_table[i].descent = f.get_uint16(); - if (char_table[i].descent > 0) - char_table[i].descent = 0; - } - - require_tag(left_extent_tag); - f.seek(tag_info(left_extent_tag).value); - for (i = 0; i < nchars; i++) - char_table[i].left_extent = int16(f.get_uint16()); - - require_tag(right_extent_tag); - f.seek(tag_info(right_extent_tag).value); - for (i = 0; i < nchars; i++) - char_table[i].right_extent = f.get_uint16(); -} - -static -void output_pclweight() -{ - require_tag(stroke_weight_tag); - int stroke_weight = tag_info(stroke_weight_tag).value; - int pcl_stroke_weight; - if (stroke_weight < 128) - pcl_stroke_weight = -3; - else if (stroke_weight == 128) - pcl_stroke_weight = 0; - else if (stroke_weight <= 145) - pcl_stroke_weight = 1; - else if (stroke_weight <= 179) - pcl_stroke_weight = 3; - else - pcl_stroke_weight = 4; - printf("pclweight %d\n", pcl_stroke_weight); -} - -static -void output_pclproportional() -{ - require_tag(spacing_tag); - printf("pclproportional %d\n", tag_info(spacing_tag).value == 0); -} - -static -void read_and_output_pcltypeface(File &f) -{ - printf("pcltypeface "); - require_tag(typeface_tag); - f.seek(tag_info(typeface_tag).value); - for (uint32 i = 0; i < tag_info(typeface_tag).count; i++) { - unsigned char c = f.get_byte(); - if (c == '\0') - break; - putchar(c); - } - printf("\n"); -} - -static -void output_pclstyle() -{ - unsigned pcl_style = 0; - // older tfms don't have the posture tag - if (tag_info(posture_tag).present) { - if (tag_info(posture_tag).value) - pcl_style |= 1; - } - else { - require_tag(slant_tag); - if (tag_info(slant_tag).value != 0) - pcl_style |= 1; - } - require_tag(appearance_width_tag); - if (tag_info(appearance_width_tag).value < 100) // guess - pcl_style |= 4; - printf("pclstyle %d\n", pcl_style); -} - -static -void output_slant() -{ - require_tag(slant_tag); - int slant = int16(tag_info(slant_tag).value); - if (slant != 0) - printf("slant %f\n", slant/100.0); -} - -static -void output_ligatures() -{ - // don't use ligatures for fixed space font - require_tag(spacing_tag); - if (tag_info(spacing_tag).value != 0) - return; - static const char *ligature_names[] = { - "fi", "fl", "ff", "ffi", "ffl" - }; - - static const char *ligature_chars[] = { - "fi", "fl", "ff", "Fi", "Fl" - }; - - unsigned ligature_mask = 0; - unsigned int i; - for (i = 0; i < nchars; i++) { - uint16 msl = char_table[i].msl; - if (msl < msl_name_table_size - && char_table[i].symbol_set != NO_SYMBOL_SET) { - for (name_list *p = msl_name_table[msl]; p; p = p->next) - for (unsigned int j = 0; j < SIZEOF(ligature_chars); j++) - if (strcmp(p->name, ligature_chars[j]) == 0) { - ligature_mask |= 1 << j; - break; - } - } - } - if (ligature_mask) { - printf("ligatures"); - for (i = 0; i < SIZEOF(ligature_names); i++) - if (ligature_mask & (1 << i)) - printf(" %s", ligature_names[i]); - printf(" 0\n"); - } -} - -static -void read_and_output_kernpairs(File &f) -{ - if (tag_info(pair_kern_tag).present) { - printf("kernpairs\n"); - f.seek(tag_info(pair_kern_tag).value); - uint16 n_pairs = f.get_uint16(); - for (int i = 0; i < n_pairs; i++) { - uint16 i1 = f.get_uint16(); - uint16 i2 = f.get_uint16(); - int16 val = int16(f.get_uint16()); - if (char_table[i1].symbol_set != NO_SYMBOL_SET - && char_table[i2].symbol_set != NO_SYMBOL_SET - && char_table[i1].msl < msl_name_table_size - && char_table[i2].msl < msl_name_table_size) { - for (name_list *p = msl_name_table[char_table[i1].msl]; - p; - p = p->next) - for (name_list *q = msl_name_table[char_table[i2].msl]; - q; - q = q->next) - printf("%s %s %d\n", p->name, q->name, scale(val)); - } - } - } -} - -static -void output_charset() -{ - require_tag(slant_tag); - double slant_angle = int16(tag_info(slant_tag).value)*PI/18000.0; - double slant = sin(slant_angle)/cos(slant_angle); - - require_tag(x_height_tag); - require_tag(lower_ascent_tag); - require_tag(lower_descent_tag); - - printf("charset\n"); - unsigned int i; - for (i = 0; i < nchars; i++) { - uint16 msl = char_table[i].msl; - if (msl < msl_name_table_size - && msl_name_table[msl]) { - if (char_table[i].symbol_set != NO_SYMBOL_SET) { - printf("%s\t%d,%d", - msl_name_table[msl]->name, - scale(char_table[i].width), - scale(char_table[i].ascent)); - int depth = scale(- char_table[i].descent); - if (depth < 0) - depth = 0; - int italic_correction = 0; - int left_italic_correction = 0; - int subscript_correction = 0; - if (italic_flag) { - italic_correction = scale(char_table[i].right_extent - - char_table[i].width - + italic_sep); - if (italic_correction < 0) - italic_correction = 0; - subscript_correction = int((tag_info(x_height_tag).value - * slant * .8) + .5); - if (subscript_correction > italic_correction) - subscript_correction = italic_correction; - left_italic_correction = scale(italic_sep - - char_table[i].left_extent); - } - if (subscript_correction != 0) - printf(",%d,%d,%d,%d", - depth, italic_correction, left_italic_correction, - subscript_correction); - else if (left_italic_correction != 0) - printf(",%d,%d,%d", depth, italic_correction, left_italic_correction); - else if (italic_correction != 0) - printf(",%d,%d", depth, italic_correction); - else if (depth != 0) - printf(",%d", depth); - // This is fairly arbitrary. Fortunately it doesn't much matter. - unsigned type = 0; - if (char_table[i].ascent > (tag_info(lower_ascent_tag).value*9)/10) - type |= 2; - if (char_table[i].descent < (int16(tag_info(lower_descent_tag).value)*9)/10) - type |= 1; - printf("\t%d\t%d\n", - type, - char_table[i].symbol_set*256 + char_table[i].code); - for (name_list *p = msl_name_table[msl]->next; p; p = p->next) - printf("%s\t\"\n", p->name); - } - else - warning("MSL %1 not in any of the searched symbol sets", msl); - } - } -} - -static -void dump_tags(File &f) -{ - int i; - for (i = min_tag; i <= max_tag; i++) { - enum tag_type t = tag_type(i); - if (tag_info(t).present) { - fprintf(stderr, - "%d %d %d %d\n", i, tag_info(t).type, tag_info(t).count, - tag_info(t).value); - if (tag_info(t).type == FLOAT_TYPE - && tag_info(t).count == 1) { - f.seek(tag_info(t).value); - uint32 num = f.get_uint32(); - uint32 den = f.get_uint32(); - fprintf(stderr, "(%u/%u = %g)\n", num, den, (double)num/den); - } - } - } -} - -static -int read_map(const char *file) -{ - errno = 0; - FILE *fp = fopen(file, "r"); - if (!fp) { - error("can't open `%1': %2", file, strerror(errno)); - return 0; - } - current_filename = file; - char buf[512]; - current_lineno = 0; - while (fgets(buf, int(sizeof(buf)), fp)) { - current_lineno++; - char *ptr = buf; - while (csspace(*ptr)) - ptr++; - if (*ptr == '\0' || *ptr == '#') - continue; - ptr = strtok(ptr, " \n\t"); - if (!ptr) - continue; - int n; - if (sscanf(ptr, "%d", &n) != 1) { - error("bad map file"); - fclose(fp); - return 0; - } - if (n < 0) { - error("negative code"); - fclose(fp); - return 0; - } - if ((size_t)n >= msl_name_table_size) { - size_t old_size = msl_name_table_size; - name_list **old_table = msl_name_table; - msl_name_table_size = n + 256; - msl_name_table = new name_list *[msl_name_table_size]; - if (old_table) { - memcpy(msl_name_table, old_table, old_size*sizeof(name_list *)); - a_delete old_table; - } - for (size_t i = old_size; i < msl_name_table_size; i++) - msl_name_table[i] = 0; - } - ptr = strtok(0, " \n\t"); - if (!ptr) { - error("missing names"); - fclose(fp); - return 0; - } - for (; ptr; ptr = strtok(0, " \n\t")) - msl_name_table[n] = new name_list(ptr, msl_name_table[n]); - } - fclose(fp); - return 1; -} - -static -const char *xbasename(const char *s) -{ - // DIR_SEPS[] are possible directory separator characters, see - // nonposix.h. We want the rightmost separator of all possible - // ones. Example: d:/foo\\bar. - const char *b = strrchr(s, DIR_SEPS[0]), *b1; - const char *sep = &DIR_SEPS[1]; - - while (*sep) - { - b1 = strrchr(s, *sep); - if (b1 && (!b || b1 > b)) - b = b1; - sep++; - } - return b ? b + 1 : s; -} diff --git a/contrib/groff/src/utils/indxbib/indxbib.cc b/contrib/groff/src/utils/indxbib/indxbib.cc deleted file mode 100644 index 9fced93..0000000 --- a/contrib/groff/src/utils/indxbib/indxbib.cc +++ /dev/null @@ -1,789 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001, 2002 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 "lib.h" - -#include -#include -#include - -#include "posix.h" -#include "errarg.h" -#include "error.h" -#include "stringclass.h" -#include "cset.h" -#include "cmap.h" - -#include "defs.h" -#include "index.h" - -#include "nonposix.h" - -extern "C" const char *Version_string; - -#define DEFAULT_HASH_TABLE_SIZE 997 -#define TEMP_INDEX_TEMPLATE "indxbibXXXXXX" - -// (2^n - MALLOC_OVERHEAD) should be a good argument for malloc(). - -#define MALLOC_OVERHEAD 16 - -#ifdef BLOCK_SIZE -#undef BLOCK_SIZE -#endif - -const int BLOCK_SIZE = ((1024 - MALLOC_OVERHEAD - sizeof(struct block *) - - sizeof(int)) / sizeof(int)); -struct block { - block *next; - int used; - int v[BLOCK_SIZE]; - - block(block *p = 0) : next(p), used(0) { } -}; - -struct block; - -union table_entry { - block *ptr; - int count; -}; - -struct word_list { - word_list *next; - char *str; - int len; - word_list(const char *, int, word_list *); -}; - -table_entry *hash_table; -int hash_table_size = DEFAULT_HASH_TABLE_SIZE; -// We make this the same size as hash_table so we only have to do one -// mod per key. -static word_list **common_words_table = 0; -char *key_buffer; - -FILE *indxfp; -int ntags = 0; -string filenames; -char *temp_index_file = 0; - -const char *ignore_fields = "XYZ"; -const char *common_words_file = COMMON_WORDS_FILE; -int n_ignore_words = 100; -int truncate_len = 6; -int shortest_len = 3; -int max_keys_per_item = 100; - -static void usage(FILE *stream); -static void write_hash_table(); -static void init_hash_table(); -static void read_common_words_file(); -static int store_key(char *s, int len); -static void possibly_store_key(char *s, int len); -static int do_whole_file(const char *filename); -static int do_file(const char *filename); -static void store_reference(int filename_index, int pos, int len); -static void check_integer_arg(char opt, const char *arg, int min, int *res); -static void store_filename(const char *); -static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp); -static char *get_cwd(); - -extern "C" { - void cleanup(); - void catch_fatal_signals(); - void ignore_fatal_signals(); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - - const char *basename = 0; - typedef int (*parser_t)(const char *); - parser_t parser = do_file; - const char *directory = 0; - const char *foption = 0; - int opt; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "c:o:h:i:k:l:t:n:c:d:f:vw", - long_options, NULL)) - != EOF) - switch (opt) { - case 'c': - common_words_file = optarg; - break; - case 'd': - directory = optarg; - break; - case 'f': - foption = optarg; - break; - case 'h': - check_integer_arg('h', optarg, 1, &hash_table_size); - if (!is_prime(hash_table_size)) { - while (!is_prime(++hash_table_size)) - ; - warning("%1 not prime: using %2 instead", optarg, hash_table_size); - } - break; - case 'i': - ignore_fields = optarg; - break; - case 'k': - check_integer_arg('k', optarg, 1, &max_keys_per_item); - break; - case 'l': - check_integer_arg('l', optarg, 0, &shortest_len); - break; - case 'n': - check_integer_arg('n', optarg, 0, &n_ignore_words); - break; - case 'o': - basename = optarg; - break; - case 't': - check_integer_arg('t', optarg, 1, &truncate_len); - break; - case 'w': - parser = do_whole_file; - break; - case 'v': - printf("GNU indxbib (groff) version %s\n", Version_string); - exit(0); - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - break; - } - if (optind >= argc && foption == 0) - fatal("no files and no -f option"); - if (!directory) { - char *path = get_cwd(); - store_filename(path); - a_delete path; - } - else - store_filename(directory); - init_hash_table(); - store_filename(common_words_file); - store_filename(ignore_fields); - key_buffer = new char[truncate_len]; - read_common_words_file(); - if (!basename) - basename = optind < argc ? argv[optind] : DEFAULT_INDEX_NAME; - const char *p = strrchr(basename, DIR_SEPS[0]), *p1; - const char *sep = &DIR_SEPS[1]; - while (*sep) { - p1 = strrchr(basename, *sep); - if (p1 && (!p || p1 > p)) - p = p1; - sep++; - } - size_t name_max; - if (p) { - char *dir = strsave(basename); - dir[p - basename] = '\0'; - name_max = file_name_max(dir); - a_delete dir; - } - else - name_max = file_name_max("."); - const char *filename = p ? p + 1 : basename; - if (name_max >= 0 && - (strlen(filename) + sizeof(INDEX_SUFFIX) - 1) > name_max) - fatal("`%1.%2' is too long for a filename", filename, INDEX_SUFFIX); - if (p) { - p++; - temp_index_file = new char[p - basename + sizeof(TEMP_INDEX_TEMPLATE)]; - memcpy(temp_index_file, basename, p - basename); - strcpy(temp_index_file + (p - basename), TEMP_INDEX_TEMPLATE); - } - else { - temp_index_file = strsave(TEMP_INDEX_TEMPLATE); - } - catch_fatal_signals(); - int fd = mkstemp(temp_index_file); - if (fd < 0) - fatal("can't create temporary index file: %1", strerror(errno)); - indxfp = fdopen(fd, FOPEN_WB); - if (indxfp == 0) - fatal("fdopen failed"); - if (fseek(indxfp, sizeof(index_header), 0) < 0) - fatal("can't seek past index header: %1", strerror(errno)); - int failed = 0; - if (foption) { - FILE *fp = stdin; - if (strcmp(foption, "-") != 0) { - errno = 0; - fp = fopen(foption, "r"); - if (!fp) - fatal("can't open `%1': %2", foption, strerror(errno)); - } - string path; - int lineno = 1; - for (;;) { - int c; - for (c = getc(fp); c != '\n' && c != EOF; c = getc(fp)) { - if (c == '\0') - error_with_file_and_line(foption, lineno, - "nul character in pathname ignored"); - else - path += c; - } - if (path.length() > 0) { - path += '\0'; - if (!(*parser)(path.contents())) - failed = 1; - path.clear(); - } - if (c == EOF) - break; - lineno++; - } - if (fp != stdin) - fclose(fp); - } - for (int i = optind; i < argc; i++) - if (!(*parser)(argv[i])) - failed = 1; - write_hash_table(); - if (fclose(indxfp) < 0) - fatal("error closing temporary index file: %1", strerror(errno)); - char *index_file = new char[strlen(basename) + sizeof(INDEX_SUFFIX)]; - strcpy(index_file, basename); - strcat(index_file, INDEX_SUFFIX); -#ifdef HAVE_RENAME -#ifdef __EMX__ - unline(index_file); -#endif /* __EMX__ */ - if (rename(temp_index_file, index_file) < 0) { -#ifdef __MSDOS__ - // RENAME could fail on plain MSDOS filesystems because - // INDEX_FILE is an invalid filename, e.g. it has multiple dots. - char *fname = p ? index_file + (p - basename) : 0; - char *dot = 0; - - // Replace the dot with an underscore and try again. - if (fname - && (dot = strchr(fname, '.')) != 0 - && strcmp(dot, INDEX_SUFFIX) != 0) - *dot = '_'; - if (rename(temp_index_file, index_file) < 0) -#endif - fatal("can't rename temporary index file: %1", strerror(errno)); - } -#else /* not HAVE_RENAME */ - ignore_fatal_signals(); - if (unlink(index_file) < 0) { - if (errno != ENOENT) - fatal("can't unlink `%1': %2", index_file, strerror(errno)); - } - if (link(temp_index_file, index_file) < 0) - fatal("can't link temporary index file: %1", strerror(errno)); - if (unlink(temp_index_file) < 0) - fatal("can't unlink temporary index file: %1", strerror(errno)); -#endif /* not HAVE_RENAME */ - temp_index_file = 0; - return failed; -} - -static void usage(FILE *stream) -{ - fprintf(stream, -"usage: %s [-vw] [-c file] [-d dir] [-f file] [-h n] [-i XYZ] [-k n]\n" -" [-l n] [-n n] [-o base] [-t n] [files...]\n", - program_name); -} - -static void check_integer_arg(char opt, const char *arg, int min, int *res) -{ - char *ptr; - long n = strtol(arg, &ptr, 10); - if (n == 0 && ptr == arg) - error("argument to -%1 not an integer", opt); - else if (n < min) - error("argument to -%1 must not be less than %2", opt, min); - else { - if (n > INT_MAX) - error("argument to -%1 greater than maximum integer", opt); - else if (*ptr != '\0') - error("junk after integer argument to -%1", opt); - *res = int(n); - } -} - -static char *get_cwd() -{ - char *buf; - int size = 12; - - for (;;) { - buf = new char[size]; - if (getcwd(buf, size)) - break; - if (errno != ERANGE) - fatal("cannot get current working directory: %1", strerror(errno)); - a_delete buf; - if (size == INT_MAX) - fatal("current working directory longer than INT_MAX"); - if (size > INT_MAX/2) - size = INT_MAX; - else - size *= 2; - } - return buf; -} - -word_list::word_list(const char *s, int n, word_list *p) -: next(p), len(n) -{ - str = new char[n]; - memcpy(str, s, n); -} - -static void read_common_words_file() -{ - if (n_ignore_words <= 0) - return; - errno = 0; - FILE *fp = fopen(common_words_file, "r"); - if (!fp) - fatal("can't open `%1': %2", common_words_file, strerror(errno)); - common_words_table = new word_list * [hash_table_size]; - for (int i = 0; i < hash_table_size; i++) - common_words_table[i] = 0; - int count = 0; - int key_len = 0; - for (;;) { - int c = getc(fp); - while (c != EOF && !csalnum(c)) - c = getc(fp); - if (c == EOF) - break; - do { - if (key_len < truncate_len) - key_buffer[key_len++] = cmlower(c); - c = getc(fp); - } while (c != EOF && csalnum(c)); - if (key_len >= shortest_len) { - int h = hash(key_buffer, key_len) % hash_table_size; - common_words_table[h] = new word_list(key_buffer, key_len, - common_words_table[h]); - } - if (++count >= n_ignore_words) - break; - key_len = 0; - if (c == EOF) - break; - } - n_ignore_words = count; - fclose(fp); -} - -static int do_whole_file(const char *filename) -{ - errno = 0; - FILE *fp = fopen(filename, "r"); - if (!fp) { - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } - int count = 0; - int key_len = 0; - int c; - while ((c = getc(fp)) != EOF) { - if (csalnum(c)) { - key_len = 1; - key_buffer[0] = c; - while ((c = getc(fp)) != EOF) { - if (!csalnum(c)) - break; - if (key_len < truncate_len) - key_buffer[key_len++] = c; - } - if (store_key(key_buffer, key_len)) { - if (++count >= max_keys_per_item) - break; - } - if (c == EOF) - break; - } - } - store_reference(filenames.length(), 0, 0); - store_filename(filename); - fclose(fp); - return 1; -} - -static int do_file(const char *filename) -{ - errno = 0; - // Need binary I/O for MS-DOS/MS-Windows, because indxbib relies on - // byte counts to be consistent with fseek. - FILE *fp = fopen(filename, FOPEN_RB); - if (fp == 0) { - error("can't open `%1': %2", filename, strerror(errno)); - return 0; - } - int filename_index = filenames.length(); - store_filename(filename); - - enum { - START, // at the start of the file; also in between references - BOL, // in the middle of a reference, at the beginning of the line - PERCENT, // seen a percent at the beginning of the line - IGNORE, // ignoring a field - IGNORE_BOL, // at the beginning of a line ignoring a field - KEY, // in the middle of a key - DISCARD, // after truncate_len bytes of a key - MIDDLE // in between keys - } state = START; - - // In states START, BOL, IGNORE_BOL, space_count how many spaces at - // the beginning have been seen. In states PERCENT, IGNORE, KEY, - // MIDDLE space_count must be 0. - int space_count = 0; - int byte_count = 0; // bytes read - int key_len = 0; - int ref_start = -1; // position of start of current reference - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - // We opened the file in binary mode, so we need to skip - // every CR character before a Newline. - if (c == '\r') { - int peek = getc(fp); - if (peek == '\n') { - byte_count++; - c = peek; - } - else - ungetc(peek, fp); - } -#if defined(__MSDOS__) || defined(_MSC_VER) - else if (c == 0x1a) // ^Z means EOF in text files - break; -#endif - byte_count++; - switch (state) { - case START: - if (c == ' ' || c == '\t') { - space_count++; - break; - } - if (c == '\n') { - space_count = 0; - break; - } - ref_start = byte_count - space_count - 1; - space_count = 0; - if (c == '%') - state = PERCENT; - else if (csalnum(c)) { - state = KEY; - key_buffer[0] = c; - key_len = 1; - } - else - state = MIDDLE; - break; - case BOL: - switch (c) { - case '%': - if (space_count > 0) { - space_count = 0; - state = MIDDLE; - } - else - state = PERCENT; - break; - case ' ': - case '\t': - space_count++; - break; - case '\n': - store_reference(filename_index, ref_start, - byte_count - 1 - space_count - ref_start); - state = START; - space_count = 0; - break; - default: - space_count = 0; - if (csalnum(c)) { - state = KEY; - key_buffer[0] = c; - key_len = 1; - } - else - state = MIDDLE; - } - break; - case PERCENT: - if (strchr(ignore_fields, c) != 0) - state = IGNORE; - else if (c == '\n') - state = BOL; - else - state = MIDDLE; - break; - case IGNORE: - if (c == '\n') - state = IGNORE_BOL; - break; - case IGNORE_BOL: - switch (c) { - case '%': - if (space_count > 0) { - state = IGNORE; - space_count = 0; - } - else - state = PERCENT; - break; - case ' ': - case '\t': - space_count++; - break; - case '\n': - store_reference(filename_index, ref_start, - byte_count - 1 - space_count - ref_start); - state = START; - space_count = 0; - break; - default: - space_count = 0; - state = IGNORE; - } - break; - case KEY: - if (csalnum(c)) { - if (key_len < truncate_len) - key_buffer[key_len++] = c; - else - state = DISCARD; - } - else { - possibly_store_key(key_buffer, key_len); - key_len = 0; - if (c == '\n') - state = BOL; - else - state = MIDDLE; - } - break; - case DISCARD: - if (!csalnum(c)) { - possibly_store_key(key_buffer, key_len); - key_len = 0; - if (c == '\n') - state = BOL; - else - state = MIDDLE; - } - break; - case MIDDLE: - if (csalnum(c)) { - state = KEY; - key_buffer[0] = c; - key_len = 1; - } - else if (c == '\n') - state = BOL; - break; - default: - assert(0); - } - } - switch (state) { - case START: - break; - case DISCARD: - case KEY: - possibly_store_key(key_buffer, key_len); - // fall through - case BOL: - case PERCENT: - case IGNORE_BOL: - case IGNORE: - case MIDDLE: - store_reference(filename_index, ref_start, - byte_count - ref_start - space_count); - break; - default: - assert(0); - } - fclose(fp); - return 1; -} - -static void store_reference(int filename_index, int pos, int len) -{ - tag t; - t.filename_index = filename_index; - t.start = pos; - t.length = len; - fwrite_or_die(&t, sizeof(t), 1, indxfp); - ntags++; -} - -static void store_filename(const char *fn) -{ - filenames += fn; - filenames += '\0'; -} - -static void init_hash_table() -{ - hash_table = new table_entry[hash_table_size]; - for (int i = 0; i < hash_table_size; i++) - hash_table[i].ptr = 0; -} - -static void possibly_store_key(char *s, int len) -{ - static int last_tagno = -1; - static int key_count; - if (last_tagno != ntags) { - last_tagno = ntags; - key_count = 0; - } - if (key_count < max_keys_per_item) { - if (store_key(s, len)) - key_count++; - } -} - -static int store_key(char *s, int len) -{ - if (len < shortest_len) - return 0; - int is_number = 1; - for (int i = 0; i < len; i++) - if (!csdigit(s[i])) { - is_number = 0; - s[i] = cmlower(s[i]); - } - if (is_number && !(len == 4 && s[0] == '1' && s[1] == '9')) - return 0; - int h = hash(s, len) % hash_table_size; - if (common_words_table) { - for (word_list *ptr = common_words_table[h]; ptr; ptr = ptr->next) - if (len == ptr->len && memcmp(s, ptr->str, len) == 0) - return 0; - } - table_entry *pp = hash_table + h; - if (!pp->ptr) - pp->ptr = new block; - else if (pp->ptr->v[pp->ptr->used - 1] == ntags) - return 1; - else if (pp->ptr->used >= BLOCK_SIZE) - pp->ptr = new block(pp->ptr); - pp->ptr->v[(pp->ptr->used)++] = ntags; - return 1; -} - -static void write_hash_table() -{ - const int minus_one = -1; - int li = 0; - for (int i = 0; i < hash_table_size; i++) { - block *ptr = hash_table[i].ptr; - if (!ptr) - hash_table[i].count = -1; - else { - hash_table[i].count = li; - block *rev = 0; - while (ptr) { - block *tem = ptr; - ptr = ptr->next; - tem->next = rev; - rev = tem; - } - while (rev) { - fwrite_or_die(rev->v, sizeof(int), rev->used, indxfp); - li += rev->used; - block *tem = rev; - rev = rev->next; - delete tem; - } - fwrite_or_die(&minus_one, sizeof(int), 1, indxfp); - li += 1; - } - } - if (sizeof(table_entry) == sizeof(int)) - fwrite_or_die(hash_table, sizeof(int), hash_table_size, indxfp); - else { - // write it out word by word - for (int i = 0; i < hash_table_size; i++) - fwrite_or_die(&hash_table[i].count, sizeof(int), 1, indxfp); - } - fwrite_or_die(filenames.contents(), 1, filenames.length(), indxfp); - if (fseek(indxfp, 0, 0) < 0) - fatal("error seeking on index file: %1", strerror(errno)); - index_header h; - h.magic = INDEX_MAGIC; - h.version = INDEX_VERSION; - h.tags_size = ntags; - h.lists_size = li; - h.table_size = hash_table_size; - h.strings_size = filenames.length(); - h.truncate = truncate_len; - h.shortest = shortest_len; - h.common = n_ignore_words; - fwrite_or_die(&h, sizeof(h), 1, indxfp); -} - -static void fwrite_or_die(const void *ptr, int size, int nitems, FILE *fp) -{ - if (fwrite(ptr, size, nitems, fp) != (size_t)nitems) - fatal("fwrite failed: %1", strerror(errno)); -} - -void fatal_error_exit() -{ - cleanup(); - exit(3); -} - -extern "C" { - -void cleanup() -{ - if (temp_index_file) - unlink(temp_index_file); -} - -} diff --git a/contrib/groff/src/utils/lkbib/lkbib.cc b/contrib/groff/src/utils/lkbib/lkbib.cc deleted file mode 100644 index 42156ea..0000000 --- a/contrib/groff/src/utils/lkbib/lkbib.cc +++ /dev/null @@ -1,137 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001 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 "lib.h" - -#include -#include -#include - -#include "errarg.h" -#include "error.h" - -#include "defs.h" -#include "refid.h" -#include "search.h" - -extern "C" const char *Version_string; - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-nv] [-p database] [-i XYZ] [-t N] keys ...\n", - program_name); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int search_default = 1; - search_list list; - int opt; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "nvVi:t:p:", long_options, NULL)) - != EOF) - switch (opt) { - case 'V': - verify_flag = 1; - break; - case 'n': - search_default = 0; - break; - case 'i': - linear_ignore_fields = optarg; - break; - case 't': - { - char *ptr; - long n = strtol(optarg, &ptr, 10); - if (n == 0 && ptr == optarg) { - error("bad integer `%1' in `t' option", optarg); - break; - } - if (n < 1) - n = 1; - linear_truncate_len = int(n); - break; - } - case 'v': - { - printf("GNU lkbib (groff) version %s\n", Version_string); - exit(0); - break; - } - case 'p': - list.add_file(optarg); - break; - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - if (optind >= argc) { - usage(stderr); - exit(1); - } - char *filename = getenv("REFER"); - if (filename) - list.add_file(filename); - else if (search_default) - list.add_file(DEFAULT_INDEX, 1); - if (list.nfiles() == 0) - fatal("no databases"); - int total_len = 0; - int i; - for (i = optind; i < argc; i++) - total_len += strlen(argv[i]); - total_len += argc - optind - 1 + 1; // for spaces and '\0' - char *buffer = new char[total_len]; - char *ptr = buffer; - for (i = optind; i < argc; i++) { - if (i > optind) - *ptr++ = ' '; - strcpy(ptr, argv[i]); - ptr = strchr(ptr, '\0'); - } - search_list_iterator iter(&list, buffer); - const char *start; - int len; - int count; - for (count = 0; iter.next(&start, &len); count++) { - if (fwrite(start, 1, len, stdout) != (size_t)len) - fatal("write error on stdout: %1", strerror(errno)); - // Can happen for last reference in file. - if (start[len - 1] != '\n') - putchar('\n'); - putchar('\n'); - } - return !count; -} diff --git a/contrib/groff/src/utils/lookbib/lookbib.cc b/contrib/groff/src/utils/lookbib/lookbib.cc deleted file mode 100644 index 65e89bc..0000000 --- a/contrib/groff/src/utils/lookbib/lookbib.cc +++ /dev/null @@ -1,141 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001 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 "lib.h" - -#include -#include -#include - -#include "errarg.h" -#include "error.h" -#include "cset.h" - -#include "refid.h" -#include "search.h" - -/* for isatty() */ -#include "posix.h" - -extern "C" { - const char *Version_string; -} - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-v] [-i XYZ] [-t N] database ...\n", - program_name); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int opt; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "vVi:t:", long_options, NULL)) != EOF) - switch (opt) { - case 'V': - verify_flag = 1; - break; - case 'i': - linear_ignore_fields = optarg; - break; - case 't': - { - char *ptr; - long n = strtol(optarg, &ptr, 10); - if (n == 0 && ptr == optarg) { - error("bad integer `%1' in `t' option", optarg); - break; - } - if (n < 1) - n = 1; - linear_truncate_len = int(n); - break; - } - case 'v': - { - printf("GNU lookbib (groff) version %s\n", Version_string); - exit(0); - break; - } - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - default: - assert(0); - } - if (optind >= argc) { - usage(stderr); - exit(1); - } - search_list list; - for (int i = optind; i < argc; i++) - list.add_file(argv[i]); - if (list.nfiles() == 0) - fatal("no databases"); - char line[1024]; - int interactive = isatty(fileno(stdin)); - for (;;) { - if (interactive) { - fputs("> ", stderr); - fflush(stderr); - } - if (!fgets(line, sizeof(line), stdin)) - break; - char *ptr = line; - while (csspace(*ptr)) - ptr++; - if (*ptr == '\0') - continue; - search_list_iterator iter(&list, line); - const char *start; - int len; - int count; - for (count = 0; iter.next(&start, &len); count++) { - if (fwrite(start, 1, len, stdout) != (size_t)len) - fatal("write error on stdout: %1", strerror(errno)); - // Can happen for last reference in file. - if (start[len - 1] != '\n') - putchar('\n'); - putchar('\n'); - } - fflush(stdout); - if (interactive) { - fprintf(stderr, "%d found\n", count); - fflush(stderr); - } - } - if (interactive) - putc('\n', stderr); - return 0; -} - diff --git a/contrib/groff/src/utils/tfmtodit/tfmtodit.cc b/contrib/groff/src/utils/tfmtodit/tfmtodit.cc deleted file mode 100644 index 9fbbe25..0000000 --- a/contrib/groff/src/utils/tfmtodit/tfmtodit.cc +++ /dev/null @@ -1,874 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989-1992, 2000, 2001 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. */ - -/* I have tried to incorporate the changes needed for TeX 3.0 tfm files, -but I haven't tested them. */ - -/* Groff requires more font metric information than TeX. The reason -for this is that TeX has separate Math Italic fonts, whereas groff -uses normal italic fonts for math. The two additional pieces of -information required by groff correspond to the two arguments to the -math_fit() macro in the Metafont programs for the CM fonts. In the -case of a font for which math_fitting is false, these two arguments -are normally ignored by Metafont. We need to get hold of these two -parameters and put them in the groff font file. - -We do this by loading this definition after cmbase when creating cm.base. - -def ignore_math_fit(expr left_adjustment,right_adjustment) = - special "adjustment"; - numspecial left_adjustment*16/designsize; - numspecial right_adjustment*16/designsize; - enddef; - -This puts the two arguments to the math_fit macro into the gf file. -(They will appear in the gf file immediately before the character to -which they apply.) We then create a gf file using this cm.base. Then -we run tfmtodit and specify this gf file with the -g option. - -This need only be done for a font for which math_fitting is false; -When it's true, the left_correction and subscript_correction should -both be zero. */ - -#include "lib.h" - -#include -#include -#include -#include "errarg.h" -#include "error.h" -#include "assert.h" -#include "cset.h" -#include "nonposix.h" - -extern "C" const char *Version_string; - -/* Values in the tfm file should be multiplied by this. */ - -#define MULTIPLIER 1 - -struct char_info_word { - unsigned char width_index; - char height_index; - char depth_index; - char italic_index; - char tag; - unsigned char remainder; -}; - -struct lig_kern_command { - unsigned char skip_byte; - unsigned char next_char; - unsigned char op_byte; - unsigned char remainder; -}; - -class tfm { - int bc; - int ec; - int nw; - int nh; - int nd; - int ni; - int nl; - int nk; - int np; - int cs; - int ds; - char_info_word *char_info; - int *width; - int *height; - int *depth; - int *italic; - lig_kern_command *lig_kern; - int *kern; - int *param; -public: - tfm(); - ~tfm(); - int load(const char *); - int contains(int); - int get_width(int); - int get_height(int); - int get_depth(int); - int get_italic(int); - int get_param(int, int *); - int get_checksum(); - int get_design_size(); - int get_lig(unsigned char, unsigned char, unsigned char *); - friend class kern_iterator; -}; - -class kern_iterator { - tfm *t; - int c; - int i; -public: - kern_iterator(tfm *); - int next(unsigned char *c1, unsigned char *c2, int *k); -}; - - -kern_iterator::kern_iterator(tfm *p) -: t(p), c(t->bc), i(-1) -{ -} - -int kern_iterator::next(unsigned char *c1, unsigned char *c2, int *k) -{ - for (; c <= t->ec; c++) - if (t->char_info[c - t->bc].tag == 1) { - if (i < 0) { - i = t->char_info[c - t->bc].remainder; - if (t->lig_kern[i].skip_byte > 128) - i = (256*t->lig_kern[i].op_byte - + t->lig_kern[i].remainder); - } - for (;;) { - int skip = t->lig_kern[i].skip_byte; - if (skip <= 128 && t->lig_kern[i].op_byte >= 128) { - *c1 = c; - *c2 = t->lig_kern[i].next_char; - *k = t->kern[256*(t->lig_kern[i].op_byte - 128) - + t->lig_kern[i].remainder]; - if (skip == 128) { - c++; - i = -1; - } - else - i += skip + 1; - return 1; - } - if (skip >= 128) - break; - i += skip + 1; - } - i = -1; - } - return 0; -} - -tfm::tfm() -: char_info(0), width(0), height(0), depth(0), italic(0), lig_kern(0), - kern(0), param(0) -{ -} - -int tfm::get_lig(unsigned char c1, unsigned char c2, unsigned char *cp) -{ - if (contains(c1) && char_info[c1 - bc].tag == 1) { - int i = char_info[c1 - bc].remainder; - if (lig_kern[i].skip_byte > 128) - i = 256*lig_kern[i].op_byte + lig_kern[i].remainder; - for (;;) { - int skip = lig_kern[i].skip_byte; - if (skip > 128) - break; - // We are only interested in normal ligatures, for which - // op_byte == 0. - if (lig_kern[i].op_byte == 0 - && lig_kern[i].next_char == c2) { - *cp = lig_kern[i].remainder; - return 1; - } - if (skip == 128) - break; - i += skip + 1; - } - } - return 0; -} - -int tfm::contains(int i) -{ - return i >= bc && i <= ec && char_info[i - bc].width_index != 0; -} - -int tfm::get_width(int i) -{ - return width[char_info[i - bc].width_index]; -} - -int tfm::get_height(int i) -{ - return height[char_info[i - bc].height_index]; -} - -int tfm::get_depth(int i) -{ - return depth[char_info[i - bc].depth_index]; -} - -int tfm::get_italic(int i) -{ - return italic[char_info[i - bc].italic_index]; -} - -int tfm::get_param(int i, int *p) -{ - if (i <= 0 || i > np) - return 0; - else { - *p = param[i - 1]; - return 1; - } -} - -int tfm::get_checksum() -{ - return cs; -} - -int tfm::get_design_size() -{ - return ds; -} - -tfm::~tfm() -{ - a_delete char_info; - a_delete width; - a_delete height; - a_delete depth; - a_delete italic; - a_delete lig_kern; - a_delete kern; - a_delete param; -} - -int read2(unsigned char *&s) -{ - int n; - n = *s++ << 8; - n |= *s++; - return n; -} - -int read4(unsigned char *&s) -{ - int n; - n = *s++ << 24; - n |= *s++ << 16; - n |= *s++ << 8; - n |= *s++; - return n; -} - - -int tfm::load(const char *file) -{ - errno = 0; - FILE *fp = fopen(file, FOPEN_RB); - if (!fp) { - error("can't open `%1': %2", file, strerror(errno)); - return 0; - } - int c1 = getc(fp); - int c2 = getc(fp); - if (c1 == EOF || c2 == EOF) { - fclose(fp); - error("unexpected end of file on `%1'", file); - return 0; - } - int lf = (c1 << 8) + c2; - int toread = lf*4 - 2; - unsigned char *buf = new unsigned char[toread]; - if (fread(buf, 1, toread, fp) != (size_t)toread) { - if (feof(fp)) - error("unexpected end of file on `%1'", file); - else - error("error on file `%1'", file); - a_delete buf; - fclose(fp); - return 0; - } - fclose(fp); - if (lf < 6) { - error("bad tfm file `%1': impossibly short", file); - a_delete buf; - return 0; - } - unsigned char *ptr = buf; - int lh = read2(ptr); - bc = read2(ptr); - ec = read2(ptr); - nw = read2(ptr); - nh = read2(ptr); - nd = read2(ptr); - ni = read2(ptr); - nl = read2(ptr); - nk = read2(ptr); - int ne = read2(ptr); - np = read2(ptr); - if (6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np != lf) { - error("bad tfm file `%1': lengths do not sum", file); - a_delete buf; - return 0; - } - if (lh < 2) { - error("bad tfm file `%1': header too short", file); - a_delete buf; - return 0; - } - char_info = new char_info_word[ec - bc + 1]; - width = new int[nw]; - height = new int[nh]; - depth = new int[nd]; - italic = new int[ni]; - lig_kern = new lig_kern_command[nl]; - kern = new int[nk]; - param = new int[np]; - int i; - cs = read4(ptr); - ds = read4(ptr); - ptr += (lh-2)*4; - for (i = 0; i < ec - bc + 1; i++) { - char_info[i].width_index = *ptr++; - unsigned char tem = *ptr++; - char_info[i].depth_index = tem & 0xf; - char_info[i].height_index = tem >> 4; - tem = *ptr++; - char_info[i].italic_index = tem >> 2; - char_info[i].tag = tem & 3; - char_info[i].remainder = *ptr++; - } - for (i = 0; i < nw; i++) - width[i] = read4(ptr); - for (i = 0; i < nh; i++) - height[i] = read4(ptr); - for (i = 0; i < nd; i++) - depth[i] = read4(ptr); - for (i = 0; i < ni; i++) - italic[i] = read4(ptr); - for (i = 0; i < nl; i++) { - lig_kern[i].skip_byte = *ptr++; - lig_kern[i].next_char = *ptr++; - lig_kern[i].op_byte = *ptr++; - lig_kern[i].remainder = *ptr++; - } - for (i = 0; i < nk; i++) - kern[i] = read4(ptr); - ptr += ne*4; - for (i = 0; i < np; i++) - param[i] = read4(ptr); - assert(ptr == buf + lf*4 - 2); - a_delete buf; - return 1; -} - -class gf { - int left[256]; - int right[256]; - static int sread4(int *p, FILE *fp); - static int uread3(int *p, FILE *fp); - static int uread2(int *p, FILE *fp); - static int skip(int n, FILE *fp); -public: - gf(); - int load(const char *file); - int get_left_adjustment(int i) { return left[i]; } - int get_right_adjustment(int i) { return right[i]; } -}; - -gf::gf() -{ - for (int i = 0; i < 256; i++) - left[i] = right[i] = 0; -} - -int gf::load(const char *file) -{ - enum { - paint_0 = 0, - paint1 = 64, - boc = 67, - boc1 = 68, - eoc = 69, - skip0 = 70, - skip1 = 71, - new_row_0 = 74, - xxx1 = 239, - yyy = 243, - no_op = 244, - pre = 247, - post = 248 - }; - int got_an_adjustment = 0; - int pending_adjustment = 0; - int left_adj, right_adj; - const int gf_id_byte = 131; - errno = 0; - FILE *fp = fopen(file, FOPEN_RB); - if (!fp) { - error("can't open `%1': %2", file, strerror(errno)); - return 0; - } - if (getc(fp) != pre || getc(fp) != gf_id_byte) { - error("bad gf file"); - return 0; - } - int n = getc(fp); - if (n == EOF) - goto eof; - if (!skip(n, fp)) - goto eof; - for (;;) { - int op = getc(fp); - if (op == EOF) - goto eof; - if (op == post) - break; - if ((op >= paint_0 && op <= paint_0 + 63) - || (op >= new_row_0 && op <= new_row_0 + 164)) - continue; - switch (op) { - case no_op: - case eoc: - case skip0: - break; - case paint1: - case skip1: - if (!skip(1, fp)) - goto eof; - break; - case paint1 + 1: - case skip1 + 1: - if (!skip(2, fp)) - goto eof; - break; - case paint1 + 2: - case skip1 + 2: - if (!skip(3, fp)) - goto eof; - break; - case boc: - { - int code; - if (!sread4(&code, fp)) - goto eof; - if (pending_adjustment) { - pending_adjustment = 0; - left[code & 0377] = left_adj; - right[code & 0377] = right_adj; - } - if (!skip(20, fp)) - goto eof; - break; - } - case boc1: - { - int code = getc(fp); - if (code == EOF) - goto eof; - if (pending_adjustment) { - pending_adjustment = 0; - left[code] = left_adj; - right[code] = right_adj; - } - if (!skip(4, fp)) - goto eof; - break; - } - case xxx1: - { - int len = getc(fp); - if (len == EOF) - goto eof; - char buf[256]; - if (fread(buf, 1, len, fp) != (size_t)len) - goto eof; - if (len == 10 /* strlen("adjustment") */ - && memcmp(buf, "adjustment", len) == 0) { - int c = getc(fp); - if (c != yyy) { - if (c != EOF) - ungetc(c, fp); - break; - } - if (!sread4(&left_adj, fp)) - goto eof; - c = getc(fp); - if (c != yyy) { - if (c != EOF) - ungetc(c, fp); - break; - } - if (!sread4(&right_adj, fp)) - goto eof; - got_an_adjustment = 1; - pending_adjustment = 1; - } - break; - } - case xxx1 + 1: - if (!uread2(&n, fp) || !skip(n, fp)) - goto eof; - break; - case xxx1 + 2: - if (!uread3(&n, fp) || !skip(n, fp)) - goto eof; - break; - case xxx1 + 3: - if (!sread4(&n, fp) || !skip(n, fp)) - goto eof; - break; - case yyy: - if (!skip(4, fp)) - goto eof; - break; - default: - fatal("unrecognized opcode `%1'", op); - break; - } - } - if (!got_an_adjustment) - warning("no adjustment specials found in gf file"); - return 1; - eof: - error("unexpected end of file"); - return 0; -} - -int gf::sread4(int *p, FILE *fp) -{ - *p = getc(fp); - if (*p >= 128) - *p -= 256; - *p <<= 8; - *p |= getc(fp); - *p <<= 8; - *p |= getc(fp); - *p <<= 8; - *p |= getc(fp); - return !ferror(fp) && !feof(fp); -} - -int gf::uread3(int *p, FILE *fp) -{ - *p = getc(fp); - *p <<= 8; - *p |= getc(fp); - *p <<= 8; - *p |= getc(fp); - return !ferror(fp) && !feof(fp); -} - -int gf::uread2(int *p, FILE *fp) -{ - *p = getc(fp); - *p <<= 8; - *p |= getc(fp); - return !ferror(fp) && !feof(fp); -} - -int gf::skip(int n, FILE *fp) -{ - while (--n >= 0) - if (getc(fp) == EOF) - return 0; - return 1; -} - - -struct char_list { - char *ch; - char_list *next; - char_list(const char *, char_list * = 0); -}; - -char_list::char_list(const char *s, char_list *p) : ch(strsave(s)), next(p) -{ -} - - -int read_map(const char *file, char_list **table) -{ - errno = 0; - FILE *fp = fopen(file, "r"); - if (!fp) { - error("can't open `%1': %2", file, strerror(errno)); - return 0; - } - for (int i = 0; i < 256; i++) - table[i] = 0; - char buf[512]; - int lineno = 0; - while (fgets(buf, int(sizeof(buf)), fp)) { - lineno++; - char *ptr = buf; - while (csspace(*ptr)) - ptr++; - if (*ptr == '\0' || *ptr == '#') - continue; - ptr = strtok(ptr, " \n\t"); - if (!ptr) - continue; - int n; - if (sscanf(ptr, "%d", &n) != 1) { - error("%1:%2: bad map file", file, lineno); - fclose(fp); - return 0; - } - if (n < 0 || n > 255) { - error("%1:%2: code out of range", file, lineno); - fclose(fp); - return 0; - } - ptr = strtok(0, " \n\t"); - if (!ptr) { - error("%1:%2: missing names", file, lineno); - fclose(fp); - return 0; - } - for (; ptr; ptr = strtok(0, " \n\t")) - table[n] = new char_list(ptr, table[n]); - } - fclose(fp); - return 1; -} - - -/* Every character that can participate in a ligature appears in the -lig_chars table. `ch' gives the full-name of the character, `name' -gives the groff name of the character, `i' gives its index in -the encoding, which is filled in later (-1 if it does not appear). */ - -struct { - const char *ch; - int i; -} lig_chars[] = { - { "f", -1 }, - { "i", -1 }, - { "l", -1 }, - { "ff", -1 }, - { "fi", -1 }, - { "fl", -1 }, - { "Fi", -1 }, - { "Fl", -1 }, -}; - -// Indices into lig_chars[]. - -enum { CH_f, CH_i, CH_l, CH_ff, CH_fi, CH_fl, CH_ffi, CH_ffl }; - -// Each possible ligature appears in this table. - -struct { - unsigned char c1, c2, res; - const char *ch; -} lig_table[] = { - { CH_f, CH_f, CH_ff, "ff" }, - { CH_f, CH_i, CH_fi, "fi" }, - { CH_f, CH_l, CH_fl, "fl" }, - { CH_ff, CH_i, CH_ffi, "ffi" }, - { CH_ff, CH_l, CH_ffl, "ffl" }, - }; - -static void usage(FILE *stream); - -int main(int argc, char **argv) -{ - program_name = argv[0]; - int special_flag = 0; - int skewchar = -1; - int opt; - const char *gf_file = 0; - static const struct option long_options[] = { - { "help", no_argument, 0, CHAR_MAX + 1 }, - { "version", no_argument, 0, 'v' }, - { NULL, 0, 0, 0 } - }; - while ((opt = getopt_long(argc, argv, "svg:k:", long_options, NULL)) != EOF) - switch (opt) { - case 'g': - gf_file = optarg; - break; - case 's': - special_flag = 1; - break; - case 'k': - { - char *ptr; - long n = strtol(optarg, &ptr, 0); - if ((n == 0 && ptr == optarg) - || *ptr != '\0' - || n < 0 - || n > UCHAR_MAX) - error("invalid skewchar"); - else - skewchar = (int)n; - break; - } - case 'v': - { - printf("GNU tfmtodit (groff) version %s\n", Version_string); - exit(0); - break; - } - case CHAR_MAX + 1: // --help - usage(stdout); - exit(0); - break; - case '?': - usage(stderr); - exit(1); - break; - case EOF: - assert(0); - } - if (argc - optind != 3) { - usage(stderr); - exit(1); - } - gf g; - if (gf_file) { - if (!g.load(gf_file)) - return 1; - } - const char *tfm_file = argv[optind]; - const char *map_file = argv[optind + 1]; - const char *font_file = argv[optind + 2]; - tfm t; - if (!t.load(tfm_file)) - return 1; - char_list *table[256]; - if (!read_map(map_file, table)) - return 1; - errno = 0; - if (!freopen(font_file, "w", stdout)) { - error("can't open `%1' for writing: %2", font_file, strerror(errno)); - return 1; - } - printf("name %s\n", font_file); - if (special_flag) - fputs("special\n", stdout); - char *internal_name = strsave(argv[optind]); - int len = strlen(internal_name); - if (len > 4 && strcmp(internal_name + len - 4, ".tfm") == 0) - internal_name[len - 4] = '\0'; - // DIR_SEPS[] are possible directory separator characters, see nonposix.h. - // We want the rightmost separator of all possible ones. - // Example: d:/foo\\bar. - const char *s = strrchr(internal_name, DIR_SEPS[0]), *s1; - const char *sep = &DIR_SEPS[1]; - while (*sep) - { - s1 = strrchr(internal_name, *sep); - if (s1 && (!s || s1 > s)) - s = s1; - sep++; - } - printf("internalname %s\n", s ? s + 1 : internal_name); - int n; - if (t.get_param(2, &n)) { - if (n > 0) - printf("spacewidth %d\n", n*MULTIPLIER); - } - if (t.get_param(1, &n) && n != 0) - printf("slant %f\n", atan2(n/double(1<<20), 1.0)*180.0/PI); - int xheight; - if (!t.get_param(5, &xheight)) - xheight = 0; - unsigned int i; - // Print the list of ligatures. - // First find the indices of each character that can participate in - // a ligature. - for (i = 0; i < 256; i++) - for (unsigned int j = 0; j < sizeof(lig_chars)/sizeof(lig_chars[0]); j++) - for (char_list *p = table[i]; p; p = p->next) - if (strcmp(lig_chars[j].ch, p->ch) == 0) - lig_chars[j].i = i; - // For each possible ligature, if its participants all exist, - // and it appears as a ligature in the tfm file, include in - // the list of ligatures. - int started = 0; - for (i = 0; i < sizeof(lig_table)/sizeof(lig_table[0]); i++) { - int i1 = lig_chars[lig_table[i].c1].i; - int i2 = lig_chars[lig_table[i].c2].i; - int r = lig_chars[lig_table[i].res].i; - if (i1 >= 0 && i2 >= 0 && r >= 0) { - unsigned char c; - if (t.get_lig(i1, i2, &c) && c == r) { - if (!started) { - started = 1; - fputs("ligatures", stdout); - } - printf(" %s", lig_table[i].ch); - } - } - } - if (started) - fputs(" 0\n", stdout); - printf("checksum %d\n", t.get_checksum()); - printf("designsize %d\n", t.get_design_size()); - // Now print out the kerning information. - int had_kern = 0; - kern_iterator iter(&t); - unsigned char c1, c2; - int k; - while (iter.next(&c1, &c2, &k)) - if (c2 != skewchar) { - k *= MULTIPLIER; - char_list *q = table[c2]; - for (char_list *p1 = table[c1]; p1; p1 = p1->next) - for (char_list *p2 = q; p2; p2 = p2->next) { - if (!had_kern) { - printf("kernpairs\n"); - had_kern = 1; - } - printf("%s %s %d\n", p1->ch, p2->ch, k); - } - } - printf("charset\n"); - char_list unnamed("---"); - for (i = 0; i < 256; i++) - if (t.contains(i)) { - char_list *p = table[i] ? table[i] : &unnamed; - int m[6]; - m[0] = t.get_width(i); - m[1] = t.get_height(i); - m[2] = t.get_depth(i); - m[3] = t.get_italic(i); - m[4] = g.get_left_adjustment(i); - m[5] = g.get_right_adjustment(i); - printf("%s\t%d", p->ch, m[0]*MULTIPLIER); - int j; - for (j = int(sizeof(m)/sizeof(m[0])) - 1; j > 0; j--) - if (m[j] != 0) - break; - for (k = 1; k <= j; k++) - printf(",%d", m[k]*MULTIPLIER); - int type = 0; - if (m[2] > 0) - type = 1; - if (m[1] > xheight) - type += 2; - printf("\t%d\t%04o\n", type, i); - for (p = p->next; p; p = p->next) - printf("%s\t\"\n", p->ch); - } - return 0; -} - -static void usage(FILE *stream) -{ - fprintf(stream, "usage: %s [-sv] [-g gf_file] [-k skewchar] tfm_file map_file font\n", - program_name); -} diff --git a/contrib/groff/win32-diffs b/contrib/groff/win32-diffs deleted file mode 100644 index d68b497..0000000 --- a/contrib/groff/win32-diffs +++ /dev/null @@ -1,2708 +0,0 @@ -diff -aruN groff-1.18/Makefile.msc groff-1.18.win32/Makefile.msc ---- groff-1.18/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,36 @@ -+ -+ -+MAKECMD = $(MAKE) -nologo -f makefile.msc -+ -+ -+all: -+ cd src\libs\libdriver -+ $(MAKECMD) -+ cd ..\libgroff -+ $(MAKECMD) -+ cd ..\..\roff\troff -+ $(MAKECMD) -+ cd ..\..\preproc\eqn -+ $(MAKECMD) -+ cd ..\pic -+ $(MAKECMD) -+ cd ..\tbl -+ $(MAKECMD) -+ cd ..\..\devices\grolj4 -+ $(MAKECMD) -+ cd ..\grotty -+ $(MAKECMD) -+ cd ..\grops -+ $(MAKECMD) -+ cd ..\grodvi -+ $(MAKECMD) -+ cd ..\..\.. -+ -del bin\*.orig -+ copy src\devices\grodvi\grodvi.exe bin -+ copy src\devices\grolj4\grolj4.exe bin -+ copy src\devices\grops\grops.exe bin -+ copy src\devices\grotty\grotty.exe bin -+ copy src\preproc\eqn\eqn.exe bin -+ copy src\preproc\pic\pic.exe bin -+ copy src\preproc\tbl\tbl.exe bin -+ copy src\roff\troff\troff.exe bin -diff -aruN groff-1.18/bin/gs.cmd groff-1.18.win32/bin/gs.cmd ---- groff-1.18/bin/gs.cmd Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/bin/gs.cmd Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,2 @@ -+@echo off -+gswin32c -sDEVICE=ljet3 -sOutputFile=%1.jep -q -dNOPAUSE %1.ps 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+mu " -+tmu " -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -diff -aruN groff-1.18/font/devascii/BI groff-1.18.win32/font/devascii/BI ---- groff-1.18/font/devascii/BI Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devascii/BI Fri Jul 5 16:06:31 2002 -@@ -0,0 +1,168 @@ -+name BI -+internalname 3 -+spacewidth 24 -+charset -+! 24 0 0041 -+" 24 0 0042 -+dq " -+lq " -+rq " -+# 24 0 0043 -+sh " -+$ 24 0 0044 -+Do " -+% 24 0 0045 -+& 24 0 0046 -+' 24 0 0047 -+aa " -+fm " -+aq " -+cq " -+( 24 0 0050 -+) 24 0 0051 -+* 24 0 0052 -+** " -++ 24 0 0053 -+pl " -+, 24 0 0054 -+\- 24 0 0055 -+hy " -+- " -+mi " -+en " -+. 24 0 0056 -+/ 24 0 0057 -+sl " -+f/ " -+0 24 0 0060 -+1 24 0 0061 -+2 24 0 0062 -+3 24 0 0063 -+4 24 0 0064 -+5 24 0 0065 -+6 24 0 0066 -+7 24 0 0067 -+8 24 0 0070 -+9 24 0 0071 -+: 24 0 0072 -+; 24 0 0073 -+< 24 0 0074 -+la " -+fo " -+= 24 0 0075 -+eq " -+> 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+mu " -+tmu " -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -diff -aruN groff-1.18/font/devascii/DESC groff-1.18.win32/font/devascii/DESC ---- groff-1.18/font/devascii/DESC Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devascii/DESC Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,8 @@ -+res 240 -+hor 24 -+vert 40 -+unitwidth 10 -+sizes 10 0 -+fonts 4 R I B BI -+tcommand -+postpro grotty -diff -aruN groff-1.18/font/devascii/I groff-1.18.win32/font/devascii/I ---- groff-1.18/font/devascii/I Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devascii/I Fri Jul 5 16:06:31 2002 -@@ -0,0 +1,168 @@ -+name I -+internalname 1 -+spacewidth 24 -+charset -+! 24 0 0041 -+" 24 0 0042 -+dq " -+lq " -+rq " -+# 24 0 0043 -+sh " -+$ 24 0 0044 -+Do " -+% 24 0 0045 -+& 24 0 0046 -+' 24 0 0047 -+aa " -+fm " -+aq " -+cq " -+( 24 0 0050 -+) 24 0 0051 -+* 24 0 0052 -+** " -++ 24 0 0053 -+pl " -+, 24 0 0054 -+\- 24 0 0055 -+hy " -+- " -+mi " -+en " -+. 24 0 0056 -+/ 24 0 0057 -+sl " -+f/ " -+0 24 0 0060 -+1 24 0 0061 -+2 24 0 0062 -+3 24 0 0063 -+4 24 0 0064 -+5 24 0 0065 -+6 24 0 0066 -+7 24 0 0067 -+8 24 0 0070 -+9 24 0 0071 -+: 24 0 0072 -+; 24 0 0073 -+< 24 0 0074 -+la " -+fo " -+= 24 0 0075 -+eq " -+> 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+mu " -+tmu " -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -diff -aruN groff-1.18/font/devascii/R groff-1.18.win32/font/devascii/R ---- groff-1.18/font/devascii/R Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devascii/R Fri Jul 5 16:06:31 2002 -@@ -0,0 +1,167 @@ -+name R -+spacewidth 24 -+charset -+! 24 0 0041 -+" 24 0 0042 -+dq " -+lq " -+rq " -+# 24 0 0043 -+sh " -+$ 24 0 0044 -+Do " -+% 24 0 0045 -+& 24 0 0046 -+' 24 0 0047 -+aa " -+fm " -+aq " -+cq " -+( 24 0 0050 -+) 24 0 0051 -+* 24 0 0052 -+** " -++ 24 0 0053 -+pl " -+, 24 0 0054 -+\- 24 0 0055 -+hy " -+- " -+mi " -+en " -+. 24 0 0056 -+/ 24 0 0057 -+sl " -+f/ " -+0 24 0 0060 -+1 24 0 0061 -+2 24 0 0062 -+3 24 0 0063 -+4 24 0 0064 -+5 24 0 0065 -+6 24 0 0066 -+7 24 0 0067 -+8 24 0 0070 -+9 24 0 0071 -+: 24 0 0072 -+; 24 0 0073 -+< 24 0 0074 -+la " -+fo " -+= 24 0 0075 -+eq " -+> 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+mu " -+tmu " -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -diff -aruN groff-1.18/font/devdvi/DESC groff-1.18.win32/font/devdvi/DESC ---- groff-1.18/font/devdvi/DESC Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devdvi/DESC Mon Jul 8 08:42:17 2002 -@@ -0,0 +1,11 @@ -+sizescale 100 -+unitwidth 131072 -+res 57816 -+hor 1 -+vert 1 -+sizes 500-1000000 0 -+styles R I B BI -+family T -+fonts 13 0 0 0 0 0 0 0 0 0 MI S EX CW -+tcommand -+postpro grodvi -diff -aruN groff-1.18/font/devlatin1/B groff-1.18.win32/font/devlatin1/B ---- groff-1.18/font/devlatin1/B Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devlatin1/B Fri Jul 5 16:06:31 2002 -@@ -0,0 +1,266 @@ -+name B -+internalname 2 -+spacewidth 24 -+charset -+! 24 0 0041 -+" 24 0 0042 -+dq " -+lq " -+rq " -+# 24 0 0043 -+sh " -+$ 24 0 0044 -+Do " -+% 24 0 0045 -+& 24 0 0046 -+' 24 0 0047 -+fm " -+aq " -+cq " -+( 24 0 0050 -+) 24 0 0051 -+* 24 0 0052 -+** " -++ 24 0 0053 -+pl " -+, 24 0 0054 -+\- 24 0 0055 -+mi " -+- " -+hy " -+en " -+. 24 0 0056 -+/ 24 0 0057 -+sl " -+f/ " -+0 24 0 0060 -+1 24 0 0061 -+2 24 0 0062 -+3 24 0 0063 -+4 24 0 0064 -+5 24 0 0065 -+6 24 0 0066 -+7 24 0 0067 -+8 24 0 0070 -+9 24 0 0071 -+: 24 0 0072 -+; 24 0 0073 -+< 24 0 0074 -+la " -+fo " -+= 24 0 0075 -+eq " -+> 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -+r! 24 0 0241 -+ct 24 0 0242 -+Po 24 0 0243 -+Cs 24 0 0244 -+Ye 24 0 0245 -+bb 24 0 0246 -+sc 24 0 0247 -+ad 24 0 0250 -+co 24 0 0251 -+Of 24 0 0252 -+Fo 24 0 0253 -+no 24 0 0254 -+shc 24 0 0255 -+rg 24 0 0256 -+a- 24 0 0257 -+de 24 0 0260 -+ao " -++- 24 0 0261 -+t+- " -+S2 24 0 0262 -+S3 24 0 0263 -+aa 24 0 0264 -+*m 24 0 0265 -+mc " -+ps 24 0 0266 -+pc 24 0 0267 -+md " -+ac 24 0 0270 -+S1 24 0 0271 -+Om 24 0 0272 -+Fc 24 0 0273 -+14 24 0 0274 -+12 24 0 0275 -+34 24 0 0276 -+r? 24 0 0277 -+`A 24 0 0300 -+'A 24 0 0301 -+^A 24 0 0302 -+~A 24 0 0303 -+:A 24 0 0304 -+oA 24 0 0305 -+AE 24 0 0306 -+,C 24 0 0307 -+`E 24 0 0310 -+'E 24 0 0311 -+^E 24 0 0312 -+:E 24 0 0313 -+`I 24 0 0314 -+'I 24 0 0315 -+^I 24 0 0316 -+:I 24 0 0317 -+-D 24 0 0320 -+~N 24 0 0321 -+`O 24 0 0322 -+'O 24 0 0323 -+^O 24 0 0324 -+~O 24 0 0325 -+:O 24 0 0326 -+mu 24 0 0327 -+tmu " -+/O 24 0 0330 -+`U 24 0 0331 -+'U 24 0 0332 -+^U 24 0 0333 -+:U 24 0 0334 -+'Y 24 0 0335 -+TP 24 0 0336 -+ss 24 0 0337 -+`a 24 0 0340 -+'a 24 0 0341 -+^a 24 0 0342 -+~a 24 0 0343 -+:a 24 0 0344 -+oa 24 0 0345 -+ae 24 0 0346 -+,c 24 0 0347 -+`e 24 0 0350 -+'e 24 0 0351 -+^e 24 0 0352 -+:e 24 0 0353 -+`i 24 0 0354 -+'i 24 0 0355 -+^i 24 0 0356 -+:i 24 0 0357 -+Sd 24 0 0360 -+~n 24 0 0361 -+`o 24 0 0362 -+'o 24 0 0363 -+^o 24 0 0364 -+~o 24 0 0365 -+:o 24 0 0366 -+di 24 0 0367 -+tdi " -+/o 24 0 0370 -+`u 24 0 0371 -+'u 24 0 0372 -+^u 24 0 0373 -+:u 24 0 0374 -+'y 24 0 0375 -+Tp 24 0 0376 -+:y 24 0 0377 -diff -aruN groff-1.18/font/devlatin1/BI groff-1.18.win32/font/devlatin1/BI ---- groff-1.18/font/devlatin1/BI Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devlatin1/BI Fri Jul 5 16:06:31 2002 -@@ -0,0 +1,266 @@ -+name BI -+internalname 3 -+spacewidth 24 -+charset -+! 24 0 0041 -+" 24 0 0042 -+dq " -+lq " -+rq " -+# 24 0 0043 -+sh " -+$ 24 0 0044 -+Do " -+% 24 0 0045 -+& 24 0 0046 -+' 24 0 0047 -+fm " -+aq " -+cq " -+( 24 0 0050 -+) 24 0 0051 -+* 24 0 0052 -+** " -++ 24 0 0053 -+pl " -+, 24 0 0054 -+\- 24 0 0055 -+mi " -+- " -+hy " -+en " -+. 24 0 0056 -+/ 24 0 0057 -+sl " -+f/ " -+0 24 0 0060 -+1 24 0 0061 -+2 24 0 0062 -+3 24 0 0063 -+4 24 0 0064 -+5 24 0 0065 -+6 24 0 0066 -+7 24 0 0067 -+8 24 0 0070 -+9 24 0 0071 -+: 24 0 0072 -+; 24 0 0073 -+< 24 0 0074 -+la " -+fo " -+= 24 0 0075 -+eq " -+> 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -+r! 24 0 0241 -+ct 24 0 0242 -+Po 24 0 0243 -+Cs 24 0 0244 -+Ye 24 0 0245 -+bb 24 0 0246 -+sc 24 0 0247 -+ad 24 0 0250 -+co 24 0 0251 -+Of 24 0 0252 -+Fo 24 0 0253 -+no 24 0 0254 -+shc 24 0 0255 -+rg 24 0 0256 -+a- 24 0 0257 -+de 24 0 0260 -+ao " -++- 24 0 0261 -+t+- " -+S2 24 0 0262 -+S3 24 0 0263 -+aa 24 0 0264 -+*m 24 0 0265 -+mc " -+ps 24 0 0266 -+pc 24 0 0267 -+md " -+ac 24 0 0270 -+S1 24 0 0271 -+Om 24 0 0272 -+Fc 24 0 0273 -+14 24 0 0274 -+12 24 0 0275 -+34 24 0 0276 -+r? 24 0 0277 -+`A 24 0 0300 -+'A 24 0 0301 -+^A 24 0 0302 -+~A 24 0 0303 -+:A 24 0 0304 -+oA 24 0 0305 -+AE 24 0 0306 -+,C 24 0 0307 -+`E 24 0 0310 -+'E 24 0 0311 -+^E 24 0 0312 -+:E 24 0 0313 -+`I 24 0 0314 -+'I 24 0 0315 -+^I 24 0 0316 -+:I 24 0 0317 -+-D 24 0 0320 -+~N 24 0 0321 -+`O 24 0 0322 -+'O 24 0 0323 -+^O 24 0 0324 -+~O 24 0 0325 -+:O 24 0 0326 -+mu 24 0 0327 -+tmu " -+/O 24 0 0330 -+`U 24 0 0331 -+'U 24 0 0332 -+^U 24 0 0333 -+:U 24 0 0334 -+'Y 24 0 0335 -+TP 24 0 0336 -+ss 24 0 0337 -+`a 24 0 0340 -+'a 24 0 0341 -+^a 24 0 0342 -+~a 24 0 0343 -+:a 24 0 0344 -+oa 24 0 0345 -+ae 24 0 0346 -+,c 24 0 0347 -+`e 24 0 0350 -+'e 24 0 0351 -+^e 24 0 0352 -+:e 24 0 0353 -+`i 24 0 0354 -+'i 24 0 0355 -+^i 24 0 0356 -+:i 24 0 0357 -+Sd 24 0 0360 -+~n 24 0 0361 -+`o 24 0 0362 -+'o 24 0 0363 -+^o 24 0 0364 -+~o 24 0 0365 -+:o 24 0 0366 -+di 24 0 0367 -+tdi " -+/o 24 0 0370 -+`u 24 0 0371 -+'u 24 0 0372 -+^u 24 0 0373 -+:u 24 0 0374 -+'y 24 0 0375 -+Tp 24 0 0376 -+:y 24 0 0377 -diff -aruN groff-1.18/font/devlatin1/DESC groff-1.18.win32/font/devlatin1/DESC ---- groff-1.18/font/devlatin1/DESC Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devlatin1/DESC Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,8 @@ -+res 240 -+hor 24 -+vert 40 -+unitwidth 10 -+sizes 10 0 -+fonts 4 R I B BI -+tcommand -+postpro grotty -diff -aruN groff-1.18/font/devlatin1/I groff-1.18.win32/font/devlatin1/I ---- groff-1.18/font/devlatin1/I Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devlatin1/I Fri Jul 5 16:06:31 2002 -@@ -0,0 +1,266 @@ -+name I -+internalname 1 -+spacewidth 24 -+charset -+! 24 0 0041 -+" 24 0 0042 -+dq " -+lq " -+rq " -+# 24 0 0043 -+sh " -+$ 24 0 0044 -+Do " -+% 24 0 0045 -+& 24 0 0046 -+' 24 0 0047 -+fm " -+aq " -+cq " -+( 24 0 0050 -+) 24 0 0051 -+* 24 0 0052 -+** " -++ 24 0 0053 -+pl " -+, 24 0 0054 -+\- 24 0 0055 -+mi " -+- " -+hy " -+en " -+. 24 0 0056 -+/ 24 0 0057 -+sl " -+f/ " -+0 24 0 0060 -+1 24 0 0061 -+2 24 0 0062 -+3 24 0 0063 -+4 24 0 0064 -+5 24 0 0065 -+6 24 0 0066 -+7 24 0 0067 -+8 24 0 0070 -+9 24 0 0071 -+: 24 0 0072 -+; 24 0 0073 -+< 24 0 0074 -+la " -+fo " -+= 24 0 0075 -+eq " -+> 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -+r! 24 0 0241 -+ct 24 0 0242 -+Po 24 0 0243 -+Cs 24 0 0244 -+Ye 24 0 0245 -+bb 24 0 0246 -+sc 24 0 0247 -+ad 24 0 0250 -+co 24 0 0251 -+Of 24 0 0252 -+Fo 24 0 0253 -+no 24 0 0254 -+shc 24 0 0255 -+rg 24 0 0256 -+a- 24 0 0257 -+de 24 0 0260 -+ao " -++- 24 0 0261 -+t+- " -+S2 24 0 0262 -+S3 24 0 0263 -+aa 24 0 0264 -+*m 24 0 0265 -+mc " -+ps 24 0 0266 -+pc 24 0 0267 -+md " -+ac 24 0 0270 -+S1 24 0 0271 -+Om 24 0 0272 -+Fc 24 0 0273 -+14 24 0 0274 -+12 24 0 0275 -+34 24 0 0276 -+r? 24 0 0277 -+`A 24 0 0300 -+'A 24 0 0301 -+^A 24 0 0302 -+~A 24 0 0303 -+:A 24 0 0304 -+oA 24 0 0305 -+AE 24 0 0306 -+,C 24 0 0307 -+`E 24 0 0310 -+'E 24 0 0311 -+^E 24 0 0312 -+:E 24 0 0313 -+`I 24 0 0314 -+'I 24 0 0315 -+^I 24 0 0316 -+:I 24 0 0317 -+-D 24 0 0320 -+~N 24 0 0321 -+`O 24 0 0322 -+'O 24 0 0323 -+^O 24 0 0324 -+~O 24 0 0325 -+:O 24 0 0326 -+mu 24 0 0327 -+tmu " -+/O 24 0 0330 -+`U 24 0 0331 -+'U 24 0 0332 -+^U 24 0 0333 -+:U 24 0 0334 -+'Y 24 0 0335 -+TP 24 0 0336 -+ss 24 0 0337 -+`a 24 0 0340 -+'a 24 0 0341 -+^a 24 0 0342 -+~a 24 0 0343 -+:a 24 0 0344 -+oa 24 0 0345 -+ae 24 0 0346 -+,c 24 0 0347 -+`e 24 0 0350 -+'e 24 0 0351 -+^e 24 0 0352 -+:e 24 0 0353 -+`i 24 0 0354 -+'i 24 0 0355 -+^i 24 0 0356 -+:i 24 0 0357 -+Sd 24 0 0360 -+~n 24 0 0361 -+`o 24 0 0362 -+'o 24 0 0363 -+^o 24 0 0364 -+~o 24 0 0365 -+:o 24 0 0366 -+di 24 0 0367 -+tdi " -+/o 24 0 0370 -+`u 24 0 0371 -+'u 24 0 0372 -+^u 24 0 0373 -+:u 24 0 0374 -+'y 24 0 0375 -+Tp 24 0 0376 -+:y 24 0 0377 -diff -aruN groff-1.18/font/devlatin1/R groff-1.18.win32/font/devlatin1/R ---- groff-1.18/font/devlatin1/R Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devlatin1/R Fri Jul 5 16:06:31 2002 -@@ -0,0 +1,265 @@ -+name R -+spacewidth 24 -+charset -+! 24 0 0041 -+" 24 0 0042 -+dq " -+lq " -+rq " -+# 24 0 0043 -+sh " -+$ 24 0 0044 -+Do " -+% 24 0 0045 -+& 24 0 0046 -+' 24 0 0047 -+fm " -+aq " -+cq " -+( 24 0 0050 -+) 24 0 0051 -+* 24 0 0052 -+** " -++ 24 0 0053 -+pl " -+, 24 0 0054 -+\- 24 0 0055 -+mi " -+- " -+hy " -+en " -+. 24 0 0056 -+/ 24 0 0057 -+sl " -+f/ " -+0 24 0 0060 -+1 24 0 0061 -+2 24 0 0062 -+3 24 0 0063 -+4 24 0 0064 -+5 24 0 0065 -+6 24 0 0066 -+7 24 0 0067 -+8 24 0 0070 -+9 24 0 0071 -+: 24 0 0072 -+; 24 0 0073 -+< 24 0 0074 -+la " -+fo " -+= 24 0 0075 -+eq " -+> 24 0 0076 -+ra " -+fc " -+? 24 0 0077 -+@ 24 0 0100 -+at " -+A 24 0 0101 -+*A " -+B 24 0 0102 -+*B " -+C 24 0 0103 -+D 24 0 0104 -+E 24 0 0105 -+*E " -+F 24 0 0106 -+G 24 0 0107 -+H 24 0 0110 -+*Y " -+I 24 0 0111 -+*I " -+J 24 0 0112 -+K 24 0 0113 -+*K " -+L 24 0 0114 -+M 24 0 0115 -+*M " -+N 24 0 0116 -+*N " -+O 24 0 0117 -+ci " -+*O " -+P 24 0 0120 -+*R " -+Q 24 0 0121 -+R 24 0 0122 -+S 24 0 0123 -+T 24 0 0124 -+*T " -+U 24 0 0125 -+V 24 0 0126 -+W 24 0 0127 -+X 24 0 0130 -+*X " -+Y 24 0 0131 -+*U " -+Z 24 0 0132 -+*Z " -+[ 24 0 0133 -+lB " -+\ 24 0 0134 -+rs " -+] 24 0 0135 -+rB " -+a^ 24 0 0136 -+^ " -+ha " -+_ 24 0 0137 -+ru " -+ul " -+` 24 0 0140 -+oq " -+ga " -+a 24 0 0141 -+b 24 0 0142 -+c 24 0 0143 -+d 24 0 0144 -+e 24 0 0145 -+f 24 0 0146 -+g 24 0 0147 -+h 24 0 0150 -+i 24 0 0151 -+.i " -+j 24 0 0152 -+k 24 0 0153 -+l 24 0 0154 -+m 24 0 0155 -+n 24 0 0156 -+o 24 0 0157 -+*o " -+p 24 0 0160 -+q 24 0 0161 -+r 24 0 0162 -+s 24 0 0163 -+t 24 0 0164 -+u 24 0 0165 -+v 24 0 0166 -+w 24 0 0167 -+x 24 0 0170 -+y 24 0 0171 -+z 24 0 0172 -+lC 24 0 0173 -+{ " -+ba 24 0 0174 -+or " -+bv " -+br " -+| " -+lb " -+lc " -+lf " -+lk " -+lt " -+rb " -+rc " -+rf " -+rk " -+rt " -+rC 24 0 0175 -+} " -+a~ 24 0 0176 -+~ " -+ap " -+ti " -+r! 24 0 0241 -+ct 24 0 0242 -+Po 24 0 0243 -+Cs 24 0 0244 -+Ye 24 0 0245 -+bb 24 0 0246 -+sc 24 0 0247 -+ad 24 0 0250 -+co 24 0 0251 -+Of 24 0 0252 -+Fo 24 0 0253 -+no 24 0 0254 -+shc 24 0 0255 -+rg 24 0 0256 -+a- 24 0 0257 -+de 24 0 0260 -+ao " -++- 24 0 0261 -+t+- " -+S2 24 0 0262 -+S3 24 0 0263 -+aa 24 0 0264 -+*m 24 0 0265 -+mc " -+ps 24 0 0266 -+pc 24 0 0267 -+md " -+ac 24 0 0270 -+S1 24 0 0271 -+Om 24 0 0272 -+Fc 24 0 0273 -+14 24 0 0274 -+12 24 0 0275 -+34 24 0 0276 -+r? 24 0 0277 -+`A 24 0 0300 -+'A 24 0 0301 -+^A 24 0 0302 -+~A 24 0 0303 -+:A 24 0 0304 -+oA 24 0 0305 -+AE 24 0 0306 -+,C 24 0 0307 -+`E 24 0 0310 -+'E 24 0 0311 -+^E 24 0 0312 -+:E 24 0 0313 -+`I 24 0 0314 -+'I 24 0 0315 -+^I 24 0 0316 -+:I 24 0 0317 -+-D 24 0 0320 -+~N 24 0 0321 -+`O 24 0 0322 -+'O 24 0 0323 -+^O 24 0 0324 -+~O 24 0 0325 -+:O 24 0 0326 -+mu 24 0 0327 -+tmu " -+/O 24 0 0330 -+`U 24 0 0331 -+'U 24 0 0332 -+^U 24 0 0333 -+:U 24 0 0334 -+'Y 24 0 0335 -+TP 24 0 0336 -+ss 24 0 0337 -+`a 24 0 0340 -+'a 24 0 0341 -+^a 24 0 0342 -+~a 24 0 0343 -+:a 24 0 0344 -+oa 24 0 0345 -+ae 24 0 0346 -+,c 24 0 0347 -+`e 24 0 0350 -+'e 24 0 0351 -+^e 24 0 0352 -+:e 24 0 0353 -+`i 24 0 0354 -+'i 24 0 0355 -+^i 24 0 0356 -+:i 24 0 0357 -+Sd 24 0 0360 -+~n 24 0 0361 -+`o 24 0 0362 -+'o 24 0 0363 -+^o 24 0 0364 -+~o 24 0 0365 -+:o 24 0 0366 -+di 24 0 0367 -+tdi " -+/o 24 0 0370 -+`u 24 0 0371 -+'u 24 0 0372 -+^u 24 0 0373 -+:u 24 0 0374 -+'y 24 0 0375 -+Tp 24 0 0376 -+:y 24 0 0377 -diff -aruN groff-1.18/font/devlj4/DESC groff-1.18.win32/font/devlj4/DESC ---- groff-1.18/font/devlj4/DESC Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devlj4/DESC Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,12 @@ -+res 600 -+unitwidth 12700 -+hor 1 -+vert 1 -+sizescale 4 -+sizes 1-3999 0 -+styles R I B BI -+fonts 6 0 0 0 0 0 S -+family T -+tcommand -+postpro grolj4 -+papersize letter -diff -aruN groff-1.18/font/devps/DESC groff-1.18.win32/font/devps/DESC ---- groff-1.18/font/devps/DESC Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devps/DESC Mon Jul 8 06:52:35 2002 -@@ -0,0 +1,13 @@ -+res 72000 -+hor 1 -+vert 1 -+sizescale 1000 -+unitwidth 1000 -+sizes 1000-10000000 0 -+styles R I B BI -+family T -+fonts 9 0 0 0 0 0 SS S ZD ZDR -+tcommand -+postpro grops -+broken 7 -+papersize letter -diff -aruN groff-1.18/font/devps/prologue groff-1.18.win32/font/devps/prologue ---- groff-1.18/font/devps/prologue Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devps/prologue Fri Jul 5 16:06:29 2002 -@@ -0,0 +1,164 @@ -+%!PS-Adobe-3.0 Resource-ProcSet -+/setpacking where{ -+pop -+currentpacking -+true setpacking -+}if -+/grops 120 dict dup begin -+/SC 32 def -+/A/show load def -+/B{0 SC 3 -1 roll widthshow}bind def -+/C{0 exch ashow}bind def -+/D{0 exch 0 SC 5 2 roll awidthshow}bind def -+/E{0 rmoveto show}bind def -+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def -+/G{0 rmoveto 0 exch ashow}bind def -+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -+/I{0 exch rmoveto show}bind def -+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def -+/K{0 exch rmoveto 0 exch ashow}bind def -+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -+/M{rmoveto show}bind def -+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def -+/O{rmoveto 0 exch ashow}bind def -+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def -+/Q{moveto show}bind def -+/R{moveto 0 SC 3 -1 roll widthshow}bind def -+/S{moveto 0 exch ashow}bind def -+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def -+/SF{ -+findfont exch -+[exch dup 0 exch 0 exch neg 0 0]makefont -+dup setfont -+[exch/setfont cvx]cvx bind def -+}bind def -+/MF{ -+findfont -+[5 2 roll -+0 3 1 roll -+neg 0 0]makefont -+dup setfont -+[exch/setfont cvx]cvx bind def -+}bind def -+/level0 0 def -+/RES 0 def -+/PL 0 def -+/LS 0 def -+/MANUAL{ -+statusdict begin/manualfeed true store end -+}bind def -+/PLG{ -+gsave newpath clippath pathbbox grestore -+exch pop add exch pop -+}bind def -+/BP{ -+/level0 save def -+1 setlinecap -+1 setlinejoin -+72 RES div dup scale -+LS{ -+90 rotate -+}{ -+0 PL translate -+}ifelse -+1 -1 scale -+}bind def -+/EP{ -+level0 restore -+showpage -+}bind def -+/DA{ -+newpath arcn stroke -+}bind def -+/SN{ -+transform -+.25 sub exch .25 sub exch -+round .25 add exch round .25 add exch -+itransform -+}bind def -+/DL{ -+SN -+moveto -+SN -+lineto stroke -+}bind def -+/DC{ -+newpath 0 360 arc closepath -+}bind def -+/TM matrix def -+/DE{ -+TM currentmatrix pop -+translate scale newpath 0 0 .5 0 360 arc closepath -+TM setmatrix -+}bind def -+/RC/rcurveto load def -+/RL/rlineto load def -+/ST/stroke load def -+/MT/moveto load def -+/CL/closepath load def -+/Fr{ -+setrgbcolor fill -+}bind def -+/Fk{ -+setcmykcolor fill -+}bind def -+/Fg{ -+setgray fill -+}bind def -+/FL/fill load def -+/LW/setlinewidth load def -+/Cr/setrgbcolor load def -+/Ck/setcmykcolor load def -+/Cg/setgray load def -+/RE{ -+findfont -+dup maxlength 1 index/FontName known not{1 add}if dict begin -+{ -+1 index/FID ne{def}{pop pop}ifelse -+}forall -+/Encoding exch def -+dup/FontName exch def -+currentdict end definefont pop -+}bind def -+/DEFS 0 def -+/EBEGIN{ -+moveto -+DEFS begin -+}bind def -+/EEND/end load def -+/CNT 0 def -+/level1 0 def -+/PBEGIN{ -+/level1 save def -+translate -+div 3 1 roll div exch scale -+neg exch neg exch translate -+0 setgray -+0 setlinecap -+1 setlinewidth -+0 setlinejoin -+10 setmiterlimit -+[]0 setdash -+/setstrokeadjust where{ -+pop -+false setstrokeadjust -+}if -+/setoverprint where{ -+pop -+false setoverprint -+}if -+newpath -+/CNT countdictstack def -+userdict begin -+/showpage{}def -+}bind def -+/PEND{ -+clear -+countdictstack CNT sub{end}repeat -+level1 restore -+}bind def -+end def -+/setpacking where{ -+pop -+setpacking -+}if -diff -aruN groff-1.18/font/devps/symbolsl.pfa groff-1.18.win32/font/devps/symbolsl.pfa ---- groff-1.18/font/devps/symbolsl.pfa Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devps/symbolsl.pfa Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,29 @@ -+%!PS-Adobe-3.0 Resource-Font -+%%DocumentNeededResources: font Symbol -+/MakeTransformedFont{ -+findfont dup maxlength dict begin -+{ -+exch dup dup/FID ne exch/UniqueID ne and{ -+exch def -+}{ -+pop pop -+}ifelse -+}forall -+/FontBBox -+currentdict/FontBBox get -+4 array copy def -+FontBBox aload pop -+4 index transform 4 2 roll -+4 index transform 4 2 roll -+FontBBox astore pop -+FontMatrix exch matrix concatmatrix -+/FontMatrix exch def -+dup/FontName exch def -+currentdict end -+definefont pop -+}bind def -+%%IncludeResource: font Symbol -+/Symbol-Slanted -+[.89 0.0 15.5 dup sin exch cos div .89 0.0 0.0] -+/Symbol -+MakeTransformedFont -diff -aruN groff-1.18/font/devps/zapfdr.pfa groff-1.18.win32/font/devps/zapfdr.pfa ---- groff-1.18/font/devps/zapfdr.pfa Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/font/devps/zapfdr.pfa Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,218 @@ -+%!PS-Adobe-3.0 Resource-Font -+%%DocumentNeededResources: font ZapfDingbats -+%%IncludeResource: font ZapfDingbats -+/ZapfDingbats findfont[-1 0 0 1 0 0]makefont -+dup length 1 add dict begin -+{ -+exch dup dup/FID ne exch/UniqueID ne and{ -+exch def -+}{ -+pop pop -+}ifelse -+}forall -+/FontName/ZapfDingbats-Reverse def -+/Metrics 202 dict dup begin -+/space[0 -278]def -+/a1[-939 -974]def -+/a2[-926 -961]def -+/a202[-939 -974]def -+/a3[-945 -980]def -+/a4[-685 -719]def -+/a5[-754 -789]def -+/a119[-755 -790]def -+/a118[-756 -791]def -+/a117[-655 -690]def -+/a11[-925 -960]def -+/a12[-904 -939]def -+/a13[-520 -549]def -+/a14[-821 -855]def -+/a15[-876 -911]def -+/a16[-898 -933]def -+/a105[-876 -911]def -+/a17[-910 -945]def -+/a18[-939 -974]def -+/a19[-721 -755]def -+/a20[-811 -846]def -+/a21[-727 -762]def -+/a22[-726 -761]def -+/a23[-572 -571]def -+/a24[-641 -677]def -+/a25[-728 -763]def -+/a26[-725 -760]def -+/a27[-724 -759]def -+/a28[-719 -754]def -+/a6[-459 -494]def -+/a7[-517 -552]def -+/a8[-502 -537]def -+/a9[-542 -577]def -+/a10[-657 -692]def -+/a29[-751 -786]def -+/a30[-753 -788]def -+/a31[-753 -788]def -+/a32[-755 -790]def -+/a33[-758 -793]def -+/a34[-759 -794]def -+/a35[-781 -816]def -+/a36[-788 -823]def -+/a37[-754 -789]def -+/a38[-806 -841]def -+/a39[-788 -823]def -+/a40[-798 -833]def -+/a41[-781 -816]def -+/a42[-796 -831]def -+/a43[-888 -923]def -+/a44[-709 -744]def -+/a45[-688 -723]def -+/a46[-714 -749]def -+/a47[-756 -790]def -+/a48[-757 -792]def -+/a49[-660 -695]def -+/a50[-741 -776]def -+/a51[-733 -768]def -+/a52[-757 -792]def -+/a53[-724 -759]def -+/a54[-672 -707]def -+/a55[-673 -708]def -+/a56[-647 -682]def -+/a57[-666 -701]def -+/a58[-791 -826]def -+/a59[-780 -815]def -+/a60[-754 -789]def -+/a61[-754 -789]def -+/a62[-673 -707]def -+/a63[-651 -687]def -+/a64[-661 -696]def -+/a65[-654 -689]def -+/a66[-752 -786]def -+/a67[-752 -787]def -+/a68[-678 -713]def -+/a69[-756 -791]def -+/a70[-749 -785]def -+/a71[-756 -791]def -+/a72[-838 -873]def -+/a73[-726 -761]def -+/a74[-727 -762]def -+/a203[-727 -762]def -+/a75[-724 -759]def -+/a204[-724 -759]def -+/a76[-857 -892]def -+/a77[-857 -892]def -+/a78[-753 -788]def -+/a79[-749 -784]def -+/a81[-403 -438]def -+/a82[-103 -138]def -+/a83[-242 -277]def -+/a84[-380 -415]def -+/a97[-357 -392]def -+/a98[-358 -392]def -+/a99[-633 -668]def -+/a100[-632 -668]def -+/a101[-697 -732]def -+/a102[-488 -544]def -+/a103[-510 -544]def -+/a104[-875 -910]def -+/a106[-632 -667]def -+/a107[-725 -760]def -+/a108[-760 -760]def -+/a112[-741 -776]def -+/a111[-561 -595]def -+/a110[-659 -694]def -+/a109[-592 -626]def -+/a120[-753 -788]def -+/a121[-753 -788]def -+/a122[-753 -788]def -+/a123[-753 -788]def -+/a124[-753 -788]def -+/a125[-753 -788]def -+/a126[-753 -788]def -+/a127[-753 -788]def -+/a128[-753 -788]def -+/a129[-753 -788]def -+/a130[-753 -788]def -+/a131[-753 -788]def -+/a132[-753 -788]def -+/a133[-753 -788]def -+/a134[-753 -788]def -+/a135[-753 -788]def -+/a136[-753 -788]def -+/a137[-753 -788]def -+/a138[-753 -788]def -+/a139[-753 -788]def -+/a140[-753 -788]def -+/a141[-753 -788]def -+/a142[-753 -788]def -+/a143[-753 -788]def -+/a144[-753 -788]def -+/a145[-753 -788]def -+/a146[-753 -788]def -+/a147[-753 -788]def -+/a148[-753 -788]def -+/a149[-753 -788]def -+/a150[-753 -788]def -+/a151[-753 -788]def -+/a152[-753 -788]def -+/a153[-753 -788]def -+/a154[-753 -788]def -+/a155[-753 -788]def -+/a156[-753 -788]def -+/a157[-753 -788]def -+/a158[-753 -788]def -+/a159[-753 -788]def -+/a160[-859 -894]def -+/a161[-803 -838]def -+/a163[-982 -1016]def -+/a164[-423 -458]def -+/a196[-713 -748]def -+/a165[-889 -924]def -+/a192[-713 -748]def -+/a166[-883 -918]def -+/a167[-892 -927]def -+/a168[-893 -928]def -+/a169[-893 -928]def -+/a170[-799 -834]def -+/a171[-838 -873]def -+/a172[-793 -828]def -+/a173[-889 -924]def -+/a162[-889 -924]def -+/a174[-882 -917]def -+/a175[-895 -930]def -+/a176[-896 -931]def -+/a177[-428 -463]def -+/a178[-848 -883]def -+/a179[-801 -836]def -+/a193[-801 -836]def -+/a180[-832 -867]def -+/a199[-832 -867]def -+/a181[-661 -696]def -+/a200[-661 -696]def -+/a182[-839 -874]def -+/a201[-839 -874]def -+/a183[-725 -760]def -+/a184[-911 -946]def -+/a197[-737 -771]def -+/a185[-830 -865]def -+/a194[-737 -771]def -+/a198[-854 -888]def -+/a186[-932 -967]def -+/a195[-854 -888]def -+/a187[-796 -831]def -+/a188[-837 -873]def -+/a189[-892 -927]def -+/a190[-935 -970]def -+/a191[-884 -918]def -+/a205[-474 -509]def -+/a206[-375 -410]def -+/a85[-474 -509]def -+/a86[-375 -410]def -+/a87[-199 -234]def -+/a88[-199 -234]def -+/a89[-355 -390]def -+/a90[-355 -390]def -+/a91[-241 -276]def -+/a92[-241 -276]def -+/a93[-282 -317]def -+/a94[-282 -317]def -+/a95[-299 -334]def -+/a96[-299 -334]def -+end def -+/ZapfDingbats-Reverse currentdict end definefont pop -diff -aruN groff-1.18/src/devices/grodvi/Makefile.msc groff-1.18.win32/src/devices/grodvi/Makefile.msc ---- groff-1.18/src/devices/grodvi/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/devices/grodvi/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,21 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c -nologo -I../../include -Tp$< -+ -+.c.obj: -+ cl -c -nologo -I../../include $< -+ -+OBJS = dvi.obj -+ -+ -+grodvi.exe : $(OBJS) -+ cl -nologo -Fe$@ *.obj ..\..\libs\libdriver\libdriver.lib ..\..\libs\libgroff\libgroff.lib -+ -+ -+ -diff -aruN groff-1.18/src/devices/grolj4/Makefile.msc groff-1.18.win32/src/devices/grolj4/Makefile.msc ---- groff-1.18/src/devices/grolj4/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/devices/grolj4/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,22 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c -nologo -I../../include -Tp$< -+ -+.c.obj: -+ cl -c -nologo -I../../include $< -+ -+OBJS = \ -+ lj4.obj -+ -+ -+grolj4.exe : $(OBJS) -+ cl -nologo -Fe$@ *.obj ..\..\libs\libdriver\libdriver.lib ..\..\libs\libgroff\libgroff.lib -+ -+ -+ -diff -aruN groff-1.18/src/devices/grops/Makefile.msc groff-1.18.win32/src/devices/grops/Makefile.msc ---- groff-1.18/src/devices/grops/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/devices/grops/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,23 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c -nologo -I../../include -Tp$< -+ -+.c.obj: -+ cl -c -nologo -I../../include $< -+ -+OBJS = \ -+ ps.obj \ -+ psrm.obj -+ -+ -+grops.exe : $(OBJS) -+ cl -nologo -Fe$@ *.obj ..\..\libs\libdriver\libdriver.lib ..\..\libs\libgroff\libgroff.lib -+ -+ -+ -diff -aruN groff-1.18/src/devices/grotty/Makefile.msc groff-1.18.win32/src/devices/grotty/Makefile.msc ---- groff-1.18/src/devices/grotty/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/devices/grotty/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,22 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c -nologo -I../../include -Tp$< -+ -+.c.obj: -+ cl -c -nologo -I../../include $< -+ -+OBJS = \ -+ tty.obj -+ -+ -+grotty.exe : $(OBJS) -+ cl -nologo -Fe$@ *.obj ..\..\libs\libdriver\libdriver.lib ..\..\libs\libgroff\libgroff.lib -+ -+ -+ -diff -aruN groff-1.18/src/include/defs.h groff-1.18.win32/src/include/defs.h ---- groff-1.18/src/include/defs.h Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/include/defs.h Mon Jul 8 08:32:01 2002 -@@ -0,0 +1,8 @@ -+ -+#define FONTPATH "c:/groff/font" -+ -+#define MACROPATH "c:/groff/tmac;c:/groff/mm" -+ -+#define DEVICE "ps" -+ -+#define PROG_PREFIX "" -diff -aruN groff-1.18/src/include/getopt.h groff-1.18.win32/src/include/getopt.h ---- groff-1.18/src/include/getopt.h Sat Aug 25 01:37:49 2001 -+++ groff-1.18.win32/src/include/getopt.h Mon Jul 8 06:47:51 2002 -@@ -162,7 +162,7 @@ - int __long_only); - # endif - #else /* not __STDC__ */ --extern int getopt (); -+extern int getopt (int a, char **b, char *c); - # ifndef __need_getopt - extern int getopt_long (); - extern int getopt_long_only (); -diff -aruN groff-1.18/src/libs/libdriver/Makefile.msc groff-1.18.win32/src/libs/libdriver/Makefile.msc ---- groff-1.18/src/libs/libdriver/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/libs/libdriver/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,22 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c -nologo -I../../include -Tp$< -+ -+.c.obj: -+ cl -c -nologo -I../../include $< -+ -+OBJS = \ -+ input.obj \ -+ printer.obj -+ -+ -+libdriver.lib : $(OBJS) -+ rm -zq $@ -+ lib /NOLOGO /OUT:$@ *.obj -+ -diff -aruN groff-1.18/src/libs/libgroff/Makefile.msc groff-1.18.win32/src/libs/libgroff/Makefile.msc ---- groff-1.18/src/libs/libgroff/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/libs/libgroff/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,59 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+#CFLAGS = -nologo -I../../include -GF -Zi -Yd -DHAVE_STRING_H=1 -+CFLAGS = -nologo -I../../include -GF -Ox -DHAVE_STRING_H=1 -+ -+ -+.SUFFIXES : .cc -+ -+ -+.cc.obj: -+ cl -c $(CFLAGS) -Tp$< -+ -+.c.obj: -+ cl -c $(CFLAGS) $< -+ -+ -+OBJS = \ -+ assert.obj \ -+ change_lf.obj \ -+ cmap.obj \ -+ color.obj \ -+ cset.obj \ -+ device.obj \ -+ errarg.obj \ -+ error.obj \ -+ fatal.obj \ -+ filename.obj \ -+ font.obj \ -+ fontfile.obj \ -+ getopt.obj \ -+ geometry.obj \ -+ htmlhint.obj \ -+ iftoa.obj \ -+ invalid.obj \ -+ itoa.obj \ -+ lf.obj \ -+ lineno.obj \ -+ macropath.obj \ -+ mkstemp.obj \ -+ mksdir.obj \ -+ nametoindex.obj \ -+ paper.obj \ -+ progname.obj \ -+ ptable.obj \ -+ searchpath.obj \ -+ string.obj \ -+ strsave.obj \ -+ tmpfile.obj \ -+ tmpname.obj \ -+ version.obj -+ -+ -+libgroff.lib : $(OBJS) -+ rm -zq $@ -+ lib /NOLOGO /OUT:$@ *.obj -+ -diff -aruN groff-1.18/src/libs/libgroff/version.cc groff-1.18.win32/src/libs/libgroff/version.cc ---- groff-1.18/src/libs/libgroff/version.cc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/libs/libgroff/version.cc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,3 @@ -+const char *version_string = "1.18"; -+const char *revision_string = "0"; -+extern "C" const char *Version_string = "1.18"; -diff -aruN groff-1.18/src/preproc/eqn/Makefile.msc groff-1.18.win32/src/preproc/eqn/Makefile.msc ---- groff-1.18/src/preproc/eqn/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/preproc/eqn/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,39 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+#CFLAGS = -nologo -I../../include -GF -Zi -Yd -+CFLAGS = -nologo -I../../include -GF -Ox -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c $(CFLAGS) -Tp$< -+ -+.c.obj: -+ cl -c $(CFLAGS) $< -+ -+OBJS = \ -+ box.obj \ -+ delim.obj \ -+ eqn.obj \ -+ lex.obj \ -+ limit.obj \ -+ list.obj \ -+ main.obj \ -+ mark.obj \ -+ other.obj \ -+ over.obj \ -+ pile.obj \ -+ script.obj \ -+ special.obj \ -+ sqrt.obj \ -+ text.obj -+ -+ -+eqn.exe : $(OBJS) -+ cl $(CFLAGS) -Fe$@ *.obj ..\..\libs\libgroff\libgroff.lib -+ -+ -+ -diff -aruN groff-1.18/src/preproc/pic/Makefile.msc groff-1.18.win32/src/preproc/pic/Makefile.msc ---- groff-1.18/src/preproc/pic/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/preproc/pic/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,31 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+#CFLAGS = -nologo -I../../include -GF -Zi -Yd -DRET_TYPE_SRAND_IS_VOID -+CFLAGS = -nologo -I../../include -GF -Ox -DRET_TYPE_SRAND_IS_VOID -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c $(CFLAGS) -Tp$< -+ -+.c.obj: -+ cl -c $(CFLAGS) $< -+ -+OBJS = \ -+ common.obj \ -+ lex.obj \ -+ main.obj \ -+ object.obj \ -+ pic.obj \ -+ tex.obj \ -+ troff.obj -+ -+ -+pic.exe : $(OBJS) -+ cl $(CFLAGS) -Fe$@ *.obj ..\..\libs\libgroff\libgroff.lib -+ -+ -+ -diff -aruN groff-1.18/src/preproc/tbl/Makefile.msc groff-1.18.win32/src/preproc/tbl/Makefile.msc ---- groff-1.18/src/preproc/tbl/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/preproc/tbl/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,26 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+#CFLAGS = -nologo -I../../include -GF -Zi -Yd -+CFLAGS = -nologo -I../../include -GF -Ox -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c $(CFLAGS) -Tp$< -+ -+.c.obj: -+ cl -c $(CFLAGS) $< -+ -+OBJS = \ -+ main.obj \ -+ table.obj -+ -+ -+tbl.exe : $(OBJS) -+ cl $(CFLAGS) -Fe$@ *.obj ..\..\libs\libgroff\libgroff.lib -+ -+ -+ -diff -aruN groff-1.18/src/roff/troff/Makefile.msc groff-1.18.win32/src/roff/troff/Makefile.msc ---- groff-1.18/src/roff/troff/Makefile.msc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/roff/troff/Makefile.msc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,34 @@ -+ -+# Makefile for Microsoft Visual C++ 6.0 -+# by Blake McBride (blake@florida-software.com) -+ -+ -+#CFLAGS = -nologo -I../../include -GF -Zi -Yd -+CFLAGS = -nologo -I../../include -GF -Ox -+ -+.SUFFIXES : .cc -+ -+.cc.obj: -+ cl -c $(CFLAGS) -Tp$< -+ -+.c.obj: -+ cl -c $(CFLAGS) $< -+ -+OBJS = \ -+ column.obj \ -+ dictionary.obj \ -+ div.obj \ -+ env.obj \ -+ input.obj \ -+ node.obj \ -+ number.obj \ -+ reg.obj \ -+ symbol.obj \ -+ majorminor.obj -+ -+ -+troff.exe : $(OBJS) -+ cl $(CFLAGS) -Fe$@ *.obj ..\..\libs\libgroff\libgroff.lib -link -map -+ -+ -+ -diff -aruN groff-1.18/src/roff/troff/majorminor.cc groff-1.18.win32/src/roff/troff/majorminor.cc ---- groff-1.18/src/roff/troff/majorminor.cc Thu Jan 1 01:00:00 1970 -+++ groff-1.18.win32/src/roff/troff/majorminor.cc Mon Jul 8 06:47:51 2002 -@@ -0,0 +1,3 @@ -+const char *major_version = "1"; -+const char *minor_version = "18"; -+const char *revision = "0"; -- cgit v1.1