diff options
author | Ruslan Ermilov <ru@FreeBSD.org> | 2001-04-17 12:12:05 +0000 |
---|---|---|
committer | Ruslan Ermilov <ru@FreeBSD.org> | 2001-04-17 12:12:05 +0000 |
commit | 1d5f6a94a87add2c3eb035043f48bb7fe1906661 (patch) | |
tree | f3137c4283de8869ebcae1dd0fe43f590276c1dc /contrib/groff/src/preproc | |
parent | c8d1b47c7fde3a8a3f5530bd5e3939bba340ab4b (diff) | |
download | src-1d5f6a94a87add2c3eb035043f48bb7fe1906661.tar.gz src-1d5f6a94a87add2c3eb035043f48bb7fe1906661.zip |
Virgin import of FSF groff v1.17
Notes
Notes:
svn path=/vendor/groff/dist/; revision=75584
Diffstat (limited to 'contrib/groff/src/preproc')
78 files changed, 40828 insertions, 0 deletions
diff --git a/contrib/groff/src/preproc/eqn/Makefile.sub b/contrib/groff/src/preproc/eqn/Makefile.sub new file mode 100644 index 000000000000..20421e1c4958 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/Makefile.sub @@ -0,0 +1,59 @@ +PROG=eqn +MAN1=eqn.n neqn.n +XLIBS=$(LIBGROFF) +OBJS=\ + eqn.o \ + main.o \ + lex.o \ + box.o \ + limit.o \ + list.o \ + over.o \ + text.o \ + script.o \ + mark.o \ + other.o \ + delim.o \ + sqrt.o \ + pile.o \ + special.o +CCSRCS=\ + $(srcdir)/main.cc \ + $(srcdir)/lex.cc \ + $(srcdir)/box.cc \ + $(srcdir)/limit.cc \ + $(srcdir)/list.cc \ + $(srcdir)/over.cc \ + $(srcdir)/text.cc \ + $(srcdir)/script.cc \ + $(srcdir)/mark.cc \ + $(srcdir)/other.cc \ + $(srcdir)/delim.cc \ + $(srcdir)/sqrt.cc \ + $(srcdir)/pile.cc \ + $(srcdir)/special.cc +HDRS=\ + $(srcdir)/box.h \ + $(srcdir)/eqn.h \ + $(srcdir)/pbox.h +GRAM=$(srcdir)/eqn.y +YTABC=$(srcdir)/eqn.cc +YTABH=$(srcdir)/eqn_tab.h +NAMEPREFIX=$(g) +CLEANADD=neqn + +all: neqn + +neqn: neqn.sh + -rm -f $@ + sed -e 's/@g@/$(g)/g' \ + -e 's|@BINDIR@|$(bindir)|g' \ + -e $(SH_SCRIPT_SED_CMD) $(srcdir)/neqn.sh >$@ + chmod +x $@ + +install_data: neqn + -rm -f $(bindir)/$(NAMEPREFIX)neqn + $(INSTALL_SCRIPT) neqn $(bindir)/$(NAMEPREFIX)neqn + +uninstall_sub: + -rm -f $(bindir)/$(NAMEPREFIX)neqn diff --git a/contrib/groff/src/preproc/eqn/TODO b/contrib/groff/src/preproc/eqn/TODO new file mode 100644 index 000000000000..210d0ab06e4d --- /dev/null +++ b/contrib/groff/src/preproc/eqn/TODO @@ -0,0 +1,49 @@ +Use the same size increases for sum prod int as eqn does. + +Perhaps chartype should be renamed. + +TeX makes {sub,super}script on a single character with an accent +into an accent onto the (character with the script). Should we do this? + +Implement mark and lineups within scripts, matrices and piles, and accents. +(Why would this be useful?) + +Perhaps push hmotions down through lists to avoid upsetting spacing +adjustments. + +Possibly generate .lf commands during compute_metrics phase. + +Consider whether there should be extra space at the side of piles. + +Provide scriptstyle displaystyle etc. + +Provide a nicer matrix syntax, eg +matrix ccc { +a then b then c above +e then f then g above +h then i then k +} + +Perhaps generate syntax error messages using the style of gpic. + +Wide accents. + +More use of \Z. + +Extensible square roots. + +Vphantom + +Smash. + +Provide a variant of vec that extends over the length of the accentee. + +Support vertical arrow delimiters. + +Make the following work: +.EQ +delim @@ +.EN +.EQ @<-@ +some equation +.EN diff --git a/contrib/groff/src/preproc/eqn/box.cc b/contrib/groff/src/preproc/eqn/box.cc new file mode 100644 index 000000000000..4e61b5dc3b74 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/box.cc @@ -0,0 +1,611 @@ +// -*- 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" + +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[.s]*7+5/10>?%d)*1z\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[.s]z\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 " .as " 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[.s]z'" + "\\s0" + "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.s]z'" + "\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(".as " 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 " .as " 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 "] " + ".as " LINE_STRING " \\x'-%dM'\n", positive_space); + if (negative_space > 0) + printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] " + ".as " 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 .as " 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 .as " 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, "<tab>"); +} diff --git a/contrib/groff/src/preproc/eqn/box.h b/contrib/groff/src/preproc/eqn/box.h new file mode 100644 index 000000000000..01bfe96a4ac3 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/box.h @@ -0,0 +1,277 @@ +// -*- 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. */ + +struct list_box; + +class box { +private: + static int next_uid; +public: + int spacing_type; + const int uid; + box(); + virtual void debug_print() = 0; + virtual ~box(); + void top_level(); + virtual int compute_metrics(int); + virtual void compute_subscript_kern(); + virtual void compute_skew(); + virtual void output(); + void extra_space(); + virtual list_box *to_list_box(); + virtual int is_simple(); + virtual int is_char(); + virtual int left_is_italic(); + virtual int right_is_italic(); + virtual void handle_char_type(int, int); + enum { FOUND_NOTHING = 0, FOUND_MARK = 1, FOUND_LINEUP = 2 }; + void set_spacing_type(char *type); + virtual void hint(unsigned); + virtual void check_tabs(int); +}; + +class box_list { +private: + int maxlen; +public: + box **p; + int len; + + box_list(box *); + ~box_list(); + void append(box *); + void list_check_tabs(int); + void list_debug_print(const char *sep); + friend class list_box; +}; + +class list_box : public box { + int is_script; + box_list list; + int sty; +public: + list_box(box *); + void debug_print(); + int compute_metrics(int); + void compute_subscript_kern(); + void output(); + void check_tabs(int); + void append(box *); + list_box *to_list_box(); + void handle_char_type(int, int); + void compute_sublist_width(int n); + friend box *make_script_box(box *, box *, box *); + friend box *make_mark_box(box *); + friend box *make_lineup_box(box *); +}; + +enum alignment { LEFT_ALIGN, RIGHT_ALIGN, CENTER_ALIGN }; + +class column : public box_list { + alignment align; + int space; +public: + column(box *); + void set_alignment(alignment); + void set_space(int); + void debug_print(const char *); + + friend class matrix_box; + friend class pile_box; +}; + +class pile_box : public box { + column col; +public: + pile_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); + void check_tabs(int); + void set_alignment(alignment a) { col.set_alignment(a); } + void set_space(int n) { col.set_space(n); } + void append(box *p) { col.append(p); } +}; + +class matrix_box : public box { +private: + int len; + int maxlen; + column **p; +public: + matrix_box(column *); + ~matrix_box(); + void append(column *); + int compute_metrics(int); + void output(); + void check_tabs(int); + void debug_print(); +}; + +class pointer_box : public box { +protected: + box *p; +public: + pointer_box(box *); + ~pointer_box(); + int compute_metrics(int); + void compute_subscript_kern(); + void compute_skew(); + void debug_print() = 0; + void check_tabs(int); +}; + +class vcenter_box : public pointer_box { +public: + vcenter_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class simple_box : public box { +public: + int compute_metrics(int); + void compute_subscript_kern(); + void compute_skew(); + void output() = 0; + void debug_print() = 0; + int is_simple(); +}; + +class quoted_text_box : public simple_box { + char *text; +public: + quoted_text_box(char *); + ~quoted_text_box(); + void debug_print(); + void output(); +}; + +class half_space_box : public simple_box { +public: + half_space_box(); + void output(); + void debug_print(); +}; + +class space_box : public simple_box { +public: + space_box(); + void output(); + void debug_print(); +}; + +class tab_box : public box { + int disabled; +public: + tab_box(); + void output(); + void debug_print(); + void check_tabs(int); +}; + +class size_box : public pointer_box { +private: + char *size; +public: + size_box(char *, box *); + ~size_box(); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class font_box : public pointer_box { +private: + char *f; +public: + font_box(char *, box *); + ~font_box(); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class fat_box : public pointer_box { +public: + fat_box(box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class vmotion_box : public pointer_box { +private: + int n; // up is >= 0 +public: + vmotion_box(int, box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +class hmotion_box : public pointer_box { + int n; +public: + hmotion_box(int, box *); + int compute_metrics(int); + void output(); + void debug_print(); +}; + +box *split_text(char *); +box *make_script_box(box *, box *, box *); +box *make_mark_box(box *); +box *make_lineup_box(box *); +box *make_delim_box(char *, box *, char *); +box *make_sqrt_box(box *); +box *make_prime_box(box *); +box *make_over_box(box *, box *); +box *make_small_over_box(box *, box *); +box *make_limit_box(box *, box *, box *); +box *make_accent_box(box *, box *); +box *make_uaccent_box(box *, box *); +box *make_overline_box(box *); +box *make_underline_box(box *); +box *make_special_box(char *, box *); + +void set_space(int); +int set_gsize(const char *); +void set_gfont(const char *); +void set_grfont(const char *); +void set_gbfont(const char *); +const char *get_gfont(); +const char *get_grfont(); +const char *get_gbfont(); +void start_string(); +void output_string(); +void do_text(const char *); +void restore_compatibility(); +void set_script_reduction(int n); +void set_minimum_size(int n); +void set_param(const char *name, int value); + +void set_char_type(const char *type, char *ch); + +void init_char_table(); +void init_extensible(); +void define_extensible(const char *name, const char *ext, const char *top = 0, + const char *mid = 0, const char *bot = 0); diff --git a/contrib/groff/src/preproc/eqn/delim.cc b/contrib/groff/src/preproc/eqn/delim.cc new file mode 100644 index 000000000000..29deded38343 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/delim.cc @@ -0,0 +1,381 @@ +// -*- 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/eqn.cc b/contrib/groff/src/preproc/eqn/eqn.cc new file mode 100644 index 000000000000..1fdda611201a --- /dev/null +++ b/contrib/groff/src/preproc/eqn/eqn.cc @@ -0,0 +1,1277 @@ +#if defined(__STDC__) || defined(__cplusplus) +#define YYCONST const +#define YYPARAMS(x) x +#define YYDEFUN(name, arglist, args) name(args) +#define YYAND , +#define YYPTR void * +#else +#define YYCONST +#define YYPARAMS(x) () +#define YYDEFUN(name, arglist, args) name arglist args; +#define YYAND ; +#define YYPTR char * +#endif +#ifndef lint +YYCONST static char yysccsid[] = "@(#)yaccpar 1.8 (Berkeley +Cygnus.28) 01/20/91"; +#endif +#define YYBYACC 1 +#ifndef YYDONT_INCLUDE_STDIO +#include <stdio.h> +#endif +#ifdef __cplusplus +#include <stdlib.h> /* for malloc/realloc/free */ +#endif +#line 20 "eqn.y" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "lib.h" +#include "box.h" +extern int non_empty_flag; +char *strsave(const char *); +int yylex(); +void yyerror(const char *); +#line 32 "eqn.y" +typedef union { + char *str; + box *b; + pile_box *pb; + matrix_box *mb; + int n; + column *col; +} YYSTYPE; +#line 45 "y.tab.c" +#define OVER 257 +#define SMALLOVER 258 +#define SQRT 259 +#define SUB 260 +#define SUP 261 +#define LPILE 262 +#define RPILE 263 +#define CPILE 264 +#define PILE 265 +#define LEFT 266 +#define RIGHT 267 +#define TO 268 +#define FROM 269 +#define SIZE 270 +#define FONT 271 +#define ROMAN 272 +#define BOLD 273 +#define ITALIC 274 +#define FAT 275 +#define ACCENT 276 +#define BAR 277 +#define UNDER 278 +#define ABOVE 279 +#define TEXT 280 +#define QUOTED_TEXT 281 +#define FWD 282 +#define BACK 283 +#define DOWN 284 +#define UP 285 +#define MATRIX 286 +#define COL 287 +#define LCOL 288 +#define RCOL 289 +#define CCOL 290 +#define MARK 291 +#define LINEUP 292 +#define TYPE 293 +#define VCENTER 294 +#define PRIME 295 +#define SPLIT 296 +#define NOSPLIT 297 +#define UACCENT 298 +#define SPECIAL 299 +#define SPACE 300 +#define GFONT 301 +#define GSIZE 302 +#define DEFINE 303 +#define NDEFINE 304 +#define TDEFINE 305 +#define SDEFINE 306 +#define UNDEF 307 +#define IFDEF 308 +#define INCLUDE 309 +#define DELIM 310 +#define CHARTYPE 311 +#define SET 312 +#define GRFONT 313 +#define GBFONT 314 +#define YYERRCODE 256 +static YYCONST short yylhs[] = { -1, + 0, 0, 6, 6, 1, 1, 1, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 4, 4, 7, 7, + 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 8, 11, 11, 12, 12, 13, + 13, 16, 16, 15, 15, 14, 14, 14, 14, 9, + 9, 10, 10, 10, +}; +static YYCONST short yylen[] = { 2, + 0, 1, 1, 2, 1, 2, 2, 1, 3, 3, + 5, 5, 1, 2, 3, 3, 1, 3, 1, 3, + 5, 1, 1, 2, 2, 1, 1, 1, 3, 2, + 2, 2, 2, 4, 5, 3, 2, 2, 2, 3, + 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 2, 3, 1, 1, 3, 3, 4, 1, + 2, 1, 3, 3, 4, 2, 2, 2, 2, 1, + 1, 1, 1, 1, +}; +static YYCONST short yydefred[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 26, 27, 28, 0, + 0, 3, 5, 0, 13, 0, 0, 17, 14, 70, + 71, 0, 0, 55, 31, 32, 33, 30, 73, 74, + 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 7, 0, 0, 24, 25, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, + 39, 0, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, + 0, 29, 15, 16, 9, 0, 0, 20, 18, 40, + 41, 0, 58, 0, 0, 0, 0, 66, 67, 68, + 69, 34, 61, 0, 0, 0, 0, 59, 35, 0, + 0, 0, 11, 12, 21, 0, 64, 0, 0, 65, +}; +static YYCONST short yydgoto[] = { 31, + 32, 33, 34, 35, 36, 84, 38, 43, 44, 52, + 85, 45, 98, 99, 118, 131, +}; +static YYCONST short yysindex[] = { 1488, + 1527, -120, -120, -120, -120, -123, -249, -249, 1566, 1566, + 1566, 1566, 0, 0, -249, -249, -249, -249, -115, 1488, + 1488, -249, 1566, -256, -251, -249, 0, 0, 0, 1488, + 0, 0, 0, -221, 0, -233, 1488, 0, 0, 0, + 0, 1488, -85, 0, 0, 0, 0, 0, 0, 0, + 0, 1488, 1566, 1566, -195, -195, -195, -195, 1566, 1566, + 1566, 1566, -272, 0, 0, 1566, -195, 0, 0, 1566, + 1402, 1527, 1527, 1527, 1527, 1566, 1566, 1566, 0, 0, + 0, 1566, 0, 1488, -113, 1488, 1444, -195, -195, -195, + -195, -195, -195, -117, -117, -117, -117, -118, 0, -195, + -195, 0, 0, 0, 0, -167, -189, 0, 0, 0, + 0, 1488, 0, -106, -123, 1488, -83, 0, 0, 0, + 0, 0, 0, 1527, 1527, 1566, 1488, 0, 0, 1488, + -105, 1488, 0, 0, 0, 1488, 0, -104, 1488, 0, +}; +static YYCONST short yyrindex[] = { 41, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 1220, 46, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 85, 128, 363, 406, 0, 0, + 0, 0, 0, 0, 0, 0, 449, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -103, 0, 0, 185, 492, 727, 770, + 813, 856, 1091, 0, 0, 0, 0, 0, 0, 1134, + 1177, 0, 0, 0, 0, 42, 1220, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -102, 0, 0, -101, + 0, 0, 0, 0, 0, 0, 0, 0, -99, 0, +}; +static YYCONST short yygindex[] = { 0, + -7, -69, 3, -66, 458, 9, -26, 52, 27, -63, + -32, 54, 0, -35, 2, -59, +}; +#define YYTABLESIZE 1865 +static YYCONST short yytable[] = { 49, + 8, 50, 42, 39, 105, 116, 122, 63, 37, 8, + 109, 113, 64, 65, 94, 95, 96, 97, 128, 137, + 140, 56, 57, 62, 68, 63, 76, 77, 69, 83, + 40, 41, 51, 53, 54, 72, 73, 86, 71, 132, + 1, 10, 78, 79, 80, 2, 74, 75, 66, 108, + 10, 129, 70, 114, 133, 134, 46, 47, 48, 135, + 87, 81, 123, 83, 82, 0, 59, 60, 61, 62, + 76, 126, 138, 0, 103, 104, 83, 106, 0, 83, + 78, 79, 80, 0, 42, 0, 78, 79, 80, 72, + 73, 0, 0, 42, 8, 0, 119, 120, 121, 81, + 124, 125, 82, 0, 0, 81, 0, 0, 82, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, + 127, 0, 83, 8, 130, 8, 8, 43, 0, 0, + 0, 83, 0, 0, 0, 10, 43, 0, 0, 0, + 130, 51, 0, 0, 139, 117, 117, 117, 117, 0, + 0, 0, 0, 0, 0, 0, 40, 41, 0, 40, + 41, 0, 40, 41, 10, 112, 10, 10, 94, 95, + 96, 97, 112, 136, 136, 56, 57, 62, 42, 63, + 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 42, 0, 42, + 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 43, 0, 43, 43, 0, 0, 0, 0, 0, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, + 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 36, + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 0, 0, 44, 42, 42, 42, 42, 42, 42, 42, + 42, 44, 0, 0, 0, 42, 42, 42, 42, 0, + 42, 42, 0, 42, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 0, 0, 45, 43, 43, 43, 43, + 43, 43, 43, 43, 45, 0, 0, 0, 43, 43, + 43, 43, 0, 43, 43, 0, 43, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 36, 36, 0, 36, 36, 0, 0, 53, 0, + 0, 0, 36, 36, 0, 0, 44, 53, 0, 0, + 36, 36, 36, 36, 0, 0, 55, 56, 57, 58, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, + 67, 0, 36, 0, 0, 44, 0, 44, 44, 0, + 0, 47, 0, 0, 0, 0, 0, 0, 0, 45, + 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 88, 89, 0, 0, 0, 0, 90, 91, 92, 93, + 0, 0, 0, 100, 0, 0, 0, 101, 45, 0, + 45, 45, 0, 107, 0, 110, 0, 0, 0, 111, + 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 0, 53, 53, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 47, 0, 47, 47, 0, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, + 0, 44, 44, 44, 44, 44, 44, 44, 44, 0, + 0, 0, 0, 44, 44, 44, 44, 0, 44, 44, + 0, 44, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 0, 0, 45, 45, 45, 45, 45, 45, + 45, 45, 0, 0, 0, 0, 45, 45, 45, 45, + 0, 45, 45, 0, 45, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 0, 0, 46, 53, 53, 53, + 53, 53, 53, 53, 53, 46, 0, 0, 0, 53, + 53, 53, 53, 0, 53, 53, 0, 53, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 0, 0, 48, + 47, 47, 47, 47, 47, 47, 47, 47, 48, 0, + 0, 0, 47, 47, 47, 47, 0, 47, 47, 0, + 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, + 46, 49, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, + 0, 46, 46, 0, 0, 51, 0, 0, 0, 0, + 0, 0, 0, 48, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 48, 0, 48, 48, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 49, 0, 49, 49, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, + 51, 51, 0, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 0, 0, 0, 46, 46, 46, 46, 46, + 46, 46, 46, 0, 0, 0, 0, 46, 46, 46, + 46, 0, 46, 46, 0, 46, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 0, 0, 0, 48, 48, + 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, + 48, 48, 48, 48, 0, 48, 48, 0, 48, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 0, 0, + 50, 49, 49, 49, 49, 49, 49, 49, 49, 50, + 0, 0, 0, 49, 49, 49, 49, 0, 49, 49, + 0, 49, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 0, 0, 52, 51, 51, 51, 51, 51, 51, + 51, 51, 52, 0, 0, 0, 51, 51, 51, 51, + 0, 51, 51, 0, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, + 0, 0, 0, 0, 50, 54, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 50, 0, 50, 50, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 0, 52, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 52, 0, 52, 52, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, + 0, 54, 54, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 19, 19, 0, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 0, 0, 0, 50, + 50, 50, 50, 50, 50, 50, 50, 0, 0, 0, + 0, 50, 50, 50, 50, 0, 50, 50, 0, 50, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 0, + 29, 0, 52, 52, 52, 52, 52, 52, 52, 52, + 0, 0, 0, 0, 52, 52, 52, 52, 0, 52, + 52, 0, 52, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 29, 0, 0, 54, 54, 54, 54, 54, + 54, 54, 54, 0, 0, 0, 0, 54, 54, 54, + 54, 0, 54, 54, 0, 54, 19, 19, 19, 0, + 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 27, 29, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, + 19, 19, 19, 19, 0, 19, 19, 0, 19, 0, + 0, 0, 0, 0, 30, 0, 102, 28, 0, 0, + 0, 0, 0, 0, 0, 29, 0, 27, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 30, 0, 0, 28, + 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, + 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 30, 0, 0, 28, 0, 0, 0, 0, 0, 0, + 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, + 0, 0, 28, 0, 0, 0, 0, 0, 0, 27, + 1, 0, 0, 2, 3, 4, 5, 6, 0, 0, + 0, 7, 8, 9, 10, 11, 12, 0, 0, 0, + 0, 13, 14, 15, 16, 17, 18, 19, 30, 0, + 0, 28, 20, 21, 22, 23, 0, 24, 25, 0, + 26, 0, 1, 0, 0, 2, 3, 4, 5, 6, + 115, 0, 0, 7, 8, 9, 10, 11, 12, 0, + 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, + 0, 0, 0, 0, 20, 21, 22, 23, 0, 24, + 25, 0, 26, 0, 0, 0, 1, 0, 0, 2, + 3, 4, 5, 6, 0, 0, 0, 7, 8, 9, + 10, 11, 12, 0, 0, 0, 0, 13, 14, 15, + 16, 17, 18, 19, 0, 0, 0, 0, 20, 21, + 22, 23, 0, 24, 25, 1, 26, 0, 2, 3, + 4, 5, 6, 0, 0, 0, 7, 8, 9, 10, + 11, 12, 0, 0, 0, 0, 13, 14, 15, 16, + 17, 18, 19, 0, 0, 0, 0, 0, 0, 22, + 23, 0, 24, 25, 0, 26, 0, 2, 3, 4, + 5, 6, 0, 0, 0, 7, 8, 9, 10, 11, + 12, 0, 0, 0, 0, 13, 14, 15, 16, 17, + 18, 19, 0, 0, 0, 0, 0, 0, 22, 23, + 0, 24, 25, 0, 26, +}; +static YYCONST short yycheck[] = { 123, + 0, 125, 123, 1, 74, 123, 125, 123, 0, 9, + 77, 125, 20, 21, 287, 288, 289, 290, 125, 125, + 125, 125, 125, 125, 281, 125, 260, 261, 280, 37, + 280, 281, 6, 7, 8, 257, 258, 123, 30, 123, + 0, 0, 276, 277, 278, 0, 268, 269, 22, 76, + 9, 115, 26, 86, 124, 125, 3, 4, 5, 126, + 52, 295, 98, 71, 298, -1, 15, 16, 17, 18, + 260, 261, 132, -1, 72, 73, 84, 75, -1, 87, + 276, 277, 278, -1, 0, -1, 276, 277, 278, 257, + 258, -1, -1, 9, 94, -1, 95, 96, 97, 295, + 268, 269, 298, -1, -1, 295, -1, -1, 298, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 127, + 112, -1, 130, 123, 116, 125, 126, 0, -1, -1, + -1, 139, -1, -1, -1, 94, 9, -1, -1, -1, + 132, 115, -1, -1, 136, 94, 95, 96, 97, -1, + -1, -1, -1, -1, -1, -1, 280, 281, -1, 280, + 281, -1, 280, 281, 123, 279, 125, 126, 287, 288, + 289, 290, 279, 279, 279, 279, 279, 279, 94, 279, + -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 123, -1, 125, + 126, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 94, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 123, -1, 125, 126, -1, -1, -1, -1, -1, 259, + 260, 261, 262, 263, 264, 265, 266, 267, -1, -1, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, -1, -1, -1, + -1, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 125, + -1, 270, 271, 272, 273, 274, 275, 276, 277, 278, + 279, 280, 281, 282, 283, 284, 285, 286, -1, -1, + -1, -1, 291, 292, 293, 294, 295, 296, 297, 298, + 299, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + -1, -1, 0, 279, 280, 281, 282, 283, 284, 285, + 286, 9, -1, -1, -1, 291, 292, 293, 294, -1, + 296, 297, -1, 299, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, -1, -1, 0, 279, 280, 281, 282, + 283, 284, 285, 286, 9, -1, -1, -1, 291, 292, + 293, 294, -1, 296, 297, -1, 299, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 257, 258, -1, 260, 261, -1, -1, 0, -1, + -1, -1, 268, 269, -1, -1, 94, 9, -1, -1, + 276, 277, 278, 279, -1, -1, 9, 10, 11, 12, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 295, + 23, -1, 298, -1, -1, 123, -1, 125, 126, -1, + -1, 0, -1, -1, -1, -1, -1, -1, -1, 94, + 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 53, 54, -1, -1, -1, -1, 59, 60, 61, 62, + -1, -1, -1, 66, -1, -1, -1, 70, 123, -1, + 125, 126, -1, 76, -1, 78, -1, -1, -1, 82, + -1, -1, 94, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 123, -1, 125, 126, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 94, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 123, -1, 125, 126, -1, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, -1, -1, + -1, 279, 280, 281, 282, 283, 284, 285, 286, -1, + -1, -1, -1, 291, 292, 293, 294, -1, 296, 297, + -1, 299, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, -1, -1, -1, 279, 280, 281, 282, 283, 284, + 285, 286, -1, -1, -1, -1, 291, 292, 293, 294, + -1, 296, 297, -1, 299, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 274, 275, -1, -1, 0, 279, 280, 281, + 282, 283, 284, 285, 286, 9, -1, -1, -1, 291, + 292, 293, 294, -1, 296, 297, -1, 299, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 275, -1, -1, 0, + 279, 280, 281, 282, 283, 284, 285, 286, 9, -1, + -1, -1, 291, 292, 293, 294, -1, 296, 297, -1, + 299, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, + 94, 9, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 123, + -1, 125, 126, -1, -1, 0, -1, -1, -1, -1, + -1, -1, -1, 94, 9, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 123, -1, 125, 126, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 94, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 123, -1, 125, 126, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 94, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 123, -1, + 125, 126, -1, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, -1, -1, -1, 279, 280, 281, 282, 283, + 284, 285, 286, -1, -1, -1, -1, 291, 292, 293, + 294, -1, 296, 297, -1, 299, 257, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, -1, -1, -1, 279, 280, + 281, 282, 283, 284, 285, 286, -1, -1, -1, -1, + 291, 292, 293, 294, -1, 296, 297, -1, 299, 257, + 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, -1, -1, + 0, 279, 280, 281, 282, 283, 284, 285, 286, 9, + -1, -1, -1, 291, 292, 293, 294, -1, 296, 297, + -1, 299, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, -1, -1, 0, 279, 280, 281, 282, 283, 284, + 285, 286, 9, -1, -1, -1, 291, 292, 293, 294, + -1, 296, 297, -1, 299, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, + -1, -1, -1, -1, 94, 9, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 123, -1, 125, 126, -1, -1, 0, + -1, -1, -1, -1, -1, -1, -1, 94, 9, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 123, -1, 125, 126, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 123, + -1, 125, 126, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 94, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 123, -1, 125, 126, -1, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 275, -1, -1, -1, 279, + 280, 281, 282, 283, 284, 285, 286, -1, -1, -1, + -1, 291, 292, 293, 294, -1, 296, 297, -1, 299, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, -1, + 9, -1, 279, 280, 281, 282, 283, 284, 285, 286, + -1, -1, -1, -1, 291, 292, 293, 294, -1, 296, + 297, -1, 299, 257, 258, 259, 260, 261, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 275, 9, -1, -1, 279, 280, 281, 282, 283, + 284, 285, 286, -1, -1, -1, -1, 291, 292, 293, + 294, -1, 296, 297, -1, 299, 257, 258, 259, -1, + -1, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 94, 9, -1, 279, 280, + 281, 282, 283, 284, 285, 286, -1, -1, -1, -1, + 291, 292, 293, 294, -1, 296, 297, -1, 299, -1, + -1, -1, -1, -1, 123, -1, 125, 126, -1, -1, + -1, -1, -1, -1, -1, 9, -1, 94, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 123, -1, -1, 126, + -1, -1, -1, -1, 9, -1, -1, -1, -1, -1, + -1, 94, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 123, -1, -1, 126, -1, -1, -1, -1, -1, -1, + 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 123, + -1, -1, 126, -1, -1, -1, -1, -1, -1, 94, + 259, -1, -1, 262, 263, 264, 265, 266, -1, -1, + -1, 270, 271, 272, 273, 274, 275, -1, -1, -1, + -1, 280, 281, 282, 283, 284, 285, 286, 123, -1, + -1, 126, 291, 292, 293, 294, -1, 296, 297, -1, + 299, -1, 259, -1, -1, 262, 263, 264, 265, 266, + 267, -1, -1, 270, 271, 272, 273, 274, 275, -1, + -1, -1, -1, 280, 281, 282, 283, 284, 285, 286, + -1, -1, -1, -1, 291, 292, 293, 294, -1, 296, + 297, -1, 299, -1, -1, -1, 259, -1, -1, 262, + 263, 264, 265, 266, -1, -1, -1, 270, 271, 272, + 273, 274, 275, -1, -1, -1, -1, 280, 281, 282, + 283, 284, 285, 286, -1, -1, -1, -1, 291, 292, + 293, 294, -1, 296, 297, 259, 299, -1, 262, 263, + 264, 265, 266, -1, -1, -1, 270, 271, 272, 273, + 274, 275, -1, -1, -1, -1, 280, 281, 282, 283, + 284, 285, 286, -1, -1, -1, -1, -1, -1, 293, + 294, -1, 296, 297, -1, 299, -1, 262, 263, 264, + 265, 266, -1, -1, -1, 270, 271, 272, 273, 274, + 275, -1, -1, -1, -1, 280, 281, 282, 283, 284, + 285, 286, -1, -1, -1, -1, -1, -1, 293, 294, + -1, 296, 297, -1, 299, +}; +#define YYFINAL 31 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 314 +#if YYDEBUG +static YYCONST char *YYCONST yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,"'\\t'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'","'~'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"OVER", +"SMALLOVER","SQRT","SUB","SUP","LPILE","RPILE","CPILE","PILE","LEFT","RIGHT", +"TO","FROM","SIZE","FONT","ROMAN","BOLD","ITALIC","FAT","ACCENT","BAR","UNDER", +"ABOVE","TEXT","QUOTED_TEXT","FWD","BACK","DOWN","UP","MATRIX","COL","LCOL", +"RCOL","CCOL","MARK","LINEUP","TYPE","VCENTER","PRIME","SPLIT","NOSPLIT", +"UACCENT","SPECIAL","SPACE","GFONT","GSIZE","DEFINE","NDEFINE","TDEFINE", +"SDEFINE","UNDEF","IFDEF","INCLUDE","DELIM","CHARTYPE","SET","GRFONT","GBFONT", +}; +static YYCONST char *YYCONST yyrule[] = { +"$accept : top", +"top :", +"top : equation", +"equation : mark", +"equation : equation mark", +"mark : from_to", +"mark : MARK mark", +"mark : LINEUP mark", +"from_to : sqrt_over", +"from_to : sqrt_over TO from_to", +"from_to : sqrt_over FROM sqrt_over", +"from_to : sqrt_over FROM sqrt_over TO from_to", +"from_to : sqrt_over FROM sqrt_over FROM from_to", +"sqrt_over : script", +"sqrt_over : SQRT sqrt_over", +"sqrt_over : sqrt_over OVER sqrt_over", +"sqrt_over : sqrt_over SMALLOVER sqrt_over", +"script : nonsup", +"script : simple SUP script", +"nonsup : simple", +"nonsup : simple SUB nonsup", +"nonsup : simple SUB simple SUP script", +"simple : TEXT", +"simple : QUOTED_TEXT", +"simple : SPLIT QUOTED_TEXT", +"simple : NOSPLIT TEXT", +"simple : '^'", +"simple : '~'", +"simple : '\\t'", +"simple : '{' equation '}'", +"simple : PILE pile_arg", +"simple : LPILE pile_arg", +"simple : RPILE pile_arg", +"simple : CPILE pile_arg", +"simple : MATRIX '{' column_list '}'", +"simple : LEFT delim equation RIGHT delim", +"simple : LEFT delim equation", +"simple : simple BAR", +"simple : simple UNDER", +"simple : simple PRIME", +"simple : simple ACCENT simple", +"simple : simple UACCENT simple", +"simple : ROMAN simple", +"simple : BOLD simple", +"simple : ITALIC simple", +"simple : FAT simple", +"simple : FONT text simple", +"simple : SIZE text simple", +"simple : FWD number simple", +"simple : BACK number simple", +"simple : UP number simple", +"simple : DOWN number simple", +"simple : TYPE text simple", +"simple : VCENTER simple", +"simple : SPECIAL text simple", +"number : text", +"pile_element_list : equation", +"pile_element_list : pile_element_list ABOVE equation", +"pile_arg : '{' pile_element_list '}'", +"pile_arg : number '{' pile_element_list '}'", +"column_list : column", +"column_list : column_list column", +"column_element_list : equation", +"column_element_list : column_element_list ABOVE equation", +"column_arg : '{' column_element_list '}'", +"column_arg : number '{' column_element_list '}'", +"column : COL column_arg", +"column : LCOL column_arg", +"column : RCOL column_arg", +"column : CCOL column_arg", +"text : TEXT", +"text : QUOTED_TEXT", +"delim : text", +"delim : '{'", +"delim : '}'", +}; +#endif +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +YYSTYPE yyval; +YYSTYPE yylval; +static short *yyss; +static YYSTYPE *yyvs; +static int yystacksize; +static int yygrow (); +static YYPTR yymalloc YYPARAMS((unsigned)); +static YYPTR yyrealloc YYPARAMS((YYPTR, unsigned)); +#define yyfree(x) free(x) +#define YYABORT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +#if YYDEBUG +#ifdef __cplusplus +extern "C" char *getenv(); +#else +extern char *getenv(); +#endif +#endif + +int +yyparse() +{ + register int yym, yyn, yystate; + register YYSTYPE *yyvsp; + register short *yyssp; + short *yysse; +#if YYDEBUG + register YYCONST char *yys; + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == 0) + { + yyss = (short *) yymalloc (YYINITDEPTH * sizeof (short)); + if (yyss == 0) + goto yyabort; + yyvs = (YYSTYPE *) yymalloc (YYINITDEPTH * sizeof (YYSTYPE)); + if (yyvs == 0) + { + yyfree (yyss); + goto yyabort; + } + yystacksize = YYINITDEPTH; + } + yysse = yyss + yystacksize - 1; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, reading %d (%s)\n", yystate, + yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, shifting to state %d\n", + yystate, yytable[yyn]); +#endif + if (yyssp >= yysse) + { + /* FIXME: Rework so there's only one of these. */ + int depth = yyssp - yyss; + if (yygrow () != 0) + goto yyoverflow; + yysse = yyss + yystacksize - 1; + yyssp = yyss + depth; + yyvsp = yyvs + depth; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, error recovery shifting\ + to state %d\n", *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysse) + { + int depth = yyssp - yyss; + if (yygrow () != 0) + goto yyoverflow; + yysse = yyss + yystacksize - 1; + yyssp = yyss + depth; + yyvsp = yyvs + depth; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("yydebug: error recovery discarding state %d\n", + *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, error recovery discards token %d (%s)\n", + yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, reducing by rule %d (%s)\n", + yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 2: +#line 126 "eqn.y" +{ yyvsp[0].b->top_level(); non_empty_flag = 1; } +break; +case 3: +#line 131 "eqn.y" +{ yyval.b = yyvsp[0].b; } +break; +case 4: +#line 133 "eqn.y" +{ + list_box *lb = yyvsp[-1].b->to_list_box(); + if (!lb) + lb = new list_box(yyvsp[-1].b); + lb->append(yyvsp[0].b); + yyval.b = lb; + } +break; +case 5: +#line 144 "eqn.y" +{ yyval.b = yyvsp[0].b; } +break; +case 6: +#line 146 "eqn.y" +{ yyval.b = make_mark_box(yyvsp[0].b); } +break; +case 7: +#line 148 "eqn.y" +{ yyval.b = make_lineup_box(yyvsp[0].b); } +break; +case 8: +#line 153 "eqn.y" +{ yyval.b = yyvsp[0].b; } +break; +case 9: +#line 155 "eqn.y" +{ yyval.b = make_limit_box(yyvsp[-2].b, 0, yyvsp[0].b); } +break; +case 10: +#line 157 "eqn.y" +{ yyval.b = make_limit_box(yyvsp[-2].b, yyvsp[0].b, 0); } +break; +case 11: +#line 159 "eqn.y" +{ yyval.b = make_limit_box(yyvsp[-4].b, yyvsp[-2].b, yyvsp[0].b); } +break; +case 12: +#line 161 "eqn.y" +{ yyval.b = make_limit_box(yyvsp[-4].b, make_limit_box(yyvsp[-2].b, yyvsp[0].b, 0), 0); } +break; +case 13: +#line 166 "eqn.y" +{ yyval.b = yyvsp[0].b; } +break; +case 14: +#line 168 "eqn.y" +{ yyval.b = make_sqrt_box(yyvsp[0].b); } +break; +case 15: +#line 170 "eqn.y" +{ yyval.b = make_over_box(yyvsp[-2].b, yyvsp[0].b); } +break; +case 16: +#line 172 "eqn.y" +{ yyval.b = make_small_over_box(yyvsp[-2].b, yyvsp[0].b); } +break; +case 17: +#line 177 "eqn.y" +{ yyval.b = yyvsp[0].b; } +break; +case 18: +#line 179 "eqn.y" +{ yyval.b = make_script_box(yyvsp[-2].b, 0, yyvsp[0].b); } +break; +case 19: +#line 184 "eqn.y" +{ yyval.b = yyvsp[0].b; } +break; +case 20: +#line 186 "eqn.y" +{ yyval.b = make_script_box(yyvsp[-2].b, yyvsp[0].b, 0); } +break; +case 21: +#line 188 "eqn.y" +{ yyval.b = make_script_box(yyvsp[-4].b, yyvsp[-2].b, yyvsp[0].b); } +break; +case 22: +#line 193 "eqn.y" +{ yyval.b = split_text(yyvsp[0].str); } +break; +case 23: +#line 195 "eqn.y" +{ yyval.b = new quoted_text_box(yyvsp[0].str); } +break; +case 24: +#line 197 "eqn.y" +{ yyval.b = split_text(yyvsp[0].str); } +break; +case 25: +#line 199 "eqn.y" +{ yyval.b = new quoted_text_box(yyvsp[0].str); } +break; +case 26: +#line 201 "eqn.y" +{ yyval.b = new half_space_box; } +break; +case 27: +#line 203 "eqn.y" +{ yyval.b = new space_box; } +break; +case 28: +#line 205 "eqn.y" +{ yyval.b = new tab_box; } +break; +case 29: +#line 207 "eqn.y" +{ yyval.b = yyvsp[-1].b; } +break; +case 30: +#line 209 "eqn.y" +{ yyvsp[0].pb->set_alignment(CENTER_ALIGN); yyval.b = yyvsp[0].pb; } +break; +case 31: +#line 211 "eqn.y" +{ yyvsp[0].pb->set_alignment(LEFT_ALIGN); yyval.b = yyvsp[0].pb; } +break; +case 32: +#line 213 "eqn.y" +{ yyvsp[0].pb->set_alignment(RIGHT_ALIGN); yyval.b = yyvsp[0].pb; } +break; +case 33: +#line 215 "eqn.y" +{ yyvsp[0].pb->set_alignment(CENTER_ALIGN); yyval.b = yyvsp[0].pb; } +break; +case 34: +#line 217 "eqn.y" +{ yyval.b = yyvsp[-1].mb; } +break; +case 35: +#line 219 "eqn.y" +{ yyval.b = make_delim_box(yyvsp[-3].str, yyvsp[-2].b, yyvsp[0].str); } +break; +case 36: +#line 221 "eqn.y" +{ yyval.b = make_delim_box(yyvsp[-1].str, yyvsp[0].b, 0); } +break; +case 37: +#line 223 "eqn.y" +{ yyval.b = make_overline_box(yyvsp[-1].b); } +break; +case 38: +#line 225 "eqn.y" +{ yyval.b = make_underline_box(yyvsp[-1].b); } +break; +case 39: +#line 227 "eqn.y" +{ yyval.b = make_prime_box(yyvsp[-1].b); } +break; +case 40: +#line 229 "eqn.y" +{ yyval.b = make_accent_box(yyvsp[-2].b, yyvsp[0].b); } +break; +case 41: +#line 231 "eqn.y" +{ yyval.b = make_uaccent_box(yyvsp[-2].b, yyvsp[0].b); } +break; +case 42: +#line 233 "eqn.y" +{ yyval.b = new font_box(strsave(get_grfont()), yyvsp[0].b); } +break; +case 43: +#line 235 "eqn.y" +{ yyval.b = new font_box(strsave(get_gbfont()), yyvsp[0].b); } +break; +case 44: +#line 237 "eqn.y" +{ yyval.b = new font_box(strsave(get_gfont()), yyvsp[0].b); } +break; +case 45: +#line 239 "eqn.y" +{ yyval.b = new fat_box(yyvsp[0].b); } +break; +case 46: +#line 241 "eqn.y" +{ yyval.b = new font_box(yyvsp[-1].str, yyvsp[0].b); } +break; +case 47: +#line 243 "eqn.y" +{ yyval.b = new size_box(yyvsp[-1].str, yyvsp[0].b); } +break; +case 48: +#line 245 "eqn.y" +{ yyval.b = new hmotion_box(yyvsp[-1].n, yyvsp[0].b); } +break; +case 49: +#line 247 "eqn.y" +{ yyval.b = new hmotion_box(-yyvsp[-1].n, yyvsp[0].b); } +break; +case 50: +#line 249 "eqn.y" +{ yyval.b = new vmotion_box(yyvsp[-1].n, yyvsp[0].b); } +break; +case 51: +#line 251 "eqn.y" +{ yyval.b = new vmotion_box(-yyvsp[-1].n, yyvsp[0].b); } +break; +case 52: +#line 253 "eqn.y" +{ yyvsp[0].b->set_spacing_type(yyvsp[-1].str); yyval.b = yyvsp[0].b; } +break; +case 53: +#line 255 "eqn.y" +{ yyval.b = new vcenter_box(yyvsp[0].b); } +break; +case 54: +#line 257 "eqn.y" +{ yyval.b = make_special_box(yyvsp[-1].str, yyvsp[0].b); } +break; +case 55: +#line 262 "eqn.y" +{ + int n; + if (sscanf(yyvsp[0].str, "%d", &n) == 1) + yyval.n = n; + a_delete yyvsp[0].str; + } +break; +case 56: +#line 272 "eqn.y" +{ yyval.pb = new pile_box(yyvsp[0].b); } +break; +case 57: +#line 274 "eqn.y" +{ yyvsp[-2].pb->append(yyvsp[0].b); yyval.pb = yyvsp[-2].pb; } +break; +case 58: +#line 279 "eqn.y" +{ yyval.pb = yyvsp[-1].pb; } +break; +case 59: +#line 281 "eqn.y" +{ yyvsp[-1].pb->set_space(yyvsp[-3].n); yyval.pb = yyvsp[-1].pb; } +break; +case 60: +#line 286 "eqn.y" +{ yyval.mb = new matrix_box(yyvsp[0].col); } +break; +case 61: +#line 288 "eqn.y" +{ yyvsp[-1].mb->append(yyvsp[0].col); yyval.mb = yyvsp[-1].mb; } +break; +case 62: +#line 293 "eqn.y" +{ yyval.col = new column(yyvsp[0].b); } +break; +case 63: +#line 295 "eqn.y" +{ yyvsp[-2].col->append(yyvsp[0].b); yyval.col = yyvsp[-2].col; } +break; +case 64: +#line 300 "eqn.y" +{ yyval.col = yyvsp[-1].col; } +break; +case 65: +#line 302 "eqn.y" +{ yyvsp[-1].col->set_space(yyvsp[-3].n); yyval.col = yyvsp[-1].col; } +break; +case 66: +#line 307 "eqn.y" +{ yyvsp[0].col->set_alignment(CENTER_ALIGN); yyval.col = yyvsp[0].col; } +break; +case 67: +#line 309 "eqn.y" +{ yyvsp[0].col->set_alignment(LEFT_ALIGN); yyval.col = yyvsp[0].col; } +break; +case 68: +#line 311 "eqn.y" +{ yyvsp[0].col->set_alignment(RIGHT_ALIGN); yyval.col = yyvsp[0].col; } +break; +case 69: +#line 313 "eqn.y" +{ yyvsp[0].col->set_alignment(CENTER_ALIGN); yyval.col = yyvsp[0].col; } +break; +case 70: +#line 317 "eqn.y" +{ yyval.str = yyvsp[0].str; } +break; +case 71: +#line 319 "eqn.y" +{ yyval.str = yyvsp[0].str; } +break; +case 72: +#line 324 "eqn.y" +{ yyval.str = yyvsp[0].str; } +break; +case 73: +#line 326 "eqn.y" +{ yyval.str = strsave("{"); } +break; +case 74: +#line 328 "eqn.y" +{ yyval.str = strsave("}"); } +break; +#line 1168 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: after reduction, shifting from state 0 to\ + state %d\n", YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, reading %d (%s)\n", + YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("yydebug: after reduction, shifting from state %d \ +to state %d\n", *yyssp, yystate); +#endif + if (yyssp >= yysse) + { + int depth = yyssp - yyss; + if (yygrow () != 0) + goto yyoverflow; + yysse = yyss + yystacksize - 1; + yyssp = yyss + depth; + yyvsp = yyvs + depth; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} + +static int +yygrow () +{ + int old_stacksize = yystacksize; + short *new_yyss; + YYSTYPE *new_yyvs; + + if (yystacksize >= YYMAXDEPTH) + return (1); + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#if YYDEBUG + if (yydebug) + printf("yydebug: growing stack size from %d to %d\n", + old_stacksize, yystacksize); +#endif + new_yyss = (short *) yyrealloc (yyss, yystacksize * sizeof (short)); + if (new_yyss == 0) + return (1); + new_yyvs = (YYSTYPE *) yyrealloc (yyvs, yystacksize * sizeof (YYSTYPE)); + if (new_yyvs == 0) + { + yyfree (new_yyss); + return (1); + } + yyss = new_yyss; + yyvs = new_yyvs; + return (0); +} + +static YYPTR +YYDEFUN (yymalloc, (bytes), unsigned bytes) +{ + YYPTR ptr = (YYPTR) malloc (bytes); + if (ptr != 0) return (ptr); + yyerror ("yyparse: memory exhausted"); + return (0); +} + +static YYPTR +YYDEFUN (yyrealloc, (old, bytes), YYPTR old YYAND unsigned bytes) +{ + YYPTR ptr = (YYPTR) realloc (old, bytes); + if (ptr != 0) return (ptr); + yyerror ("yyparse: memory exhausted"); + return (0); +} diff --git a/contrib/groff/src/preproc/eqn/eqn.h b/contrib/groff/src/preproc/eqn/eqn.h new file mode 100644 index 000000000000..70b19271cbc1 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/eqn.h @@ -0,0 +1,51 @@ +// -*- 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 <stdio.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <errno.h> +#include "cset.h" +#include "errarg.h" +#include "error.h" +#include "lib.h" + +#include "box.h" + +extern char start_delim; +extern char end_delim; +extern int non_empty_flag; +extern int inline_flag; +extern int draw_flag; +extern int one_size_reduction_flag; +extern int compatible_flag; +extern int nroff; + +void init_lex(const char *str, const char *filename, int lineno); +void lex_error(const char *message, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); + +void init_table(const char *device); + +// prefix for all registers, strings, macros +#define PREFIX "0" diff --git a/contrib/groff/src/preproc/eqn/eqn.man b/contrib/groff/src/preproc/eqn/eqn.man new file mode 100644 index 000000000000..381d97de33ab --- /dev/null +++ b/contrib/groff/src/preproc/eqn/eqn.man @@ -0,0 +1,882 @@ +.ig \"-*- nroff -*- +Copyright (C) 1989-2000 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. +.. +.ie \n(.V<\n(.v .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X +.el .ds tx TeX +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.\" The BSD man macros can't handle " in arguments to font change macros, +.\" so use \(ts instead of ". +.tr \(ts" +.TH @G@EQN @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +@g@eqn \- format equations for troff +.SH SYNOPSIS +.nr a \n(.j +.ad l +.nr i \n(.i +.in +\w'\fB@g@eqn 'u +.ti \niu +.B @g@eqn +.de OP +.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" +.el .RB "[\ " "\\$1" "\ ]" +.. +.OP \-rvCNR +.OP \-d cc +.OP \-T name +.OP \-M dir +.OP \-f F +.OP \-s n +.OP \-p n +.OP \-m n +.RI "[\ " files\|.\|.\|. "\ ]" +.br +.ad \na +.PP +It is possible to have whitespace between a command line option and its +parameter. +.SH DESCRIPTION +This manual page describes the GNU version of +.BR eqn , +which is part of the groff document formatting system. +.B eqn +compiles descriptions of equations embedded within +.B troff +input files into commands that are understood by +.BR troff . +Normally, it should be invoked using the +.B \-e +option of +.BR groff . +The syntax is quite compatible with Unix eqn. +The output of GNU eqn cannot be processed with Unix troff; +it must be processed with GNU troff. +If no files are given on the command line, the standard input +will be read. +A filename of +.B \- +will cause the standard input to be read. +.LP +.B eqn +searches for the file +.B eqnrc +in the directories given with the +.B \-M +option first, then in +.BR @SYSTEMMACRODIR@ , +.BR @LOCALMACRODIR@ , +and finally in the standard macro directory +.BR @MACRODIR@ . +If it exists, eqn will process it before the other input files. +The +.B \-R +option prevents this. +.LP +GNU eqn does not provide the functionality of neqn: +it does not support low-resolution, typewriter-like devices +(although it may work adequately for very simple input). +.SH OPTIONS +.TP +.B \-C +Recognize +.B .EQ +and +.B .EN +even when followed by a character other than space or newline. +.TP +.B \-N +Don't allow newlines within delimiters. +This option allows +.B eqn +to recover better from missing closing delimiters. +.TP +.B \-v +Print the version number. +.TP +.B \-r +Only one size reduction. +.TP +.BI \-m n +The minimum point-size is +.IR n . +eqn will not reduce the size of subscripts or superscripts to +a smaller size than +.IR n . +.TP +.BI \-T name +The output is for device +.IR name . +The only effect of this is to define a macro +.I name +with a value of +.BR 1 . +Typically +.B eqnrc +will use this to provide definitions appropriate for the output device. +The default output device is +.BR @DEVICE@ . +.TP +.BI \-M dir +Search +.I dir +for +.B eqnrc +before the default directories. +.TP +.B \-R +Don't load +.BR eqnrc . +.TP +.BI \-f F +This is equivalent to a +.BI gfont\ F +command. +.TP +.BI \-s n +This is equivalent to a +.BI gsize\ n +command. +This option is deprecated. +eqn will normally set equations at whatever the current point size +is when the equation is encountered. +.TP +.BI \-p n +This says that subscripts and superscripts should be +.I n +points smaller than the surrounding text. +This option is deprecated. +Normally eqn makes sets subscripts and superscripts at 70% +of the size of the surrounding text. +.SH USAGE +Only the differences between GNU eqn and Unix eqn are described here. +.LP +Most of the new features of GNU eqn +are based on \*(tx. +There are some references to the differences between \*(tx and GNU eqn below; +these may safely be ignored if you do not know \*(tx. +.SS Automatic spacing +.LP +.B eqn +gives each component of an equation a type, and adjusts the spacing +between components using that type. +Possible types are: +.TP \w'punctuation'u+2n +ordinary +an ordinary character such as 1 or +.IR x ; +.TP +operator +a large operator such as +.ds Su \s+5\(*S\s0 +.if \n(.g .if !c\(*S .ds Su the summation operator +\*(Su; +.TP +binary +a binary operator such as +; +.TP +relation +a relation such as =; +.TP +opening +a opening bracket such as (; +.TP +closing +a closing bracket such as ); +.TP +punctuation +a punctuation character such as ,; +.TP +inner +a subformula contained within brackets; +.TP +suppress +spacing that suppresses automatic spacing adjustment. +.LP +Components of an equation get a type in one of two ways. +.TP +.BI type\ t\ e +This yields an equation component that contains +.I e +but that has type +.IR t , +where +.I t +is one of the types mentioned above. +For example, +.B times +is defined as +.RS +.IP +.B +type "binary" \e(mu +.RE +.IP +The name of the type doesn't have to be quoted, but quoting protects +from macro expansion. +.TP +.BI chartype\ t\ text +Unquoted groups of characters are split up into individual characters, +and the type of each character is looked up; +this changes the type that is stored for each character; +it says that the characters in +.I text +from now on have type +.IR t . +For example, +.RS +.IP +.B +chartype "punctuation" .,;: +.RE +.IP +would make the characters +.B .,;: +have type punctuation +whenever they subsequently appeared in an equation. +The type +.I t +can also be +.B letter +or +.BR digit ; +in these cases +.B chartype +changes the font type of the characters. +See the Fonts subsection. +.SS New primitives +.TP +.IB e1\ smallover\ e2 +This is similar to +.BR over ; +.B smallover +reduces the size of +.I e1 +and +.IR e2 ; +it also puts less vertical space between +.I e1 +or +.I e2 +and the fraction bar. +The +.B over +primitive corresponds to the \*(tx +.B \eover +primitive in display styles; +.B smallover +corresponds to +.B \eover +in non-display styles. +.TP +.BI vcenter\ e +This vertically centers +.I e +about the math axis. +The math axis is the vertical position about which characters +such as + and - are centered; also it is the vertical position +used for the bar of fractions. +For example, +.B sum +is defined as +.RS +.IP +.B +{ type "operator" vcenter size +5 \e(*S } +.RE +.TP +.IB e1\ accent\ e2 +This sets +.I e2 +as an accent over +.IR e1 . +.I e2 +is assumed to be at the correct height for a lowercase letter; +.I e2 +will be moved down according if +.I e1 +is taller or shorter than a lowercase letter. +For example, +.B hat +is defined as +.RS +.IP +.B +accent { "^" } +.RE +.IP +.BR dotdot , +.BR dot , +.BR tilde , +.B vec +and +.B dyad +are also defined using the +.B accent +primitive. +.TP +.IB e1\ uaccent\ e2 +This sets +.I e2 +as an accent under +.IR e1 . +.I e2 +is assumed to be at the correct height for a character without a descender; +.I e2 +will be moved down if +.I e1 +has a descender. +.B utilde +is pre-defined using +.B uaccent +as a tilde accent below the baseline. +.TP +.BI split\ \(ts text \(ts +This has the same effect as simply +.RS +.IP +.I text +.RE +.IP +but +.I text +is not subject to macro expansion because it is quoted; +.I text +will be split up and the spacing between individual characters +will be adjusted. +.TP +.BI nosplit\ text +This has the same effect as +.RS +.IP +.BI \(ts text \(ts +.RE +.IP +but because +.I text +is not quoted it will be subject to macro expansion; +.I text +will not be split up +and the spacing between individual characters will not be adjusted. +.TP +.IB e\ opprime +This is a variant of +.B prime +that acts as an operator on +.IR e . +It produces a different result from +.B prime +in a case such as +.BR A\ opprime\ sub\ 1 : +with +.B opprime +the +.B 1 +will be tucked under the prime as a subscript to the +.B A +(as is conventional in mathematical typesetting), +whereas with +.B prime +the +.B 1 +will be a subscript to the prime character. +The precedence of +.B opprime +is the same as that of +.B bar +and +.BR under , +which is higher than that of everything except +.B accent +and +.BR uaccent . +In unquoted text a +.B ' +that is not the first character will be treated like +.BR opprime . +.TP +.BI special\ text\ e +This constructs a new object from +.I e +using a +.BR @g@troff (@MAN1EXT@) +macro named +.IR text . +When the macro is called, +the string +.B 0s +will contain the output for +.IR e , +and the number registers +.BR 0w , +.BR 0h , +.BR 0d , +.BR 0skern +and +.BR 0skew +will contain the width, height, depth, subscript kern, and skew of +.IR e . +(The +.I "subscript kern" +of an object says how much a subscript on that object should be tucked in; +the +.I skew +of an object says how far to the right of the center of the object an +accent over the object should be placed.) +The macro must modify +.B 0s +so that it will output the desired result with its origin at the current +point, and increase the current horizontal position by the width +of the object. +The number registers must also be modified so that they correspond to the +result. +.RS +.LP +For example, suppose you wanted a construct that `cancels' an expression +by drawing a diagonal line through it. +.IP +.nf +.ft B +.ne 6+\n(.Vu +\&.EQ +define cancel 'special Ca' +\&.EN +\&.de Ca +\&.ds 0s \eZ'\e\e*(0s'\ev'\e\en(0du'\eD'l \e\en(0wu -\e\en(0hu-\e\en(0du'\ev'\e\en(0hu' +\&.. +.ft +.fi +.LP +Then you could cancel an expression +.I e +with +.BI cancel\ {\ e\ } +.LP +Here's a more complicated construct that draws a box round an expression: +.IP +.nf +.ft B +.ne 11+\n(.Vu +\&.EQ +define box 'special Bx' +\&.EN +\&.de Bx +\&.ds 0s \eZ'\eh'1n'\e\e*(0s'\e +\eZ'\ev'\e\en(0du+1n'\eD'l \e\en(0wu+2n 0'\eD'l 0 -\e\en(0hu-\e\en(0du-2n'\e +\eD'l -\e\en(0wu-2n 0'\eD'l 0 \e\en(0hu+\e\en(0du+2n''\eh'\e\en(0wu+2n' +\&.nr 0w +2n +\&.nr 0d +1n +\&.nr 0h +1n +\&.. +.ft +.fi +.RE +.SS Customization +The appearance of equations is controlled by +a large number of parameters. These can be set using +the +.B set +command. +.TP +.BI set\ p\ n +This sets parameter +.I p +to value +.I n ; +.I n +is an integer. +For example, +.RS +.IP +.B +set x_height 45 +.RE +.IP +says that +.B eqn +should assume an x height of 0.45 ems. +.RS +.LP +Possible parameters are as follows. +Values are in units of hundredths of an em unless otherwise stated. +These descriptions are intended to be expository rather than +definitive. +.TP \w'\fBdefault_rule_thickness'u+2n +.B minimum_size +.B eqn +will not set anything at a smaller point-size than this. +The value is in points. +.TP +.B fat_offset +The +.B fat +primitive emboldens an equation +by overprinting two copies of the equation +horizontally offset by this amount. +.TP +.B over_hang +A fraction bar will be longer by twice this amount than +the maximum of the widths of the numerator and denominator; +in other words, it will overhang the numerator and +denominator by at least this amount. +.TP +.B accent_width +When +.B bar +or +.B under +is applied to a single character, +the line will be this long. +Normally, +.B bar +or +.B under +produces a line whose length is the width of the object to which it applies; +in the case of a single character, +this tends to produce a line that looks too long. +.TP +.B delimiter_factor +Extensible delimiters produced with the +.B left +and +.B right +primitives will have a combined height and depth of at least this many +thousandths of twice the maximum amount by which the sub-equation that +the delimiters enclose extends away from the axis. +.TP +.B delimiter_shortfall +Extensible delimiters produced with the +.B left +and +.B right +primitives will have a combined height and depth +not less than the difference of +twice the maximum amount by which the sub-equation that +the delimiters enclose extends away from the axis +and this amount. +.TP +.B null_delimiter_space +This much horizontal space is inserted +on each side of a fraction. +.TP +.B script_space +The width of subscripts and superscripts is increased by this amount. +.TP +.B thin_space +This amount of space is automatically inserted after punctuation +characters. +.TP +.B medium_space +This amount of space is automatically inserted on either side +of binary operators. +.TP +.B thick_space +This amount of space is automatically inserted on either side of +relations. +.TP +.B x_height +The height of lowercase letters without ascenders such as x. +.TP +.B axis_height +The height above the baseline of the center of characters +such as \(pl and \(mi. +It is important that this value is correct for the font +you are using. +.TP +.B default_rule_thickness +This should set to the thickness of the +.B \e(ru +character, or the thickness of horizontal lines produced with the +.B \eD +escape sequence. +.TP +.B num1 +The +.B over +command will shift up the numerator by at least this amount. +.TP +.B num2 +The +.B smallover +command will shift up the numerator by at least this amount. +.TP +.B denom1 +The +.B over +command will shift down the denominator by at least this amount. +.TP +.B denom2 +The +.B smallover +command will shift down the denominator by at least this amount. +.TP +.B sup1 +Normally superscripts will be shifted up by at least this amount. +.TP +.B sup2 +Superscripts within superscripts or upper limits +or numerators of +.B smallover +fractions +will be shifted up by at least this amount. +This is usually less than sup1. +.TP +.B sup3 +Superscripts within denominators or square roots +or subscripts or lower limits will be shifted up by at least +this amount. +This is usually less than sup2. +.TP +.B sub1 +Subscripts will normally be shifted down by at least this amount. +.TP +.B sub2 +When there is both a subscript and a superscript, the subscript +will be shifted down by at least this amount. +.TP +.B sup_drop +The baseline of a superscript will be no more +than this much amount below the top of the object on +which the superscript is set. +.TP +.B sub_drop +The baseline of a subscript will be at least this much below +the bottom of the object on which the subscript is set. +.TP +.B big_op_spacing1 +The baseline of an upper limit will be at least this +much above the top of the object on which the limit is set. +.TP +.B big_op_spacing2 +The baseline of a lower limit will be at least this +much below the bottom of the object on which the limit is set. +.TP +.B big_op_spacing3 +The bottom of an upper limit will be at least this much above the +top of the object on which the limit is set. +.TP +.B big_op_spacing4 +The top of a lower limit will be at least this much below +the bottom of the object on which the limit is set. +.TP +.B big_op_spacing5 +This much vertical space will be added above and below limits. +.TP +.B baseline_sep +The baselines of the rows in a pile or matrix will normally be +this far apart. +In most cases this should be equal to the sum of +.B num1 +and +.BR denom1 . +.TP +.B shift_down +The midpoint between the top baseline and the bottom baseline +in a matrix or pile will be shifted down by this much from the axis. +In most cases this should be equal to +.BR axis_height . +.TP +.B column_sep +This much space will be added between columns in a matrix. +.TP +.B matrix_side_sep +This much space will be added at each side of a matrix. +.TP +.B draw_lines +If this is non-zero, lines will be drawn using the +.B \eD +escape sequence, rather than with the +.B \el +escape sequence and the +.B \e(ru +character. +.TP +.B body_height +The amount by which the height of the equation exceeds this +will be added as extra space before the line containing the equation +(using +.BR \ex .) +The default value is 85. +.TP +.B body_depth +The amount by which the depth of the equation exceeds this +will be added as extra space after the line containing the equation +(using +.BR \ex .) +The default value is 35. +.TP +.B nroff +If this is non-zero, +then +.B ndefine +will behave like +.B define +and +.B tdefine +will be ignored, +otherwise +.B tdefine +will behave like +.B define +and +.B ndefine +will be ignored. +The default value is 0 +(This is typically changed to 1 by the +.B eqnrc +file for the +.BR ascii , +.BR latin1 , +.BR utf8 , +and +.B cp1047 +devices.) +.LP +A more precise description of the role of many of these +parameters can be found in Appendix H of +.IR The\ \*(txbook . +.RE +.SS Macros +Macros can take arguments. +In a macro body, +.BI $ n +where +.I n +is between 1 and 9, +will be replaced by the +.IR n-th +argument if the macro is called with arguments; +if there are fewer than +.I n +arguments, it will be replaced by nothing. +A word containing a left parenthesis where the part of the word +before the left parenthesis has been defined using the +.B define +command +will be recognized as a macro call with arguments; +characters following the left parenthesis +up to a matching right parenthesis will be treated as comma-separated +arguments; +commas inside nested parentheses do not terminate an argument. +.TP +.BI sdefine\ name\ X\ anything\ X +This is like the +.B define +command, but +.I name +will not be recognized if called with arguments. +.TP +.BI include\ \(ts file \(ts +Include the contents of +.IR file . +Lines of +.I file +beginning with +.B .EQ +or +.B .EN +will be ignored. +.TP +.BI ifdef\ name\ X\ anything\ X +If +.I name +has been defined by +.B define +(or has been automatically defined because +.I name +is the output device) +process +.IR anything ; +otherwise ignore +.IR anything . +.I X +can be any character not appearing in +.IR anything . +.SS Fonts +.B eqn +normally uses at least two fonts to set an equation: +an italic font for letters, +and a roman font for everything else. +The existing +.B gfont +command +changes the font that is used as the italic font. +By default this is +.BR I . +The font that is used as the roman font can be changed +using the new +.B grfont +command. +.TP +.BI grfont\ f +Set the roman font to +.IR f . +.LP +The +.B italic +primitive uses the current italic font set by +.BR gfont ; +the +.B roman +primitive uses the current roman font set by +.BR grfont . +There is also a new +.B gbfont +command, which changes the font used by the +.B bold +primitive. +If you only use the +.BR roman , +.B italic +and +.B bold +primitives to changes fonts within an equation, +you can change all the fonts used by your equations +just by using +.BR gfont , +.B grfont +and +.B gbfont +commands. +.LP +You can control which characters are treated as letters +(and therefore set in italics) by using the +.B chartype +command described above. +A type of +.B letter +will cause a character to be set in italic type. +A type of +.B digit +will cause a character to be set in roman type. +.SH FILES +.Tp \w'\fB@MACRODIR@/eqnrc'u+2n +.B @MACRODIR@/eqnrc +Initialization file. +.SH BUGS +Inline equations will be set at the point size that is current at the +beginning of the input line. +.SH "SEE ALSO" +.BR groff (@MAN1EXT@), +.BR @g@troff (@MAN1EXT@), +.BR groff_font (@MAN5EXT@), +.I The\ \*(txbook diff --git a/contrib/groff/src/preproc/eqn/eqn.y b/contrib/groff/src/preproc/eqn/eqn.y new file mode 100644 index 000000000000..833a0f01072a --- /dev/null +++ b/contrib/groff/src/preproc/eqn/eqn.y @@ -0,0 +1,331 @@ +/* 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 <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "lib.h" +#include "box.h" +extern int non_empty_flag; +char *strsave(const char *); +int yylex(); +void yyerror(const char *); +%} + +%union { + char *str; + box *b; + pile_box *pb; + matrix_box *mb; + int n; + column *col; +} + +%token OVER +%token SMALLOVER +%token SQRT +%token SUB +%token SUP +%token LPILE +%token RPILE +%token CPILE +%token PILE +%token LEFT +%token RIGHT +%token TO +%token FROM +%token SIZE +%token FONT +%token ROMAN +%token BOLD +%token ITALIC +%token FAT +%token ACCENT +%token BAR +%token UNDER +%token ABOVE +%token <str> TEXT +%token <str> QUOTED_TEXT +%token FWD +%token BACK +%token DOWN +%token UP +%token MATRIX +%token COL +%token LCOL +%token RCOL +%token CCOL +%token MARK +%token LINEUP +%token TYPE +%token VCENTER +%token PRIME +%token SPLIT +%token NOSPLIT +%token UACCENT +%token SPECIAL + +/* these are handled in the lexer */ +%token SPACE +%token GFONT +%token GSIZE +%token DEFINE +%token NDEFINE +%token TDEFINE +%token SDEFINE +%token UNDEF +%token IFDEF +%token INCLUDE +%token DELIM +%token CHARTYPE +%token SET +%token GRFONT +%token GBFONT + +/* The original eqn manual says that `left' is right associative. It's lying. +Consider `left ( ~ left ( ~ right ) right )'. */ + +%right LEFT +%left RIGHT +%right LPILE RPILE CPILE PILE TEXT QUOTED_TEXT MATRIX MARK LINEUP '^' '~' '\t' '{' SPLIT NOSPLIT +%right FROM TO +%left SQRT OVER SMALLOVER +%right SUB SUP +%right ROMAN BOLD ITALIC FAT FONT SIZE FWD BACK DOWN UP TYPE VCENTER SPECIAL +%right BAR UNDER PRIME +%left ACCENT UACCENT + +%type <b> mark from_to sqrt_over script simple equation nonsup +%type <n> number +%type <str> text delim +%type <pb> pile_element_list pile_arg +%type <mb> column_list +%type <col> column column_arg column_element_list + +%% +top: + /* empty */ + | equation + { $1->top_level(); non_empty_flag = 1; } + ; + +equation: + mark + { $$ = $1; } + | equation mark + { + list_box *lb = $1->to_list_box(); + if (!lb) + lb = new list_box($1); + lb->append($2); + $$ = lb; + } + ; + +mark: + from_to + { $$ = $1; } + | MARK mark + { $$ = make_mark_box($2); } + | LINEUP mark + { $$ = make_lineup_box($2); } + ; + +from_to: + sqrt_over %prec FROM + { $$ = $1; } + | sqrt_over TO from_to + { $$ = make_limit_box($1, 0, $3); } + | sqrt_over FROM sqrt_over + { $$ = make_limit_box($1, $3, 0); } + | sqrt_over FROM sqrt_over TO from_to + { $$ = make_limit_box($1, $3, $5); } + | sqrt_over FROM sqrt_over FROM from_to + { $$ = make_limit_box($1, make_limit_box($3, $5, 0), 0); } + ; + +sqrt_over: + script + { $$ = $1; } + | SQRT sqrt_over + { $$ = make_sqrt_box($2); } + | sqrt_over OVER sqrt_over + { $$ = make_over_box($1, $3); } + | sqrt_over SMALLOVER sqrt_over + { $$ = make_small_over_box($1, $3); } + ; + +script: + nonsup + { $$ = $1; } + | simple SUP script + { $$ = make_script_box($1, 0, $3); } + ; + +nonsup: + simple %prec SUP + { $$ = $1; } + | simple SUB nonsup + { $$ = make_script_box($1, $3, 0); } + | simple SUB simple SUP script + { $$ = make_script_box($1, $3, $5); } + ; + +simple: + TEXT + { $$ = split_text($1); } + | QUOTED_TEXT + { $$ = new quoted_text_box($1); } + | SPLIT QUOTED_TEXT + { $$ = split_text($2); } + | NOSPLIT TEXT + { $$ = new quoted_text_box($2); } + | '^' + { $$ = new half_space_box; } + | '~' + { $$ = new space_box; } + | '\t' + { $$ = new tab_box; } + | '{' equation '}' + { $$ = $2; } + | PILE pile_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + | LPILE pile_arg + { $2->set_alignment(LEFT_ALIGN); $$ = $2; } + | RPILE pile_arg + { $2->set_alignment(RIGHT_ALIGN); $$ = $2; } + | CPILE pile_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + | MATRIX '{' column_list '}' + { $$ = $3; } + | LEFT delim equation RIGHT delim + { $$ = make_delim_box($2, $3, $5); } + | LEFT delim equation + { $$ = make_delim_box($2, $3, 0); } + | simple BAR + { $$ = make_overline_box($1); } + | simple UNDER + { $$ = make_underline_box($1); } + | simple PRIME + { $$ = make_prime_box($1); } + | simple ACCENT simple + { $$ = make_accent_box($1, $3); } + | simple UACCENT simple + { $$ = make_uaccent_box($1, $3); } + | ROMAN simple + { $$ = new font_box(strsave(get_grfont()), $2); } + | BOLD simple + { $$ = new font_box(strsave(get_gbfont()), $2); } + | ITALIC simple + { $$ = new font_box(strsave(get_gfont()), $2); } + | FAT simple + { $$ = new fat_box($2); } + | FONT text simple + { $$ = new font_box($2, $3); } + | SIZE text simple + { $$ = new size_box($2, $3); } + | FWD number simple + { $$ = new hmotion_box($2, $3); } + | BACK number simple + { $$ = new hmotion_box(-$2, $3); } + | UP number simple + { $$ = new vmotion_box($2, $3); } + | DOWN number simple + { $$ = new vmotion_box(-$2, $3); } + | TYPE text simple + { $3->set_spacing_type($2); $$ = $3; } + | VCENTER simple + { $$ = new vcenter_box($2); } + | SPECIAL text simple + { $$ = make_special_box($2, $3); } + ; + +number: + text + { + int n; + if (sscanf($1, "%d", &n) == 1) + $$ = n; + a_delete $1; + } + ; + +pile_element_list: + equation + { $$ = new pile_box($1); } + | pile_element_list ABOVE equation + { $1->append($3); $$ = $1; } + ; + +pile_arg: + '{' pile_element_list '}' + { $$ = $2; } + | number '{' pile_element_list '}' + { $3->set_space($1); $$ = $3; } + ; + +column_list: + column + { $$ = new matrix_box($1); } + | column_list column + { $1->append($2); $$ = $1; } + ; + +column_element_list: + equation + { $$ = new column($1); } + | column_element_list ABOVE equation + { $1->append($3); $$ = $1; } + ; + +column_arg: + '{' column_element_list '}' + { $$ = $2; } + | number '{' column_element_list '}' + { $3->set_space($1); $$ = $3; } + ; + +column: + COL column_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + | LCOL column_arg + { $2->set_alignment(LEFT_ALIGN); $$ = $2; } + | RCOL column_arg + { $2->set_alignment(RIGHT_ALIGN); $$ = $2; } + | CCOL column_arg + { $2->set_alignment(CENTER_ALIGN); $$ = $2; } + ; + +text: TEXT + { $$ = $1; } + | QUOTED_TEXT + { $$ = $1; } + ; + +delim: + text + { $$ = $1; } + | '{' + { $$ = strsave("{"); } + | '}' + { $$ = strsave("}"); } + ; + +%% diff --git a/contrib/groff/src/preproc/eqn/eqn_tab.h b/contrib/groff/src/preproc/eqn/eqn_tab.h new file mode 100644 index 000000000000..9a8b3cb22595 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/eqn_tab.h @@ -0,0 +1,67 @@ +#define OVER 257 +#define SMALLOVER 258 +#define SQRT 259 +#define SUB 260 +#define SUP 261 +#define LPILE 262 +#define RPILE 263 +#define CPILE 264 +#define PILE 265 +#define LEFT 266 +#define RIGHT 267 +#define TO 268 +#define FROM 269 +#define SIZE 270 +#define FONT 271 +#define ROMAN 272 +#define BOLD 273 +#define ITALIC 274 +#define FAT 275 +#define ACCENT 276 +#define BAR 277 +#define UNDER 278 +#define ABOVE 279 +#define TEXT 280 +#define QUOTED_TEXT 281 +#define FWD 282 +#define BACK 283 +#define DOWN 284 +#define UP 285 +#define MATRIX 286 +#define COL 287 +#define LCOL 288 +#define RCOL 289 +#define CCOL 290 +#define MARK 291 +#define LINEUP 292 +#define TYPE 293 +#define VCENTER 294 +#define PRIME 295 +#define SPLIT 296 +#define NOSPLIT 297 +#define UACCENT 298 +#define SPECIAL 299 +#define SPACE 300 +#define GFONT 301 +#define GSIZE 302 +#define DEFINE 303 +#define NDEFINE 304 +#define TDEFINE 305 +#define SDEFINE 306 +#define UNDEF 307 +#define IFDEF 308 +#define INCLUDE 309 +#define DELIM 310 +#define CHARTYPE 311 +#define SET 312 +#define GRFONT 313 +#define GBFONT 314 +typedef union { + char *str; + box *b; + pile_box *pb; + matrix_box *mb; + int n; + column *col; +} YYSTYPE; +extern YYSTYPE yylval; diff --git a/contrib/groff/src/preproc/eqn/lex.cc b/contrib/groff/src/preproc/eqn/lex.cc new file mode 100644 index 000000000000..25faec2bcecf --- /dev/null +++ b/contrib/groff/src/preproc/eqn/lex.cc @@ -0,0 +1,1165 @@ +// -*- 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 "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) +{ + 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 (illegal_input_char(c)) + lex_error("illegal 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 illegal 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 new file mode 100644 index 000000000000..046885d2a580 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/limit.cc @@ -0,0 +1,195 @@ +// -*- 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 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[.s]\n", uid); + if (!(style <= SCRIPT_STYLE && one_size_reduction_flag)) + set_script_size(); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\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 "]\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 "]]", 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 "]]", 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 new file mode 100644 index 000000000000..1118fa1b1660 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/list.cc @@ -0,0 +1,237 @@ +// -*- 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 new file mode 100644 index 000000000000..6dc03f0b0543 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/main.cc @@ -0,0 +1,419 @@ +// -*- 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 "eqn.h" +#include "stringclass.h" +#include "device.h" +#include "searchpath.h" +#include "macropath.h" +#include "htmlindicate.h" +#include "pbox.h" + +#define STARTUP_FILE "eqnrc" + +extern int yyparse(); + +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; +// if we encounter a region marked as an image then we +// do not mark up inline equations. +int suppress_html = 0; + + +int read_line(FILE *fp, string *p) +{ + p->clear(); + int c = -1; + while ((c = getc(fp)) != EOF) { + if (!illegal_input_char(c)) + *p += char(c); + else + error("illegal input character code `%1'", c); + if (c == '\n') + break; + } + current_lineno++; + return p->length() > 0; +} + +void do_file(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() >= 12 + && linebuf[0] == '.' && linebuf[1] == 'H' && linebuf[2] == 'T' + && linebuf[3] == 'M' && linebuf[4] == 'L' && linebuf[5] == '-' + && linebuf[6] == 'I' && linebuf[7] == 'M' && linebuf[8] == 'A' + && linebuf[9] == 'G' && linebuf[10] == 'E' + && linebuf[11] == '\n') { + put_string(linebuf, stdout); + suppress_html++; + } + else if (linebuf.length() >= 16 + && linebuf[0] == '.' && linebuf[1] == 'H' && linebuf[2] == 'T' + && linebuf[3] == 'M' && linebuf[4] == 'L' && linebuf[5] == '-' + && linebuf[6] == 'I' && linebuf[7] == 'M' && linebuf[8] == 'A' + && linebuf[9] == 'G' && linebuf[10] == 'E' && linebuf[11] == '-' + && linebuf[12] == 'E' && linebuf[13] == 'N' && linebuf[14] == 'D' + && linebuf[15] == '\n') { + put_string(linebuf, stdout); + suppress_html--; + } + else if (linebuf.length() >= 4 + && linebuf[0] == '.' + && linebuf[1] == 'E' + && linebuf[2] == 'Q' + && (linebuf[3] == ' ' || linebuf[3] == '\n' + || compatible_flag)) { + if (html && (suppress_html == 0)) + graphic_start(0); + put_string(linebuf, stdout); + int start_lineno = current_lineno + 1; + str.clear(); + for (;;) { + if (!read_line(fp, &linebuf)) + fatal("end of file before .EN"); + if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') { + if (linebuf[2] == 'N' + && (linebuf.length() == 3 || linebuf[3] == ' ' + || linebuf[3] == '\n' || compatible_flag)) + break; + else if (linebuf[2] == 'Q' && linebuf.length() > 3 + && (linebuf[3] == ' ' || linebuf[3] == '\n' + || compatible_flag)) + fatal("nested .EQ"); + } + str += linebuf; + } + str += '\0'; + start_string(); + init_lex(str.contents(), current_filename, start_lineno); + non_empty_flag = 0; + inline_flag = 0; + yyparse(); + if (non_empty_flag) { + printf(".lf %d\n", current_lineno - 1); + output_string(); + } + restore_compatibility(); + printf(".lf %d\n", current_lineno); + put_string(linebuf, stdout); + if (html && (suppress_html == 0)) + graphic_end(); + } + 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("end of file before `%1'", end_delim); + linebuf += '\0'; + ptr = &linebuf[0]; + } + str += '\0'; + if (html && (suppress_html == 0)) { + printf(".as %s ", LINE_STRING); + graphic_start(1); + printf("\n"); + } + init_lex(str.contents(), current_filename, start_lineno); + yyparse(); + if (html && (suppress_html == 0)) { + printf(".as %s ", LINE_STRING); + graphic_end(); + 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; + } + } + printf(".lf %d\n", current_lineno); + output_string(); + restore_compatibility(); + 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': + { + extern const char *Version_string; + 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 (illegal_input_char(optarg[0])) + error("bad delimiter `%1'", optarg[0]); + else if (illegal_input_char(optarg[1])) + error("bad delimiter `%1'", optarg[1]); + else { + start_delim = optarg[0]; + end_delim = optarg[1]; + } + break; + case 'f': + set_gfont(optarg); + break; + case 'T': + device = optarg; + 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 new file mode 100644 index 000000000000..99d1b75f2f78 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/mark.cc @@ -0,0 +1,121 @@ +// -*- 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/neqn.man b/contrib/groff/src/preproc/eqn/neqn.man new file mode 100644 index 000000000000..bca7dc2ed912 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/neqn.man @@ -0,0 +1,21 @@ +.TH @G@NEQN @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +@g@neqn \- format equations for ascii output +.SH SYNOPSIS +.B @g@neqn +[@g@eqn options] +.SH DESCRIPTION +The +.B @g@neqn +program is actually just a shell script which invokes the +.BR @g@eqn (@MAN1EXT@) +command with the +.B ascii +output device. +.LP +Note that +.B @g@eqn +does not support low-resolution, typewriter-like devices (although it may +work adequately for very simple input). +.SH "SEE ALSO" +.BR @g@eqn (@MAN1EXT@) diff --git a/contrib/groff/src/preproc/eqn/neqn.sh b/contrib/groff/src/preproc/eqn/neqn.sh index 6a60d138391d..8f6bc8befe51 100644 --- a/contrib/groff/src/preproc/eqn/neqn.sh +++ b/contrib/groff/src/preproc/eqn/neqn.sh @@ -2,4 +2,8 @@ # Provision of this shell script should not be taken to imply that use of # GNU eqn with groff -Tascii|-Tlatin1|-Tutf8|-Tcp1047 is supported. +: ${GROFF_BIN_PATH=@BINDIR@} +export PATH=$GROFF_BIN_PATH:$PATH exec @g@eqn -Tascii ${1+"$@"} + +# eof diff --git a/contrib/groff/src/preproc/eqn/other.cc b/contrib/groff/src/preproc/eqn/other.cc new file mode 100644 index 000000000000..eb9e50a2bc57 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/other.cc @@ -0,0 +1,601 @@ +// -*- 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 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, "<overline char>"); +} + +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, "<underline char>"); +} + + +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[.s]\n", uid); + printf(".ps %s\n", size); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid); + int r = p->compute_metrics(style); + printf(".ps \\n[" SIZE_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 size_box::output() +{ + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); + p->output(); + printf("\\s[\\n[" SIZE_FORMAT "]]", 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 new file mode 100644 index 000000000000..06b032129fd7 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/over.cc @@ -0,0 +1,196 @@ +// -*- 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 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[.s]\n", uid); + set_script_size(); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\n", uid); + } + int mark_uid; + 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 "]\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 "]]", 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 "]]", 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/pbox.h b/contrib/groff/src/preproc/eqn/pbox.h new file mode 100644 index 000000000000..d1f16ac486ae --- /dev/null +++ b/contrib/groff/src/preproc/eqn/pbox.h @@ -0,0 +1,141 @@ +// -*- 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. */ + +extern int fat_offset; + +extern int over_hang; +extern int accent_width; + +extern int delimiter_factor; +extern int delimiter_shortfall; + +extern int null_delimiter_space; +extern int script_space; +extern int thin_space; +extern int medium_space; +extern int thick_space; + +extern int num1; +extern int num2; +// we don't use num3, because we don't have \atop +extern int denom1; +extern int denom2; +extern int axis_height; +extern int sup1; +extern int sup2; +extern int sup3; +extern int default_rule_thickness; +extern int sub1; +extern int sub2; +extern int sup_drop; +extern int sub_drop; +extern int x_height; +extern int big_op_spacing1; +extern int big_op_spacing2; +extern int big_op_spacing3; +extern int big_op_spacing4; +extern int big_op_spacing5; + +extern int baseline_sep; +extern int shift_down; +extern int column_sep; +extern int matrix_side_sep; + +// ms.eqn relies on this! + +#define LINE_STRING "10" +#define MARK_OR_LINEUP_FLAG_REG "MK" + +#define WIDTH_FORMAT PREFIX "w%d" +#define HEIGHT_FORMAT PREFIX "h%d" +#define DEPTH_FORMAT PREFIX "d%d" +#define TOTAL_FORMAT PREFIX "t%d" +#define SIZE_FORMAT PREFIX "z%d" +#define SMALL_SIZE_FORMAT PREFIX "Z%d" +#define SUP_RAISE_FORMAT PREFIX "p%d" +#define SUB_LOWER_FORMAT PREFIX "b%d" +#define SUB_KERN_FORMAT PREFIX "k%d" +#define FONT_FORMAT PREFIX "f%d" +#define SKEW_FORMAT PREFIX "s%d" +#define LEFT_WIDTH_FORMAT PREFIX "lw%d" +#define LEFT_DELIM_STRING_FORMAT PREFIX "l%d" +#define RIGHT_DELIM_STRING_FORMAT PREFIX "r%d" +#define SQRT_STRING_FORMAT PREFIX "sqr%d" +#define SQRT_WIDTH_FORMAT PREFIX "sq%d" +#define BASELINE_SEP_FORMAT PREFIX "bs%d" +// this needs two parameters, the uid and the column index +#define COLUMN_WIDTH_FORMAT PREFIX "cw%d,%d" + +#define BAR_STRING PREFIX "sqb" +#define TEMP_REG PREFIX "temp" +#define MARK_REG PREFIX "mark" +#define MARK_WIDTH_REG PREFIX "mwidth" +#define SAVED_MARK_REG PREFIX "smark" +#define MAX_SIZE_REG PREFIX "mxsz" +#define REPEAT_APPEND_STRING_MACRO PREFIX "ras" +#define TOP_HEIGHT_REG PREFIX "th" +#define TOP_DEPTH_REG PREFIX "td" +#define MID_HEIGHT_REG PREFIX "mh" +#define MID_DEPTH_REG PREFIX "md" +#define BOT_HEIGHT_REG PREFIX "bh" +#define BOT_DEPTH_REG PREFIX "bd" +#define EXT_HEIGHT_REG PREFIX "eh" +#define EXT_DEPTH_REG PREFIX "ed" +#define TOTAL_HEIGHT_REG PREFIX "tot" +#define DELTA_REG PREFIX "delta" +#define DELIM_STRING PREFIX "delim" +#define DELIM_WIDTH_REG PREFIX "dwidth" +#define SAVED_FONT_REG PREFIX "sfont" +#define SAVED_PREV_FONT_REG PREFIX "spfont" +#define SAVED_INLINE_FONT_REG PREFIX "sifont" +#define SAVED_INLINE_PREV_FONT_REG PREFIX "sipfont" +#define SAVED_SIZE_REG PREFIX "ssize" +#define SAVED_INLINE_SIZE_REG PREFIX "sisize" +#define SAVED_INLINE_PREV_SIZE_REG PREFIX "sipsize" +#define SAVE_FONT_STRING PREFIX "sfont" +#define RESTORE_FONT_STRING PREFIX "rfont" +#define INDEX_REG PREFIX "i" +#define TEMP_MACRO PREFIX "tempmac" + +#define DELIMITER_CHAR "\\(EQ" + +const int CRAMPED_SCRIPT_STYLE = 0; +const int SCRIPT_STYLE = 1; +const int CRAMPED_DISPLAY_STYLE = 2; +const int DISPLAY_STYLE = 3; + +extern int script_style(int); +extern int cramped_style(int); + +const int ORDINARY_TYPE = 0; +const int OPERATOR_TYPE = 1; +const int BINARY_TYPE = 2; +const int RELATION_TYPE = 3; +const int OPENING_TYPE = 4; +const int CLOSING_TYPE = 5; +const int PUNCTUATION_TYPE = 6; +const int INNER_TYPE = 7; +const int SUPPRESS_TYPE = 8; + +void set_script_size(); + +enum { HINT_PREV_IS_ITALIC = 01, HINT_NEXT_IS_ITALIC = 02 }; + +extern const char *current_roman_font; diff --git a/contrib/groff/src/preproc/eqn/pile.cc b/contrib/groff/src/preproc/eqn/pile.cc new file mode 100644 index 000000000000..0df5241f0fee --- /dev/null +++ b/contrib/groff/src/preproc/eqn/pile.cc @@ -0,0 +1,293 @@ +// -*- 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 new file mode 100644 index 000000000000..7c2e6c258807 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/script.cc @@ -0,0 +1,221 @@ +// -*- 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 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[.s]\n", uid); + if (!(style <= SCRIPT_STYLE && one_size_reduction_flag)) + set_script_size(); + printf(".nr " SMALL_SIZE_FORMAT " \\n[.s]\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 "]\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 "]]", uid); + sup->output(); + printf("\\s[\\n[" SIZE_FORMAT "]]", 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 "]]", uid); + printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid); + sub->output(); + printf("\\s[\\n[" SIZE_FORMAT "]]", 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 new file mode 100644 index 000000000000..310261ae4c59 --- /dev/null +++ b/contrib/groff/src/preproc/eqn/special.cc @@ -0,0 +1,115 @@ +// -*- 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 new file mode 100644 index 000000000000..6109ffeaf67c --- /dev/null +++ b/contrib/groff/src/preproc/eqn/sqrt.cc @@ -0,0 +1,179 @@ +// -*- 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 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[.s]\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[.s]\n"); + printf(".ps \\n[" SIZE_FORMAT "]\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[.s]<\\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[.s]\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 "]\n", uid); + return r; +} + +void sqrt_box::output() +{ + printf("\\Z" DELIMITER_CHAR); + printf("\\s[\\n[" SMALL_SIZE_FORMAT "]]", uid); + printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); + printf("\\*[" SQRT_STRING_FORMAT "]", uid); + printf("\\s[\\n[" SIZE_FORMAT "]]", 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 new file mode 100644 index 000000000000..b0f1700c221d --- /dev/null +++ b/contrib/groff/src/preproc/eqn/text.cc @@ -0,0 +1,528 @@ +// -*- 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/Makefile.sub b/contrib/groff/src/preproc/grn/Makefile.sub new file mode 100644 index 000000000000..ffa0ad209cc4 --- /dev/null +++ b/contrib/groff/src/preproc/grn/Makefile.sub @@ -0,0 +1,17 @@ +PROG=grn +MAN1=grn.n +MLIB=$(LIBM) +XLIBS=$(LIBGROFF) +OBJS=\ + hdb.o \ + hpoint.o \ + hgraph.o \ + main.o +CCSRCS=\ + $(srcdir)/hdb.cc \ + $(srcdir)/hpoint.cc \ + $(srcdir)/hgraph.cc \ + $(srcdir)/main.cc +HDRS=\ + $(srcdir)/gprint.h +NAMEPREFIX=$(g) diff --git a/contrib/groff/src/preproc/grn/README b/contrib/groff/src/preproc/grn/README new file mode 100644 index 000000000000..b5b9fc9abd83 --- /dev/null +++ b/contrib/groff/src/preproc/grn/README @@ -0,0 +1,60 @@ +This is grn from the Berkeley ditroff distribution. It has no +AT&T code and is therefore freely distributable. + +Tim Theisen <tim@cs.wisc.edu> + +===================================================================== + +This is the modified code for the groff. It uses the different +devxxx format that is ascii rather than binary as in the +Berkeley distribution. Since groff does not have the \Ds option +for line drawing (dotted, dashed, etc.), this version includes +the routines for drawing curves and arcs, so it does not use the +\D~, \Da nor \Dc. Although also included in here is a routine +for drawing the optional gremlin style curves, it is not used +because the gremlin editor uses the conventional spline +algorithm. The Berkeley grn has the choice of different +stipples. Here, only different shades of gray will be painted +depending on the gremlin file. It is possible to upgrade this at +a later time. (Daniel Senderowicz <daniel@synchrods.com> 12/28/99) + +===================================================================== + +It has been further modified by Werner Lemberg <wl@gnu.org> to fit +better into the groff package. + + . Replaced Makefile with Makefile.sub. + + . Removed dev.h since it is unused. + + . Renamed grn.1 to grn.man; this man page has been extensively + revised. + + . Used error() and fatal() from libgroff for all source files. + + . Renamed *.c to *.cc; updates as needed for C++ (prototypes, proper + casts, standard header files etc). Heavy formatting. + + . main.cc: + + Using groff's default values instead of DEVDIR, DEFAULTDEV, PRINTER, + TYPESETTER, and GREMLIB. + + `res' is now an integer. + + Added `-C' command flag (for compatibility mode) as with other + preprocessors. + + Added `-F' and `-v' option (similar to troff). + + Renamed `-L' option to `-M' for consistence. + + Removed `-P' option. + + Using font::load_desc() for scanning DESC files. + + Removed SYSV-specific code. + + Using macro_path.open_file() for getting gremlin graphic files. + + Added usage(). diff --git a/contrib/groff/src/preproc/grn/gprint.h b/contrib/groff/src/preproc/grn/gprint.h new file mode 100644 index 000000000000..b25305b3ca03 --- /dev/null +++ b/contrib/groff/src/preproc/grn/gprint.h @@ -0,0 +1,84 @@ +/* Last non-groff version: gprint.h 1.1 84/10/08 + * + * This file contains standard definitions used by the gprint program. + */ + +#include <stdio.h> +#include <math.h> + + +#define xorn(x,y) (x) + /* was 512 */ +#define yorn(x,y) (511 - (y)) /* switch direction for */ + /* y-coordinates */ + +#define STYLES 6 +#define SIZES 4 +#define FONTS 4 +#define SOLID -1 +#define DOTTED 004 /* 014 */ +#define DASHED 020 /* 034 */ +#define DOTDASHED 024 /* 054 */ +#define LONGDASHED 074 + +#define DEFTHICK -1 /* default thicknes */ +#define DEFSTYLE SOLID /* default line style */ + +#define TRUE 1 +#define FALSE 0 + +#define nullelt -1 +#define nullpt -1 +#define nullun NULL + +#define BOTLEFT 0 +#define BOTRIGHT 1 +#define CENTCENT 2 +#define VECTOR 3 +#define ARC 4 +#define CURVE 5 +#define POLYGON 6 +#define TOPLEFT 10 +#define TOPCENT 11 +#define TOPRIGHT 12 +#define CENTLEFT 13 +#define CENTRIGHT 14 +#define BOTCENT 15 +#define TEXT(t) ( (t <= CENTCENT) || (t >= TOPLEFT) ) + +/* WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING + * The above (TEXT) test is dependent on the relative values of the + * constants and will have to change if these values change or if new + * commands are added with value greater than BOTCENT + */ + +#define NUSER 4 +#define NFONTS 4 +#define NBRUSHES 6 +#define NSIZES 4 +#define NJUSTS 9 +#define NSTIPPLES 16 + +#define ADD 1 +#define DELETE 2 +#define MOD 3 + +typedef struct point { + float x, y; + struct point *nextpt; +} POINT; + +typedef struct elmt { + int type, brushf, size, textlength; + char *textpt; + POINT *ptlist; + struct elmt *nextelt, *setnext; +} ELT; + +#define DBNextElt(elt) (elt->nextelt) +#define DBNextofSet(elt) (elt->setnext) +#define DBNullelt(elt) (elt == NULL) +#define Nullpoint(pt) ((pt) == (POINT *) NULL) +#define PTNextPoint(pt) (pt->nextpt) + +/* EOF */ diff --git a/contrib/groff/src/preproc/grn/grn.man b/contrib/groff/src/preproc/grn/grn.man new file mode 100644 index 000000000000..f2613da1b27f --- /dev/null +++ b/contrib/groff/src/preproc/grn/grn.man @@ -0,0 +1,636 @@ +.ig \"-*- nroff -*- +Copyright (C) 2000 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. +.. +.de TQ +.br +.ns +.TP \\$1 +.. +.\" Like TP, but if specified indent is more than half +.\" the current line-length - indent, use the default indent. +.de Tp +.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP +.el .TP "\\$1" +.. +.TH @G@GRN @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.SH NAME +@g@grn \- groff preprocessor for gremlin files +.SH SYNOPSIS +.BR @g@grn +[ +.B \-Cv +] +[ +.BI \-T dev +] +[ +.BI \-M dir +] +[ +.BI \-F dir +] +[ +.IR file\.\.\. +] +.PP +It is possible to have whitespace between a command line option and its +parameter. +.SH DESCRIPTION +.I @g@grn +is a preprocessor for including +.I gremlin +pictures in +.I groff +input. +.I @g@grn +writes to standard output, processing only input lines between two that +start with +.B .GS +and +.BR .GE. +Those lines must contain +.I @g@grn +commands (see below). +These commands request a +.I gremlin +file, and the picture in that file is +converted and placed in the +.I @g@troff +input stream. +The +.B .GS +request may be followed by a C, L, or R to center, left, or right +justify the whole +.I gremlin +picture (default justification is center). +If no +.I file +is mentioned, the standard input is read. +At the end of the picture, the position on the page is the bottom of the +.I gremlin +picture. +If the +.I @g@grn +entry is ended with +.B .GF +instead of +.BR .GE , +the position is left at the top of the picture. +.PP +Please note that currently only the \-me macro package has support for +.BR .GS , +.BR .GE , +and +.BR .GF . +.PP +The following command-line options are understood: +.TP +.BI \-T dev +Prepare output for printer +.IR dev . +The default device is +.BR @DEVICE@ . +See +.BR groff (@MAN1EXT@) +for acceptable devices. +.TP +.BI \-M dir +Prepend +.I dir +to the default search path for +.I gremlin +files. +The default path is (in that order) the current directory, the home +directory, +.BR @SYSTEMMACRODIR@ , +.BR @LOCALMACRODIR@ , +and +.BR @MACRODIR@ . +.TP +.BI \-F dir +Search +.I dir +for subdirectories +.BI dev name +.RI ( name +is the name of the device) for the +.B DESC +file before the normal +.BR @FONTDIR@ . +.TP +.B \-C +Recognize +.B .GS +and +.B .GE +(resp. +.BR .GF ) +even when followed by a character other than space or newline. +.\".TP +.\".B \-s +.\"This switch causes the picture to be traversed twice: +.\"The first time, only the interiors of filled polygons (as borderless +.\"polygons) are printed. +.\"The second time, the outline is printed as a 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. +.TP +.B \-v +Print the version number. +.SH GRN COMMANDS +Each input line between +.B .GS +and +.B .GE +may have one +.I @g@grn +command. +Commands consist of one or two strings separated by white space, the first +string being the command and the second its operand. +Commands may be upper or lower case and abbreviated down to one character. +.PP +Commands that affect a picture's environment (those listed before +.BR default , +see below) are only in effect for the current picture: +The environment is reinitialized to the defaults at the start of the next +picture. +The commands are as follows: +.TP +.BI 1\ N +.TQ +.BI 2\ N +.TQ +.BI 3\ N +.TQ +.BI 4\ N +Set +.IR gremlin 's +text size number 1 (2, 3, or 4) to +.I N +points. +The default is 12 (resp. 16, 24, and 36). +.TP +.BI roman\ f +.TQ +.BI italics\ f +.TQ +.BI bold\ f +.TQ +.BI special\ f +Set the roman (italics, bold, or special) font to +.IR @g@troff 's +font +.I f +(either a name or number). +The default is R (resp. I, B, and S). +.TP +.BI l\ f +.TQ +.BI stipple\ f +Set the stipple font to +.IR @g@troff 's +stipple font +.I f +(name or number). +The command +.B stipple +may be abbreviated down as far as `st' (to avoid +confusion with +.BR special ). +There is +.I no +default for stipples (unless one is set by the default command), and it is +illegal to include a +.I gremlin +picture with polygons without specifying a +stipple font. +.TP +.BI x\ N +.TQ +.BI scale\ N +Magnify the picture (in addition to any default magnification) by +.IR N , +a floating point number larger than zero. +The command +.B scale +may be abbreviated down to `sc'. +.TP +.BI narrow\ N +.TQ +.BI medium\ N +.TQ +.BI thick\ N +Set the thickness of +.IR gremlin 's +narrow (resp. medium and thick) lines to +.I N +times 0.15pt (this value can be changed at compile time). +The default is 1.0 (resp. 3.0 and 5.0), which corresponds to 0.15pt +(resp. 0.45pt and 0.75pt). +A thickness value of zero selects the smallest available line thickness. +Negative values cause the line thickness to be proportional to the current +point size. +.TP +.BI pointscale\ <off/on> +Scale text to match the picture. +Gremlin text is usually printed in the point size specified with the +commands +.BR 1 ,\ 2 ,\ 3 ,\ or\ 4 +regardless of any scaling factors in the picture. +Setting +.B pointscale +will cause the point sizes to scale with the picture (within +.IR @g@troff 's +limitations, of course). +An operand of anything but +.I off +will turn text scaling on. +.TP +.B default +Reset the picture environment defaults to the settings in the current +picture. +This is meant to be used as a global parameter setting mechanism at the +beginning of the +.I @g@troff +input file, but can be used at any time to reset the +default settings. +.TP +.BI width\ N +Forces the picture to be +.I N +inches wide. +This overrides any scaling factors present in the same picture. +.RB ` width +.IR 0 ' +is ignored. +.TP +.BI height\ N +Forces picture to be +.I N +inches high, overriding other scaling factors. +If both `width' and `height' are specified the tighter constraint will +determine the scale of the picture. +.B Height +and +.B width +commands are not saved with a +.B default +command. +They will, however, affect point size scaling if that option is set. +.TP +.BI file\ name +Get picture from +.I gremlin +file +.I name +located the current directory (or in the library directory; see the +.B \-M +option above). +If two +.B file +commands are given, the second one overrides the first. +If +.I name +doesn't exist, an error message is reported and processing continues from +the +.B .GE +line. +.SH NOTES ABOUT GROFF +Since +.I @g@grn +is a preprocessor, it doesn't know about current indents, point sizes, +margins, number registers, etc. +Consequently, no +.I @g@troff +input can be placed between the +.B .GS +and +.B .GE +requests. +However, +.I gremlin +text is now processed by +.IR @g@troff , +so anything legal in a single line of +.I @g@troff +input is legal in a line of +.I gremlin +text (barring `.' directives at the beginning of a line). +Thus, it is possible to have equations within a +.I gremlin +figure by including in the +.I gremlin +file +.I eqn +expressions enclosed by previously defined delimiters (e.g. +.IR $$ ). +.PP +When using +.I @g@grn +along with other preprocessors, it is best to run +.I tbl +before +.IR @g@grn , +.IR pic , +and/or +.I ideal +to avoid overworking +.IR tbl . +.I Eqn +should always be run last. +.PP +A picture is considered an entity, but that doesn't stop +.I @g@troff +from trying to break it up if it falls off the end of a page. +Placing the picture between `keeps' in \-me macros will ensure proper +placement. +.PP +.I @g@grn +uses +.IR @g@troff 's +number registers +.B g1 +through +.B g9 +and sets registers +.B g1 +and +.B g2 +to the width and height of the +.I gremlin +figure (in device units) before entering the +.B .GS +request (this is for those who want to rewrite these macros). +.SH GREMLIN FILE FORMAT +There exist two distinct +.I gremlin +file formats, the original format from the +.I AED +graphic terminal version, and the +.I SUN +or +.I X11 +version. +An extension to the +.IR SUN / X11 +version allowing reference points with negative coordinates is +.B not +compatible with the +.I AED +version. +As long as a +.I gremlin +file does not contain negative coordinates, either format will be read +correctly by either version of +.I gremlin +or +.IR @g@grn . +The other difference to the +.IR SUN / X11 +format is the use of names for picture objects (e.g., POLYGON, CURVE) +instead of numbers. +Files representing the same picture are shown in Table 1 in each format. +.sp +.DS +.TS +center, tab(@); +l lw(0.1i) l. +sungremlinfile@@gremlinfile +0 240.00 128.00@@0 240.00 128.00 +CENTCENT@@2 +240.00 128.00@@240.00 128.00 +185.00 120.00@@185.00 120.00 +240.00 120.00@@240.00 120.00 +296.00 120.00@@296.00 120.00 +*@@-1.00 -1.00 +2 3@@2 3 +10 A Triangle@@10 A Triangle +POLYGON@@6 +224.00 416.00@@224.00 416.00 +96.00 160.00@@96.00 160.00 +384.00 160.00@@384.00 160.00 +*@@-1.00 -1.00 +5 1@@5 1 +0@@0 +-1@@-1 +.T& +css. +.sp +Table 1. File examples +.TE +.DE +.sp +.IP \(bu +The first line of each +.I gremlin +file contains either the string +.B gremlinfile +.RI ( AED +version) or +.B sungremlinfile +.RI ( SUN / X11 ) +.IP \(bu +The second line of the file contains an orientation, and +.B x +and +.B y +values for a positioning point, separated by spaces. +The orientation, either +.B 0 +or +.BR 1 , +is ignored by the +.IR SUN / X11 +version. +.B 0 +means that +.I gremlin +will display things in horizontal format (drawing area wider than it is +tall, with menu across top). +.B 1 +means that +.I gremlin +will display things in vertical format (drawing area taller than it is wide, +with menu on left side). +.B x +and +.B y +are floating point values giving a positioning point to be used when this +file is read into another file. +The stuff on this line really isn't all that important; a value of ``1 0.00 +0.00'' is suggested. +.IP \(bu +The rest of the file consists of zero or more element specifications. +After the last element specification is a line containing the string ``-1''. +.SH ELEMENT SPECIFICATIONS +.IP \(bu +The first line of each element contains a single decimal number giving the +type of the element +.RI ( AED +version) or its ASCII name +.RI ( SUN / X11 +version). +See Table 2. +.sp +.DS +.TS +center, tab(@); +css +ccc +nll. +\fIgremlin\fP File Format \(mi Object Type Specification +.sp +\fIAED\fP Number@\fISUN\fP/\fIX11\fP Name@Description +0@BOTLEFT@bottom-left-justified text +1@BOTRIGHT@bottom-right-justified text +2@CENTCENT@center-justified text +3@VECTOR@vector +4@ARC@arc +5@CURVE@curve +6@POLYGON@polygon +10@TOPLEFT@top-left-justified text +11@TOPCENT@top-center-justified text +12@TOPRIGHT@top-right-justified text +13@CENTLEFT@left-center-justified text +14@CENTRIGHT@right-center-justified text +15@BOTCENT@bottom-center-justified text +.T& +css. +.sp +Table 2. +Type Specifications in \fIgremlin\fP Files +.TE +.DE +.sp +.IP \(bu +After the object type comes a variable number of lines, each specifying a +point used to display the element. +Each line contains an x-coordinate and a y-coordinate in floating point +format, separated by spaces. +The list of points is terminated by a line containing the string ``-1.0 +-1.0'' +.RI ( AED +version) or a single asterisk, ``*'' +.RI ( SUN / X11 +version). +.IP \(bu +After the points comes a line containing two decimal values, giving the +brush and size for the element. +The brush determines the style in which things are drawn. +For vectors, arcs, and curves there are six legal brush values: +.sp +.DS +.TS +center, tab(@); +ncw(0.1i)l. +1 \(mi@@thin dotted lines +2 \(mi@@thin dot-dashed lines +3 \(mi@@thick solid lines +4 \(mi@@thin dashed lines +5 \(mi@@thin solid lines +6 \(mi@@medium solid lines +.TE +.DE +.sp +For polygons, one more value, 0, is legal. +It specifies a polygon with an invisible border. +For text, the brush selects a font as follows: +.sp +.DS +.TS +center, tab(@); +ncw(0.1i)l. +1 \(mi@@roman (R font in groff) +2 \(mi@@italics (I font in groff) +3 \(mi@@bold (B font in groff) +4 \(mi@@special (S font in groff) +.TE +.DE +.sp +If you're using +.I @g@grn +to run your pictures through +.IR groff , +the font is really just a starting font: +The text string can contain formatting sequences like +``\\fI'' +or +``\\d'' +which may change the font (as well as do many other things). +For text, the size field is a decimal value between 1 and 4. +It selects the size of the font in which the text will be drawn. +For polygons, this size field is interpreted as a stipple number to fill the +polygon with. +The number is used to index into a stipple font at print time. +.IP \(bu +The last line of each element contains a decimal number and a string of +characters, separated by a single space. +The number is a count of the number of characters in the string. +This information is only used for text elements, and contains the text +string. +There can be spaces inside the text. +For arcs, curves, and vectors, this line of the element contains the string +``0''. +.SH NOTES ON COORDINATES +.I gremlin +was designed for +.IR AED s, +and its coordinates reflect the +.I AED +coordinate space. +For vertical pictures, x-values range 116 to 511, and y-values from 0 to +483. +For horizontal pictures, x-values range from 0 to 511 and y-values range +from 0 to 367. +Although you needn't absolutely stick to this range, you'll get best results +if you at least stay in this vicinity. +Also, point lists are terminated by a point of (-1, -1), so you shouldn't +ever use negative coordinates. +.I gremlin +writes out coordinates using format ``%f1.2''; it's probably a good idea to +use the same format if you want to modify the +.I @g@grn +code. +.SH NOTES ON SUN/X11 COORDINATES +There is no longer a restriction on the range of coordinates used to create +objects in the +.IR SUN / X11 +version of +.IR gremlin . +However, files with negative coordinates +.B will +cause problems if displayed on the +.IR AED . +.SH FILES +.Tp \w'@FONTDIR@/devname/DESC'u+3n +.BI @FONTDIR@/dev name /DESC +Device description file for device +.IR name . +.SH SEE ALSO +.BR gremlin (1), +.BR groff (@MAN1EXT@), +.BR @g@pic (@MAN1EXT@), +.BR ideal (1) +.SH HISTORY +.PP +David Slattengren and Barry Roitblat wrote the original Berkeley +.IR @g@grn . +.PP +Daniel Senderowicz and Werner Lemberg modified it for +.IR groff . diff --git a/contrib/groff/src/preproc/grn/hdb.cc b/contrib/groff/src/preproc/grn/hdb.cc new file mode 100644 index 000000000000..fd5bb48a679c --- /dev/null +++ b/contrib/groff/src/preproc/grn/hdb.cc @@ -0,0 +1,326 @@ +/* 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 <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "errarg.h" +#include "error.h" + +#define MAXSTRING 128 + +/* 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, "%s\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,"%s\n", string) == EOF) */ + /* I changed the scanf format because the element */ + /* can have two words (e.g. CURVE SPLINE) */ + if (fscanf(file, "\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') + 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 + * <space>* <digit>*'.'<digit>* <space>* <digit>*'.'<digit>* + * -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 new file mode 100644 index 000000000000..79637209774e --- /dev/null +++ b/contrib/groff/src/preproc/grn/hgraph.cc @@ -0,0 +1,1043 @@ +/* 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 "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); +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 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); + 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) + | + | 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 proper parameters, HGCurve is + | called. + *----------------------------------------------------------------------------*/ + +void +drawwig(POINT * ptr) +{ + 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) { + /* HGCurve(&x[0], &y[0], npts); */ /*Gremlin looks different, so... */ + 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 new file mode 100644 index 000000000000..f4e1ca827755 --- /dev/null +++ b/contrib/groff/src/preproc/grn/hpoint.cc @@ -0,0 +1,49 @@ +/* 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 <stdlib.h> +#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 new file mode 100644 index 000000000000..92e64c6ae77b --- /dev/null +++ b/contrib/groff/src/preproc/grn/main.cc @@ -0,0 +1,905 @@ +/* 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<nn> (integer <nn>) - Set association between stipple <nn> + * and a stipple `character'. <nn> 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 <ctype.h> +#include <stdlib.h> +#include <string.h> +#include "gprint.h" + +#include "device.h" +#include "font.h" +#include "searchpath.h" +#include "macropath.h" + +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "defs.h" + +/* 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': + extern const char *Version_string; + 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("illegal 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/Makefile.sub b/contrib/groff/src/preproc/html/Makefile.sub new file mode 100644 index 000000000000..9d5045a97b31 --- /dev/null +++ b/contrib/groff/src/preproc/html/Makefile.sub @@ -0,0 +1,7 @@ +PROG=pre-grohtml +# MAN1=pre-grohtml.n +MAN1= +XLIBS=$(LIBGROFF) +OBJS=pre-html.o pushbackbuffer.o +CCSRCS=$(srcdir)/pre-html.cc $(srcdir)/pushbackbuffer.cc +NAMEPREFIX=$(g) diff --git a/contrib/groff/src/preproc/html/pre-html.cc b/contrib/groff/src/preproc/html/pre-html.cc new file mode 100644 index 000000000000..8357dd6e4603 --- /dev/null +++ b/contrib/groff/src/preproc/html/pre-html.cc @@ -0,0 +1,1160 @@ +// -*- 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. */ + +#define PREHTMLC + +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <errno.h> +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" +#include "posix.h" +#include "defs.h" + +#include <errno.h> +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef _POSIX_VERSION +#include <sys/wait.h> +#define PID_T pid_t +#else /* not _POSIX_VERSION */ +#define PID_T int +#endif /* not _POSIX_VERSION */ + +extern char *strerror(); + +#include "pre-html.h" +#include "pushbackbuffer.h" +#include "html-strings.h" + +#define POSTSCRIPTRES 72000 // maybe there is a better way to find this? --fixme-- +#define DEFAULT_IMAGE_RES 80 // 80 pixels per inch resolution +#define DEFAULT_VERTICAL_OFFSET 45 // DEFAULT_VERTICAL_OFFSET/72 of an inch +#define IMAGE_BOARDER_PIXELS 0 +#define MAX_WIDTH 8 // inches +#define INLINE_LEADER_CHAR '\\' + +#define TRANSPARENT "-background \"#FFF\" -transparent \"#FFF\"" + +#if 0 +# define DEBUGGING +# define DEBUG_HTML +#endif + +#if !defined(TRUE) +# define TRUE (1==1) +#endif +#if !defined(FALSE) +# define FALSE (1==0) +#endif + +void stop() {} + +typedef enum {CENTERED, LEFT, RIGHT, INLINE} IMAGE_ALIGNMENT; + +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 = 0; // name of postscript file +static char *regionFileName = 0; // name of file containing all image regions +static char *imagePageStem = 0; // stem of all files containing page images +static char *image_device = "pnmraw"; +static int image_res = DEFAULT_IMAGE_RES; +static int vertical_offset= DEFAULT_VERTICAL_OFFSET; +static char *image_template = 0; // image template filename +static int troff_arg = 0; // troff arg index +static char *command_prefix = 0; // optional prefix for some installations. +static char *troff_command = 0; +#if defined(DEBUGGING) +static int debug = FALSE; +static char *troffFileName = 0; // output of pre-html output which is sent to troff -Tps +static char *htmlFileName = 0; // output of pre-html output which is sent to troff -Thtml +#endif + + +/* + * 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) +{ + fprintf(stderr, "%s: %s: %s", program_name, s, strerror(errno)); +} + +/* + * 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_to_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 != 0) { + 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 i=0; + unsigned int old_used; + int n; + + while (! feof(fp)) { + if (tail == 0) { + 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 (n<l) { + r = write(stdoutfd, s, l-n); + if (r<0) { + sys_fatal("write"); + } + n += r; + s += r; + } +} + +/* + * writeString - writes a string to stdout. + */ + +static void writeString (char *s) +{ + writeNbytes(s, strlen(s)); +} + +/* + * makeFileName - creates the image filename template. + */ + +void makeFileName () +{ + char buffer[8192]; + + sprintf(buffer, "grohtml-%d", (int)getpid()); + strcat(buffer, "-%d"); + image_template = (char *)malloc(strlen(buffer)+1); + strcpy(image_template, buffer); +} + +/* + * 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 (is_html) { + /* + * emit image name and enable output + */ + writeString("\\O2\\O1\\O4\n"); + } else { + /* + * postscript, therefore emit image boundaries + */ + writeString("\\O2\\O4\n"); + } +} + +/* + * 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) +{ + if (pos == INLINE) { + writeString("\\O3\\O5'"); + writeString(image_template); writeString(".png'"); + } else { + writeString(".begin \\{\\\n"); + switch (pos) { + + case LEFT: + writeString(". image l "); + break; + case RIGHT: + writeString(". image r "); + break; + case CENTERED: + default: + writeString(". image c "); + } + writeString(image_template); writeString(".png\n"); + if (! is_html) { + writeString(".bp\n"); + writeString(".tl ''''\n"); + } + writeString("\\}\n"); + } + if (is_html) { + writeString("\\O0\n"); + } else { + // reset min/max registers + writeString("\\O0\\O1\n"); + } +} + +/* + * 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 ((k<s->used) && (j<l) && (s->buffer[k] == string[j])) { + j++; + k++; + } + if (j == l) { + *i = k; + *t = s; + return( TRUE ); + } else if ((k<s->used) && (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 ((k<s->used) && (isspace(s->buffer[k]))) { + k++; + } + if (k == s->used) { + k = 0; + s = s->next; + } else { + *i = k; + return( TRUE ); + } + } + return( FALSE ); +} + +/* + * skip_to_newline - skips all characters until a newline is seen. + * The newline is also consumed. + */ + +void char_buffer::skip_to_newline (char_block **t, int *i) +{ + int j=*i; + + if (*t) { + while ((j < (*t)->used) && ((*t)->buffer[j] != '\n')) { + j++; + } + if ((j < (*t)->used) && ((*t)->buffer[j] == '\n')) { + j++; + } + if (j == (*t)->used) { + *i = 0; + if ((*t)->buffer[j-1] == '\n') { + *t = (*t)->next; + } else { + *t = (*t)->next; + skip_to_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 r; + int i=0; + + if (t != 0) { + do { + /* + * remember to check the shortest string last + */ + if (can_see(&t, &i, HTML_IMAGE_END)) { + write_end_image(FALSE); + skip_to_newline(&t, &i); + } else if (can_see(&t, &i, HTML_IMAGE_LEFT)) { + write_start_image(LEFT, FALSE); + skip_to_newline(&t, &i); + } else if (can_see(&t, &i, HTML_IMAGE_RIGHT)) { + write_start_image(RIGHT, FALSE); + skip_to_newline(&t, &i); + } else if (can_see(&t, &i, HTML_IMAGE_CENTERED)) { + write_start_image(CENTERED, FALSE); + skip_to_newline(&t, &i); + } else { + write_upto_newline(&t, &i, FALSE); + } + } while (t != 0); + } + 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 = 0; +} + +/* + * 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); +}; + +/* + * imageList - constructor. + */ + +imageList::imageList () + : head(0), tail(0), count(0) +{ +} + +/* + * imageList - deconstructor. + */ + +imageList::~imageList () +{ + while (head != 0) { + imageItem *i = head; + head = head->next; + delete i; + } +} + +/* + * createAllPages - creates a set of images, one per page. + */ + +static void createAllPages (void) +{ + char buffer[4096]; + + sprintf(buffer, + "echo showpage | gs -q -dSAFER -sDEVICE=%s -r%d -sOutputFile=%s%%d %s - > /dev/null 2>&1 \n", + image_device, + image_res, + imagePageStem, + psFileName); +#if defined(DEBUGGING) + fwrite(buffer, sizeof(char), strlen(buffer), stderr); + fflush(stderr); +#endif + system(buffer); +} + +/* + * removeAllPages - removes all page images. + */ + +static void removeAllPages (void) +{ +#if !defined(DEBUGGING) + char buffer[4096]; + int i=1; + + do { + sprintf(buffer, "%s%d", imagePageStem, i); + i++; + } while (remove(buffer) == 0); +#endif +} + +/* + * abs - returns the absolute value. + */ + +int abs (int x) +{ + if (x < 0) { + return( -x ); + } else { + return( x ); + } +} + +/* + * 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 ); + } +} + +/* + * createImage - generates a minimal png file from the set of page images. + */ + +static void createImage (imageItem *i) +{ + if (i->X1 != -1) { + char buffer[4096]; + 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; + + sprintf(buffer, + "pnmcut %d %d %d %d < %s%d | pnmtopng %s > %s \n", + x1, y1, x2-x1+1, y2-y1+1, + imagePageStem, + i->pageNo, + TRANSPARENT, + i->imageName); +#if defined(DEBUGGING) + fprintf(stderr, buffer); +#endif + system(buffer); +#if defined(DEBUGGING) + } else { + 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 == 0) { + head = i; + tail = i; + } else { + tail->next = i; + tail = i; + } + createImage(i); +} + +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; + char *name; + int i=0; + + if (t != 0) { + stop(); + do { + /* + * remember to check the shortest string last + */ + if (can_see(&t, &i, HTML_IMAGE_END)) { + write_end_image(TRUE); + skip_to_newline(&t, &i); + } else if (can_see(&t, &i, HTML_IMAGE_LEFT)) { + write_start_image(LEFT, TRUE); + skip_to_newline(&t, &i); + } else if (can_see(&t, &i, HTML_IMAGE_RIGHT)) { + write_start_image(RIGHT, TRUE); + skip_to_newline(&t, &i); + } else if (can_see(&t, &i, HTML_IMAGE_CENTERED)) { + stop(); + write_start_image(CENTERED, TRUE); + skip_to_newline(&t, &i); + } else { + write_upto_newline(&t, &i, TRUE); + } + } while (t != 0); + } + 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); + char ch; + + 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 = max(f->readInt(), MAX_WIDTH*image_res); + char *name = f->readString(); + int res = POSTSCRIPTRES; // --fixme-- prefer (f->readInt()) providing that troff can discover the value + listOfImages.add(x1, y1, x2, y2, page, res, maxx, name); + while ((f->putPB(f->getPB()) != '\n') && + (f->putPB(f->getPB()) != eof)) { + ch = f->getPB(); + } + if (f->putPB(f->getPB()) == '\n') { + ch = f->getPB(); + } + } else { + /* + * write any error messages out to the user + */ + fputc(f->getPB(), stderr); + } + } +} + +/* + * 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); + 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 troff + */ + +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] = troff_command; /* use troff */ + } +} + +/* + * do_html - sets the troff number htmlflip and + * writes out the buffer to troff -Thtml + */ + +int char_buffer::do_html(int argc, char *argv[]) +{ + int pdes[2]; + PID_T pid; + + if (pipe(pdes) < 0) + sys_fatal("pipe"); + + alterDeviceTo(argc, argv, 0); + argv += troff_arg; // skip all arguments up to troff/groff + argc -= troff_arg; + +#if defined(DEBUG_HTML) + write_file_html(); + writeString("--------------- troff --------------------------\n"); + write_file_troff(); +#else + pid = fork(); + if (pid < 0) + sys_fatal("fork"); + + if (pid == 0) { + // child + replaceFd(0, pdes[0]); + // close end we are not using + if (close(pdes[1])<0) + sys_fatal("close"); + replaceFd(1, copyofstdoutfd); // and restore stdout + + execvp(argv[0], argv); + error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0); + fflush(stderr); /* just in case error() doesn't */ + exit(1); + } else { + // parent + +#if defined(DEBUGGING) + /* + * slight security risk so only enabled if compiled with defined(DEBUGGING) + */ + if (debug) { + replaceFd(1, creat(htmlFileName, S_IWUSR|S_IRUSR)); + write_file_html(); + } +#endif + replaceFd(1, pdes[1]); + // close end we are not using + if (close(pdes[0])<0) + sys_fatal("close"); + + write_file_html(); + waitForChild(pid); + } +#endif + return( 0 ); +} + +/* + * addps4html - appends -rps4html=1 onto the command list for troff. + */ + +char **addps4html (int argc, char *argv[]) +{ + char **new_argv = (char **)malloc((argc+2)*sizeof(char *)); + int i=0; + + while (i<argc) { + new_argv[i] = argv[i]; + i++; + } + new_argv[argc] = "-rps4html=1"; + argc++; + new_argv[argc] = NULL; + return( new_argv ); +} + +/* + * do_image - writes out the buffer to troff -Tps + */ + +int char_buffer::do_image(int argc, char *argv[]) +{ + PID_T pid; + int pdes[2]; + + if (pipe(pdes) < 0) + sys_fatal("pipe"); + + alterDeviceTo(argc, argv, 1); + argv += troff_arg; // skip all arguments up to troff/groff + argc -= troff_arg; + argv = addps4html(argc, argv); + argc++; + + pid = fork(); + if (pid == 0) { + // child + + int psFd = creat(psFileName, S_IWUSR|S_IRUSR); + int regionFd = creat(regionFileName, S_IWUSR|S_IRUSR); + + replaceFd(1, psFd); + replaceFd(0, pdes[0]); + replaceFd(2, regionFd); + + // close end we are not using + if (close(pdes[1])<0) + sys_fatal("close"); + + execvp(argv[0], argv); + error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0); + fflush(stderr); /* just in case error() doesn't */ + exit(1); + } else { + // parent + +#if defined(DEBUGGING) + /* + * slight security risk so only enabled if compiled with defined(DEBUGGING) + */ + if (debug) { + replaceFd(1, creat(troffFileName, S_IWUSR|S_IRUSR)); + write_file_troff(); + } +#endif + replaceFd(1, pdes[1]); + write_file_troff(); + waitForChild(pid); + } + return( 0 ); +} + +static char_buffer inputFile; + + +/* + * usage - emit usage arguments. + */ + +void usage(FILE *stream) +{ + fprintf(stream, "usage: %s troffname [-P-o vertical_image_offset] [-P-i image_resolution] [troff flags] [files]\n", program_name); + fprintf(stream, " vertical_image_offset (default %d/72 of an inch)\n", vertical_offset); + fprintf(stream, " image_resolution (default %d) pixels per inch\n", image_res); +} + +/* + * scanArguments - scans for -P-i and -P-o arguments. + */ + +int scanArguments (int argc, char **argv) +{ + int i=1; + + while (i<argc) { + if (strncmp(argv[i], "-i", 2) == 0) { + image_res = atoi((char *)(argv[i]+2)); + } else if (strncmp(argv[i], "-o", 2) == 0) { + vertical_offset = atoi((char *)(argv[i]+2)); + } else if ((strcmp(argv[i], "-v") == 0) + || (strcmp(argv[i], "--version") == 0)) { + extern const char *Version_string; + printf("GNU pre-grohtml (groff) version %s\n", Version_string); + exit(0); + } else if ((strcmp(argv[i], "-h") == 0) + || (strcmp(argv[i], "--help") == 0) + || (strcmp(argv[i], "-?") == 0)) { + usage(stdout); + exit(0); + } else if (strcmp(argv[i], "troff") == 0) { + /* remember troff argument number */ + troff_arg = i; +#if defined(DEBUGGING) + } else if (strcmp(argv[i], "-d") == 0) { + debug = TRUE; +#endif + } else if (argv[i][0] != '-') { + return( i ); + } + i++; + } + return( argc ); +} + +/* + * makeTempFiles - name the temporary files + */ + +static void makeTempFiles (void) +{ +#if defined(DEBUGGING) + psFileName = "/tmp/prehtml-ps"; + regionFileName = "/tmp/prehtml-region"; + imagePageStem = "/tmp/prehtml-page"; + troffFileName = "/tmp/prehtml-troff"; + htmlFileName = "/tmp/prehtml-html"; +#else + psFileName = mktemp(xtmptemplate("-ps-")); + regionFileName = mktemp(xtmptemplate("-regions-")); + imagePageStem = mktemp(xtmptemplate("-page-")); +#endif +} + +/* + * removeTempFiles - remove the temporary files + */ + +static void removeTempFiles (void) +{ +#if !defined(DEBUGGING) + remove(psFileName); + remove(regionFileName); +#endif +} + +/* + * findPrefix - finds the optional prefix to the groff utilities. + * It also builds the 'troff' executable name. + */ + +static void findPrefix (void) +{ + command_prefix = getenv("GROFF_COMMAND_PREFIX"); + if (!command_prefix) + command_prefix = PROG_PREFIX; + troff_command = (char *)malloc(strlen("troff")+strlen(command_prefix)+1); + strcpy(troff_command, command_prefix); + strcat(troff_command, "troff"); +} + + +int main(int argc, char **argv) +{ + program_name = argv[0]; + int i; + int found=0; + int ok=1; + + findPrefix(); + makeFileName(); + i = scanArguments(argc, argv); + 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("-"); + } + makeTempFiles(); + ok = inputFile.do_image(argc, argv); + if (ok == 0) { + createAllPages(); + generateImages(regionFileName); + ok = inputFile.do_html(argc, argv); + removeAllPages(); + } + removeTempFiles(); + 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 = 0; + return 1; +} diff --git a/contrib/groff/src/preproc/html/pre-html.h b/contrib/groff/src/preproc/html/pre-html.h new file mode 100644 index 000000000000..f9a590c17b7e --- /dev/null +++ b/contrib/groff/src/preproc/html/pre-html.h @@ -0,0 +1,37 @@ +// -*- 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. */ + +/* + * defines functions implemented within pre-html.c + */ + +#if !defined(PREHTMLH) +# define PREHTMLH +# if defined(PREHTMLC) +# define EXTERN +# else +# define EXTERN extern +# endif + + +extern void sys_fatal (const char *s); + +#undef EXTERN +#endif diff --git a/contrib/groff/src/preproc/html/pushbackbuffer.cc b/contrib/groff/src/preproc/html/pushbackbuffer.cc new file mode 100644 index 000000000000..1d380f4da942 --- /dev/null +++ b/contrib/groff/src/preproc/html/pushbackbuffer.cc @@ -0,0 +1,337 @@ +// -*- 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 <stdio.h> +#include <signal.h> +#include <ctype.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <errno.h> +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "stringclass.h" +#include "posix.h" + +#include <errno.h> +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "pushbackbuffer.h" +#include "pre-html.h" + +#if !defined(TRUE) +# define TRUE (1==1) +#endif + +#if !defined(FALSE) +# define FALSE (1==0) +#endif + +# define ERROR(X) (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<MAXPUSHBACKSTACK) { + charStack[stackPtr] = ch ; + stackPtr++; + } else { + ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant"); + } + return( ch ); +} + +/* + * isWhite - returns TRUE if a white character is found. This character is NOT consumed. + */ + +static int isWhite (char ch) +{ + return( (ch==' ') || (ch == '\t') || (ch == '\n') ); +} + +/* + * skipToNewline - skips characters until a newline is seen. + */ + +void pushBackBuffer::skipToNewline (void) +{ + char ch; + + while ((putPB(getPB()) != '\n') && (! eofFound)) { + ch = getPB(); + } +} + +/* + * skipUntilToken - skips until a token is seen + */ + +void pushBackBuffer::skipUntilToken (void) +{ + char ch; + + while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) { + ch = getPB(); + if (ch == '#') { + skipToNewline(); + } + } +} + +/* + * isString - returns TRUE if the string, s, matches the pushed back string. + * if TRUE is returned then this string is consumed, otherwise it is + * left alone. + */ + +int pushBackBuffer::isString (char *s) +{ + int length=strlen(s); + int i=0; + int j; + + while ((i<length) && (putPB(getPB())==s[i])) { + if (getPB() != s[i]) { + ERROR("assert failed"); + } + i++; + } + if (i==length) { + return( TRUE ); + } else { + i--; + while (i>=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. + */ + +static int isHexDigit (char ch) +{ + return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) ); +} + +/* + * 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 integer; + int fraction; + char ch; + float f; + + integer = readInt(); + if (putPB(getPB()) == '.') { + ch = getPB(); + fraction = readInt(); + f = convertToFloat(integer, fraction); + return( f ); + } else { + return( (float)integer ); + } +} + +/* + * 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/html/pushbackbuffer.h b/contrib/groff/src/preproc/html/pushbackbuffer.h new file mode 100644 index 000000000000..93cb3f1a4e82 --- /dev/null +++ b/contrib/groff/src/preproc/html/pushbackbuffer.h @@ -0,0 +1,54 @@ +// -*- 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. */ + + +#define eof (char)-1 + + +/* + * defines the class and methods implemented within pushbackbuffer.cc + */ + +class pushBackBuffer +{ + private: + char *charStack; + int stackPtr; /* index to push back stack */ + int debug; + int verbose; + int eofFound; + char *fileName; + int lineNo; + int stdIn; + + public: + pushBackBuffer (char *); + ~ pushBackBuffer (); + char getPB (void); + char putPB (char ch); + void skipUntilToken (void); + void skipToNewline (void); + float readNumber (void); + int readInt (void); + char *readString (void); + int isString (char *string); +}; + + diff --git a/contrib/groff/src/preproc/pic/Makefile.sub b/contrib/groff/src/preproc/pic/Makefile.sub new file mode 100644 index 000000000000..f1e292731c14 --- /dev/null +++ b/contrib/groff/src/preproc/pic/Makefile.sub @@ -0,0 +1,31 @@ +PROG=pic +MAN1=pic.n +XLIBS=$(LIBGROFF) +MLIB=$(LIBM) +OBJS=\ + pic.o \ + lex.o \ + main.o \ + object.o \ + common.o \ + troff.o \ + tex.o + # fig.o +CCSRCS=\ + $(srcdir)/lex.cc \ + $(srcdir)/main.cc \ + $(srcdir)/object.cc \ + $(srcdir)/common.cc \ + $(srcdir)/troff.cc \ + $(srcdir)/tex.cc +HDRS=\ + $(srcdir)/common.h \ + $(srcdir)/object.h \ + $(srcdir)/output.h \ + $(srcdir)/pic.h \ + $(srcdir)/position.h \ + $(srcdir)/text.h +GRAM=$(srcdir)/pic.y +YTABC=$(srcdir)/pic.cc +YTABH=$(srcdir)/pic_tab.h +NAMEPREFIX=$(g) diff --git a/contrib/groff/src/preproc/pic/TODO b/contrib/groff/src/preproc/pic/TODO new file mode 100644 index 000000000000..2346b575e1de --- /dev/null +++ b/contrib/groff/src/preproc/pic/TODO @@ -0,0 +1,37 @@ +Dotted and dashed ellipses. + +In troff mode, dotted and dashed splines. + +Make DELIMITED have type lstr; this would allow us to give better +error messages for problems within the body of for and if constructs. + +In troff mode without -x, fake \D't' with .ps commands. + +Perhaps an option to set command char. + +Add an output class for dumb line printers. It wouldn't be pretty but +it would be better than nothing. Integrate it with texinfo. Useful +for groff -Tascii as well. + +Option to allow better positioning of arrowheads on arcs. + +Perhaps add PostScript output mode. + +Change the interface to the output class so that output devices have +the opportunity to handle arrowheads themselves. + +Consider whether the line thickness should scale. + +Consider whether the test in a for loop should be fuzzy (as it +apparently is in grap). + +Possibly change fillval so that zero is black. + +Provide a way of getting text blocks (positioned with `.in' rather +than \h), into pic. Should be possible to use block of diverted text +in pic. Possibly something similar to T{ and T} in tbl. + +Option to provide macro backtraces. + +Have a path that is searched by `copy' statement. Set by environment +variable or command line option. diff --git a/contrib/groff/src/preproc/pic/common.cc b/contrib/groff/src/preproc/pic/common.cc new file mode 100644 index 000000000000..e83ef3122583 --- /dev/null +++ b/contrib/groff/src/preproc/pic/common.cc @@ -0,0 +1,497 @@ +// -*- 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/common.h b/contrib/groff/src/preproc/pic/common.h new file mode 100644 index 000000000000..25a6e10c689c --- /dev/null +++ b/contrib/groff/src/preproc/pic/common.h @@ -0,0 +1,70 @@ +// -*- 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. */ + +class common_output : public output { +private: + void dash_line(const position &start, const position &end, + const line_type <, double dash_width, double gap_width, + double *offsetp); + void dash_arc(const position ¢, double rad, + double start_angle, double end_angle, const line_type <, + double dash_width, double gap_width, double *offsetp); + void dot_line(const position &start, const position &end, + const line_type <, double gap_width, double *offsetp); + void dot_arc(const position ¢, double rad, + double start_angle, double end_angle, const line_type <, + double gap_width, double *offsetp); +protected: + virtual void dot(const position &, const line_type &) = 0; + void dashed_circle(const position &, double rad, const line_type &); + void dotted_circle(const position &, double rad, const line_type &); + void dashed_arc(const position &, const position &, const position &, + const line_type &); + void dotted_arc(const position &, const position &, const position &, + const line_type &); + virtual void solid_arc(const position ¢, double rad, double start_angle, + double end_angle, const line_type <); + void dashed_rounded_box(const position &, const distance &, double, + const line_type &); + void dotted_rounded_box(const position &, const distance &, double, + const line_type &); + void solid_rounded_box(const position &, const distance &, double, + const line_type &); + void filled_rounded_box(const position &, const distance &, double, double); +public: + void start_picture(double sc, const position &ll, const position &ur) = 0; + void finish_picture() = 0; + void circle(const position &, double rad, const line_type &, double) = 0; + void text(const position &, text_piece *, int, double) = 0; + void line(const position &, const position *, int n, const line_type &) = 0; + void polygon(const position *, int n, const line_type &, double) = 0; + void spline(const position &, const position *, int n, + const line_type &) = 0; + void arc(const position &, const position &, const position &, + const line_type &) = 0; + void ellipse(const position &, const distance &, + const line_type &, double) = 0; + void rounded_box(const position &, const distance &, double, + const line_type &, double); +}; + +int compute_arc_center(const position &start, const position ¢, + const position &end, position *result); + diff --git a/contrib/groff/src/preproc/pic/lex.cc b/contrib/groff/src/preproc/pic/lex.cc new file mode 100644 index 000000000000..5b6d439a0440 --- /dev/null +++ b/contrib/groff/src/preproc/pic/lex.cc @@ -0,0 +1,1940 @@ +// -*- 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 "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 (illegal_input_char(c)) + lex_error("illegal 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 illegal 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 }, + { "command", COMMAND }, + { "copy", COPY }, + { "cos", COS }, + { "cw", CW }, + { "dashed", DASHED }, + { "define", DEFINE }, + { "diam", DIAMETER }, + { "diameter", DIAMETER }, + { "do", DO }, + { "dotted", DOTTED }, + { "down", DOWN }, + { "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 }, + { "of", OF }, + { "plot", PLOT }, + { "print", PRINT }, + { "rad", RADIUS }, + { "radius", RADIUS }, + { "rand", RAND }, + { "reset", RESET }, + { "right", RIGHT }, + { "rjust", RJUST }, + { "same", SAME }, + { "sh", SH }, + { "sin", SIN }, + { "solid", SOLID }, + { "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 }, + { "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 (illegal_input_char(c)) { + error("illegal input character code %1", c); + c = getc(fp); + } + if (c == '\n') + lineno++; + return c; +} + +int simple_file_input::peek() +{ + int c = getc(fp); + while (illegal_input_char(c)) { + error("illegal 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 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 new file mode 100644 index 000000000000..87d2b9300074 --- /dev/null +++ b/contrib/groff/src/preproc/pic/main.cc @@ -0,0 +1,635 @@ +// -*- 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 "pic.h" + +extern int yyparse(); + +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 (illegal_input_char(c)) { + error("illegal 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 (illegal_input_char(c)) { + error("illegal 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 +} + +#ifdef __MSDOS__ +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__ */ + +int main(int argc, char **argv) +{ +#ifdef __MSDOS__ + argv[0] = fix_program_name(argv[0], "pic"); +#endif /* __MSDOS__ */ + 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': + { + extern const char *Version_string; + 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 new file mode 100644 index 000000000000..6b346330e4e2 --- /dev/null +++ b/contrib/groff/src/preproc/pic/object.cc @@ -0,0 +1,1833 @@ +// -*- 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 "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); +} + +void output::command(const char *, const char *, int) +{ +} + +void output::set_location(const char *, int) +{ +} + +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 <) +{ + 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; + // A value > 1 means fill with the current color. + out->polygon(v, 3, slt, 2.0); + } + 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; +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(); + virtual void set_fill(double); +}; + +graphic_object::graphic_object() : ntext(0), text(0), aligned(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_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->text(center(), text, ntext, angle); +} + +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); +protected: + double fill; // < 0 if not filled +}; + +closed_object::closed_object(const position &pos) +: rectangle_object(pos), fill(-1.0) +{ +} + +void closed_object::set_fill(double f) +{ + assert(f >= 0.0); + fill = f; +} + + +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) + return; + 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); + } +} + +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) + return; + out->ellipse(cent, dim, lt, fill); +} + +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) + return; + out->circle(cent, dim.x/2.0, lt, fill); +} + +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->line(strt, v, n, lt); + if (arrow_at_start) + draw_arrow(strt, strt-v[0], aht, lt); + if (arrow_at_end) + draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt); +} + +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->spline(strt, v, n, lt); + if (arrow_at_start) + draw_arrow(strt, strt-v[0], aht, lt); + if (arrow_at_end) + draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt); +} + +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; + 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); + } + if (arrow_at_end) { + position e = en - cent; + draw_arrow(en, + (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)), + aht, lt); + } +} + +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_DEFAULT_FILLED|IS_FILLED)) { + 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. */ + +path::path(corner c) +: crn(c), label_list(0), ypath(0) +{ +} + +path::path(char *l, corner c) +: crn(c), ypath(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 +{ + 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 pos = ((p->obj)->*(crn))(); + result->x = pos.x; + result->y = pos.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/object.h b/contrib/groff/src/preproc/pic/object.h new file mode 100644 index 000000000000..2748e81e8465 --- /dev/null +++ b/contrib/groff/src/preproc/pic/object.h @@ -0,0 +1,217 @@ +// -*- 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. */ + +struct place; + +enum object_type { + OTHER_OBJECT, + BOX_OBJECT, + CIRCLE_OBJECT, + ELLIPSE_OBJECT, + ARC_OBJECT, + SPLINE_OBJECT, + LINE_OBJECT, + ARROW_OBJECT, + MOVE_OBJECT, + TEXT_OBJECT, + BLOCK_OBJECT, + MARK_OBJECT + }; + +struct bounding_box; + +struct object { + object *prev; + object *next; + object(); + virtual ~object(); + virtual position origin(); + virtual double width(); + virtual double radius(); + virtual double height(); + virtual position north(); + virtual position south(); + virtual position east(); + virtual position west(); + virtual position north_east(); + virtual position north_west(); + virtual position south_east(); + virtual position south_west(); + virtual position start(); + virtual position end(); + virtual position center(); + virtual place *find_label(const char *); + virtual void move_by(const position &); + virtual int blank(); + virtual void update_bounding_box(bounding_box *); + virtual object_type type() = 0; + virtual void print(); + virtual void print_text(); +}; + +typedef position (object::*corner)(); + +struct place { + object *obj; + double x, y; +}; + +struct string_list; + +class path { + corner crn; + string_list *label_list; + path *ypath; +public: + path(corner = 0); + path(char *, corner = 0); + ~path(); + void append(corner); + void append(char *); + void set_ypath(path *); + int follow(const place &, place *) const; +}; + +struct object_list { + object *head; + object *tail; + object_list(); + void append(object *); + void wrap_up_block(object_list *); +}; + +declare_ptable(place) + +// these go counterclockwise +enum direction { + RIGHT_DIRECTION, + UP_DIRECTION, + LEFT_DIRECTION, + DOWN_DIRECTION + }; + +struct graphics_state { + double x, y; + direction dir; +}; + +struct saved_state : public graphics_state { + saved_state *prev; + PTABLE(place) *tbl; +}; + + +struct text_item { + text_item *next; + char *text; + adjustment adj; + const char *filename; + int lineno; + + text_item(char *, const char *, int); + ~text_item(); +}; + +const unsigned long IS_DOTTED = 01; +const unsigned long IS_DASHED = 02; +const unsigned long IS_CLOCKWISE = 04; +const unsigned long IS_INVISIBLE = 020; +const unsigned long HAS_LEFT_ARROW_HEAD = 040; +const unsigned long HAS_RIGHT_ARROW_HEAD = 0100; +const unsigned long HAS_SEGMENT = 0200; +const unsigned long IS_SAME = 0400; +const unsigned long HAS_FROM = 01000; +const unsigned long HAS_AT = 02000; +const unsigned long HAS_WITH = 04000; +const unsigned long HAS_HEIGHT = 010000; +const unsigned long HAS_WIDTH = 020000; +const unsigned long HAS_RADIUS = 040000; +const unsigned long HAS_TO = 0100000; +const unsigned long IS_CHOPPED = 0200000; +const unsigned long IS_DEFAULT_CHOPPED = 0400000; +const unsigned long HAS_THICKNESS = 01000000; +const unsigned long IS_FILLED = 02000000; +const unsigned long IS_DEFAULT_FILLED = 04000000; +const unsigned long IS_ALIGNED = 010000000; + +struct segment { + int is_absolute; + position pos; + segment *next; + segment(const position &, int, segment *); +}; + +struct rectangle_object; +struct graphic_object; +struct linear_object; + +struct object_spec { + unsigned long flags; + object_type type; + object_list oblist; + PTABLE(place) *tbl; + double dash_width; + position from; + position to; + position at; + position by; + path *with; + text_item *text; + double height; + double radius; + double width; + double segment_width; + double segment_height; + double start_chop; + double end_chop; + double thickness; + double fill; + direction dir; + segment *segment_list; + position segment_pos; + int segment_is_absolute; + + object_spec(object_type); + ~object_spec(); + object *make_object(position *, direction *); + graphic_object *make_box(position *, direction *); + graphic_object *make_block(position *, direction *); + graphic_object *make_text(position *, direction *); + graphic_object *make_ellipse(position *, direction *); + graphic_object *make_circle(position *, direction *); + linear_object *make_line(position *, direction *); + linear_object *make_arc(position *, direction *); + graphic_object *make_linear(position *, direction *); + graphic_object *make_move(position *, direction *); + int position_rectangle(rectangle_object *p, position *curpos, + direction *dirp); +}; + + +object *make_object(object_spec *, position *, direction *); + +object *make_mark_object(); +object *make_command_object(char *, const char *, int); + +int lookup_variable(const char *name, double *val); +void define_variable(const char *name, double val); + +void print_picture(object *); + diff --git a/contrib/groff/src/preproc/pic/output.h b/contrib/groff/src/preproc/pic/output.h new file mode 100644 index 000000000000..ac490db463e3 --- /dev/null +++ b/contrib/groff/src/preproc/pic/output.h @@ -0,0 +1,79 @@ +// -*- 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. */ + +struct line_type { + enum { invisible, solid, dotted, dashed } type; + double dash_width; + double thickness; // the thickness is in points + + line_type(); +}; + + +class output { +protected: + char *args; + double desired_height; // zero if no height specified + double desired_width; // zero if no depth specified + double compute_scale(double, const position &, const position &); +public: + output(); + virtual ~output(); + void set_desired_width_height(double wid, double ht); + void set_args(const char *); + virtual void start_picture(double sc, const position &ll, const position &ur) = 0; + virtual void finish_picture() = 0; + virtual void circle(const position &, double rad, + const line_type &, double) = 0; + virtual void text(const position &, text_piece *, int, double) = 0; + virtual void line(const position &, const position *, int n, + const line_type &) = 0; + virtual void polygon(const position *, int n, + const line_type &, double) = 0; + virtual void spline(const position &, const position *, int n, + const line_type &) = 0; + virtual void arc(const position &, const position &, const position &, + const line_type &) = 0; + virtual void ellipse(const position &, const distance &, + const line_type &, double) = 0; + virtual void rounded_box(const position &, const distance &, double, + const line_type &, double) = 0; + virtual void command(const char *, const char *, int); + virtual void set_location(const char *, int); + virtual int supports_filled_polygons(); + virtual void begin_block(const position &ll, const position &ur); + virtual void end_block(); +}; + +extern output *out; + +/* #define FIG_SUPPORT 1 */ +#define TEX_SUPPORT 1 + +output *make_troff_output(); + +#ifdef TEX_SUPPORT +output *make_tex_output(); +output *make_tpic_output(); +#endif /* TEX_SUPPORT */ + +#ifdef FIG_SUPPORT +output *make_fig_output(); +#endif /* FIG_SUPPORT */ diff --git a/contrib/groff/src/preproc/pic/pic.cc b/contrib/groff/src/preproc/pic/pic.cc new file mode 100644 index 000000000000..f6d97bb2d202 --- /dev/null +++ b/contrib/groff/src/preproc/pic/pic.cc @@ -0,0 +1,5216 @@ +#ifndef lint +/*static char yysccsid[] = "from: @(#)yaccpar 1.9 (Berkeley) 02/21/93";*/ +static char yyrcsid[] = "$Id: pic.cc,v 1.3 2000/11/14 20:40:28 wlemb Exp $"; +#endif +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING (yyerrflag!=0) +#define YYPREFIX "yy" +#line 20 "/home/cjk/groff/src/preproc/pic/pic.y" +#include "pic.h" +#include "ptable.h" +#include "object.h" + +extern int delim_flag; +extern void do_copy(const char *); +extern void copy_rest_thru(const char *, const char *); +extern void copy_file_thru(const char *, const char *, const char *); +extern void push_body(const char *); +extern void do_for(char *var, double from, double to, + int by_is_multiplicative, double by, char *body); +extern void do_lookahead(); + +#ifndef HAVE_FMOD +extern "C" { + double fmod(double, double); +} +#endif + +#undef rand +#undef srand +extern "C" { + int rand(); +#ifdef RET_TYPE_SRAND_IS_VOID + void srand(unsigned int); +#else + int srand(unsigned int); +#endif +} + +/* Maximum number of characters produced by printf("%g") */ +#define GDIGITS 14 + +int yylex(); +void yyerror(const char *); + +void reset(const char *nm); +void reset_all(); + +place *lookup_label(const char *); +void define_label(const char *label, const place *pl); + +direction current_direction; +position current_position; + +implement_ptable(place) + +PTABLE(place) top_table; + +PTABLE(place) *current_table = &top_table; +saved_state *current_saved_state = 0; + +object_list olist; + +const char *ordinal_postfix(int n); +const char *object_type_name(object_type type); +char *format_number(const char *form, double n); +char *do_sprintf(const char *form, const double *v, int nv); + +#line 82 "/home/cjk/groff/src/preproc/pic/pic.y" +typedef union { + char *str; + int n; + double x; + struct { double x, y; } pair; + struct { double x; char *body; } if_data; + struct { char *str; const char *filename; int lineno; } lstr; + struct { double *v; int nv; int maxv; } dv; + struct { double val; int is_multiplicative; } by; + place pl; + object *obj; + corner crn; + path *pth; + object_spec *spec; + saved_state *pstate; + graphics_state state; + object_type obtype; +} YYSTYPE; +#line 92 "y.tab.c" +#define LABEL 257 +#define VARIABLE 258 +#define NUMBER 259 +#define TEXT 260 +#define COMMAND_LINE 261 +#define DELIMITED 262 +#define ORDINAL 263 +#define TH 264 +#define LEFT_ARROW_HEAD 265 +#define RIGHT_ARROW_HEAD 266 +#define DOUBLE_ARROW_HEAD 267 +#define LAST 268 +#define UP 269 +#define DOWN 270 +#define LEFT 271 +#define RIGHT 272 +#define BOX 273 +#define CIRCLE 274 +#define ELLIPSE 275 +#define ARC 276 +#define LINE 277 +#define ARROW 278 +#define MOVE 279 +#define SPLINE 280 +#define HEIGHT 281 +#define RADIUS 282 +#define WIDTH 283 +#define DIAMETER 284 +#define FROM 285 +#define TO 286 +#define AT 287 +#define WITH 288 +#define BY 289 +#define THEN 290 +#define SOLID 291 +#define DOTTED 292 +#define DASHED 293 +#define CHOP 294 +#define SAME 295 +#define INVISIBLE 296 +#define LJUST 297 +#define RJUST 298 +#define ABOVE 299 +#define BELOW 300 +#define OF 301 +#define THE 302 +#define WAY 303 +#define BETWEEN 304 +#define AND 305 +#define HERE 306 +#define DOT_N 307 +#define DOT_E 308 +#define DOT_W 309 +#define DOT_S 310 +#define DOT_NE 311 +#define DOT_SE 312 +#define DOT_NW 313 +#define DOT_SW 314 +#define DOT_C 315 +#define DOT_START 316 +#define DOT_END 317 +#define DOT_X 318 +#define DOT_Y 319 +#define DOT_HT 320 +#define DOT_WID 321 +#define DOT_RAD 322 +#define SIN 323 +#define COS 324 +#define ATAN2 325 +#define LOG 326 +#define EXP 327 +#define SQRT 328 +#define K_MAX 329 +#define K_MIN 330 +#define INT 331 +#define RAND 332 +#define SRAND 333 +#define COPY 334 +#define THRU 335 +#define TOP 336 +#define BOTTOM 337 +#define UPPER 338 +#define LOWER 339 +#define SH 340 +#define PRINT 341 +#define CW 342 +#define CCW 343 +#define FOR 344 +#define DO 345 +#define IF 346 +#define ELSE 347 +#define ANDAND 348 +#define OROR 349 +#define NOTEQUAL 350 +#define EQUALEQUAL 351 +#define LESSEQUAL 352 +#define GREATEREQUAL 353 +#define LEFT_CORNER 354 +#define RIGHT_CORNER 355 +#define CENTER 356 +#define END 357 +#define START 358 +#define RESET 359 +#define UNTIL 360 +#define PLOT 361 +#define THICKNESS 362 +#define FILL 363 +#define ALIGNED 364 +#define SPRINTF 365 +#define COMMAND 366 +#define DEFINE 367 +#define UNDEF 368 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 0, 16, 17, 17, 28, 28, 29, 29, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 31, 30, + 30, 32, 33, 30, 34, 35, 30, 36, 30, 30, + 37, 30, 30, 30, 38, 38, 38, 26, 26, 27, + 27, 27, 39, 7, 23, 23, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 15, 15, 15, 15, 40, 42, 15, 15, 41, 41, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 43, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 25, 25, 24, 24, 19, + 19, 6, 6, 6, 6, 6, 6, 44, 44, 5, + 5, 13, 13, 13, 13, 13, 14, 14, 14, 22, + 22, 21, 21, 8, 8, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 11, 11, 12, 12, 12, 10, + 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; +short yylen[] = { 2, + 1, 1, 3, 1, 3, 0, 1, 1, 2, 3, + 4, 1, 1, 1, 1, 1, 2, 2, 0, 3, + 2, 0, 0, 7, 0, 0, 6, 0, 10, 1, + 0, 4, 1, 1, 2, 2, 3, 1, 2, 1, + 1, 1, 0, 5, 0, 2, 1, 1, 3, 3, + 3, 3, 3, 3, 3, 3, 2, 0, 2, 3, + 1, 4, 4, 4, 0, 0, 6, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 3, 0, 4, 3, 3, 3, 3, 2, 2, 3, + 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, + 3, 2, 2, 2, 3, 2, 3, 2, 3, 2, + 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 3, 2, 1, 5, 0, 3, 1, + 1, 1, 3, 3, 5, 5, 6, 1, 4, 3, + 3, 1, 2, 2, 3, 1, 1, 1, 3, 1, + 3, 1, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 2, 1, 2, 3, 1, 1, 2, 1, + 5, 4, 3, 3, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 2, 3, 4, 4, + 6, 4, 4, 4, 6, 6, 4, 4, 3, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 2, +}; +short yydefred[] = { 0, + 8, 0, 2, 0, 0, 0, 0, 126, 16, 12, + 13, 14, 15, 71, 72, 73, 74, 75, 76, 77, + 78, 0, 19, 0, 0, 0, 0, 0, 0, 0, + 65, 82, 0, 4, 0, 0, 79, 68, 0, 9, + 0, 0, 0, 0, 25, 0, 147, 204, 205, 150, + 152, 189, 190, 146, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 187, 188, 0, 0, + 195, 196, 201, 203, 202, 0, 0, 0, 0, 0, + 132, 130, 148, 0, 0, 0, 0, 0, 0, 41, + 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, + 35, 0, 0, 0, 0, 0, 31, 3, 0, 114, + 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 102, 103, 0, 0, 0, + 112, 113, 120, 121, 122, 123, 117, 118, 0, 0, + 125, 0, 119, 36, 0, 0, 10, 0, 22, 0, + 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 191, 193, 197, 199, 192, 194, 198, 200, + 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 206, 207, 208, + 209, 210, 0, 143, 0, 0, 164, 156, 157, 158, + 159, 160, 161, 162, 0, 155, 153, 154, 39, 0, + 0, 57, 0, 0, 0, 43, 0, 0, 0, 0, + 81, 128, 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 167, 100, 0, 170, 0, 0, + 101, 0, 0, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 62, 0, 11, 0, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, + 218, 141, 0, 151, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 149, 133, 134, 163, 0, 0, 53, + 0, 0, 0, 0, 0, 51, 0, 0, 50, 49, + 0, 66, 83, 32, 175, 0, 0, 0, 0, 165, + 0, 169, 0, 0, 23, 0, 219, 220, 0, 222, + 223, 224, 0, 0, 227, 228, 230, 0, 0, 0, + 0, 0, 44, 0, 127, 0, 0, 174, 173, 0, + 166, 0, 0, 27, 0, 0, 0, 135, 139, 0, + 0, 0, 0, 70, 67, 172, 0, 24, 46, 221, + 225, 226, 137, 0, 0, 171, 0, 0, 28, 0, + 0, 29, +}; +short yydgoto[] = { 2, + 106, 182, 108, 405, 91, 92, 33, 93, 94, 266, + 267, 268, 109, 96, 34, 3, 35, 36, 97, 226, + 98, 99, 384, 341, 110, 101, 102, 244, 5, 38, + 46, 287, 382, 160, 356, 411, 246, 39, 334, 115, + 395, 376, 116, 205, +}; +short yysindex[] = { 25, + 0, 0, 0,11784, 59, -47, -5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -250, 0,10817, -218,10934, -197,11387, 90,10817, + 0, 0, -214, 0, 25,10516, 0, 0, -36, 0, + 25,10934, 75, -192, 0, -124, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 106, 107, 110, 111, 113, + 120, 122, 124, 143, 146, 153, 0, 0, -213, -41, + 0, 0, 0, 0, 0,11061,10934,11387,11387, 635, + 0, 0, 0, -61, -64, 2542, 44, 834, 356, 0, +10817, 0, 133,10934,10934, 1378, -91, -294, -64, -279, + 0, -28, -52,10817, 25, 25, 0, 0,11406, 0, + 0, 0,11694,11694,11694,11694,11387,11387,11387,11387, +11505,11505,11505, 3348,11609, 0, 0,11694,11694,11694, + 0, 0, 0, 0, 0, 0, 0, 0,11387,11694, + 0, 1491, 0, 0, -33,10189, 0,10934, 0, -46, + 0,10934,10934,10934,10934,10934,10934,10934,10934,10934, +10633,10934, 0, 0, 0, 0, 0, 0, 0, 0, + 1524, 194, 195, -23, -26, 150, 150, -56, 0,11387, +11387,11387,11387,11387,11387,11387,11505,11387,11387,11387, +11387,11387,11387,11387,11505, -29, 213, 0, 0, 0, + 0, 0, -7, 0,11609,11609, 0, 0, 0, 0, + 0, 0, 0, 0, 167, 0, 0, 0, 0,11387, + 150, 0,10934,10934,11387, 0,10934,10934, -230, -230, + 0, 0, 139,11784, 177, 11, 0, 1491, 1491, 1491, + 1491, 1491, 1491, 1491, 1491, 635, 44, 44, 44, 2101, + 432, 834, 2101, 17, 0, 0, 2435, 0,11178, 623, + 0, 1491, 1491, 1491, 1491, 1491, 0, -47, -5, 0, + 0, 0, -64, 0, 44, 0, 18, 0, 240, 246, + 244, 248, 249, 250, 252, 253, 257, 0, 260, 262, + 0, 0,11505, 0, 1, 1953, 1821, 158, 158, 4, + 4, 1491, -19, 48, 4, 200, 200, 150, 150, 150, + 150, -42, 213, 0, 0, 0, 0, 1044, 1953, 0, + 1924, -43, 4, 46, 1953, 0, 1924, -43, 0, 0, + 19, 0, 0, 0, 0, 834, 2101, 2101, 266, 0, + 49, 0, 1079, 195, 0, -49, 0, 0,10934, 0, + 0, 0,10934,10934, 0, 0, 0, 33, 8,11505, +11505,11387, 0,11387, 0,11784, 2101, 0, 0, 2101, + 0, -49, 55, 0, 275, 277, 290, 0, 0, 7, + 44, 1484, 1491, 0, 0, 0, 293, 0, 0, 0, + 0, 0, 0,11283, -10, 0,11387, 1491, 0, 1491, + 74, 0, +}; +short yyrindex[] = { 204, + 0, 0, 0, 338, 94, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, + 0, 0, 399, 0, 27, 412, 0, 0, 443, 0, +10384, 0, 0, 454, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8824, + 0, 0, 0, 0, 4444, 8610, 9125, 0, 0, 0, + 467, 0, 0, 0, 0, 954, 0, 970, 0, 0, + 0,10077, 0, 487,11820,11820, 0, 0, 31, 0, + 0, 0, 9459, 9500, 9245, 9351, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9612, 9720, 9761, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9868, + 0, 4996, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 299, 0, 114, 0, 0, 456, 566, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3115, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5297, 5406, 5707, + 5816, 6117, 6226, 6527, 6636, 0, 6937, 7046, 7347, 0, + 0, 0, 0, 0, 0, 0, 8697, 0, 0, 0, + 0, 7456, 7757, 7866, 8167, 8276, 0, 9870, 1967, 3642, + 4085, 184, 233, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4001, 4110, 3224, 3558, 2229, + 2338, 4887, 9004, 0, 2672, 1786, 1895, 900, 1009, 1343, + 1452, 0, 3667, 0, 0, 0, 0, 0, 29, 0, + 38, 182, 2781, 0, 96, 0, 468, 578, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 299, 0, 0, 495, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 530, 0, 0, 0, 0, + 0, 495, 0, 0, 0, 0, 0, 0, 0, 0, + 4553, -4, 39, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, + 0, 0, +}; +short yygindex[] = { 0, + -24, 480, -89, 0, -18, 189, 0, 0, -48, 0, + 0, 354, 3172, -87, -114, -3, 0, 0, 1313, -74, + 0, 0, -21, 0, 9, 326, -57, 2, 324, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; +#define YYTABLESIZE 12186 +short yytable[] = { 90, + 215, 4, 216, 112, 247, 90, 207, 155, 203, 44, + 41, 152, 37, 201, 199, 232, 200, 203, 202, 215, + 303, 216, 201, 199, 228, 200, 6, 202, 237, 8, + 7, 235, 100, 198, 87, 34, 118, 238, 100, 103, + 203, 284, 156, 229, 153, 201, 199, 214, 200, 215, + 202, 216, 43, 237, 238, 42, 229, 173, 174, 375, + 111, 181, 374, 186, 187, 204, 87, 183, 403, 237, + 239, 240, 237, 388, 204, 215, 90, 216, 238, 129, + 231, 238, 129, 1, 45, 265, 215, 237, 216, 90, + 215, 370, 216, 7, 34, 52, 238, 204, 248, 249, + 250, 251, 252, 253, 254, 255, 256, 256, 256, 100, + 270, 243, 245, 272, 273, 274, 271, 40, 323, 6, + 241, 237, 100, 7, 275, 276, 7, 37, 34, 113, + 238, 256, 117, 7, 29, 158, 52, 161, 7, 52, + 175, 176, 159, 330, 332, 162, 163, 336, 338, 164, + 165, 6, 166, 237, 52, 7, 132, 132, 132, 167, + 34, 168, 238, 169, 37, 306, 307, 308, 309, 310, + 311, 312, 313, 315, 316, 317, 318, 319, 320, 321, + 256, 56, 170, 63, 7, 171, 347, 348, 52, 7, + 270, 270, 172, 230, 203, 47, 325, 326, 236, 201, + 199, 50, 200, 6, 202, 328, 51, 242, 329, 331, + 333, 265, 335, 337, 265, 288, 7, 235, 352, 198, + 52, 154, 56, 239, 277, 56, 130, 47, 130, 177, + 178, 8, 64, 50, 301, 302, 203, 304, 51, 206, + 56, 201, 63, 204, 353, 305, 202, 339, 340, 324, + 354, 204, 37, 208, 209, 210, 211, 212, 213, 327, + 239, 394, 371, 342, 239, 239, 239, 239, 239, 343, + 239, 377, 344, 350, 56, 131, 63, 131, 256, 355, + 357, 188, 239, 239, 189, 239, 358, 359, 360, 361, + 362, 64, 237, 204, 6, 363, 364, 365, 265, 265, + 366, 238, 367, 369, 237, 381, 56, 373, 63, 380, + 383, 389, 179, 180, 399, 400, 239, 401, 237, 190, + 191, 192, 193, 194, 195, 64, 6, 238, 265, 237, + 402, 265, 237, 406, 409, 412, 29, 1, 238, 47, + 58, 238, 59, 60, 282, 256, 256, 392, 239, 393, + 7, 7, 7, 7, 7, 114, 7, 64, 119, 52, + 398, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 0, 0, 237, 237, 0, 408, + 0, 0, 410, 0, 37, 52, 238, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 30, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 61, 0, 0, 0, 0, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, + 7, 7, 7, 7, 7, 0, 0, 7, 0, 7, + 0, 0, 33, 52, 52, 56, 225, 7, 7, 7, + 7, 7, 7, 21, 7, 217, 0, 30, 7, 7, + 6, 6, 0, 6, 6, 0, 18, 55, 0, 0, + 61, 56, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 0, 0, 17, 239, 217, 0, + 0, 30, 217, 0, 45, 217, 217, 217, 217, 217, + 217, 33, 217, 0, 61, 107, 0, 0, 55, 194, + 195, 55, 21, 239, 217, 217, 0, 217, 0, 0, + 0, 157, 225, 30, 239, 18, 55, 239, 0, 69, + 56, 0, 0, 0, 0, 33, 61, 6, 0, 0, + 0, 0, 0, 6, 6, 17, 21, 6, 217, 6, + 0, 217, 0, 45, 0, 0, 0, 0, 0, 18, + 55, 0, 6, 0, 6, 239, 185, 33, 6, 6, + 0, 239, 239, 239, 239, 239, 239, 54, 21, 17, + 217, 0, 0, 0, 0, 0, 0, 45, 69, 0, + 0, 18, 55, 0, 0, 0, 0, 0, 239, 0, + 0, 0, 239, 0, 0, 239, 239, 239, 239, 239, + 239, 17, 239, 345, 0, 217, 349, 0, 54, 45, + 0, 54, 69, 227, 239, 239, 0, 239, 218, 219, + 220, 221, 222, 223, 0, 224, 54, 286, 0, 0, + 0, 289, 290, 291, 292, 293, 294, 295, 296, 297, + 299, 300, 0, 0, 69, 0, 0, 0, 239, 203, + 0, 239, 0, 0, 201, 199, 196, 200, 0, 202, + 54, 203, 0, 0, 0, 0, 201, 199, 196, 200, + 0, 202, 235, 0, 198, 0, 0, 0, 0, 0, + 239, 217, 0, 0, 197, 0, 198, 0, 0, 346, + 378, 379, 54, 0, 218, 219, 220, 221, 222, 223, + 0, 224, 217, 217, 217, 217, 204, 0, 217, 217, + 217, 217, 217, 217, 217, 217, 217, 217, 204, 0, + 396, 55, 0, 397, 0, 0, 217, 217, 217, 217, + 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, + 217, 217, 217, 217, 217, 217, 217, 55, 0, 217, + 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, + 217, 217, 217, 0, 0, 0, 0, 0, 217, 217, + 217, 217, 217, 217, 217, 217, 217, 217, 217, 0, + 0, 217, 217, 217, 217, 0, 0, 217, 217, 0, + 217, 0, 0, 217, 217, 217, 217, 217, 217, 217, + 217, 217, 217, 217, 0, 0, 55, 217, 217, 217, + 217, 0, 239, 239, 239, 239, 0, 0, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 385, 0, + 0, 54, 386, 387, 0, 0, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 54, 0, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 0, 0, 0, 0, 0, 239, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 213, + 0, 239, 239, 239, 239, 0, 0, 239, 239, 0, + 239, 0, 0, 239, 239, 239, 239, 239, 239, 239, + 239, 239, 239, 239, 225, 0, 54, 239, 239, 239, + 239, 0, 213, 0, 0, 188, 213, 0, 189, 213, + 213, 213, 213, 213, 213, 0, 213, 0, 0, 0, + 0, 0, 0, 47, 0, 0, 0, 0, 213, 213, + 0, 213, 0, 0, 0, 0, 0, 0, 0, 48, + 190, 191, 192, 193, 194, 195, 0, 0, 0, 0, + 0, 0, 190, 191, 192, 193, 194, 195, 0, 0, + 0, 0, 213, 0, 47, 213, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 214, 0, + 48, 0, 47, 48, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 213, 0, 0, 0, 48, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 214, 0, 0, 0, 214, 47, 0, 214, 214, + 214, 214, 214, 214, 0, 214, 0, 0, 0, 0, + 0, 0, 48, 0, 0, 0, 0, 214, 214, 0, + 214, 0, 0, 0, 0, 0, 0, 0, 47, 0, + 203, 0, 0, 0, 0, 201, 199, 0, 200, 0, + 202, 0, 0, 217, 48, 0, 0, 0, 0, 0, + 0, 214, 0, 235, 214, 198, 218, 219, 220, 221, + 222, 223, 0, 224, 0, 203, 0, 0, 0, 0, + 201, 199, 196, 200, 0, 202, 0, 0, 0, 0, + 0, 0, 0, 214, 0, 0, 0, 204, 235, 0, + 198, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 213, 213, 213, 213, + 0, 0, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 204, 0, 0, 0, 0, 0, 0, 0, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 0, 0, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 47, 0, 0, + 0, 0, 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 48, 0, 213, 213, 213, 213, 0, + 0, 213, 213, 47, 213, 0, 0, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 0, 48, + 0, 213, 213, 213, 213, 214, 214, 214, 214, 0, + 0, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 0, 0, 0, 0, 0, 0, 0, 0, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 0, 0, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 0, 0, 0, 372, + 0, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 215, 0, 214, 214, 214, 214, 0, 0, + 214, 214, 0, 214, 0, 0, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 0, 0, 0, + 214, 214, 214, 214, 0, 215, 0, 0, 0, 215, + 0, 0, 215, 215, 215, 215, 215, 215, 0, 215, + 0, 190, 191, 192, 193, 194, 195, 0, 184, 0, + 0, 215, 215, 0, 215, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 203, 0, 0, 0, 0, 201, + 199, 0, 200, 0, 202, 0, 233, 234, 192, 193, + 194, 195, 0, 0, 0, 215, 0, 235, 215, 198, + 0, 0, 0, 257, 258, 259, 0, 0, 0, 0, + 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 215, 285, 0, + 0, 204, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 216, 0, 0, 0, 216, 0, + 0, 216, 216, 216, 216, 216, 216, 0, 216, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 314, + 216, 216, 0, 216, 0, 0, 0, 322, 0, 0, + 203, 0, 0, 0, 0, 201, 199, 203, 200, 0, + 202, 0, 201, 199, 0, 200, 0, 202, 0, 0, + 0, 0, 0, 235, 216, 198, 0, 216, 0, 0, + 235, 0, 198, 0, 0, 0, 0, 0, 0, 0, + 203, 0, 0, 0, 0, 201, 199, 196, 200, 0, + 202, 0, 0, 0, 0, 0, 216, 204, 0, 0, + 0, 0, 0, 197, 204, 198, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, + 215, 215, 215, 0, 0, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 368, 0, 204, 0, 0, + 0, 0, 0, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 0, 0, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 0, 0, 0, 0, 0, 215, 215, 215, 215, 215, + 215, 215, 215, 215, 215, 215, 0, 0, 215, 215, + 215, 215, 390, 391, 215, 215, 0, 215, 0, 0, + 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, + 215, 0, 0, 0, 215, 215, 215, 215, 216, 216, + 216, 216, 0, 0, 216, 216, 216, 216, 216, 216, + 216, 216, 216, 216, 0, 233, 234, 192, 193, 194, + 195, 0, 216, 216, 216, 216, 216, 216, 216, 216, + 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, + 216, 216, 216, 0, 0, 216, 216, 216, 216, 216, + 216, 216, 216, 216, 216, 216, 216, 216, 216, 0, + 0, 0, 404, 0, 216, 216, 216, 216, 216, 216, + 216, 216, 216, 216, 216, 211, 0, 216, 216, 216, + 216, 0, 0, 216, 216, 0, 216, 0, 0, 216, + 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, + 0, 0, 0, 216, 216, 216, 216, 0, 211, 0, + 0, 0, 0, 0, 188, 211, 211, 189, 211, 211, + 211, 190, 191, 192, 193, 194, 195, 0, 190, 191, + 192, 193, 194, 195, 211, 211, 0, 211, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, + 0, 0, 201, 199, 0, 200, 0, 202, 0, 0, + 0, 233, 234, 192, 193, 194, 195, 0, 211, 0, + 235, 211, 198, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 211, 0, 0, 0, 204, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, + 0, 0, 0, 0, 212, 212, 0, 212, 212, 212, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 212, 212, 0, 212, 0, 0, 0, + 203, 0, 0, 0, 0, 201, 199, 0, 200, 0, + 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 235, 0, 198, 0, 212, 0, 203, + 212, 0, 0, 0, 201, 199, 0, 200, 0, 202, + 0, 0, 0, 204, 0, 0, 0, 0, 204, 204, + 204, 204, 235, 204, 198, 0, 0, 204, 0, 212, + 0, 0, 0, 0, 0, 0, 204, 0, 204, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 211, 211, 211, 211, 204, 0, 211, 211, + 211, 211, 211, 211, 211, 211, 211, 211, 0, 0, + 204, 0, 0, 0, 0, 0, 211, 211, 211, 211, + 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, + 211, 211, 211, 211, 211, 211, 211, 0, 0, 211, + 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, + 211, 211, 211, 0, 0, 0, 0, 0, 211, 211, + 211, 211, 211, 211, 211, 211, 211, 211, 211, 0, + 0, 211, 211, 211, 211, 0, 0, 211, 211, 0, + 211, 0, 0, 211, 211, 211, 211, 211, 211, 211, + 211, 211, 211, 211, 0, 0, 264, 211, 211, 211, + 211, 212, 212, 212, 212, 0, 0, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 0, 190, 0, + 192, 193, 194, 195, 0, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 0, 0, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 0, 0, 0, 0, 0, 212, 212, 212, + 212, 212, 212, 212, 212, 212, 212, 212, 232, 0, + 212, 212, 212, 212, 0, 0, 212, 212, 0, 212, + 0, 0, 212, 212, 212, 212, 212, 212, 212, 212, + 212, 212, 212, 0, 0, 0, 212, 212, 212, 212, + 0, 232, 0, 0, 0, 0, 0, 204, 232, 232, + 204, 233, 232, 192, 193, 194, 195, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 232, 232, 0, + 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 192, 193, 194, 195, 0, 0, 0, 0, + 0, 0, 0, 0, 204, 204, 204, 204, 204, 204, + 0, 232, 0, 0, 232, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 234, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 232, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 234, 52, 53, 0, 0, 0, 0, 234, 234, 0, + 0, 234, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 234, 234, 0, 234, + 0, 0, 0, 0, 0, 0, 0, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 234, 0, 0, 234, 0, 0, 77, 78, 79, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 81, 82, 83, 84, 85, 0, + 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 351, 0, 0, 0, 0, 232, 232, 232, 232, 0, + 0, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 0, 0, 0, 0, 0, 0, 0, 0, 232, + 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 0, 0, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 232, 232, 232, 232, 232, 0, 0, 0, 0, + 0, 232, 232, 232, 232, 232, 232, 232, 232, 232, + 232, 232, 0, 0, 232, 232, 232, 232, 0, 0, + 232, 232, 0, 232, 0, 0, 232, 232, 232, 232, + 232, 232, 232, 232, 232, 232, 232, 213, 0, 0, + 232, 232, 232, 232, 234, 234, 234, 234, 0, 0, + 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 0, 0, 0, 0, 0, 0, 0, 0, 234, 234, + 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 234, 234, 234, 234, 234, 234, 234, 0, + 0, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 234, 234, 234, 234, 0, 0, 0, 0, 0, + 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, + 234, 233, 0, 234, 234, 234, 234, 0, 0, 234, + 234, 0, 234, 0, 0, 234, 234, 234, 234, 234, + 234, 234, 234, 234, 234, 234, 0, 0, 0, 234, + 234, 234, 234, 0, 233, 52, 53, 0, 0, 0, + 0, 233, 233, 0, 0, 233, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 233, 233, 0, 233, 0, 0, 0, 0, 0, 0, + 0, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 233, 0, 0, 233, 0, 0, + 77, 78, 79, 80, 0, 0, 0, 0, 0, 0, + 231, 0, 0, 0, 0, 0, 0, 0, 81, 82, + 83, 84, 85, 0, 0, 0, 233, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, + 231, 231, 0, 0, 231, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, + 231, 0, 231, 0, 0, 0, 0, 0, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 231, 0, 0, 231, 77, 78, 79, + 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 81, 82, 83, 84, 85, + 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 233, 233, + 233, 233, 0, 0, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 0, 0, 0, 0, 0, 0, + 0, 0, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 0, 0, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 0, + 0, 0, 0, 0, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 0, 0, 233, 233, 233, + 233, 0, 0, 233, 233, 0, 233, 0, 0, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 0, 0, 0, 233, 233, 233, 233, 231, 231, 231, + 231, 0, 0, 231, 231, 231, 231, 231, 231, 231, + 231, 231, 231, 0, 0, 0, 0, 0, 0, 0, + 0, 231, 231, 231, 231, 231, 231, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, + 231, 231, 0, 0, 231, 231, 231, 231, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 0, 0, + 0, 0, 0, 231, 231, 231, 231, 231, 231, 231, + 231, 231, 231, 231, 144, 0, 231, 231, 231, 231, + 0, 0, 231, 231, 0, 231, 0, 0, 231, 231, + 231, 231, 231, 231, 231, 231, 231, 231, 231, 0, + 0, 0, 231, 231, 231, 231, 0, 144, 0, 0, + 0, 0, 0, 0, 144, 144, 0, 144, 144, 144, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 144, 0, 0, 144, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, + 0, 95, 0, 0, 0, 0, 0, 144, 0, 0, + 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 236, 95, 0, 0, + 0, 0, 0, 236, 236, 0, 0, 236, 0, 0, + 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 236, 0, 0, 95, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 95, 95, 95, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 236, 0, 0, 236, + 0, 0, 0, 0, 0, 0, 0, 283, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 236, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, + 0, 144, 144, 144, 144, 0, 95, 144, 0, 144, + 144, 144, 144, 144, 144, 144, 144, 263, 0, 0, + 0, 0, 0, 264, 0, 144, 144, 144, 144, 144, + 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 144, 144, 144, 0, 0, 0, 0, 144, + 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 144, 144, 144, 144, 144, 144, 0, 0, + 144, 144, 144, 144, 0, 0, 144, 144, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 144, 144, + 144, 144, 144, 0, 95, 0, 144, 144, 144, 144, + 236, 236, 236, 236, 0, 0, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 0, 0, 0, 0, + 0, 0, 0, 0, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 0, 0, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 236, 95, 95, 0, 0, 0, 236, 236, 236, 236, + 236, 236, 236, 236, 236, 236, 236, 235, 0, 236, + 236, 236, 236, 0, 0, 236, 236, 0, 236, 0, + 0, 236, 236, 236, 236, 0, 0, 236, 236, 236, + 236, 236, 0, 0, 0, 236, 236, 236, 236, 0, + 235, 0, 0, 0, 0, 0, 0, 235, 235, 0, + 0, 235, 0, 0, 260, 0, 0, 0, 0, 0, + 261, 0, 0, 0, 0, 262, 235, 0, 52, 53, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, + 235, 0, 0, 235, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 0, 145, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 235, 77, 78, 79, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, + 14, 81, 82, 83, 84, 85, 145, 145, 0, 145, + 145, 145, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 145, 0, 0, 145, 0, + 0, 0, 0, 0, 14, 0, 0, 189, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, + 0, 0, 145, 0, 0, 0, 14, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 235, 235, 235, 235, 0, 0, + 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, + 0, 0, 0, 0, 0, 0, 0, 0, 235, 235, + 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, + 235, 235, 235, 235, 235, 235, 235, 235, 235, 0, + 0, 235, 235, 235, 235, 235, 235, 235, 235, 235, + 235, 235, 235, 235, 235, 0, 0, 0, 0, 0, + 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, + 235, 0, 0, 235, 235, 235, 235, 0, 189, 235, + 235, 0, 235, 0, 189, 235, 235, 235, 235, 189, + 0, 235, 235, 235, 235, 235, 0, 0, 0, 235, + 235, 235, 235, 145, 145, 145, 145, 0, 0, 145, + 0, 145, 145, 145, 145, 145, 145, 145, 145, 0, + 0, 0, 189, 0, 0, 0, 0, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 0, 0, 0, + 0, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 237, 0, 145, 145, 145, 145, 0, 0, 145, 145, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 145, 145, 145, 145, 145, 0, 0, 0, 145, 145, + 145, 145, 0, 237, 0, 0, 0, 0, 0, 0, + 237, 237, 0, 0, 237, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, + 0, 0, 0, 237, 0, 0, 237, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 238, 15, 0, 0, 0, 0, 0, 238, + 238, 0, 0, 238, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 238, 0, + 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, + 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 238, 0, 0, 238, 0, 0, 0, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 237, 237, 237, + 237, 0, 0, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 0, 0, 0, 0, 0, 0, 0, + 0, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 0, 0, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 237, 237, 237, 237, 0, 0, + 0, 0, 0, 237, 237, 237, 237, 237, 237, 237, + 237, 237, 237, 237, 0, 0, 237, 237, 237, 237, + 0, 190, 237, 237, 0, 237, 0, 190, 237, 237, + 0, 0, 190, 0, 237, 237, 237, 237, 237, 0, + 0, 0, 237, 237, 237, 237, 238, 238, 238, 238, + 0, 0, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 0, 0, 0, 190, 0, 0, 0, 0, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 0, 0, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 238, 238, 238, 238, 0, 0, 0, + 0, 0, 238, 238, 238, 238, 238, 238, 238, 238, + 238, 238, 238, 131, 0, 238, 238, 238, 238, 0, + 0, 238, 238, 0, 238, 0, 0, 0, 238, 0, + 0, 0, 0, 238, 238, 238, 238, 238, 0, 0, + 0, 238, 238, 238, 238, 0, 131, 0, 0, 0, + 0, 0, 0, 131, 131, 0, 131, 131, 131, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 131, 0, 0, 131, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 131, 0, 0, 131, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, + 0, 0, 136, 136, 0, 0, 136, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 136, 0, 0, 136, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 136, 0, 0, 136, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 136, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 131, 131, 131, 131, 0, 0, 131, 0, 131, 131, + 131, 131, 131, 131, 131, 131, 0, 0, 0, 0, + 0, 0, 0, 0, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 0, 0, 0, 0, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 0, 0, 0, 0, 0, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 0, 0, 131, + 131, 131, 131, 0, 0, 131, 131, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 131, 131, 131, + 131, 131, 0, 0, 0, 131, 131, 131, 131, 136, + 136, 136, 136, 0, 0, 136, 0, 136, 136, 136, + 136, 136, 136, 136, 136, 0, 0, 0, 0, 0, + 0, 0, 0, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 0, 0, 0, 0, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 0, 0, 0, 0, 0, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 140, 0, 136, 136, + 136, 136, 0, 0, 136, 136, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 136, 136, 136, 136, + 136, 0, 0, 0, 136, 136, 136, 136, 0, 140, + 0, 0, 0, 0, 0, 0, 140, 140, 0, 0, + 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 140, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, + 0, 0, 140, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 140, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, + 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 140, 140, 140, 140, 0, 0, 140, + 0, 140, 140, 140, 140, 140, 140, 140, 140, 0, + 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 0, 0, 0, + 0, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 0, 0, 0, 0, 0, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 0, 0, 140, 140, 140, 140, 0, 0, 140, 140, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 140, 140, 140, 140, 140, 0, 0, 0, 140, 140, + 140, 140, 88, 88, 88, 88, 0, 0, 88, 0, + 88, 88, 88, 88, 88, 88, 88, 88, 0, 0, + 0, 0, 0, 0, 0, 0, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 90, 0, 0, 0, + 0, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 0, 0, 0, 0, 0, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 90, + 0, 88, 88, 88, 88, 0, 90, 88, 88, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, + 88, 88, 88, 88, 0, 90, 0, 88, 88, 88, + 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, + 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, + 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, + 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 90, 90, 90, 90, 0, 0, 90, + 0, 90, 90, 90, 90, 90, 90, 90, 90, 0, + 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 0, 0, 0, + 0, 0, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 0, 0, 0, 0, 0, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 0, 0, 90, 90, 90, 90, 0, 0, 90, 90, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 90, 90, 90, 90, 90, 0, 0, 0, 90, 90, + 90, 90, 92, 92, 92, 92, 0, 0, 92, 0, + 92, 92, 92, 92, 92, 92, 92, 92, 0, 0, + 0, 0, 0, 0, 0, 0, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 96, 0, 0, 0, + 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 0, 0, 0, 0, 0, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, + 0, 92, 92, 92, 92, 0, 96, 92, 92, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, + 92, 92, 92, 92, 0, 96, 0, 92, 92, 92, + 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, + 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, + 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, + 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 96, 96, 96, 96, 0, 0, 96, + 0, 96, 96, 96, 96, 96, 96, 96, 96, 0, + 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, + 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 0, 0, 0, 0, 0, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 0, 0, 96, 96, 96, 96, 0, 0, 96, 96, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 96, 96, 96, 96, 96, 0, 0, 0, 96, 96, + 96, 96, 94, 94, 94, 94, 0, 0, 94, 0, + 94, 94, 94, 94, 94, 94, 94, 94, 0, 0, + 0, 0, 0, 0, 0, 0, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 84, 0, 0, 0, + 0, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 0, 0, 0, 0, 0, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 84, + 0, 94, 94, 94, 94, 0, 84, 94, 94, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, + 94, 94, 94, 94, 0, 84, 0, 94, 94, 94, + 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, + 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, + 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, + 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 84, 84, 84, 84, 0, 0, 84, + 0, 84, 84, 84, 84, 84, 84, 84, 84, 0, + 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, + 0, 0, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 0, 0, 0, 0, 0, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 0, 0, 84, 84, 84, 84, 0, 0, 84, 84, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 84, 84, 84, 84, 84, 0, 0, 0, 84, 84, + 84, 84, 85, 85, 85, 85, 0, 0, 85, 0, + 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, + 0, 0, 0, 0, 0, 0, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 86, 0, 0, 0, + 0, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 0, 0, 0, 0, 0, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 86, + 0, 85, 85, 85, 85, 0, 86, 85, 85, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, + 85, 85, 85, 85, 0, 86, 0, 85, 85, 85, + 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, + 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, + 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, + 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 86, 86, 86, 86, 0, 0, 86, + 0, 86, 86, 86, 86, 86, 86, 86, 86, 0, + 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, + 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 0, 0, 0, 0, 0, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 0, 0, 86, 86, 86, 86, 0, 0, 86, 86, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 86, 86, 86, 86, 86, 0, 0, 0, 86, 86, + 86, 86, 87, 87, 87, 87, 0, 0, 87, 0, + 87, 87, 87, 87, 87, 87, 87, 87, 0, 0, + 0, 0, 0, 0, 0, 0, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 97, 0, 0, 0, + 0, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 0, 0, 0, 0, 0, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 97, + 0, 87, 87, 87, 87, 0, 97, 87, 87, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, + 87, 87, 87, 87, 0, 97, 0, 87, 87, 87, + 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, + 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, + |