diff options
author | ru <ru@FreeBSD.org> | 2001-04-17 12:23:50 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2001-04-17 12:23:50 +0000 |
commit | 61352401d3a90e1f7df92a3b0c656abdd58db6cf (patch) | |
tree | 00e2ca5da289f187526a4d9a20bc79d3dbf54dc8 /contrib/groff/troff | |
parent | 42d565388eaa8c9f931d7188a3f2f9c5951f6b3b (diff) | |
download | FreeBSD-src-61352401d3a90e1f7df92a3b0c656abdd58db6cf.zip FreeBSD-src-61352401d3a90e1f7df92a3b0c656abdd58db6cf.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r75587,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/groff/troff')
-rw-r--r-- | contrib/groff/troff/Makefile.sub | 57 | ||||
-rw-r--r-- | contrib/groff/troff/TODO | 137 | ||||
-rw-r--r-- | contrib/groff/troff/charinfo.h | 171 | ||||
-rw-r--r-- | contrib/groff/troff/column.cc | 732 | ||||
-rw-r--r-- | contrib/groff/troff/dictionary.cc | 212 | ||||
-rw-r--r-- | contrib/groff/troff/dictionary.h | 92 | ||||
-rw-r--r-- | contrib/groff/troff/div.cc | 1127 | ||||
-rw-r--r-- | contrib/groff/troff/div.h | 150 | ||||
-rw-r--r-- | contrib/groff/troff/env.cc | 3215 | ||||
-rw-r--r-- | contrib/groff/troff/env.h | 334 | ||||
-rw-r--r-- | contrib/groff/troff/hvunits.h | 340 | ||||
-rw-r--r-- | contrib/groff/troff/hyphen.us | 4449 | ||||
-rw-r--r-- | contrib/groff/troff/input.cc | 6406 | ||||
-rw-r--r-- | contrib/groff/troff/node.cc | 4920 | ||||
-rw-r--r-- | contrib/groff/troff/node.h | 495 | ||||
-rw-r--r-- | contrib/groff/troff/number.cc | 669 | ||||
-rw-r--r-- | contrib/groff/troff/reg.cc | 473 | ||||
-rw-r--r-- | contrib/groff/troff/reg.h | 73 | ||||
-rw-r--r-- | contrib/groff/troff/request.h | 79 | ||||
-rw-r--r-- | contrib/groff/troff/symbol.cc | 150 | ||||
-rw-r--r-- | contrib/groff/troff/symbol.h | 73 | ||||
-rw-r--r-- | contrib/groff/troff/token.h | 201 | ||||
-rw-r--r-- | contrib/groff/troff/troff.h | 83 |
23 files changed, 0 insertions, 24638 deletions
diff --git a/contrib/groff/troff/Makefile.sub b/contrib/groff/troff/Makefile.sub deleted file mode 100644 index 342ad59..0000000 --- a/contrib/groff/troff/Makefile.sub +++ /dev/null @@ -1,57 +0,0 @@ -PROG=troff -MAN1=troff.n -XLIBS=$(LIBGROFF) -MLIB=$(LIBM) -OBJS=\ - env.o \ - node.o \ - input.o \ - div.o \ - symbol.o \ - dictionary.o \ - reg.o \ - number.o \ - majorminor.o -CCSRCS=\ - $(srcdir)/env.cc \ - $(srcdir)/node.cc \ - $(srcdir)/input.cc \ - $(srcdir)/div.cc \ - $(srcdir)/symbol.cc \ - $(srcdir)/dictionary.cc \ - $(srcdir)/reg.cc \ - $(srcdir)/number.cc \ - majorminor.cc -HDRS=\ - $(srcdir)/charinfo.h \ - $(srcdir)/dictionary.h \ - $(srcdir)/div.h \ - $(srcdir)/env.h \ - $(srcdir)/hvunits.h \ - $(srcdir)/node.h \ - $(srcdir)/reg.h \ - $(srcdir)/request.h \ - $(srcdir)/symbol.h \ - $(srcdir)/token.h \ - $(srcdir)/troff.h -GENSRCS=majorminor.cc -NAMEPREFIX=$(g) - -majorminor.cc: $(top_srcdir)/VERSION $(top_srcdir)/REVISION - @echo Making $@ - @-rm -f $@ - @echo const char \*major_version = \ - \"`sed -e 's/^\([^.]*\)\..*$$/\1/' $(top_srcdir)/VERSION`\"\; >$@ - @echo const char \*minor_version = \ - \"`sed -e 's/^[^.]*\.\([0-9]*\).*$$/\1/' $(top_srcdir)/VERSION`\"\; >>$@ - @echo const char \*revision = \"`cat $(top_srcdir)/REVISION`\"\; >>$@ - -install_data: hyphen.us - -test -d $(datadir) || $(mkinstalldirs) $(datadir) - -test -d $(datasubdir) || $(mkinstalldirs) $(datasubdir) - -test -d $(tmacdir) || $(mkinstalldirs) $(tmacdir) - -rm -f $(tmacdir)/hyphen.us - $(INSTALL_DATA) $(srcdir)/hyphen.us $(tmacdir)/hyphen.us - -uninstall_sub: - -rm -f $(tmacdir)/hyphen.us diff --git a/contrib/groff/troff/TODO b/contrib/groff/troff/TODO deleted file mode 100644 index 3e6480b..0000000 --- a/contrib/groff/troff/TODO +++ /dev/null @@ -1,137 +0,0 @@ -Give a more helpful error message when the indent is set to a value -greater than the line-length. - -Tracing. This is a pain to implement because requests are responsible -for reading their own arguments. - -Possibly implement -s option (stop every N pages). This functionality -would be more appropriate in a postprocessor. - -Line breaking should be smarter. In particular, it should be possible -to shrink spaces. Also avoid having a line that's been shrunk a lot -next to a line that's been stretched a lot. The difficulty is to -design a mechanism that allows the user complete control over the -decision of where to break the line. - -Provide a mechanism to control the shape of the rag in non-justified -text. - -Add a discretionary break escape sequence. \B'...'...'...' like TeX. - -Think about kerning between characters and spaces. (Need to implement -get_breakpoints and split methods for kern_pair_node class.) - -In troff, if .L > 1 when a diversion is reread in no-fill mode, then -extra line-spacing is added on. Groff at the moment treats line-spacing -like vertical spacing and doesn't do this. - -Suppose \(ch comes from a special font S, and that the current font is -R. Suppose that R contains a hyphen character and that S does not. -Suppose that the current font is R. Suppose that \(ch is in a word -and has a non-zero hyphen-type. Then we ought to be able to hyphenate, -but we won't be able to because we will look for the hyphen only in -font S and not in font R. - -Variant of tm which doesn't write a newline. - -Perhaps the current input level should be accessible in a number register. - -Should \w deal with a newline like \X? - -Have another look at uses of token::delimiter. Perhaps we need to -distinguish the case where we want to see if a token could start a -number, from the case where we want to see if it could occur somewhere -in a number expression. - -Provide a facility like copy thru in pic. - -Fancier implementation of font families which doesn't group fonts into -families purely on the basis of their names. - -In the DESC file make the number of fonts optional if they are all on -one line. - -Number register to give the diversion level. - -Time various alternative implementations of scale (both in font.c and -number.c). On a sparc it's faster to always do it in floating point. - -Devise a more compact representation for the hyphenation patterns trie. - -Have a per-environment parameter to increase letter-spacing. - -Number register to return character height. - -Number register to return character slant. - -Request to set character height. - -Request to set character slant. - -Provide some way to upcase or downcase strings. - -Support non-uniformly scalable fonts. Perhaps associate a suffix with -a particular range of sizes. eg - sizesuffix .display 14-512 -Then is you ask for R at pointsize 16, groff will first look for -R.display and then R. Probably necessary to be able to specify a -separate unitwidth for each sizesuffix (eg. for X). - -Variant of `.it' for which a line interrupted with \c counts as one -input line. - -Make it possible to suppress hyphenation on a word-by-word basis. -(Perhaps store hyphenation flags in tfont.) - -Possibly allow multiple simultaneous input line traps. - -Unpaddable, breakable space escape sequence. - -Support hanging punctuation. - -In justified text, if the last line of a paragraph is only a little -bit short it might be desirable to justify the line. Allow the user -control over this. - -Have a blank line macro like the end macro. When a blank line macro -has been set, then a blank line causes the blank line macro to be -called rather than doing the equivalent of .sp. - -The pm request could print where the macro was defined. Also could -optionally print the contents of a macro. - -Provide some way to round numbers to multiples of the current -horizontal or vertical resolution. - -Better string-processing support (search). - -Generalized ligatures. - -Provide some way for a macro to tell whether it was called with `'' or -`.'. This would be useful for implementing a tracing macro package. - -Request to remove an environment. (Maintain a count of the references -to the environment from the environment table, environment dictionary -or environment stack.) - -Perhaps in the nr request a leading `-' should only be recognized as a -decrement when it's at the same input level as the request. - -Don't ever change a charinfo. Create new variants instead and chain -them together. - -Make it possible to tr characters onto \~. - -Unix troff appears to read the first character of a request name in -copy mode. Should we do the same? - -Number register giving name of end macro. - -More thorough range checking. - -Provide syntax for octal and hexadecimal numeric constants. Perhaps -o#100 and x#7f as per Scheme. Or perhaps PostScript 16#7f. Ambiguity -between whether `c' is treated as digit or scaling indicator. - -Request to return from a macro (ie ignore the rest of the current -input level). diff --git a/contrib/groff/troff/charinfo.h b/contrib/groff/troff/charinfo.h deleted file mode 100644 index a4ecd57..0000000 --- a/contrib/groff/troff/charinfo.h +++ /dev/null @@ -1,171 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -class macro; - -class charinfo { - static int next_index; - charinfo *translation; - int index; - int number; - macro *mac; - unsigned char special_translation; - unsigned char hyphenation_code; - unsigned char flags; - unsigned char ascii_code; - char not_found; - char transparent_translate; // non-zero means translation applies to - // to transparent throughput -public: - enum { - ENDS_SENTENCE = 1, - BREAK_BEFORE = 2, - BREAK_AFTER = 4, - OVERLAPS_HORIZONTALLY = 8, - OVERLAPS_VERTICALLY = 16, - TRANSPARENT = 32, - NUMBERED = 64 - }; - enum { - TRANSLATE_NONE, - TRANSLATE_SPACE, - TRANSLATE_DUMMY, - TRANSLATE_STRETCHABLE_SPACE, - TRANSLATE_HYPHEN_INDICATOR - }; - symbol nm; - charinfo(symbol s); - int get_index(); - int ends_sentence(); - int overlaps_vertically(); - int overlaps_horizontally(); - int can_break_before(); - int can_break_after(); - int transparent(); - unsigned char get_hyphenation_code(); - unsigned char get_ascii_code(); - void set_hyphenation_code(unsigned char); - void set_ascii_code(unsigned char); - charinfo *get_translation(int = 0); - void set_translation(charinfo *, int); - void set_flags(unsigned char); - void set_special_translation(int, int); - int get_special_translation(int = 0); - macro *set_macro(macro *); - macro *get_macro(); - int first_time_not_found(); - void set_number(int); - int get_number(); - int numbered(); - symbol *get_symbol(); -}; - -charinfo *get_charinfo(symbol); -extern charinfo *charset_table[]; -charinfo *get_charinfo_by_number(int); - -inline int charinfo::overlaps_horizontally() -{ - return flags & OVERLAPS_HORIZONTALLY; -} - -inline int charinfo::overlaps_vertically() -{ - return flags & OVERLAPS_VERTICALLY; -} - -inline int charinfo::can_break_before() -{ - return flags & BREAK_BEFORE; -} - -inline int charinfo::can_break_after() -{ - return flags & BREAK_AFTER; -} - -inline int charinfo::ends_sentence() -{ - return flags & ENDS_SENTENCE; -} - -inline int charinfo::transparent() -{ - return flags & TRANSPARENT; -} - -inline int charinfo::numbered() -{ - return flags & NUMBERED; -} - -inline charinfo *charinfo::get_translation(int transparent_throughput) -{ - return (transparent_throughput && !transparent_translate - ? 0 - : translation); -} - -inline unsigned char charinfo::get_hyphenation_code() -{ - return hyphenation_code; -} - -inline unsigned char charinfo::get_ascii_code() -{ - return ascii_code; -} - -inline void charinfo::set_flags(unsigned char c) -{ - flags = c; -} - -inline int charinfo::get_index() -{ - return index; -} - -inline int charinfo::get_special_translation(int transparent_throughput) -{ - return (transparent_throughput && !transparent_translate - ? int(TRANSLATE_NONE) - : special_translation); -} - -inline macro *charinfo::get_macro() -{ - return mac; -} - -inline int charinfo::first_time_not_found() -{ - if (not_found) - return 0; - else { - not_found = 1; - return 1; - } -} - -inline symbol *charinfo::get_symbol() -{ - return( &nm ); -} diff --git a/contrib/groff/troff/column.cc b/contrib/groff/troff/column.cc deleted file mode 100644 index 096f381..0000000 --- a/contrib/groff/troff/column.cc +++ /dev/null @@ -1,732 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifdef COLUMN - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "div.h" -#include "reg.h" -#include "stringclass.h" - -void output_file::vjustify(vunits, symbol) -{ - // do nothing -} - -struct justification_spec; -struct output_line; - -class column : public output_file { -private: - output_file *out; - vunits bottom; - output_line *col; - output_line **tail; - void add_output_line(output_line *); - void begin_page(int pageno, vunits page_length); - void flush(); - void print_line(hunits, vunits, node *, vunits, vunits); - void vjustify(vunits, symbol); - void transparent_char(unsigned char c); - void copy_file(hunits, vunits, const char *); - int is_printing(); - void check_bottom(); -public: - column(); - ~column(); - void start(); - void output(); - void justify(const justification_spec &); - void trim(); - void reset(); - vunits get_bottom(); - vunits get_last_extra_space(); - int is_active() { return out != 0; } -}; - -column *the_column = 0; - -struct transparent_output_line; -struct vjustify_output_line; - -class output_line { - output_line *next; -public: - output_line(); - virtual ~output_line(); - virtual void output(output_file *, vunits); - virtual transparent_output_line *as_transparent_output_line(); - virtual vjustify_output_line *as_vjustify_output_line(); - virtual vunits distance(); - virtual vunits height(); - virtual void reset(); - virtual vunits extra_space(); // post line - friend class column; - friend class justification_spec; -}; - -class position_output_line : public output_line { - vunits dist; -public: - position_output_line(vunits); - vunits distance(); -}; - -class node_output_line : public position_output_line { - node *nd; - hunits page_offset; - vunits before; - vunits after; -public: - node_output_line(vunits, node *, hunits, vunits, vunits); - ~node_output_line(); - void output(output_file *, vunits); - vunits height(); - vunits extra_space(); -}; - -class vjustify_output_line : public position_output_line { - vunits current; - symbol typ; -public: - vjustify_output_line(vunits dist, symbol); - vunits height(); - vjustify_output_line *as_vjustify_output_line(); - void vary(vunits amount); - void reset(); - symbol type(); -}; - -inline symbol vjustify_output_line::type() -{ - return typ; -} - -class copy_file_output_line : public position_output_line { - symbol filename; - hunits hpos; -public: - copy_file_output_line(vunits, const char *, hunits); - void output(output_file *, vunits); -}; - -class transparent_output_line : public output_line { - string buf; -public: - transparent_output_line(); - void output(output_file *, vunits); - void append_char(unsigned char c); - transparent_output_line *as_transparent_output_line(); -}; - -output_line::output_line() : next(0) -{ -} - -output_line::~output_line() -{ -} - -void output_line::reset() -{ -} - -transparent_output_line *output_line::as_transparent_output_line() -{ - return 0; -} - -vjustify_output_line *output_line::as_vjustify_output_line() -{ - return 0; -} - -void output_line::output(output_file *, vunits) -{ -} - -vunits output_line::distance() -{ - return V0; -} - -vunits output_line::height() -{ - return V0; -} - -vunits output_line::extra_space() -{ - return V0; -} - -position_output_line::position_output_line(vunits d) -: dist(d) -{ -} - -vunits position_output_line::distance() -{ - return dist; -} - -node_output_line::node_output_line(vunits d, node *n, hunits po, vunits b, vunits a) -: position_output_line(d), nd(n), page_offset(po), before(b), after(a) -{ -} - -node_output_line::~node_output_line() -{ - delete_node_list(nd); -} - -void node_output_line::output(output_file *out, vunits pos) -{ - out->print_line(page_offset, pos, nd, before, after); - nd = 0; -} - -vunits node_output_line::height() -{ - return after; -} - -vunits node_output_line::extra_space() -{ - return after; -} - -vjustify_output_line::vjustify_output_line(vunits d, symbol t) -: position_output_line(d), typ(t) -{ -} - -void vjustify_output_line::reset() -{ - current = V0; -} - -vunits vjustify_output_line::height() -{ - return current; -} - -vjustify_output_line *vjustify_output_line::as_vjustify_output_line() -{ - return this; -} - -inline void vjustify_output_line::vary(vunits amount) -{ - current += amount; -} - -transparent_output_line::transparent_output_line() -{ -} - -transparent_output_line *transparent_output_line::as_transparent_output_line() -{ - return this; -} - -void transparent_output_line::append_char(unsigned char c) -{ - assert(c != 0); - buf += c; -} - -void transparent_output_line::output(output_file *out, vunits) -{ - int len = buf.length(); - for (int i = 0; i < len; i++) - out->transparent_char(buf[i]); -} - -copy_file_output_line::copy_file_output_line(vunits d, const char *f, hunits h) -: position_output_line(d), hpos(h), filename(f) -{ -} - -void copy_file_output_line::output(output_file *out, vunits pos) -{ - out->copy_file(hpos, pos, filename.contents()); -} - -column::column() -: bottom(V0), col(0), tail(&col), out(0) -{ -} - -column::~column() -{ - assert(out != 0); - error("automatically outputting column before exiting"); - output(); - delete the_output; -} - -void column::start() -{ - assert(out == 0); - if (!the_output) - init_output(); - assert(the_output != 0); - out = the_output; - the_output = this; -} - -void column::begin_page(int pageno, vunits page_length) -{ - assert(out != 0); - if (col) { - error("automatically outputting column before beginning next page"); - output(); - the_output->begin_page(pageno, page_length); - } - else - out->begin_page(pageno, page_length); - -} - -void column::flush() -{ - assert(out != 0); - out->flush(); -} - -int column::is_printing() -{ - assert(out != 0); - return out->is_printing(); -} - -vunits column::get_bottom() -{ - return bottom; -} - -void column::add_output_line(output_line *ln) -{ - *tail = ln; - bottom += ln->distance(); - bottom += ln->height(); - ln->next = 0; - tail = &(*tail)->next; -} - -void column::print_line(hunits page_offset, vunits pos, node *nd, - vunits before, vunits after) -{ - assert(out != 0); - add_output_line(new node_output_line(pos - bottom, nd, page_offset, before, after)); -} - -void column::vjustify(vunits pos, symbol typ) -{ - assert(out != 0); - add_output_line(new vjustify_output_line(pos - bottom, typ)); -} - -void column::transparent_char(unsigned char c) -{ - assert(out != 0); - transparent_output_line *tl = 0; - if (*tail) - tl = (*tail)->as_transparent_output_line(); - if (!tl) { - tl = new transparent_output_line; - add_output_line(tl); - } - tl->append_char(c); -} - -void column::copy_file(hunits page_offset, vunits pos, const char *filename) -{ - assert(out != 0); - add_output_line(new copy_file_output_line(pos - bottom, filename, page_offset)); -} - -void column::trim() -{ - output_line **spp = 0; - for (output_line **pp = &col; *pp; pp = &(*pp)->next) - if ((*pp)->as_vjustify_output_line() == 0) - spp = 0; - else if (!spp) - spp = pp; - if (spp) { - output_line *ln = *spp; - *spp = 0; - tail = spp; - while (ln) { - output_line *tem = ln->next; - bottom -= ln->distance(); - bottom -= ln->height(); - delete ln; - ln = tem; - } - } -} - -void column::reset() -{ - bottom = V0; - for (output_line *ln = col; ln; ln = ln->next) { - bottom += ln->distance(); - ln->reset(); - bottom += ln->height(); - } -} - -void column::check_bottom() -{ - vunits b; - for (output_line *ln = col; ln; ln = ln->next) { - b += ln->distance(); - b += ln->height(); - } - assert(b == bottom); -} - -void column::output() -{ - assert(out != 0); - vunits vpos(V0); - output_line *ln = col; - while (ln) { - vpos += ln->distance(); - ln->output(out, vpos); - vpos += ln->height(); - output_line *tem = ln->next; - delete ln; - ln = tem; - } - tail = &col; - bottom = V0; - col = 0; - the_output = out; - out = 0; -} - -vunits column::get_last_extra_space() -{ - if (!col) - return V0; - for (output_line *p = col; p->next; p = p->next) - ; - return p->extra_space(); -} - -class justification_spec { - vunits height; - symbol *type; - vunits *amount; - int n; - int maxn; -public: - justification_spec(vunits); - ~justification_spec(); - void append(symbol t, vunits v); - void justify(output_line *, vunits *bottomp) const; -}; - -justification_spec::justification_spec(vunits h) -: height(h), n(0), maxn(10) -{ - type = new symbol[maxn]; - amount = new vunits[maxn]; -} - -justification_spec::~justification_spec() -{ - a_delete type; - a_delete amount; -} - -void justification_spec::append(symbol t, vunits v) -{ - if (v <= V0) { - if (v < V0) - warning(WARN_RANGE, - "maximum space for vertical justification must not be negative"); - else - warning(WARN_RANGE, - "maximum space for vertical justification must not be zero"); - return; - } - if (n >= maxn) { - maxn *= 2; - symbol *old_type = type; - type = new symbol[maxn]; - int i; - for (i = 0; i < n; i++) - type[i] = old_type[i]; - a_delete old_type; - vunits *old_amount = amount; - amount = new vunits[maxn]; - for (i = 0; i < n; i++) - amount[i] = old_amount[i]; - a_delete old_amount; - } - assert(n < maxn); - type[n] = t; - amount[n] = v; - n++; -} - -void justification_spec::justify(output_line *col, vunits *bottomp) const -{ - if (*bottomp >= height) - return; - vunits total; - output_line *p; - for (p = col; p; p = p->next) { - vjustify_output_line *sp = p->as_vjustify_output_line(); - if (sp) { - symbol t = sp->type(); - for (int i = 0; i < n; i++) { - if (t == type[i]) - total += amount[i]; - } - } - } - vunits gap = height - *bottomp; - for (p = col; p; p = p->next) { - vjustify_output_line *sp = p->as_vjustify_output_line(); - if (sp) { - symbol t = sp->type(); - for (int i = 0; i < n; i++) { - if (t == type[i]) { - if (total <= gap) { - sp->vary(amount[i]); - gap -= amount[i]; - } - else { - // gap < total - vunits v = scale(amount[i], gap, total); - sp->vary(v); - gap -= v; - } - total -= amount[i]; - } - } - } - } - assert(total == V0); - *bottomp = height - gap; -} - -void column::justify(const justification_spec &js) -{ - check_bottom(); - js.justify(col, &bottom); - check_bottom(); -} - -void column_justify() -{ - vunits height; - if (!the_column->is_active()) - error("can't justify column - column not active"); - else if (get_vunits(&height, 'v')) { - justification_spec js(height); - symbol nm = get_long_name(1); - if (!nm.is_null()) { - vunits v; - if (get_vunits(&v, 'v')) { - js.append(nm, v); - int err = 0; - while (has_arg()) { - nm = get_long_name(1); - if (nm.is_null()) { - err = 1; - break; - } - if (!get_vunits(&v, 'v')) { - err = 1; - break; - } - js.append(nm, v); - } - if (!err) - the_column->justify(js); - } - } - } - skip_line(); -} - -void column_start() -{ - if (the_column->is_active()) - error("can't start column - column already active"); - else - the_column->start(); - skip_line(); -} - -void column_output() -{ - if (!the_column->is_active()) - error("can't output column - column not active"); - else - the_column->output(); - skip_line(); -} - -void column_trim() -{ - if (!the_column->is_active()) - error("can't trim column - column not active"); - else - the_column->trim(); - skip_line(); -} - -void column_reset() -{ - if (!the_column->is_active()) - error("can't reset column - column not active"); - else - the_column->reset(); - skip_line(); -} - -class column_bottom_reg : public reg { -public: - const char *get_string(); -}; - -const char *column_bottom_reg::get_string() -{ - return i_to_a(the_column->get_bottom().to_units()); -} - -class column_extra_space_reg : public reg { -public: - const char *get_string(); -}; - -const char *column_extra_space_reg::get_string() -{ - return i_to_a(the_column->get_last_extra_space().to_units()); -} - -class column_active_reg : public reg { -public: - const char *get_string(); -}; - -const char *column_active_reg::get_string() -{ - return the_column->is_active() ? "1" : "0"; -} - -static int no_vjustify_mode = 0; - -class vjustify_node : public node { - symbol typ; -public: - vjustify_node(symbol); - int reread(int *); - const char *type(); - int same(node *); - node *copy(); -}; - -vjustify_node::vjustify_node(symbol t) -: typ(t) -{ -} - -node *vjustify_node::copy() -{ - return new vjustify_node(typ); -} - -const char *vjustify_node::type() -{ - return "vjustify_node"; -} - -int vjustify_node::same(node *nd) -{ - return typ == ((vjustify_node *)nd)->typ; -} - -int vjustify_node::reread(int *bolp) -{ - curdiv->vjustify(typ); - *bolp = 1; - return 1; -} - -void macro_diversion::vjustify(symbol type) -{ - if (!no_vjustify_mode) - mac->append(new vjustify_node(type)); -} - -void top_level_diversion::vjustify(symbol type) -{ - if (no_space_mode || no_vjustify_mode) - return; - assert(first_page_begun); // I'm not sure about this. - the_output->vjustify(vertical_position, type); -} - -void no_vjustify() -{ - skip_line(); - no_vjustify_mode = 1; -} - -void restore_vjustify() -{ - skip_line(); - no_vjustify_mode = 0; -} - -void init_column_requests() -{ - the_column = new column; - init_request("cols", column_start); - init_request("colo", column_output); - init_request("colj", column_justify); - init_request("colr", column_reset); - init_request("colt", column_trim); - init_request("nvj", no_vjustify); - init_request("rvj", restore_vjustify); - number_reg_dictionary.define(".colb", new column_bottom_reg); - number_reg_dictionary.define(".colx", new column_extra_space_reg); - number_reg_dictionary.define(".cola", new column_active_reg); - number_reg_dictionary.define(".nvj", - new constant_int_reg(&no_vjustify_mode)); -} - -#endif /* COLUMN */ diff --git a/contrib/groff/troff/dictionary.cc b/contrib/groff/troff/dictionary.cc deleted file mode 100644 index 169536c..0000000 --- a/contrib/groff/troff/dictionary.cc +++ /dev/null @@ -1,212 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" - -// is `p' a good size for a hash table - -static int is_good_size(int p) -{ - const int SMALL = 10; - unsigned i; - for (i = 2; i <= p/2; i++) - if (p % i == 0) - return 0; - for (i = 0x100; i != 0; i <<= 8) - if (i % p <= SMALL || i % p > p - SMALL) - return 0; - return 1; -} - -dictionary::dictionary(int n) : size(n), used(0), threshold(0.5), factor(1.5) -{ - table = new association[n]; -} - -// see Knuth, Sorting and Searching, p518, Algorithm L -// we can't use double-hashing because we want a remove function - -void *dictionary::lookup(symbol s, void *v) -{ - int i; - for (i = int(s.hash() % size); - table[i].v != 0; - i == 0 ? i = size - 1: --i) - if (s == table[i].s) { - if (v != 0) { - void *temp = table[i].v; - table[i].v = v; - return temp; - } - else - return table[i].v; - } - if (v == 0) - return 0; - ++used; - table[i].v = v; - table[i].s = s; - if ((double)used/(double)size >= threshold || used + 1 >= size) { - int old_size = size; - size = int(size*factor); - while (!is_good_size(size)) - ++size; - association *old_table = table; - table = new association[size]; - used = 0; - for (i = 0; i < old_size; i++) - if (old_table[i].v != 0) - (void)lookup(old_table[i].s, old_table[i].v); - a_delete old_table; - } - return 0; -} - -void *dictionary::lookup(const char *p) -{ - symbol s(p, MUST_ALREADY_EXIST); - if (s.is_null()) - return 0; - else - return lookup(s); -} - -// see Knuth, Sorting and Searching, p527, Algorithm R - -void *dictionary::remove(symbol s) -{ - // this relies on the fact that we are using linear probing - int i; - for (i = int(s.hash() % size); - table[i].v != 0 && s != table[i].s; - i == 0 ? i = size - 1: --i) - ; - void *p = table[i].v; - while (table[i].v != 0) { - table[i].v = 0; - int j = i; - int r; - do { - --i; - if (i < 0) - i = size - 1; - if (table[i].v == 0) - break; - r = int(table[i].s.hash() % size); - } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r)); - table[j] = table[i]; - } - if (p != 0) - --used; - return p; -} - -dictionary_iterator::dictionary_iterator(dictionary &d) : dict(&d), i(0) -{ -} - -int dictionary_iterator::get(symbol *sp, void **vp) -{ - for (; i < dict->size; i++) - if (dict->table[i].v) { - *sp = dict->table[i].s; - *vp = dict->table[i].v; - i++; - return 1; - } - return 0; -} - -object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od) - : di(od.d) -{ -} - -object::object() : rcount(0) -{ -} - -object::~object() -{ -} - -void object::add_reference() -{ - rcount += 1; -} - -void object::remove_reference() -{ - if (--rcount == 0) - delete this; -} - -object_dictionary::object_dictionary(int n) : d(n) -{ -} - -object *object_dictionary::lookup(symbol nm) -{ - return (object *)d.lookup(nm); -} - -void object_dictionary::define(symbol nm, object *obj) -{ - obj->add_reference(); - obj = (object *)d.lookup(nm, obj); - if (obj) - obj->remove_reference(); -} - -void object_dictionary::rename(symbol oldnm, symbol newnm) -{ - object *obj = (object *)d.remove(oldnm); - if (obj) { - obj = (object *)d.lookup(newnm, obj); - if (obj) - obj->remove_reference(); - } -} - -void object_dictionary::remove(symbol nm) -{ - object *obj = (object *)d.remove(nm); - if (obj) - obj->remove_reference(); -} - -// Return non-zero if oldnm was defined. - -int object_dictionary::alias(symbol newnm, symbol oldnm) -{ - object *obj = (object *)d.lookup(oldnm); - if (obj) { - obj->add_reference(); - obj = (object *)d.lookup(newnm, obj); - if (obj) - obj->remove_reference(); - return 1; - } - return 0; -} - diff --git a/contrib/groff/troff/dictionary.h b/contrib/groff/troff/dictionary.h deleted file mode 100644 index 4f319be..0000000 --- a/contrib/groff/troff/dictionary.h +++ /dev/null @@ -1,92 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - - -// there is no distinction between name with no value and name with NULL value -// null names are not permitted (they will be ignored). - -struct association { - symbol s; - void *v; - association() : v(0) {} -}; - -class dictionary; - -class dictionary_iterator { - dictionary *dict; - int i; -public: - dictionary_iterator(dictionary &); - int get(symbol *, void **); -}; - -class dictionary { - int size; - int used; - double threshold; - double factor; - association *table; - void rehash(int); -public: - dictionary(int); - void *lookup(symbol s, void *v=0); // returns value associated with key - void *lookup(const char *); - // if second parameter not NULL, value will be replaced - void *remove(symbol); - friend class dictionary_iterator; -}; - -class object { - int rcount; - public: - object(); - virtual ~object(); - void add_reference(); - void remove_reference(); -}; - -class object_dictionary; - -class object_dictionary_iterator { - dictionary_iterator di; -public: - object_dictionary_iterator(object_dictionary &); - int get(symbol *, object **); -}; - -class object_dictionary { - dictionary d; -public: - object_dictionary(int); - object *lookup(symbol nm); - void define(symbol nm, object *obj); - void rename(symbol oldnm, symbol newnm); - void remove(symbol nm); - int alias(symbol newnm, symbol oldnm); - friend class object_dictionary_iterator; -}; - - -inline int object_dictionary_iterator::get(symbol *sp, object **op) -{ - return di.get(sp, (void **)op); -} diff --git a/contrib/groff/troff/div.cc b/contrib/groff/troff/div.cc deleted file mode 100644 index 013ea66..0000000 --- a/contrib/groff/troff/div.cc +++ /dev/null @@ -1,1127 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -// diversions - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "div.h" -#include "reg.h" - -int exit_started = 0; // the exit process has started -int done_end_macro = 0; // the end macro (if any) has finished -int seen_last_page_ejector = 0; // seen the LAST_PAGE_EJECTOR cookie -int last_page_number = 0; // if > 0, the number of the last page - // specified with -o -static int began_page_in_end_macro = 0; // a new page was begun during the end macro - -static int last_post_line_extra_space = 0; // needed for \n(.a -static int nl_reg_contents = -1; -static int dl_reg_contents = 0; -static int dn_reg_contents = 0; -static int vertical_position_traps_flag = 1; -static vunits truncated_space; -static vunits needed_space; - -diversion::diversion(symbol s) -: prev(0), nm(s), vertical_position(V0), high_water_mark(V0), marked_place(V0) -{ -} - -struct vertical_size { - vunits pre_extra, post_extra, pre, post; - vertical_size(vunits vs, vunits post_vs); -}; - -vertical_size::vertical_size(vunits vs, vunits post_vs) -: pre_extra(V0), post_extra(V0), pre(vs), post(post_vs) -{ -} - -void node::set_vertical_size(vertical_size *) -{ -} - -void extra_size_node::set_vertical_size(vertical_size *v) -{ - if (n < V0) { - if (-n > v->pre_extra) - v->pre_extra = -n; - } - else if (n > v->post_extra) - v->post_extra = n; -} - -void vertical_size_node::set_vertical_size(vertical_size *v) -{ - if (n < V0) - v->pre = -n; - else - v->post = n; -} - -top_level_diversion *topdiv; - -diversion *curdiv; - -void do_divert(int append) -{ - tok.skip(); - symbol nm = get_name(); - if (nm.is_null()) { - if (curdiv->prev) { - diversion *temp = curdiv; - curdiv = curdiv->prev; - delete temp; - } - else - warning(WARN_DI, "diversion stack underflow"); - } - else { - macro_diversion *md = new macro_diversion(nm, append); - md->prev = curdiv; - curdiv = md; - } - skip_line(); -} - -void divert() -{ - do_divert(0); -} - -void divert_append() -{ - do_divert(1); -} - -void diversion::need(vunits n) -{ - vunits d = distance_to_next_trap(); - if (d < n) { - space(d, 1); - truncated_space = -d; - needed_space = n; - } -} - -macro_diversion::macro_diversion(symbol s, int append) -: diversion(s), max_width(H0) -{ -#if 0 - if (append) { - /* We don't allow recursive appends eg: - - .da a - .a - .di - - This causes an infinite loop in troff anyway. - This is because the user could do - - .as a foo - - in the diversion, and this would mess things up royally, - since there would be two things appending to the same - macro_header. - To make it work, we would have to copy the _contents_ - of the macro into which we were diverting; this doesn't - strike me as worthwhile. - However, - - .di a - .a - .a - .di - - will work and will make `a' contain two copies of what it contained - before; in troff, `a' would contain nothing. */ - request_or_macro *rm - = (request_or_macro *)request_dictionary.remove(s); - if (!rm || (mac = rm->to_macro()) == 0) - mac = new macro; - } - else - mac = new macro; -#endif - // We can now catch the situation described above by comparing - // the length of the charlist in the macro_header with the length - // stored in the macro. When we detect this, we copy the contents. - mac = new macro; - if (append) { - request_or_macro *rm - = (request_or_macro *)request_dictionary.lookup(s); - if (rm) { - macro *m = rm->to_macro(); - if (m) - *mac = *m; - } - } -} - -macro_diversion::~macro_diversion() -{ - request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); - macro *m = rm ? rm->to_macro() : 0; - if (m) { - *m = *mac; - delete mac; - } - else - request_dictionary.define(nm, mac); - mac = 0; - dl_reg_contents = max_width.to_units(); - dn_reg_contents = vertical_position.to_units(); -} - -vunits macro_diversion::distance_to_next_trap() -{ - if (!diversion_trap.is_null() && diversion_trap_pos > vertical_position) - return diversion_trap_pos - vertical_position; - else - // Substract vresolution so that vunits::vunits does not overflow. - return vunits(INT_MAX - vresolution); -} - -void macro_diversion::transparent_output(unsigned char c) -{ - mac->append(c); -} - -void macro_diversion::transparent_output(node *n) -{ - mac->append(n); -} - -void macro_diversion::output(node *nd, int retain_size, - vunits vs, vunits post_vs, hunits width) -{ - vertical_size v(vs, post_vs); - while (nd != 0) { - nd->set_vertical_size(&v); - node *temp = nd; - nd = nd->next; - if (temp->interpret(mac)) { - delete temp; - } - else { -#if 1 - temp->freeze_space(); -#endif - mac->append(temp); - } - } - last_post_line_extra_space = v.post_extra.to_units(); - if (!retain_size) { - v.pre = vs; - v.post = post_vs; - } - if (width > max_width) - max_width = width; - vunits x = v.pre + v.pre_extra + v.post + v.post_extra; - if (vertical_position_traps_flag - && !diversion_trap.is_null() && diversion_trap_pos > vertical_position - && diversion_trap_pos <= vertical_position + x) { - vunits trunc = vertical_position + x - diversion_trap_pos; - if (trunc > v.post) - trunc = v.post; - v.post -= trunc; - x -= trunc; - truncated_space = trunc; - spring_trap(diversion_trap); - } - mac->append(new vertical_size_node(-v.pre)); - mac->append(new vertical_size_node(v.post)); - mac->append('\n'); - vertical_position += x; - if (vertical_position - v.post > high_water_mark) - high_water_mark = vertical_position - v.post; -} - -void macro_diversion::space(vunits n, int) -{ - if (vertical_position_traps_flag - && !diversion_trap.is_null() && diversion_trap_pos > vertical_position - && diversion_trap_pos <= vertical_position + n) { - truncated_space = vertical_position + n - diversion_trap_pos; - n = diversion_trap_pos - vertical_position; - spring_trap(diversion_trap); - } - else if (n + vertical_position < V0) - n = -vertical_position; - mac->append(new diverted_space_node(n)); - vertical_position += n; -} - -void macro_diversion::copy_file(const char *filename) -{ - mac->append(new diverted_copy_file_node(filename)); -} - -top_level_diversion::top_level_diversion() -: page_number(0), page_count(0), last_page_count(-1), - page_length(units_per_inch*11), - prev_page_offset(units_per_inch), page_offset(units_per_inch), - page_trap_list(0), have_next_page_number(0), - ejecting_page(0), before_first_page(1), no_space_mode(0) -{ -} - -// find the next trap after pos - -trap *top_level_diversion::find_next_trap(vunits *next_trap_pos) -{ - trap *next_trap = 0; - for (trap *pt = page_trap_list; pt != 0; pt = pt->next) - if (!pt->nm.is_null()) { - if (pt->position >= V0) { - if (pt->position > vertical_position - && pt->position < page_length - && (next_trap == 0 || pt->position < *next_trap_pos)) { - next_trap = pt; - *next_trap_pos = pt->position; - } - } - else { - vunits pos = pt->position; - pos += page_length; - if (pos > 0 && pos > vertical_position && (next_trap == 0 || pos < *next_trap_pos)) { - next_trap = pt; - *next_trap_pos = pos; - } - } - } - return next_trap; -} - -vunits top_level_diversion::distance_to_next_trap() -{ - vunits d; - if (!find_next_trap(&d)) - return page_length - vertical_position; - else - return d - vertical_position; -} - -void top_level_diversion::output(node *nd, int retain_size, - vunits vs, vunits post_vs, hunits /*width*/) -{ - no_space_mode = 0; - vunits next_trap_pos; - trap *next_trap = find_next_trap(&next_trap_pos); - if (before_first_page && begin_page()) - fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); - vertical_size v(vs, post_vs); - for (node *tem = nd; tem != 0; tem = tem->next) - tem->set_vertical_size(&v); - last_post_line_extra_space = v.post_extra.to_units(); - if (!retain_size) { - v.pre = vs; - v.post = post_vs; - } - vertical_position += v.pre; - vertical_position += v.pre_extra; - the_output->print_line(page_offset, vertical_position, nd, - v.pre + v.pre_extra, v.post_extra); - vertical_position += v.post_extra; - if (vertical_position > high_water_mark) - high_water_mark = vertical_position; - if (vertical_position_traps_flag && vertical_position >= page_length) - begin_page(); - else if (vertical_position_traps_flag - && next_trap != 0 && vertical_position >= next_trap_pos) { - nl_reg_contents = vertical_position.to_units(); - truncated_space = v.post; - spring_trap(next_trap->nm); - } - else if (v.post > V0) { - vertical_position += v.post; - if (vertical_position_traps_flag - && next_trap != 0 && vertical_position >= next_trap_pos) { - truncated_space = vertical_position - next_trap_pos; - vertical_position = next_trap_pos; - nl_reg_contents = vertical_position.to_units(); - spring_trap(next_trap->nm); - } - else if (vertical_position_traps_flag && vertical_position >= page_length) - begin_page(); - else - nl_reg_contents = vertical_position.to_units(); - } - else - nl_reg_contents = vertical_position.to_units(); -} - -void top_level_diversion::transparent_output(unsigned char c) -{ - if (before_first_page && begin_page()) - // This can only happen with the transparent() request. - fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); - const char *s = asciify(c); - while (*s) - the_output->transparent_char(*s++); -} - -void top_level_diversion::transparent_output(node * /*n*/) -{ - error("can't transparently output node at top level"); -} - -void top_level_diversion::copy_file(const char *filename) -{ - if (before_first_page && begin_page()) - fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request"); - the_output->copy_file(page_offset, vertical_position, filename); -} - -void top_level_diversion::space(vunits n, int forced) -{ - if (no_space_mode) { - if (!forced) - return; - else - no_space_mode = 0; - } - if (before_first_page) { - if (begin_page()) { - // This happens if there's a top of page trap, and the first-page - // transition is caused by `'sp'. - truncated_space = n > V0 ? n : V0; - return; - } - } - vunits next_trap_pos; - trap *next_trap = find_next_trap(&next_trap_pos); - vunits y = vertical_position + n; - if (vertical_position_traps_flag && next_trap != 0 && y >= next_trap_pos) { - vertical_position = next_trap_pos; - nl_reg_contents = vertical_position.to_units(); - truncated_space = y - vertical_position; - spring_trap(next_trap->nm); - } - else if (y < V0) { - vertical_position = V0; - nl_reg_contents = vertical_position.to_units(); - } - else if (vertical_position_traps_flag && y >= page_length && n >= V0) - begin_page(); - else { - vertical_position = y; - nl_reg_contents = vertical_position.to_units(); - } -} - -trap::trap(symbol s, vunits n, trap *p) - : next(p), position(n), nm(s) -{ -} - -void top_level_diversion::add_trap(symbol nm, vunits pos) -{ - trap *first_free_slot = 0; - trap **p; - for (p = &page_trap_list; *p; p = &(*p)->next) { - if ((*p)->nm.is_null()) { - if (first_free_slot == 0) - first_free_slot = *p; - } - else if ((*p)->position == pos) { - (*p)->nm = nm; - return; - } - } - if (first_free_slot) { - first_free_slot->nm = nm; - first_free_slot->position = pos; - } - else - *p = new trap(nm, pos, 0); -} - -void top_level_diversion::remove_trap(symbol nm) -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->nm == nm) { - p->nm = NULL_SYMBOL; - return; - } -} - -void top_level_diversion::remove_trap_at(vunits pos) -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->position == pos) { - p->nm = NULL_SYMBOL; - return; - } -} - -void top_level_diversion::change_trap(symbol nm, vunits pos) -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->nm == nm) { - p->position = pos; - return; - } -} - -void top_level_diversion::print_traps() -{ - for (trap *p = page_trap_list; p; p = p->next) - if (p->nm.is_null()) - fprintf(stderr, " empty\n"); - else - fprintf(stderr, "%s\t%d\n", p->nm.contents(), p->position.to_units()); - fflush(stderr); -} - -void end_diversions() -{ - while (curdiv != topdiv) { - error("automatically ending diversion `%1' on exit", - curdiv->nm.contents()); - diversion *tem = curdiv; - curdiv = curdiv->prev; - delete tem; - } -} - -void cleanup_and_exit(int exit_code) -{ - if (the_output) { - the_output->trailer(topdiv->get_page_length()); - delete the_output; - } - exit(exit_code); -} - -// returns non-zero if it sprung a top of page trap - -int top_level_diversion::begin_page() -{ - if (exit_started) { - if (page_count == last_page_count - ? curenv->is_empty() - : (done_end_macro && (seen_last_page_ejector || began_page_in_end_macro))) - cleanup_and_exit(0); - if (!done_end_macro) - began_page_in_end_macro = 1; - } - if (last_page_number > 0 && page_number == last_page_number) - cleanup_and_exit(0); - if (!the_output) - init_output(); - ++page_count; - if (have_next_page_number) { - page_number = next_page_number; - have_next_page_number = 0; - } - else if (before_first_page == 1) - page_number = 1; - else - page_number++; - // spring the top of page trap if there is one - vunits next_trap_pos; - vertical_position = -vresolution; - trap *next_trap = find_next_trap(&next_trap_pos); - vertical_position = V0; - high_water_mark = V0; - ejecting_page = 0; - // If before_first_page was 2, then the top of page transition was undone - // using eg .nr nl 0-1. See nl_reg::set_value. - if (before_first_page != 2) - the_output->begin_page(page_number, page_length); - before_first_page = 0; - nl_reg_contents = vertical_position.to_units(); - if (vertical_position_traps_flag && next_trap != 0 && next_trap_pos == V0) { - truncated_space = V0; - spring_trap(next_trap->nm); - return 1; - } - else - return 0; -} - -void continue_page_eject() -{ - if (topdiv->get_ejecting()) { - if (curdiv != topdiv) - error("can't continue page ejection because of current diversion"); - else if (!vertical_position_traps_flag) - error("can't continue page ejection because vertical position traps disabled"); - else { - push_page_ejector(); - topdiv->space(topdiv->get_page_length(), 1); - } - } -} - -void top_level_diversion::set_next_page_number(int n) -{ - next_page_number= n; - have_next_page_number = 1; -} - -int top_level_diversion::get_next_page_number() -{ - return have_next_page_number ? next_page_number : page_number + 1; -} - -void top_level_diversion::set_page_length(vunits n) -{ - page_length = n; -} - -diversion::~diversion() -{ -} - -void page_offset() -{ - hunits n; - // The troff manual says that the default scaling indicator is v, - // but it is in fact m: v wouldn't make sense for a horizontally - // oriented request. - if (!has_arg() || !get_hunits(&n, 'm', topdiv->page_offset)) - n = topdiv->prev_page_offset; - topdiv->prev_page_offset = topdiv->page_offset; - topdiv->page_offset = n; - skip_line(); -} - -void page_length() -{ - vunits n; - if (has_arg() && get_vunits(&n, 'v', topdiv->get_page_length())) - topdiv->set_page_length(n); - else - topdiv->set_page_length(11*units_per_inch); - skip_line(); -} - -void when_request() -{ - vunits n; - if (get_vunits(&n, 'v')) { - symbol s = get_name(); - if (s.is_null()) - topdiv->remove_trap_at(n); - else - topdiv->add_trap(s, n); - } - skip_line(); -} - -void begin_page() -{ - int got_arg = 0; - int n; - if (has_arg() && get_integer(&n, topdiv->get_page_number())) - got_arg = 1; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (curdiv == topdiv) { - if (topdiv->before_first_page) { - if (!break_flag) { - if (got_arg) - topdiv->set_next_page_number(n); - if (got_arg || !topdiv->no_space_mode) - topdiv->begin_page(); - } - else if (topdiv->no_space_mode && !got_arg) - topdiv->begin_page(); - else { - /* Given this - - .wh 0 x - .de x - .tm \\n% - .. - .bp 3 - - troff prints - - 1 - 3 - - This code makes groff do the same. */ - - push_page_ejector(); - topdiv->begin_page(); - if (got_arg) - topdiv->set_next_page_number(n); - topdiv->set_ejecting(); - } - } - else { - push_page_ejector(); - if (break_flag) - curenv->do_break(); - if (got_arg) - topdiv->set_next_page_number(n); - if (!(topdiv->no_space_mode && !got_arg)) - topdiv->set_ejecting(); - } - } - tok.next(); -} - -void no_space() -{ - if (curdiv == topdiv) - topdiv->no_space_mode = 1; - skip_line(); -} - -void restore_spacing() -{ - if (curdiv == topdiv) - topdiv->no_space_mode = 0; - skip_line(); -} - -/* It is necessary to generate a break before before reading the argument, -because otherwise arguments using | will be wrong. But if we just -generate a break as usual, then the line forced out may spring a trap -and thus push a macro onto the input stack before we have had a chance -to read the argument to the sp request. We resolve this dilemma by -setting, before generating the break, a flag which will postpone the -actual pushing of the macro associated with the trap sprung by the -outputting of the line forced out by the break till after we have read -the argument to the request. If the break did cause a trap to be -sprung, then we don't actually do the space. */ - -void space_request() -{ - postpone_traps(); - if (break_flag) - curenv->do_break(); - vunits n; - if (!has_arg() || !get_vunits(&n, 'v')) - n = curenv->get_vertical_spacing(); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (!unpostpone_traps()) - curdiv->space(n); - else - // The line might have had line spacing that was truncated. - truncated_space += n; - tok.next(); -} - -void blank_line() -{ - curenv->do_break(); - if (!trap_sprung_flag) - curdiv->space(curenv->get_vertical_spacing()); - else - truncated_space += curenv->get_vertical_spacing(); -} - -/* need_space might spring a trap and so we must be careful that the -BEGIN_TRAP token is not skipped over. */ - -void need_space() -{ - vunits n; - if (!has_arg() || !get_vunits(&n, 'v')) - n = curenv->get_vertical_spacing(); - while (!tok.newline() && !tok.eof()) - tok.next(); - curdiv->need(n); - tok.next(); -} - -void page_number() -{ - int n; - if (has_arg() && get_integer(&n, topdiv->get_page_number())) - topdiv->set_next_page_number(n); - skip_line(); -} - -vunits saved_space; - -void save_vertical_space() -{ - vunits x; - if (get_vunits(&x, 'v')) { - if (curdiv->distance_to_next_trap() > x) - curdiv->space(x, 1); - else - saved_space = x; - } - skip_line(); -} - -void output_saved_vertical_space() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (saved_space > V0) - curdiv->space(saved_space, 1); - saved_space = V0; - tok.next(); -} - -void flush_output() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (the_output) - the_output->flush(); - tok.next(); -} - -void macro_diversion::set_diversion_trap(symbol s, vunits n) -{ - diversion_trap = s; - diversion_trap_pos = n; -} - -void macro_diversion::clear_diversion_trap() -{ - diversion_trap = NULL_SYMBOL; -} - -void top_level_diversion::set_diversion_trap(symbol, vunits) -{ - error("can't set diversion trap when no current diversion"); -} - -void top_level_diversion::clear_diversion_trap() -{ - error("can't set diversion trap when no current diversion"); -} - -void diversion_trap() -{ - vunits n; - if (has_arg() && get_vunits(&n, 'v')) { - symbol s = get_name(); - if (!s.is_null()) - curdiv->set_diversion_trap(s, n); - else - curdiv->clear_diversion_trap(); - } - else - curdiv->clear_diversion_trap(); - skip_line(); -} - -void change_trap() -{ - symbol s = get_name(1); - if (!s.is_null()) { - vunits x; - if (has_arg() && get_vunits(&x, 'v')) - topdiv->change_trap(s, x); - else - topdiv->remove_trap(s); - } - skip_line(); -} - -void print_traps() -{ - topdiv->print_traps(); - skip_line(); -} - -void mark() -{ - symbol s = get_name(); - if (s.is_null()) - curdiv->marked_place = curdiv->get_vertical_position(); - else if (curdiv == topdiv) - set_number_reg(s, nl_reg_contents); - else - set_number_reg(s, curdiv->get_vertical_position().to_units()); - skip_line(); -} - -// This is truly bizarre. It is documented in the SQ manual. - -void return_request() -{ - vunits dist = curdiv->marked_place - curdiv->get_vertical_position(); - if (has_arg()) { - if (tok.ch() == '-') { - tok.next(); - vunits x; - if (get_vunits(&x, 'v')) - dist = -x; - } - else { - vunits x; - if (get_vunits(&x, 'v')) - dist = x >= V0 ? x - curdiv->get_vertical_position() : V0; - } - } - if (dist < V0) - curdiv->space(dist); - skip_line(); -} - -void vertical_position_traps() -{ - int n; - if (has_arg() && get_integer(&n)) - vertical_position_traps_flag = (n != 0); - else - vertical_position_traps_flag = 1; - skip_line(); -} - -class page_offset_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int page_offset_reg::get_value(units *res) -{ - *res = topdiv->get_page_offset().to_units(); - return 1; -} - -const char *page_offset_reg::get_string() -{ - return i_to_a(topdiv->get_page_offset().to_units()); -} - -class page_length_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int page_length_reg::get_value(units *res) -{ - *res = topdiv->get_page_length().to_units(); - return 1; -} - -const char *page_length_reg::get_string() -{ - return i_to_a(topdiv->get_page_length().to_units()); -} - -class vertical_position_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int vertical_position_reg::get_value(units *res) -{ - if (curdiv == topdiv && topdiv->before_first_page) - *res = -1; - else - *res = curdiv->get_vertical_position().to_units(); - return 1; -} - -const char *vertical_position_reg::get_string() -{ - if (curdiv == topdiv && topdiv->before_first_page) - return "-1"; - else - return i_to_a(curdiv->get_vertical_position().to_units()); -} - -class high_water_mark_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int high_water_mark_reg::get_value(units *res) -{ - *res = curdiv->get_high_water_mark().to_units(); - return 1; -} - -const char *high_water_mark_reg::get_string() -{ - return i_to_a(curdiv->get_high_water_mark().to_units()); -} - -class distance_to_next_trap_reg : public reg { -public: - int get_value(units *); - const char *get_string(); -}; - -int distance_to_next_trap_reg::get_value(units *res) -{ - *res = curdiv->distance_to_next_trap().to_units(); - return 1; -} - -const char *distance_to_next_trap_reg::get_string() -{ - return i_to_a(curdiv->distance_to_next_trap().to_units()); -} - -class diversion_name_reg : public reg { -public: - const char *get_string(); -}; - -const char *diversion_name_reg::get_string() -{ - return curdiv->get_diversion_name(); -} - -class page_number_reg : public general_reg { -public: - page_number_reg(); - int get_value(units *); - void set_value(units); -}; - -page_number_reg::page_number_reg() -{ -} - -void page_number_reg::set_value(units n) -{ - topdiv->set_page_number(n); -} - -int page_number_reg::get_value(units *res) -{ - *res = topdiv->get_page_number(); - return 1; -} - -class next_page_number_reg : public reg { -public: - const char *get_string(); -}; - -const char *next_page_number_reg::get_string() -{ - return i_to_a(topdiv->get_next_page_number()); -} - -class page_ejecting_reg : public reg { -public: - const char *get_string(); -}; - -const char *page_ejecting_reg::get_string() -{ - return i_to_a(topdiv->get_ejecting()); -} - -class constant_vunits_reg : public reg { - vunits *p; -public: - constant_vunits_reg(vunits *); - const char *get_string(); -}; - -constant_vunits_reg::constant_vunits_reg(vunits *q) : p(q) -{ -} - -const char *constant_vunits_reg::get_string() -{ - return i_to_a(p->to_units()); -} - -class nl_reg : public variable_reg { -public: - nl_reg(); - void set_value(units); -}; - -nl_reg::nl_reg() : variable_reg(&nl_reg_contents) -{ -} - -void nl_reg::set_value(units n) -{ - variable_reg::set_value(n); - // Setting nl to a negative value when the vertical position in - // the top-level diversion is 0 undoes the top of page transition, - // so that the header macro will be called as if the top of page - // transition hasn't happened. This is used by Larry Wall's - // wrapman program. Setting before_first_page to 2 rather than 1, - // tells top_level_diversion::begin_page not to call - // output_file::begin_page again. - if (n < 0 && topdiv->get_vertical_position() == V0) - topdiv->before_first_page = 2; -} - -void init_div_requests() -{ - init_request("wh", when_request); - init_request("ch", change_trap); - init_request("pl", page_length); - init_request("po", page_offset); - init_request("rs", restore_spacing); - init_request("ns", no_space); - init_request("sp", space_request); - init_request("di", divert); - init_request("da", divert_append); - init_request("bp", begin_page); - init_request("ne", need_space); - init_request("pn", page_number); - init_request("dt", diversion_trap); - init_request("rt", return_request); - init_request("mk", mark); - init_request("sv", save_vertical_space); - init_request("os", output_saved_vertical_space); - init_request("fl", flush_output); - init_request("vpt", vertical_position_traps); - init_request("ptr", print_traps); - number_reg_dictionary.define(".a", - new constant_int_reg(&last_post_line_extra_space)); - number_reg_dictionary.define(".z", new diversion_name_reg); - number_reg_dictionary.define(".o", new page_offset_reg); - number_reg_dictionary.define(".p", new page_length_reg); - number_reg_dictionary.define(".d", new vertical_position_reg); - number_reg_dictionary.define(".h", new high_water_mark_reg); - number_reg_dictionary.define(".t", new distance_to_next_trap_reg); - number_reg_dictionary.define("dl", new variable_reg(&dl_reg_contents)); - number_reg_dictionary.define("dn", new variable_reg(&dn_reg_contents)); - number_reg_dictionary.define("nl", new nl_reg); - number_reg_dictionary.define(".vpt", - new constant_int_reg(&vertical_position_traps_flag)); - number_reg_dictionary.define("%", new page_number_reg); - number_reg_dictionary.define(".pn", new next_page_number_reg); - number_reg_dictionary.define(".trunc", - new constant_vunits_reg(&truncated_space)); - number_reg_dictionary.define(".ne", - new constant_vunits_reg(&needed_space)); - number_reg_dictionary.define(".pe", new page_ejecting_reg); -} diff --git a/contrib/groff/troff/div.h b/contrib/groff/troff/div.h deleted file mode 100644 index e97e0a7..0000000 --- a/contrib/groff/troff/div.h +++ /dev/null @@ -1,150 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -class diversion { - friend void do_divert(int append); - friend void end_diversions(); - diversion *prev; -protected: - symbol nm; - vunits vertical_position; - vunits high_water_mark; -public: - vunits marked_place; - diversion(symbol s = NULL_SYMBOL); - virtual ~diversion(); - virtual void output(node *nd, int retain_size, vunits vs, vunits post_vs, - hunits width) = 0; - virtual void transparent_output(unsigned char) = 0; - virtual void transparent_output(node *) = 0; - virtual void space(vunits distance, int forced = 0) = 0; -#ifdef COLUMN - virtual void vjustify(symbol) = 0; -#endif /* COLUMN */ - vunits get_vertical_position() { return vertical_position; } - vunits get_high_water_mark() { return high_water_mark; } - virtual vunits distance_to_next_trap() = 0; - void need(vunits); - const char *get_diversion_name() { return nm.contents(); } - virtual void set_diversion_trap(symbol, vunits) = 0; - virtual void clear_diversion_trap() = 0; - virtual void copy_file(const char *filename) = 0; -}; - -class macro; - -class macro_diversion : public diversion { - macro *mac; - hunits max_width; - symbol diversion_trap; - vunits diversion_trap_pos; -public: - macro_diversion(symbol, int); - ~macro_diversion(); - void output(node *nd, int retain_size, vunits vs, vunits post_vs, - hunits width); - void transparent_output(unsigned char); - void transparent_output(node *); - void space(vunits distance, int forced = 0); -#ifdef COLUMN - void vjustify(symbol); -#endif /* COLUMN */ - vunits distance_to_next_trap(); - void set_diversion_trap(symbol, vunits); - void clear_diversion_trap(); - void copy_file(const char *filename); -}; - -struct trap { - trap *next; - vunits position; - symbol nm; - trap(symbol, vunits, trap *); -}; - -struct output_file; - -class top_level_diversion : public diversion { - int page_number; - int page_count; - int last_page_count; - vunits page_length; - hunits prev_page_offset; - hunits page_offset; - trap *page_trap_list; - trap *find_next_trap(vunits *); - int have_next_page_number; - int next_page_number; - int ejecting_page; // Is the current page being ejected? -public: - int before_first_page; - int no_space_mode; - top_level_diversion(); - void output(node *nd, int retain_size, vunits vs, vunits post_vs, - hunits width); - void transparent_output(unsigned char); - void transparent_output(node *); - void space(vunits distance, int forced = 0); -#ifdef COLUMN - void vjustify(symbol); -#endif /* COLUMN */ - hunits get_page_offset() { return page_offset; } - vunits get_page_length() { return page_length; } - vunits distance_to_next_trap(); - void add_trap(symbol nm, vunits pos); - void change_trap(symbol nm, vunits pos); - void remove_trap(symbol); - void remove_trap_at(vunits pos); - void print_traps(); - int get_page_count() { return page_count; } - int get_page_number() { return page_number; } - int get_next_page_number(); - void set_page_number(int n) { page_number = n; } - int begin_page(); - void set_next_page_number(int); - void set_page_length(vunits); - void copy_file(const char *filename); - int get_ejecting() { return ejecting_page; } - void set_ejecting() { ejecting_page = 1; } - friend void page_offset(); - void set_diversion_trap(symbol, vunits); - void clear_diversion_trap(); - void set_last_page() { last_page_count = page_count; } -}; - -extern top_level_diversion *topdiv; -extern diversion *curdiv; - -extern int exit_started; -extern int done_end_macro; -extern int last_page_number; -extern int seen_last_page_ejector; - -void spring_trap(symbol); // implemented by input.c -extern int trap_sprung_flag; -void postpone_traps(); -int unpostpone_traps(); - -void push_page_ejector(); -void continue_page_eject(); -void handle_first_page_transition(); -void blank_line(); - -extern void cleanup_and_exit(int); diff --git a/contrib/groff/troff/env.cc b/contrib/groff/troff/env.cc deleted file mode 100644 index fbea78e..0000000 --- a/contrib/groff/troff/env.cc +++ /dev/null @@ -1,3215 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "div.h" -#include "reg.h" -#include "charinfo.h" -#include "searchpath.h" -#include "macropath.h" -#include <math.h> - -symbol default_family("T"); - -enum { ADJUST_LEFT = 0, ADJUST_BOTH = 1, ADJUST_CENTER = 3, ADJUST_RIGHT = 5 }; - -enum { HYPHEN_LAST_LINE = 2, HYPHEN_LAST_CHARS = 4, HYPHEN_FIRST_CHARS = 8 }; - -struct env_list { - environment *env; - env_list *next; - env_list(environment *e, env_list *p) : env(e), next(p) {} -}; - -env_list *env_stack; -const int NENVIRONMENTS = 10; -environment *env_table[NENVIRONMENTS]; -dictionary env_dictionary(10); -environment *curenv; -static int next_line_number = 0; - -charinfo *field_delimiter_char; -charinfo *padding_indicator_char; - -int translate_space_to_dummy = 0; - -class pending_output_line { - node *nd; - int no_fill; - vunits vs; - vunits post_vs; - hunits width; -#ifdef WIDOW_CONTROL - int last_line; // Is it the last line of the paragraph? -#endif /* WIDOW_CONTROL */ -public: - pending_output_line *next; - - pending_output_line(node *, int, vunits, vunits, hunits, - pending_output_line * = 0); - ~pending_output_line(); - int output(); - -#ifdef WIDOW_CONTROL - friend void environment::mark_last_line(); - friend void environment::output(node *, int, vunits, vunits, hunits); -#endif /* WIDOW_CONTROL */ -}; - -pending_output_line::pending_output_line(node *n, int nf, vunits v, vunits pv, - hunits w, pending_output_line *p) -: nd(n), no_fill(nf), vs(v), post_vs(pv), width(w), -#ifdef WIDOW_CONTROL - last_line(0), -#endif /* WIDOW_CONTROL */ - next(p) -{ -} - -pending_output_line::~pending_output_line() -{ - delete_node_list(nd); -} - -int pending_output_line::output() -{ - if (trap_sprung_flag) - return 0; -#ifdef WIDOW_CONTROL - if (next && next->last_line && !no_fill) { - curdiv->need(vs + post_vs + vunits(vresolution)); - if (trap_sprung_flag) { - next->last_line = 0; // Try to avoid infinite loops. - return 0; - } - } -#endif - curdiv->output(nd, no_fill, vs, post_vs, width); - nd = 0; - return 1; -} - -void environment::output(node *nd, int no_fill, vunits vs, vunits post_vs, - hunits width) -{ -#ifdef WIDOW_CONTROL - while (pending_lines) { - if (widow_control && !pending_lines->no_fill && !pending_lines->next) - break; - if (!pending_lines->output()) - break; - pending_output_line *tem = pending_lines; - pending_lines = pending_lines->next; - delete tem; - } -#else /* WIDOW_CONTROL */ - output_pending_lines(); -#endif /* WIDOW_CONTROL */ - if (!trap_sprung_flag && !pending_lines -#ifdef WIDOW_CONTROL - && (!widow_control || no_fill) -#endif /* WIDOW_CONTROL */ - ) - curdiv->output(nd, no_fill, vs, post_vs, width); - else { - pending_output_line **p; - for (p = &pending_lines; *p; p = &(*p)->next) - ; - *p = new pending_output_line(nd, no_fill, vs, post_vs, width); - } -} - -// a line from .tl goes at the head of the queue - -void environment::output_title(node *nd, int no_fill, vunits vs, - vunits post_vs, hunits width) -{ - if (!trap_sprung_flag) - curdiv->output(nd, no_fill, vs, post_vs, width); - else - pending_lines = new pending_output_line(nd, no_fill, vs, post_vs, width, - pending_lines); -} - -void environment::output_pending_lines() -{ - while (pending_lines && pending_lines->output()) { - pending_output_line *tem = pending_lines; - pending_lines = pending_lines->next; - delete tem; - } -} - -#ifdef WIDOW_CONTROL - -void environment::mark_last_line() -{ - if (!widow_control || !pending_lines) - return; - for (pending_output_line *p = pending_lines; p->next; p = p->next) - ; - if (!p->no_fill) - p->last_line = 1; -} - -void widow_control_request() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->widow_control = n != 0; - else - curenv->widow_control = 1; - skip_line(); -} - -#endif /* WIDOW_CONTROL */ - -/* font_size functions */ - -size_range *font_size::size_table = 0; -int font_size::nranges = 0; - -extern "C" { - -int compare_ranges(const void *p1, const void *p2) -{ - return ((size_range *)p1)->min - ((size_range *)p2)->min; -} - -} - -void font_size::init_size_table(int *sizes) -{ - nranges = 0; - while (sizes[nranges*2] != 0) - nranges++; - assert(nranges > 0); - size_table = new size_range[nranges]; - for (int i = 0; i < nranges; i++) { - size_table[i].min = sizes[i*2]; - size_table[i].max = sizes[i*2 + 1]; - } - qsort(size_table, nranges, sizeof(size_range), compare_ranges); -} - -font_size::font_size(int sp) -{ - for (int i = 0; i < nranges; i++) { - if (sp < size_table[i].min) { - if (i > 0 && size_table[i].min - sp >= sp - size_table[i - 1].max) - p = size_table[i - 1].max; - else - p = size_table[i].min; - return; - } - if (sp <= size_table[i].max) { - p = sp; - return; - } - } - p = size_table[nranges - 1].max; -} - -int font_size::to_units() -{ - return scale(p, units_per_inch, sizescale*72); -} - -// we can't do this in a static constructor because various dictionaries -// have to get initialized first - -void init_environments() -{ - curenv = env_table[0] = new environment("0"); -} - -void tab_character() -{ - curenv->tab_char = get_optional_char(); - skip_line(); -} - -void leader_character() -{ - curenv->leader_char = get_optional_char(); - skip_line(); -} - -void environment::add_char(charinfo *ci) -{ - if (interrupted) - ; - // don't allow fields in dummy environments - else if (ci == field_delimiter_char && !dummy) { - if (current_field) - wrap_up_field(); - else - start_field(); - } - else if (current_field && ci == padding_indicator_char) - add_padding(); - else if (current_tab) { - if (tab_contents == 0) - tab_contents = new line_start_node; - if (ci != hyphen_indicator_char) - tab_contents = tab_contents->add_char(ci, this, &tab_width); - else - tab_contents = tab_contents->add_discretionary_hyphen(); - } - else { - if (line == 0) - start_line(); - if (ci != hyphen_indicator_char) - line = line->add_char(ci, this, &width_total); - else - line = line->add_discretionary_hyphen(); - } -} - -node *environment::make_char_node(charinfo *ci) -{ - return make_node(ci, this); -} - -void environment::add_node(node *n) -{ - assert(n != 0); - if (current_tab || current_field) - n->freeze_space(); - if (interrupted) { - delete n; - } - else if (current_tab) { - n->next = tab_contents; - tab_contents = n; - tab_width += n->width(); - } - else { - if (line == 0) { - if (discarding && n->discardable()) { - // XXX possibly: input_line_start -= n->width(); - delete n; - return; - } - start_line(); - } - width_total += n->width(); - space_total += n->nspaces(); - n->next = line; - line = n; - } -} - - -void environment::add_hyphen_indicator() -{ - if (current_tab || interrupted || current_field - || hyphen_indicator_char != 0) - return; - if (line == 0) - start_line(); - line = line->add_discretionary_hyphen(); -} - -int environment::get_hyphenation_flags() -{ - return hyphenation_flags; -} - -int environment::get_hyphen_line_max() -{ - return hyphen_line_max; -} - -int environment::get_hyphen_line_count() -{ - return hyphen_line_count; -} - -int environment::get_center_lines() -{ - return center_lines; -} - -int environment::get_right_justify_lines() -{ - return right_justify_lines; -} - -void environment::add_italic_correction() -{ - if (current_tab) { - if (tab_contents) - tab_contents = tab_contents->add_italic_correction(&tab_width); - } - else if (line) - line = line->add_italic_correction(&width_total); -} - -void environment::space_newline() -{ - assert(!current_tab && !current_field); - if (interrupted) - return; - hunits x = H0; - if (!translate_space_to_dummy) { - x = env_space_width(this); - if (node_list_ends_sentence(line) == 1) - x += env_sentence_space_width(this); - } - if (line != 0 && line->merge_space(x)) { - width_total += x; - return; - } - add_node(new word_space_node(x)); - possibly_break_line(spread_flag); - spread_flag = 0; -} - -void environment::space() -{ - if (interrupted) - return; - if (current_field && padding_indicator_char == 0) { - add_padding(); - return; - } - hunits x = translate_space_to_dummy ? H0 : env_space_width(this); - node *p = current_tab ? tab_contents : line; - hunits *tp = current_tab ? &tab_width : &width_total; - if (p && p->nspaces() == 1 && p->width() == x - && node_list_ends_sentence(p->next) == 1) { - hunits xx = translate_space_to_dummy ? H0 : env_sentence_space_width(this); - if (p->merge_space(xx)) { - *tp += xx; - return; - } - } - if (p && p->merge_space(x)) { - *tp += x; - return; - } - add_node(new word_space_node(x)); - possibly_break_line(spread_flag); - spread_flag = 0; -} - -void environment::set_font(symbol nm) -{ - if (interrupted) - return; - if (nm == symbol("P")) { - if (family->make_definite(prev_fontno) < 0) - return; - int tem = fontno; - fontno = prev_fontno; - prev_fontno = tem; - } - else { - prev_fontno = fontno; - int n = symbol_fontno(nm); - if (n < 0) { - n = next_available_font_position(); - if (!mount_font(n, nm)) - return; - } - if (family->make_definite(n) < 0) - return; - fontno = n; - } -} - -void environment::set_font(int n) -{ - if (interrupted) - return; - if (is_good_fontno(n)) { - prev_fontno = fontno; - fontno = n; - } - else - warning(WARN_FONT, "bad font number"); -} - -void environment::set_family(symbol fam) -{ - if (fam.is_null()) { - if (prev_family->make_definite(fontno) < 0) - return; - font_family *tem = family; - family = prev_family; - prev_family = tem; - } - else { - font_family *f = lookup_family(fam); - if (f->make_definite(fontno) < 0) - return; - prev_family = family; - family = f; - } -} - -void environment::set_size(int n) -{ - if (interrupted) - return; - if (n == 0) { - font_size temp = prev_size; - prev_size = size; - size = temp; - int temp2 = prev_requested_size; - prev_requested_size = requested_size; - requested_size = temp2; - } - else { - prev_size = size; - size = font_size(n); - prev_requested_size = requested_size; - requested_size = n; - } -} - -void environment::set_char_height(int n) -{ - if (interrupted) - return; - if (n == requested_size || n <= 0) - char_height = 0; - else - char_height = n; -} - -void environment::set_char_slant(int n) -{ - if (interrupted) - return; - char_slant = n; -} - -environment::environment(symbol nm) -: dummy(0), - prev_line_length((units_per_inch*13)/2), - line_length((units_per_inch*13)/2), - prev_title_length((units_per_inch*13)/2), - title_length((units_per_inch*13)/2), - prev_size(sizescale*10), - size(sizescale*10), - requested_size(sizescale*10), - prev_requested_size(sizescale*10), - char_height(0), - char_slant(0), - space_size(12), - sentence_space_size(12), - adjust_mode(ADJUST_BOTH), - fill(1), - interrupted(0), - prev_line_interrupted(0), - center_lines(0), - right_justify_lines(0), - prev_vertical_spacing(points_to_units(12)), - vertical_spacing(points_to_units(12)), - prev_post_vertical_spacing(0), - post_vertical_spacing(0), - prev_line_spacing(1), - line_spacing(1), - prev_indent(0), - indent(0), - temporary_indent(0), - have_temporary_indent(0), - underline_lines(0), - input_trap_count(0), - line(0), - prev_text_length(0), - width_total(0), - space_total(0), - input_line_start(0), - tabs(units_per_inch/2, TAB_LEFT), - current_tab(TAB_NONE), - leader_node(0), - tab_char(0), - leader_char(charset_table['.']), - current_field(0), - discarding(0), - spread_flag(0), - margin_character_flags(0), - margin_character_node(0), - margin_character_distance(points_to_units(10)), - numbering_nodes(0), - number_text_separation(1), - line_number_indent(0), - line_number_multiple(1), - no_number_count(0), - hyphenation_flags(1), - hyphen_line_count(0), - hyphen_line_max(-1), - hyphenation_space(H0), - hyphenation_margin(H0), - composite(0), - pending_lines(0), -#ifdef WIDOW_CONTROL - widow_control(0), -#endif /* WIDOW_CONTROL */ - name(nm), - control_char('.'), - no_break_control_char('\''), - hyphen_indicator_char(0) -{ - prev_family = family = lookup_family(default_family); - prev_fontno = fontno = 1; - if (!is_good_fontno(1)) - fatal("font number 1 not a valid font"); - if (family->make_definite(1) < 0) - fatal("invalid default family `%1'", default_family.contents()); - prev_fontno = fontno; -} - -environment::environment(const environment *e) -: dummy(1), - prev_line_length(e->prev_line_length), - line_length(e->line_length), - prev_title_length(e->prev_title_length), - title_length(e->title_length), - prev_size(e->prev_size), - size(e->size), - requested_size(e->requested_size), - prev_requested_size(e->prev_requested_size), - char_height(e->char_height), - char_slant(e->char_slant), - prev_fontno(e->prev_fontno), - fontno(e->fontno), - prev_family(e->prev_family), - family(e->family), - space_size(e->space_size), - sentence_space_size(e->sentence_space_size), - adjust_mode(e->adjust_mode), - fill(e->fill), - interrupted(0), - prev_line_interrupted(0), - center_lines(0), - right_justify_lines(0), - prev_vertical_spacing(e->prev_vertical_spacing), - vertical_spacing(e->vertical_spacing), - prev_post_vertical_spacing(e->prev_post_vertical_spacing), - post_vertical_spacing(e->post_vertical_spacing), - prev_line_spacing(e->prev_line_spacing), - line_spacing(e->line_spacing), - prev_indent(e->prev_indent), - indent(e->indent), - temporary_indent(0), - have_temporary_indent(0), - underline_lines(0), - input_trap_count(0), - line(0), - prev_text_length(e->prev_text_length), - width_total(0), - space_total(0), - input_line_start(0), - tabs(e->tabs), - current_tab(TAB_NONE), - leader_node(0), - tab_char(e->tab_char), - leader_char(e->leader_char), - current_field(0), - discarding(0), - spread_flag(0), - margin_character_flags(e->margin_character_flags), - margin_character_node(e->margin_character_node), - margin_character_distance(e->margin_character_distance), - numbering_nodes(0), - number_text_separation(e->number_text_separation), - line_number_indent(e->line_number_indent), - line_number_multiple(e->line_number_multiple), - no_number_count(e->no_number_count), - hyphenation_flags(e->hyphenation_flags), - hyphen_line_count(0), - hyphen_line_max(e->hyphen_line_max), - hyphenation_space(e->hyphenation_space), - hyphenation_margin(e->hyphenation_margin), - composite(0), - pending_lines(0), -#ifdef WIDOW_CONTROL - widow_control(e->widow_control), -#endif /* WIDOW_CONTROL */ - name(e->name), // so that eg `.if "\n[.ev]"0"' works - control_char(e->control_char), - no_break_control_char(e->no_break_control_char), - hyphen_indicator_char(e->hyphen_indicator_char) -{ -} - -void environment::copy(const environment *e) -{ - prev_line_length = e->prev_line_length; - line_length = e->line_length; - prev_title_length = e->prev_title_length; - title_length = e->title_length; - prev_size = e->prev_size; - size = e->size; - prev_requested_size = e->prev_requested_size; - requested_size = e->requested_size; - char_height = e->char_height; - char_slant = e->char_slant; - space_size = e->space_size; - sentence_space_size = e->sentence_space_size; - adjust_mode = e->adjust_mode; - fill = e->fill; - interrupted = 0; - prev_line_interrupted = 0; - center_lines = 0; - right_justify_lines = 0; - prev_vertical_spacing = e->prev_vertical_spacing; - vertical_spacing = e->vertical_spacing; - prev_post_vertical_spacing = e->prev_post_vertical_spacing, - post_vertical_spacing = e->post_vertical_spacing, - prev_line_spacing = e->prev_line_spacing; - line_spacing = e->line_spacing; - prev_indent = e->prev_indent; - indent = e->indent; - have_temporary_indent = 0; - temporary_indent = 0; - underline_lines = 0; - input_trap_count = 0; - prev_text_length = e->prev_text_length; - width_total = 0; - space_total = 0; - input_line_start = 0; - control_char = e->control_char; - no_break_control_char = e->no_break_control_char; - hyphen_indicator_char = e->hyphen_indicator_char; - spread_flag = 0; - line = 0; - pending_lines = 0; - discarding = 0; - tabs = e->tabs; - current_tab = TAB_NONE; - current_field = 0; - margin_character_flags = e->margin_character_flags; - margin_character_node = e->margin_character_node; - margin_character_distance = e->margin_character_distance; - numbering_nodes = 0; - number_text_separation = e->number_text_separation; - line_number_multiple = e->line_number_multiple; - line_number_indent = e->line_number_indent; - no_number_count = e->no_number_count; - tab_char = e->tab_char; - leader_char = e->leader_char; - hyphenation_flags = e->hyphenation_flags; - fontno = e->fontno; - prev_fontno = e->prev_fontno; - dummy = e->dummy; - family = e->family; - prev_family = e->prev_family; - leader_node = 0; -#ifdef WIDOW_CONTROL - widow_control = e->widow_control; -#endif /* WIDOW_CONTROL */ - hyphen_line_max = e->hyphen_line_max; - hyphen_line_count = 0; - hyphenation_space = e->hyphenation_space; - hyphenation_margin = e->hyphenation_margin; - composite = 0; -} - -environment::~environment() -{ - delete leader_node; - delete_node_list(line); - delete_node_list(numbering_nodes); -} - -hunits environment::get_input_line_position() -{ - hunits n; - if (line == 0) - n = -input_line_start; - else - n = width_total - input_line_start; - if (current_tab) - n += tab_width; - return n; -} - -void environment::set_input_line_position(hunits n) -{ - input_line_start = line == 0 ? -n : width_total - n; - if (current_tab) - input_line_start += tab_width; -} - -hunits environment::get_line_length() -{ - return line_length; -} - -hunits environment::get_saved_line_length() -{ - if (line) - return target_text_length + saved_indent; - else - return line_length; -} - -vunits environment::get_vertical_spacing() -{ - return vertical_spacing; -} - -vunits environment::get_post_vertical_spacing() -{ - return post_vertical_spacing; -} - -int environment::get_line_spacing() -{ - return line_spacing; -} - -vunits environment::total_post_vertical_spacing() -{ - vunits tem(post_vertical_spacing); - if (line_spacing > 1) - tem += (line_spacing - 1)*vertical_spacing; - return tem; -} - -int environment::get_bold() -{ - return get_bold_fontno(fontno); -} - -hunits environment::get_digit_width() -{ - return env_digit_width(this); -} - -int environment::get_adjust_mode() -{ - return adjust_mode; -} - -int environment::get_fill() -{ - return fill; -} - -hunits environment::get_indent() -{ - return indent; -} - -hunits environment::get_saved_indent() -{ - if (line) - return saved_indent; - else if (have_temporary_indent) - return temporary_indent; - else - return indent; -} - -hunits environment::get_temporary_indent() -{ - return temporary_indent; -} - -hunits environment::get_title_length() -{ - return title_length; -} - -node *environment::get_prev_char() -{ - for (node *n = current_tab ? tab_contents : line; n; n = n->next) { - node *last = n->last_char_node(); - if (last) - return last; - } - return 0; -} - -hunits environment::get_prev_char_width() -{ - node *last = get_prev_char(); - if (!last) - return H0; - return last->width(); -} - -hunits environment::get_prev_char_skew() -{ - node *last = get_prev_char(); - if (!last) - return H0; - return last->skew(); -} - -vunits environment::get_prev_char_height() -{ - node *last = get_prev_char(); - if (!last) - return V0; - vunits min, max; - last->vertical_extent(&min, &max); - return -min; -} - -vunits environment::get_prev_char_depth() -{ - node *last = get_prev_char(); - if (!last) - return V0; - vunits min, max; - last->vertical_extent(&min, &max); - return max; -} - -hunits environment::get_text_length() -{ - hunits n = line == 0 ? H0 : width_total; - if (current_tab) - n += tab_width; - return n; -} - -hunits environment::get_prev_text_length() -{ - return prev_text_length; -} - - -static int sb_reg_contents = 0; -static int st_reg_contents = 0; -static int ct_reg_contents = 0; -static int rsb_reg_contents = 0; -static int rst_reg_contents = 0; -static int skw_reg_contents = 0; -static int ssc_reg_contents = 0; - -void environment::width_registers() -{ - // this is used to implement \w; it sets the st, sb, ct registers - vunits min = 0, max = 0, cur = 0; - int character_type = 0; - ssc_reg_contents = line ? line->subscript_correction().to_units() : 0; - skw_reg_contents = line ? line->skew().to_units() : 0; - line = reverse_node_list(line); - vunits real_min = V0; - vunits real_max = V0; - vunits v1, v2; - for (node *tem = line; tem; tem = tem->next) { - tem->vertical_extent(&v1, &v2); - v1 += cur; - if (v1 < real_min) - real_min = v1; - v2 += cur; - if (v2 > real_max) - real_max = v2; - if ((cur += tem->vertical_width()) < min) - min = cur; - else if (cur > max) - max = cur; - character_type |= tem->character_type(); - } - line = reverse_node_list(line); - st_reg_contents = -min.to_units(); - sb_reg_contents = -max.to_units(); - rst_reg_contents = -real_min.to_units(); - rsb_reg_contents = -real_max.to_units(); - ct_reg_contents = character_type; -} - -node *environment::extract_output_line() -{ - if (current_tab) - wrap_up_tab(); - node *n = line; - line = 0; - return n; -} - -/* environment related requests */ - -void environment_switch() -{ - int pop = 0; // 1 means pop, 2 means pop but no error message on underflow - if (curenv->is_dummy()) - error("can't switch environments when current environment is dummy"); - else if (!has_arg()) - pop = 1; - else { - symbol nm; - if (!tok.delimiter()) { - // It looks like a number. - int n; - if (get_integer(&n)) { - if (n >= 0 && n < NENVIRONMENTS) { - env_stack = new env_list(curenv, env_stack); - if (env_table[n] == 0) - env_table[n] = new environment(i_to_a(n)); - curenv = env_table[n]; - } - else - nm = i_to_a(n); - } - else - pop = 2; - } - else { - nm = get_long_name(1); - if (nm.is_null()) - pop = 2; - } - if (!nm.is_null()) { - environment *e = (environment *)env_dictionary.lookup(nm); - if (!e) { - e = new environment(nm); - (void)env_dictionary.lookup(nm, e); - } - env_stack = new env_list(curenv, env_stack); - curenv = e; - } - } - if (pop) { - if (env_stack == 0) { - if (pop == 1) - error("environment stack underflow"); - } - else { - curenv = env_stack->env; - env_list *tem = env_stack; - env_stack = env_stack->next; - delete tem; - } - } - skip_line(); -} - -void environment_copy() -{ - symbol nm; - environment *e=0; - tok.skip(); - if (!tok.delimiter()) { - // It looks like a number. - int n; - if (get_integer(&n)) { - if (n >= 0 && n < NENVIRONMENTS) - e = env_table[n]; - else - nm = i_to_a(n); - } - } - else - nm = get_long_name(1); - if (!e && !nm.is_null()) - e = (environment *)env_dictionary.lookup(nm); - if (e == 0) { - error("No environment to copy from"); - return; - } - else - curenv->copy(e); - skip_line(); -} - -static symbol P_symbol("P"); - -void font_change() -{ - symbol s = get_name(); - int is_number = 1; - if (s.is_null() || s == P_symbol) { - s = P_symbol; - is_number = 0; - } - else { - for (const char *p = s.contents(); p != 0 && *p != 0; p++) - if (!csdigit(*p)) { - is_number = 0; - break; - } - } - if (is_number) - curenv->set_font(atoi(s.contents())); - else - curenv->set_font(s); - skip_line(); -} - -void family_change() -{ - symbol s = get_name(1); - if (!s.is_null()) - curenv->set_family(s); - skip_line(); -} - -void point_size() -{ - int n; - if (has_arg() && get_number(&n, 'z', curenv->get_requested_point_size())) { - if (n <= 0) - n = 1; - curenv->set_size(n); - } - else - curenv->set_size(0); - skip_line(); -} - -void space_size() -{ - int n; - if (get_integer(&n)) { - curenv->space_size = n; - if (has_arg() && get_integer(&n)) - curenv->sentence_space_size = n; - else - curenv->sentence_space_size = curenv->space_size; - } - skip_line(); -} - -void fill() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->fill = 1; - tok.next(); -} - -void no_fill() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->fill = 0; - tok.next(); -} - -void center() -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - else if (n < 0) - n = 0; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->right_justify_lines = 0; - curenv->center_lines = n; - tok.next(); -} - -void right_justify() -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - else if (n < 0) - n = 0; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->center_lines = 0; - curenv->right_justify_lines = n; - tok.next(); -} - -void line_length() -{ - hunits temp; - if (has_arg() && get_hunits(&temp, 'm', curenv->line_length)) { - if (temp < H0) { - warning(WARN_RANGE, "bad line length %1u", temp.to_units()); - temp = H0; - } - } - else - temp = curenv->prev_line_length; - curenv->prev_line_length = curenv->line_length; - curenv->line_length = temp; - skip_line(); -} - -void title_length() -{ - hunits temp; - if (has_arg() && get_hunits(&temp, 'm', curenv->title_length)) { - if (temp < H0) { - warning(WARN_RANGE, "bad title length %1u", temp.to_units()); - temp = H0; - } - } - else - temp = curenv->prev_title_length; - curenv->prev_title_length = curenv->title_length; - curenv->title_length = temp; - skip_line(); -} - -void vertical_spacing() -{ - vunits temp; - if (has_arg() && get_vunits(&temp, 'p', curenv->vertical_spacing)) { - if (temp <= V0) { - warning(WARN_RANGE, "vertical spacing must be greater than 0"); - temp = vresolution; - } - } - else - temp = curenv->prev_vertical_spacing; - curenv->prev_vertical_spacing = curenv->vertical_spacing; - curenv->vertical_spacing = temp; - skip_line(); -} - -void post_vertical_spacing() -{ - vunits temp; - if (has_arg() && get_vunits(&temp, 'p', curenv->post_vertical_spacing)) { - if (temp < V0) { - warning(WARN_RANGE, - "post vertical spacing must be greater than or equal to 0"); - temp = V0; - } - } - else - temp = curenv->prev_post_vertical_spacing; - curenv->prev_post_vertical_spacing = curenv->post_vertical_spacing; - curenv->post_vertical_spacing = temp; - skip_line(); -} - -void line_spacing() -{ - int temp; - if (has_arg() && get_integer(&temp)) { - if (temp < 1) { - warning(WARN_RANGE, "value %1 out of range: interpreted as 1", temp); - temp = 1; - } - } - else - temp = curenv->prev_line_spacing; - curenv->prev_line_spacing = curenv->line_spacing; - curenv->line_spacing = temp; - skip_line(); -} - -void indent() -{ - hunits temp; - if (has_arg() && get_hunits(&temp, 'm', curenv->indent)) { - if (temp < H0) { - warning(WARN_RANGE, "indent cannot be negative"); - temp = H0; - } - } - else - temp = curenv->prev_indent; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - curenv->have_temporary_indent = 0; - curenv->prev_indent = curenv->indent; - curenv->indent = temp; - tok.next(); -} - -void temporary_indent() -{ - int err = 0; - hunits temp; - if (!get_hunits(&temp, 'm', curenv->get_indent())) - err = 1; - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (temp < H0) { - warning(WARN_RANGE, "total indent cannot be negative"); - temp = H0; - } - if (!err) { - curenv->temporary_indent = temp; - curenv->have_temporary_indent = 1; - } - tok.next(); -} - -void underline() -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - if (n <= 0) { - if (curenv->underline_lines > 0) { - curenv->prev_fontno = curenv->fontno; - curenv->fontno = curenv->pre_underline_fontno; - } - curenv->underline_lines = 0; - } - else { - curenv->underline_lines = n; - curenv->pre_underline_fontno = curenv->fontno; - curenv->fontno = get_underline_fontno(); - } - skip_line(); -} - -void control_char() -{ - curenv->control_char = '.'; - if (has_arg()) { - if (tok.ch() == 0) - error("bad control character"); - else - curenv->control_char = tok.ch(); - } - skip_line(); -} - -void no_break_control_char() -{ - curenv->no_break_control_char = '\''; - if (has_arg()) { - if (tok.ch() == 0) - error("bad control character"); - else - curenv->no_break_control_char = tok.ch(); - } - skip_line(); -} - -void margin_character() -{ - while (tok.space()) - tok.next(); - charinfo *ci = tok.get_char(); - if (ci) { - // Call tok.next() only after making the node so that - // .mc \s+9\(br\s0 works. - node *nd = curenv->make_char_node(ci); - tok.next(); - if (nd) { - delete curenv->margin_character_node; - curenv->margin_character_node = nd; - curenv->margin_character_flags = (MARGIN_CHARACTER_ON - |MARGIN_CHARACTER_NEXT); - hunits d; - if (has_arg() && get_hunits(&d, 'm')) - curenv->margin_character_distance = d; - } - } - else { - check_missing_character(); - curenv->margin_character_flags &= ~MARGIN_CHARACTER_ON; - if (curenv->margin_character_flags == 0) { - delete curenv->margin_character_node; - curenv->margin_character_node = 0; - } - } - skip_line(); -} - -void number_lines() -{ - delete_node_list(curenv->numbering_nodes); - curenv->numbering_nodes = 0; - if (has_arg()) { - node *nd = 0; - for (int i = '9'; i >= '0'; i--) { - node *tem = make_node(charset_table[i], curenv); - if (!tem) { - skip_line(); - return; - } - tem->next = nd; - nd = tem; - } - curenv->numbering_nodes = nd; - curenv->line_number_digit_width = env_digit_width(curenv); - int n; - if (!tok.delimiter()) { - if (get_integer(&n, next_line_number)) { - next_line_number = n; - if (next_line_number < 0) { - warning(WARN_RANGE, "negative line number"); - next_line_number = 0; - } - } - } - else - while (!tok.space() && !tok.newline() && !tok.eof()) - tok.next(); - if (has_arg()) { - if (!tok.delimiter()) { - if (get_integer(&n)) { - if (n <= 0) { - warning(WARN_RANGE, "negative or zero line number multiple"); - } - else - curenv->line_number_multiple = n; - } - } - else - while (!tok.space() && !tok.newline() && !tok.eof()) - tok.next(); - if (has_arg()) { - if (!tok.delimiter()) { - if (get_integer(&n)) - curenv->number_text_separation = n; - } - else - while (!tok.space() && !tok.newline() && !tok.eof()) - tok.next(); - if (has_arg() && !tok.delimiter() && get_integer(&n)) - curenv->line_number_indent = n; - } - } - } - skip_line(); -} - -void no_number() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->no_number_count = n > 0 ? n : 0; - else - curenv->no_number_count = 1; - skip_line(); -} - -void no_hyphenate() -{ - curenv->hyphenation_flags = 0; - skip_line(); -} - -void hyphenate_request() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->hyphenation_flags = n; - else - curenv->hyphenation_flags = 1; - skip_line(); -} - -void hyphen_char() -{ - curenv->hyphen_indicator_char = get_optional_char(); - skip_line(); -} - -void hyphen_line_max_request() -{ - int n; - if (has_arg() && get_integer(&n)) - curenv->hyphen_line_max = n; - else - curenv->hyphen_line_max = -1; - skip_line(); -} - -void environment::interrupt() -{ - if (!dummy) { - add_node(new transparent_dummy_node); - interrupted = 1; - } -} - -void environment::newline() -{ - if (underline_lines > 0) { - if (--underline_lines == 0) { - prev_fontno = fontno; - fontno = pre_underline_fontno; - } - } - if (current_field) - wrap_up_field(); - if (current_tab) - wrap_up_tab(); - // strip trailing spaces - while (line != 0 && line->discardable()) { - width_total -= line->width(); - space_total -= line->nspaces(); - node *tem = line; - line = line->next; - delete tem; - } - node *to_be_output = 0; - hunits to_be_output_width; - prev_line_interrupted = 0; - if (dummy) - space_newline(); - else if (interrupted) { - interrupted = 0; - // see environment::final_break - prev_line_interrupted = exit_started ? 2 : 1; - } - else if (center_lines > 0) { - --center_lines; - hunits x = target_text_length - width_total; - if (x > H0) - saved_indent += x/2; - to_be_output = line; - to_be_output_width = width_total; - line = 0; - } - else if (right_justify_lines > 0) { - --right_justify_lines; - hunits x = target_text_length - width_total; - if (x > H0) - saved_indent += x; - to_be_output = line; - to_be_output_width = width_total; - line = 0; - } - else if (fill) - space_newline(); - else { - to_be_output = line; - to_be_output_width = width_total; - line = 0; - } - input_line_start = line == 0 ? H0 : width_total; - if (to_be_output) { - output_line(to_be_output, to_be_output_width); - hyphen_line_count = 0; - } - if (input_trap_count > 0) { - if (--input_trap_count == 0) - spring_trap(input_trap); - } -} - -void environment::output_line(node *n, hunits width) -{ - prev_text_length = width; - if (margin_character_flags) { - hunits d = line_length + margin_character_distance - saved_indent - width; - if (d > 0) { - n = new hmotion_node(d, n); - width += d; - } - margin_character_flags &= ~MARGIN_CHARACTER_NEXT; - node *tem; - if (!margin_character_flags) { - tem = margin_character_node; - margin_character_node = 0; - } - else - tem = margin_character_node->copy(); - tem->next = n; - n = tem; - width += tem->width(); - } - node *nn = 0; - while (n != 0) { - node *tem = n->next; - n->next = nn; - nn = n; - n = tem; - } - if (!saved_indent.is_zero()) - nn = new hmotion_node(saved_indent, nn); - width += saved_indent; - if (no_number_count > 0) - --no_number_count; - else if (numbering_nodes) { - hunits w = (line_number_digit_width - *(3+line_number_indent+number_text_separation)); - if (next_line_number % line_number_multiple != 0) - nn = new hmotion_node(w, nn); - else { - hunits x = w; - nn = new hmotion_node(number_text_separation*line_number_digit_width, - nn); - x -= number_text_separation*line_number_digit_width; - char buf[30]; - sprintf(buf, "%3d", next_line_number); - for (char *p = strchr(buf, '\0') - 1; p >= buf && *p != ' '; --p) { - node *gn = numbering_nodes; - for (int count = *p - '0'; count > 0; count--) - gn = gn->next; - gn = gn->copy(); - x -= gn->width(); - gn->next = nn; - nn = gn; - } - nn = new hmotion_node(x, nn); - } - width += w; - ++next_line_number; - } - output(nn, !fill, vertical_spacing, total_post_vertical_spacing(), width); -} - -void environment::start_line() -{ - assert(line == 0); - discarding = 0; - line = new line_start_node; - if (have_temporary_indent) { - saved_indent = temporary_indent; - have_temporary_indent = 0; - } - else - saved_indent = indent; - target_text_length = line_length - saved_indent; - width_total = H0; - space_total = 0; -} - -hunits environment::get_hyphenation_space() -{ - return hyphenation_space; -} - -void hyphenation_space_request() -{ - hunits n; - if (get_hunits(&n, 'm')) { - if (n < H0) { - warning(WARN_RANGE, "hyphenation space cannot be negative"); - n = H0; - } - curenv->hyphenation_space = n; - } - skip_line(); -} - -hunits environment::get_hyphenation_margin() -{ - return hyphenation_margin; -} - -void hyphenation_margin_request() -{ - hunits n; - if (get_hunits(&n, 'm')) { - if (n < H0) { - warning(WARN_RANGE, "hyphenation margin cannot be negative"); - n = H0; - } - curenv->hyphenation_margin = n; - } - skip_line(); -} - -breakpoint *environment::choose_breakpoint() -{ - hunits x = width_total; - int s = space_total; - node *n = line; - breakpoint *best_bp = 0; // the best breakpoint so far - int best_bp_fits = 0; - while (n != 0) { - x -= n->width(); - s -= n->nspaces(); - breakpoint *bp = n->get_breakpoints(x, s); - while (bp != 0) { - if (bp->width <= target_text_length) { - if (!bp->hyphenated) { - breakpoint *tem = bp->next; - bp->next = 0; - while (tem != 0) { - breakpoint *tem1 = tem; - tem = tem->next; - delete tem1; - } - if (best_bp_fits - // Decide whether to use the hyphenated breakpoint. - && (hyphen_line_max < 0 - // Only choose the hyphenated breakpoint if it would not - // exceed the maximum number of consecutive hyphenated - // lines. - || hyphen_line_count + 1 <= hyphen_line_max) - && !(adjust_mode == ADJUST_BOTH - // Don't choose the hyphenated breakpoint if the line - // can be justified by adding no more than - // hyphenation_space to any word space. - ? (bp->nspaces > 0 - && (((target_text_length - bp->width - + (bp->nspaces - 1)*hresolution)/bp->nspaces) - <= hyphenation_space)) - // Don't choose the hyphenated breakpoint if the line - // is no more than hyphenation_margin short. - : target_text_length - bp->width <= hyphenation_margin)) { - delete bp; - return best_bp; - } - if (best_bp) - delete best_bp; - return bp; - } - else { - if ((adjust_mode == ADJUST_BOTH - ? hyphenation_space == H0 - : hyphenation_margin == H0) - && (hyphen_line_max < 0 - || hyphen_line_count + 1 <= hyphen_line_max)) { - // No need to consider a non-hyphenated breakpoint. - if (best_bp) - delete best_bp; - return bp; - } - // It fits but it's hyphenated. - if (!best_bp_fits) { - if (best_bp) - delete best_bp; - best_bp = bp; - bp = bp->next; - best_bp_fits = 1; - } - else { - breakpoint *tem = bp; - bp = bp->next; - delete tem; - } - } - } - else { - if (best_bp) - delete best_bp; - best_bp = bp; - bp = bp->next; - } - } - n = n->next; - } - if (best_bp) { - if (!best_bp_fits) - warning(WARN_BREAK, "can't break line"); - return best_bp; - } - return 0; -} - -void environment::hyphenate_line() -{ - if (line == 0) - return; - hyphenation_type prev_type = line->get_hyphenation_type(); - node **startp; - for (startp = &line->next; *startp != 0; startp = &(*startp)->next) { - hyphenation_type this_type = (*startp)->get_hyphenation_type(); - if (prev_type == HYPHEN_BOUNDARY && this_type == HYPHEN_MIDDLE) - break; - prev_type = this_type; - } - if (*startp == 0) - return; - node *tem = *startp; - int i = 0; - do { - ++i; - tem = tem->next; - } while (tem != 0 && tem->get_hyphenation_type() == HYPHEN_MIDDLE); - int inhibit = (tem != 0 && tem->get_hyphenation_type() == HYPHEN_INHIBIT); - node *end = tem; - hyphen_list *sl = 0; - tem = *startp; - node *forward = 0; - while (tem != end) { - sl = tem->get_hyphen_list(sl); - node *tem1 = tem; - tem = tem->next; - tem1->next = forward; - forward = tem1; - } - if (!inhibit) { - // this is for characters like hyphen and emdash - int prev_code = 0; - for (hyphen_list *h = sl; h; h = h->next) { - h->breakable = (prev_code != 0 - && h->next != 0 - && h->next->hyphenation_code != 0); - prev_code = h->hyphenation_code; - } - } - if (hyphenation_flags != 0 - && !inhibit - // this may not be right if we have extra space on this line - && !((hyphenation_flags & HYPHEN_LAST_LINE) - && (curdiv->distance_to_next_trap() - <= vertical_spacing + total_post_vertical_spacing())) - && i >= 4) - hyphenate(sl, hyphenation_flags); - while (forward != 0) { - node *tem1 = forward; - forward = forward->next; - tem1->next = 0; - tem = tem1->add_self(tem, &sl); - } - *startp = tem; -} - -static node *node_list_reverse(node *n) -{ - node *res = 0; - while (n) { - node *tem = n; - n = n->next; - tem->next = res; - res = tem; - } - return res; -} - -static void distribute_space(node *n, int nspaces, hunits desired_space, - int force_reverse = 0) -{ - static int reverse = 0; - if (force_reverse || reverse) - n = node_list_reverse(n); - for (node *tem = n; tem; tem = tem->next) - tem->spread_space(&nspaces, &desired_space); - if (force_reverse || reverse) - (void)node_list_reverse(n); - if (!force_reverse) - reverse = !reverse; - assert(desired_space.is_zero() && nspaces == 0); -} - -void environment::possibly_break_line(int forced) -{ - if (!fill || current_tab || current_field || dummy) - return; - while (line != 0 - && (forced - // When a macro follows a paragraph in fill mode, the - // current line should not be empty. - || (width_total - line->width()) > target_text_length)) { - hyphenate_line(); - breakpoint *bp = choose_breakpoint(); - if (bp == 0) - // we'll find one eventually - return; - node *pre, *post; - node **ndp = &line; - while (*ndp != bp->nd) - ndp = &(*ndp)->next; - bp->nd->split(bp->index, &pre, &post); - *ndp = post; - hunits extra_space_width = H0; - switch(adjust_mode) { - case ADJUST_BOTH: - if (bp->nspaces != 0) - extra_space_width = target_text_length - bp->width; - break; - case ADJUST_CENTER: - saved_indent += (target_text_length - bp->width)/2; - break; - case ADJUST_RIGHT: - saved_indent += target_text_length - bp->width; - break; - } - distribute_space(pre, bp->nspaces, extra_space_width); - hunits output_width = bp->width + extra_space_width; - input_line_start -= output_width; - if (bp->hyphenated) - hyphen_line_count++; - else - hyphen_line_count = 0; - delete bp; - space_total = 0; - width_total = 0; - node *first_non_discardable = 0; - node *tem; - for (tem = line; tem != 0; tem = tem->next) - if (!tem->discardable()) - first_non_discardable = tem; - node *to_be_discarded; - if (first_non_discardable) { - to_be_discarded = first_non_discardable->next; - first_non_discardable->next = 0; - for (tem = line; tem != 0; tem = tem->next) { - width_total += tem->width(); - space_total += tem->nspaces(); - } - discarding = 0; - } - else { - discarding = 1; - to_be_discarded = line; - line = 0; - } - // Do output_line() here so that line will be 0 iff the - // the environment will be empty. - output_line(pre, output_width); - while (to_be_discarded != 0) { - tem = to_be_discarded; - to_be_discarded = to_be_discarded->next; - input_line_start -= tem->width(); - delete tem; - } - if (line != 0) { - if (have_temporary_indent) { - saved_indent = temporary_indent; - have_temporary_indent = 0; - } - else - saved_indent = indent; - target_text_length = line_length - saved_indent; - } - } -} - -/* -Do the break at the end of input after the end macro (if any). - -Unix troff behaves as follows: if the last line is - -foo bar\c - -it will output foo on the current page, and bar on the next page; -if the last line is - -foo\c - -or - -foo bar - -everything will be output on the current page. This behaviour must be -considered a bug. - -The problem is that some macro packages rely on this. For example, -the ATK macros have an end macro that emits \c if it needs to print a -table of contents but doesn't do a 'bp in the end macro; instead the -'bp is done in the bottom of page trap. This works with Unix troff, -provided that the current environment is not empty at the end of the -input file. - -The following will make macro packages that do that sort of thing work -even if the current environment is empty at the end of the input file. -If the last input line used \c and this line occurred in the end macro, -then we'll force everything out on the current page, but we'll make -sure that the environment isn't empty so that we won't exit at the -bottom of this page. -*/ - -void environment::final_break() -{ - if (prev_line_interrupted == 2) { - do_break(); - add_node(new transparent_dummy_node); - } - else - do_break(); -} - -void environment::do_break() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - topdiv->begin_page(); - return; - } - if (current_tab) - wrap_up_tab(); - if (line) { - line = new space_node(H0, line); // this is so that hyphenation works - space_total++; - possibly_break_line(); - } - while (line != 0 && line->discardable()) { - width_total -= line->width(); - space_total -= line->nspaces(); - node *tem = line; - line = line->next; - delete tem; - } - discarding = 0; - input_line_start = H0; - if (line != 0) { - if (fill) { - switch (adjust_mode) { - case ADJUST_CENTER: - saved_indent += (target_text_length - width_total)/2; - break; - case ADJUST_RIGHT: - saved_indent += target_text_length - width_total; - break; - } - } - node *tem = line; - line = 0; - output_line(tem, width_total); - hyphen_line_count = 0; - } - prev_line_interrupted = 0; -#ifdef WIDOW_CONTROL - mark_last_line(); - output_pending_lines(); -#endif /* WIDOW_CONTROL */ -} - -int environment::is_empty() -{ - return !current_tab && line == 0 && pending_lines == 0; -} - -void break_request() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - tok.next(); -} - -void title() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_title(); - return; - } - node *part[3]; - hunits part_width[3]; - part[0] = part[1] = part[2] = 0; - environment env(curenv); - environment *oldenv = curenv; - curenv = &env; - read_title_parts(part, part_width); - curenv = oldenv; - curenv->size = env.size; - curenv->prev_size = env.prev_size; - curenv->requested_size = env.requested_size; - curenv->prev_requested_size = env.prev_requested_size; - curenv->char_height = env.char_height; - curenv->char_slant = env.char_slant; - curenv->fontno = env.fontno; - curenv->prev_fontno = env.prev_fontno; - node *n = 0; - node *p = part[2]; - while (p != 0) { - node *tem = p; - p = p->next; - tem->next = n; - n = tem; - } - hunits title_length(curenv->title_length); - hunits f = title_length - part_width[1]; - hunits f2 = f/2; - n = new hmotion_node(f2 - part_width[2], n); - p = part[1]; - while (p != 0) { - node *tem = p; - p = p->next; - tem->next = n; - n = tem; - } - n = new hmotion_node(f - f2 - part_width[0], n); - p = part[0]; - while (p != 0) { - node *tem = p; - p = p->next; - tem->next = n; - n = tem; - } - curenv->output_title(n, !curenv->fill, curenv->vertical_spacing, - curenv->total_post_vertical_spacing(), title_length); - curenv->hyphen_line_count = 0; - tok.next(); -} - -void adjust() -{ - curenv->adjust_mode |= 1; - if (has_arg()) { - switch (tok.ch()) { - case 'l': - curenv->adjust_mode = ADJUST_LEFT; - break; - case 'r': - curenv->adjust_mode = ADJUST_RIGHT; - break; - case 'c': - curenv->adjust_mode = ADJUST_CENTER; - break; - case 'b': - case 'n': - curenv->adjust_mode = ADJUST_BOTH; - break; - default: - int n; - if (get_integer(&n)) { - if (n < 0) - warning(WARN_RANGE, "negative adjustment mode"); - else if (n > 5) { - curenv->adjust_mode = 5; - warning(WARN_RANGE, "adjustment mode `%1' out of range", n); - } - else - curenv->adjust_mode = n; - } - } - } - skip_line(); -} - -void no_adjust() -{ - curenv->adjust_mode &= ~1; - skip_line(); -} - -void input_trap() -{ - curenv->input_trap_count = 0; - int n; - if (has_arg() && get_integer(&n)) { - if (n <= 0) - warning(WARN_RANGE, - "number of lines for input trap must be greater than zero"); - else { - symbol s = get_name(1); - if (!s.is_null()) { - curenv->input_trap_count = n; - curenv->input_trap = s; - } - } - } - skip_line(); -} - -/* tabs */ - -// must not be R or C or L or a legitimate part of a number expression -const char TAB_REPEAT_CHAR = 'T'; - -struct tab { - tab *next; - hunits pos; - tab_type type; - tab(hunits, tab_type); - enum { BLOCK = 1024 }; - static tab *free_list; - void *operator new(size_t); - void operator delete(void *); -}; - -tab *tab::free_list = 0; - -void *tab::operator new(size_t n) -{ - assert(n == sizeof(tab)); - if (!free_list) { - free_list = (tab *)new char[sizeof(tab)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - tab *p = free_list; - free_list = (tab *)(free_list->next); - p->next = 0; - return p; -} - -#ifdef __GNUG__ -/* cfront can't cope with this. */ -inline -#endif -void tab::operator delete(void *p) -{ - if (p) { - ((tab *)p)->next = free_list; - free_list = (tab *)p; - } -} - -tab::tab(hunits x, tab_type t) : next(0), pos(x), type(t) -{ -} - -tab_stops::tab_stops(hunits distance, tab_type type) - : initial_list(0) -{ - repeated_list = new tab(distance, type); -} - -tab_stops::~tab_stops() -{ - clear(); -} - -tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance) -{ - hunits lastpos = 0; - tab *tem; - for (tem = initial_list; tem && tem->pos <= curpos; tem = tem->next) - lastpos = tem->pos; - if (tem) { - *distance = tem->pos - curpos; - return tem->type; - } - if (repeated_list == 0) - return TAB_NONE; - hunits base = lastpos; - for (;;) { - for (tem = repeated_list; tem && tem->pos + base <= curpos; tem = tem->next) - lastpos = tem->pos; - if (tem) { - *distance = tem->pos + base - curpos; - return tem->type; - } - assert(lastpos > 0); - base += lastpos; - } - return TAB_NONE; -} - -const char *tab_stops::to_string() -{ - static char *buf = 0; - static int buf_size = 0; - // figure out a maximum on the amount of space we can need - int count = 0; - tab *p; - for (p = initial_list; p; p = p->next) - ++count; - for (p = repeated_list; p; p = p->next) - ++count; - // (10 for digits + 1 for u + 1 for 'C' or 'R') + 2 for ' &' + 1 for '\0' - int need = count*12 + 3; - if (buf == 0 || need > buf_size) { - if (buf) - a_delete buf; - buf_size = need; - buf = new char[buf_size]; - } - char *ptr = buf; - for (p = initial_list; p; p = p->next) { - strcpy(ptr, i_to_a(p->pos.to_units())); - ptr = strchr(ptr, '\0'); - *ptr++ = 'u'; - *ptr = '\0'; - switch (p->type) { - case TAB_LEFT: - break; - case TAB_RIGHT: - *ptr++ = 'R'; - break; - case TAB_CENTER: - *ptr++ = 'C'; - break; - case TAB_NONE: - default: - assert(0); - } - } - if (repeated_list) - *ptr++ = TAB_REPEAT_CHAR; - for (p = repeated_list; p; p = p->next) { - strcpy(ptr, i_to_a(p->pos.to_units())); - ptr = strchr(ptr, '\0'); - *ptr++ = 'u'; - *ptr = '\0'; - switch (p->type) { - case TAB_LEFT: - break; - case TAB_RIGHT: - *ptr++ = 'R'; - break; - case TAB_CENTER: - *ptr++ = 'C'; - break; - case TAB_NONE: - default: - assert(0); - } - } - *ptr++ = '\0'; - return buf; -} - -tab_stops::tab_stops() : initial_list(0), repeated_list(0) -{ -} - -tab_stops::tab_stops(const tab_stops &ts) - : initial_list(0), repeated_list(0) -{ - tab **p = &initial_list; - tab *t = ts.initial_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } - p = &repeated_list; - t = ts.repeated_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } -} - -void tab_stops::clear() -{ - while (initial_list) { - tab *tem = initial_list; - initial_list = initial_list->next; - delete tem; - } - while (repeated_list) { - tab *tem = repeated_list; - repeated_list = repeated_list->next; - delete tem; - } -} - -void tab_stops::add_tab(hunits pos, tab_type type, int repeated) -{ - tab **p; - for (p = repeated ? &repeated_list : &initial_list; *p; p = &(*p)->next) - ; - *p = new tab(pos, type); -} - - -void tab_stops::operator=(const tab_stops &ts) -{ - clear(); - tab **p = &initial_list; - tab *t = ts.initial_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } - p = &repeated_list; - t = ts.repeated_list; - while (t) { - *p = new tab(t->pos, t->type); - t = t->next; - p = &(*p)->next; - } -} - -void set_tabs() -{ - hunits pos; - hunits prev_pos = 0; - int first = 1; - int repeated = 0; - tab_stops tabs; - while (has_arg()) { - if (tok.ch() == TAB_REPEAT_CHAR) { - tok.next(); - repeated = 1; - prev_pos = 0; - } - if (!get_hunits(&pos, 'm', prev_pos)) - break; - tab_type type = TAB_LEFT; - if (tok.ch() == 'C') { - tok.next(); - type = TAB_CENTER; - } - else if (tok.ch() == 'R') { - tok.next(); - type = TAB_RIGHT; - } - else if (tok.ch() == 'L') { - tok.next(); - } - if (pos <= prev_pos && !first) - warning(WARN_RANGE, - "positions of tab stops must be strictly increasing"); - else { - tabs.add_tab(pos, type, repeated); - prev_pos = pos; - first = 0; - } - } - curenv->tabs = tabs; - skip_line(); -} - -const char *environment::get_tabs() -{ - return tabs.to_string(); -} - -#if 0 -tab_stops saved_tabs; - -void tabs_save() -{ - saved_tabs = curenv->tabs; - skip_line(); -} - -void tabs_restore() -{ - curenv->tabs = saved_tabs; - skip_line(); -} -#endif - -tab_type environment::distance_to_next_tab(hunits *distance) -{ - return curenv->tabs.distance_to_next_tab(get_input_line_position(), distance); -} - -void field_characters() -{ - field_delimiter_char = get_optional_char(); - if (field_delimiter_char) - padding_indicator_char = get_optional_char(); - else - padding_indicator_char = 0; - skip_line(); -} - -void environment::wrap_up_tab() -{ - if (!current_tab) - return; - if (line == 0) - start_line(); - hunits tab_amount; - switch (current_tab) { - case TAB_RIGHT: - tab_amount = tab_distance - tab_width; - line = make_tab_node(tab_amount, line); - break; - case TAB_CENTER: - tab_amount = tab_distance - tab_width/2; - line = make_tab_node(tab_amount, line); - break; - case TAB_NONE: - case TAB_LEFT: - default: - assert(0); - } - width_total += tab_amount; - width_total += tab_width; - if (current_field) { - if (tab_precedes_field) { - pre_field_width += tab_amount; - tab_precedes_field = 0; - } - field_distance -= tab_amount; - field_spaces += tab_field_spaces; - } - if (tab_contents != 0) { - node *tem; - for (tem = tab_contents; tem->next != 0; tem = tem->next) - ; - tem->next = line; - line = tab_contents; - } - tab_field_spaces = 0; - tab_contents = 0; - tab_width = H0; - tab_distance = H0; - current_tab = TAB_NONE; -} - -node *environment::make_tab_node(hunits d, node *next) -{ - if (leader_node != 0 && d < 0) { - error("motion generated by leader cannot be negative"); - delete leader_node; - leader_node = 0; - } - if (!leader_node) - return new hmotion_node(d, next); - node *n = new hline_node(d, leader_node, next); - leader_node = 0; - return n; -} - -void environment::handle_tab(int is_leader) -{ - hunits d; - if (current_tab) - wrap_up_tab(); - charinfo *ci = is_leader ? leader_char : tab_char; - delete leader_node; - leader_node = ci ? make_char_node(ci) : 0; - tab_type t = distance_to_next_tab(&d); - switch (t) { - case TAB_NONE: - return; - case TAB_LEFT: - add_node(make_tab_node(d)); - return; - case TAB_RIGHT: - case TAB_CENTER: - tab_width = 0; - tab_distance = d; - tab_contents = 0; - current_tab = t; - tab_field_spaces = 0; - return; - default: - assert(0); - } -} - -void environment::start_field() -{ - assert(!current_field); - hunits d; - if (distance_to_next_tab(&d) != TAB_NONE) { - pre_field_width = get_text_length(); - field_distance = d; - current_field = 1; - field_spaces = 0; - tab_field_spaces = 0; - for (node *p = line; p; p = p->next) - if (p->nspaces()) { - p->freeze_space(); - space_total--; - } - tab_precedes_field = current_tab != TAB_NONE; - } - else - error("zero field width"); -} - -void environment::wrap_up_field() -{ - if (!current_tab && field_spaces == 0) - add_padding(); - hunits padding = field_distance - (get_text_length() - pre_field_width); - if (current_tab && tab_field_spaces != 0) { - hunits tab_padding = scale(padding, - tab_field_spaces, - field_spaces + tab_field_spaces); - padding -= tab_padding; - distribute_space(tab_contents, tab_field_spaces, tab_padding, 1); - tab_field_spaces = 0; - tab_width += tab_padding; - } - if (field_spaces != 0) { - distribute_space(line, field_spaces, padding, 1); - width_total += padding; - if (current_tab) { - // the start of the tab has been moved to the right by padding, so - tab_distance -= padding; - if (tab_distance <= H0) { - // use the next tab stop instead - current_tab = tabs.distance_to_next_tab(get_input_line_position() - - tab_width, - &tab_distance); - if (current_tab == TAB_NONE || current_tab == TAB_LEFT) { - width_total += tab_width; - if (current_tab == TAB_LEFT) { - line = make_tab_node(tab_distance, line); - width_total += tab_distance; - current_tab = TAB_NONE; - } - if (tab_contents != 0) { - node *tem; - for (tem = tab_contents; tem->next != 0; tem = tem->next) - ; - tem->next = line; - line = tab_contents; - tab_contents = 0; - } - tab_width = H0; - tab_distance = H0; - } - } - } - } - current_field = 0; -} - -void environment::add_padding() -{ - if (current_tab) { - tab_contents = new space_node(H0, tab_contents); - tab_field_spaces++; - } - else { - if (line == 0) - start_line(); - line = new space_node(H0, line); - field_spaces++; - } -} - -typedef int (environment::*INT_FUNCP)(); -typedef vunits (environment::*VUNITS_FUNCP)(); -typedef hunits (environment::*HUNITS_FUNCP)(); -typedef const char *(environment::*STRING_FUNCP)(); - -class int_env_reg : public reg { - INT_FUNCP func; - public: - int_env_reg(INT_FUNCP); - const char *get_string(); - int get_value(units *val); -}; - -class vunits_env_reg : public reg { - VUNITS_FUNCP func; - public: - vunits_env_reg(VUNITS_FUNCP f); - const char *get_string(); - int get_value(units *val); -}; - - -class hunits_env_reg : public reg { - HUNITS_FUNCP func; - public: - hunits_env_reg(HUNITS_FUNCP f); - const char *get_string(); - int get_value(units *val); -}; - -class string_env_reg : public reg { - STRING_FUNCP func; -public: - string_env_reg(STRING_FUNCP); - const char *get_string(); -}; - -int_env_reg::int_env_reg(INT_FUNCP f) : func(f) -{ -} - -int int_env_reg::get_value(units *val) -{ - *val = (curenv->*func)(); - return 1; -} - -const char *int_env_reg::get_string() -{ - return i_to_a((curenv->*func)()); -} - -vunits_env_reg::vunits_env_reg(VUNITS_FUNCP f) : func(f) -{ -} - -int vunits_env_reg::get_value(units *val) -{ - *val = (curenv->*func)().to_units(); - return 1; -} - -const char *vunits_env_reg::get_string() -{ - return i_to_a((curenv->*func)().to_units()); -} - -hunits_env_reg::hunits_env_reg(HUNITS_FUNCP f) : func(f) -{ -} - -int hunits_env_reg::get_value(units *val) -{ - *val = (curenv->*func)().to_units(); - return 1; -} - -const char *hunits_env_reg::get_string() -{ - return i_to_a((curenv->*func)().to_units()); -} - -string_env_reg::string_env_reg(STRING_FUNCP f) : func(f) -{ -} - -const char *string_env_reg::get_string() -{ - return (curenv->*func)(); -} - -class horizontal_place_reg : public general_reg { -public: - horizontal_place_reg(); - int get_value(units *); - void set_value(units); -}; - -horizontal_place_reg::horizontal_place_reg() -{ -} - -int horizontal_place_reg::get_value(units *res) -{ - *res = curenv->get_input_line_position().to_units(); - return 1; -} - -void horizontal_place_reg::set_value(units n) -{ - curenv->set_input_line_position(hunits(n)); -} - -const char *environment::get_font_family_string() -{ - return family->nm.contents(); -} - -const char *environment::get_name_string() -{ - return name.contents(); -} - -// Convert a quantity in scaled points to ascii decimal fraction. - -const char *sptoa(int sp) -{ - assert(sp > 0); - assert(sizescale > 0); - if (sizescale == 1) - return i_to_a(sp); - if (sp % sizescale == 0) - return i_to_a(sp/sizescale); - // See if 1/sizescale is exactly representable as a decimal fraction, - // ie its only prime factors are 2 and 5. - int n = sizescale; - int power2 = 0; - while ((n & 1) == 0) { - n >>= 1; - power2++; - } - int power5 = 0; - while ((n % 5) == 0) { - n /= 5; - power5++; - } - if (n == 1) { - int decimal_point = power5 > power2 ? power5 : power2; - if (decimal_point <= 10) { - int factor = 1; - int t; - for (t = decimal_point - power2; --t >= 0;) - factor *= 2; - for (t = decimal_point - power5; --t >= 0;) - factor *= 5; - if (factor == 1 || sp <= INT_MAX/factor) - return if_to_a(sp*factor, decimal_point); - } - } - double s = double(sp)/double(sizescale); - double factor = 10.0; - double val = s; - int decimal_point = 0; - do { - double v = ceil(s*factor); - if (v > INT_MAX) - break; - val = v; - factor *= 10.0; - } while (++decimal_point < 10); - return if_to_a(int(val), decimal_point); -} - -const char *environment::get_point_size_string() -{ - return sptoa(curenv->get_point_size()); -} - -const char *environment::get_requested_point_size_string() -{ - return sptoa(curenv->get_requested_point_size()); -} - -#define init_int_env_reg(name, func) \ - number_reg_dictionary.define(name, new int_env_reg(&environment::func)) - -#define init_vunits_env_reg(name, func) \ - number_reg_dictionary.define(name, new vunits_env_reg(&environment::func)) - -#define init_hunits_env_reg(name, func) \ - number_reg_dictionary.define(name, new hunits_env_reg(&environment::func)) - -#define init_string_env_reg(name, func) \ - number_reg_dictionary.define(name, new string_env_reg(&environment::func)) - -void init_env_requests() -{ - init_request("it", input_trap); - init_request("ad", adjust); - init_request("na", no_adjust); - init_request("ev", environment_switch); - init_request("evc", environment_copy); - init_request("lt", title_length); - init_request("ps", point_size); - init_request("ft", font_change); - init_request("fam", family_change); - init_request("ss", space_size); - init_request("fi", fill); - init_request("nf", no_fill); - init_request("ce", center); - init_request("rj", right_justify); - init_request("vs", vertical_spacing); - init_request("ls", line_spacing); - init_request("ll", line_length); - init_request("in", indent); - init_request("ti", temporary_indent); - init_request("ul", underline); - init_request("cu", underline); - init_request("cc", control_char); - init_request("c2", no_break_control_char); - init_request("br", break_request); - init_request("tl", title); - init_request("ta", set_tabs); - init_request("fc", field_characters); - init_request("mc", margin_character); - init_request("nn", no_number); - init_request("nm", number_lines); - init_request("tc", tab_character); - init_request("lc", leader_character); - init_request("hy", hyphenate_request); - init_request("hc", hyphen_char); - init_request("nh", no_hyphenate); - init_request("hlm", hyphen_line_max_request); -#ifdef WIDOW_CONTROL - init_request("wdc", widow_control_request); -#endif /* WIDOW_CONTROL */ -#if 0 - init_request("tas", tabs_save); - init_request("tar", tabs_restore); -#endif - init_request("hys", hyphenation_space_request); - init_request("hym", hyphenation_margin_request); - init_request("pvs", post_vertical_spacing); - init_int_env_reg(".f", get_font); - init_int_env_reg(".b", get_bold); - init_hunits_env_reg(".i", get_indent); - init_hunits_env_reg(".in", get_saved_indent); - init_int_env_reg(".j", get_adjust_mode); - init_hunits_env_reg(".k", get_text_length); - init_hunits_env_reg(".l", get_line_length); - init_hunits_env_reg(".ll", get_saved_line_length); - init_int_env_reg(".L", get_line_spacing); - init_hunits_env_reg(".n", get_prev_text_length); - init_string_env_reg(".s", get_point_size_string); - init_string_env_reg(".sr", get_requested_point_size_string); - init_int_env_reg(".ps", get_point_size); - init_int_env_reg(".psr", get_requested_point_size); - init_int_env_reg(".u", get_fill); - init_vunits_env_reg(".v", get_vertical_spacing); - init_vunits_env_reg(".pvs", get_post_vertical_spacing); - init_hunits_env_reg(".w", get_prev_char_width); - init_int_env_reg(".ss", get_space_size); - init_int_env_reg(".sss", get_sentence_space_size); - init_string_env_reg(".fam", get_font_family_string); - init_string_env_reg(".ev", get_name_string); - init_int_env_reg(".hy", get_hyphenation_flags); - init_int_env_reg(".hlm", get_hyphen_line_max); - init_int_env_reg(".hlc", get_hyphen_line_count); - init_hunits_env_reg(".lt", get_title_length); - init_string_env_reg(".tabs", get_tabs); - init_hunits_env_reg(".csk", get_prev_char_skew); - init_vunits_env_reg(".cht", get_prev_char_height); - init_vunits_env_reg(".cdp", get_prev_char_depth); - init_int_env_reg(".ce", get_center_lines); - init_int_env_reg(".rj", get_right_justify_lines); - init_hunits_env_reg(".hys", get_hyphenation_space); - init_hunits_env_reg(".hym", get_hyphenation_margin); - number_reg_dictionary.define("ln", new variable_reg(&next_line_number)); - number_reg_dictionary.define("ct", new variable_reg(&ct_reg_contents)); - number_reg_dictionary.define("sb", new variable_reg(&sb_reg_contents)); - number_reg_dictionary.define("st", new variable_reg(&st_reg_contents)); - number_reg_dictionary.define("rsb", new variable_reg(&rsb_reg_contents)); - number_reg_dictionary.define("rst", new variable_reg(&rst_reg_contents)); - number_reg_dictionary.define("ssc", new variable_reg(&ssc_reg_contents)); - number_reg_dictionary.define("skw", new variable_reg(&skw_reg_contents)); - number_reg_dictionary.define("hp", new horizontal_place_reg); -} - -// Hyphenation - TeX's hyphenation algorithm with a less fancy implementation. - -struct trie_node; - -class trie { - trie_node *tp; - virtual void do_match(int len, void *val) = 0; - virtual void do_delete(void *) = 0; - void delete_trie_node(trie_node *); -public: - trie() : tp(0) {} - virtual ~trie(); // virtual to shut up g++ - void insert(const char *, int, void *); - // find calls do_match for each match it finds - void find(const char *pat, int patlen); - void clear(); -}; - -class hyphen_trie : private trie { - int *h; - void do_match(int i, void *v); - void do_delete(void *v); - void insert_pattern(const char *pat, int patlen, int *num); -public: - hyphen_trie() {} - ~hyphen_trie() {} - void hyphenate(const char *word, int len, int *hyphens); - void read_patterns_file(const char *name); -}; - - -struct hyphenation_language { - symbol name; - dictionary exceptions; - hyphen_trie patterns; - hyphenation_language(symbol nm) : name(nm), exceptions(501) {} - ~hyphenation_language() { } -}; - -dictionary language_dictionary(5); -hyphenation_language *current_language = 0; - -static void set_hyphenation_language() -{ - symbol nm = get_name(1); - if (!nm.is_null()) { - current_language = (hyphenation_language *)language_dictionary.lookup(nm); - if (!current_language) { - current_language = new hyphenation_language(nm); - (void)language_dictionary.lookup(nm, (void *)current_language); - } - } - skip_line(); -} - -const int WORD_MAX = 1024; - -static void hyphen_word() -{ - if (!current_language) { - error("no current hyphenation language"); - skip_line(); - return; - } - char buf[WORD_MAX + 1]; - unsigned char pos[WORD_MAX + 2]; - for (;;) { - tok.skip(); - if (tok.newline() || tok.eof()) - break; - int i = 0; - int npos = 0; - while (i < WORD_MAX && !tok.space() && !tok.newline() && !tok.eof()) { - charinfo *ci = tok.get_char(1); - if (ci == 0) { - skip_line(); - return; - } - tok.next(); - if (ci->get_ascii_code() == '-') { - if (i > 0 && (npos == 0 || pos[npos - 1] != i)) - pos[npos++] = i; - } - else { - int c = ci->get_hyphenation_code(); - if (c == 0) - break; - buf[i++] = c; - } - } - if (i > 0) { - pos[npos] = 0; - buf[i] = 0; - unsigned char *tem = new unsigned char[npos + 1]; - memcpy(tem, pos, npos+1); - tem = (unsigned char *)current_language->exceptions.lookup(symbol(buf), - tem); - if (tem) - a_delete tem; - } - } - skip_line(); -} - -struct trie_node { - char c; - trie_node *down; - trie_node *right; - void *val; - trie_node(char, trie_node *); -}; - -trie_node::trie_node(char ch, trie_node *p) -: c(ch), down(0), right(p), val(0) -{ -} - -trie::~trie() -{ - clear(); -} - -void trie::clear() -{ - delete_trie_node(tp); - tp = 0; -} - - -void trie::delete_trie_node(trie_node *p) -{ - if (p) { - delete_trie_node(p->down); - delete_trie_node(p->right); - if (p->val) - do_delete(p->val); - delete p; - } -} - -void trie::insert(const char *pat, int patlen, void *val) -{ - trie_node **p = &tp; - assert(patlen > 0 && pat != 0); - for (;;) { - while (*p != 0 && (*p)->c < pat[0]) - p = &((*p)->right); - if (*p == 0 || (*p)->c != pat[0]) - *p = new trie_node(pat[0], *p); - if (--patlen == 0) { - (*p)->val = val; - break; - } - ++pat; - p = &((*p)->down); - } -} - -void trie::find(const char *pat, int patlen) -{ - trie_node *p = tp; - for (int i = 0; p != 0 && i < patlen; i++) { - while (p != 0 && p->c < pat[i]) - p = p->right; - if (p != 0 && p->c == pat[i]) { - if (p->val != 0) - do_match(i+1, p->val); - p = p->down; - } - else - break; - } -} - -struct operation { - operation *next; - short distance; - short num; - operation(int, int, operation *); -}; - -operation::operation(int i, int j, operation *op) -: next(op), distance(j), num(i) -{ -} - -void hyphen_trie::insert_pattern(const char *pat, int patlen, int *num) -{ - operation *op = 0; - for (int i = 0; i < patlen+1; i++) - if (num[i] != 0) - op = new operation(num[i], patlen - i, op); - insert(pat, patlen, op); -} - -void hyphen_trie::hyphenate(const char *word, int len, int *hyphens) -{ - int j; - for (j = 0; j < len+1; j++) - hyphens[j] = 0; - for (j = 0; j < len - 1; j++) { - h = hyphens + j; - find(word + j, len - j); - } -} - -inline int max(int m, int n) -{ - return m > n ? m : n; -} - -void hyphen_trie::do_match(int i, void *v) -{ - operation *op = (operation *)v; - while (op != 0) { - h[i - op->distance] = max(h[i - op->distance], op->num); - op = op->next; - } -} - -void hyphen_trie::do_delete(void *v) -{ - operation *op = (operation *)v; - while (op) { - operation *tem = op; - op = tem->next; - delete tem; - } -} - -void hyphen_trie::read_patterns_file(const char *name) -{ - clear(); - char buf[WORD_MAX]; - int num[WORD_MAX+1]; - errno = 0; - char *path = 0; - FILE *fp = macro_path.open_file(name, &path); - if (fp == 0) { - error("can't find hyphenation patterns file `%1'", name); - return; - } - int c = getc(fp); - for (;;) { - for (;;) { - if (c == '%') { - do { - c = getc(fp); - } while (c != EOF && c != '\n'); - } - if (c == EOF || !csspace(c)) - break; - c = getc(fp); - } - if (c == EOF) - break; - int i = 0; - num[0] = 0; - do { - if (csdigit(c)) - num[i] = c - '0'; - else { - buf[i++] = c; - num[i] = 0; - } - c = getc(fp); - } while (i < WORD_MAX && c != EOF && !csspace(c) && c != '%'); - insert_pattern(buf, i, num); - } - fclose(fp); - a_delete path; - return; -} - -void hyphenate(hyphen_list *h, unsigned flags) -{ - if (!current_language) - return; - while (h) { - while (h && h->hyphenation_code == 0) - h = h->next; - int len = 0; - char hbuf[WORD_MAX+2]; - char *buf = hbuf + 1; - hyphen_list *tem; - for (tem = h; tem && len < WORD_MAX; tem = tem->next) { - if (tem->hyphenation_code != 0) - buf[len++] = tem->hyphenation_code; - else - break; - } - hyphen_list *nexth = tem; - if (len > 2) { - buf[len] = 0; - unsigned char *pos - = (unsigned char *)current_language->exceptions.lookup(buf); - if (pos != 0) { - int j = 0; - int i = 1; - for (tem = h; tem != 0; tem = tem->next, i++) - if (pos[j] == i) { - tem->hyphen = 1; - j++; - } - } - else { - hbuf[0] = hbuf[len+1] = '.'; - int num[WORD_MAX+3]; - current_language->patterns.hyphenate(hbuf, len+2, num); - int i; - num[2] = 0; - if (flags & 8) - num[3] = 0; - if (flags & 4) - --len; - for (i = 2, tem = h; i < len && tem; tem = tem->next, i++) - if (num[i] & 1) - tem->hyphen = 1; - } - } - h = nexth; - } -} - -static void hyphenation_patterns_file() -{ - symbol name = get_long_name(1); - if (!name.is_null()) { - if (!current_language) - error("no current hyphenation language"); - else - current_language->patterns.read_patterns_file(name.contents()); - } - skip_line(); -} - -class hyphenation_language_reg : public reg { -public: - const char *get_string(); -}; - -const char *hyphenation_language_reg::get_string() -{ - return current_language ? current_language->name.contents() : ""; -} - -void init_hyphen_requests() -{ - init_request("hw", hyphen_word); - init_request("hla", set_hyphenation_language); - init_request("hpf", hyphenation_patterns_file); - number_reg_dictionary.define(".hla", new hyphenation_language_reg); -} diff --git a/contrib/groff/troff/env.h b/contrib/groff/troff/env.h deleted file mode 100644 index 1db463d..0000000 --- a/contrib/groff/troff/env.h +++ /dev/null @@ -1,334 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -struct size_range { - int min; - int max; -}; - -class font_size { - static size_range *size_table; - static int nranges; - int p; -public: - font_size(); - font_size(int points); - int to_points(); - int to_scaled_points(); - int to_units(); - int operator==(font_size); - int operator!=(font_size); - static void init_size_table(int *sizes); -}; - -inline font_size::font_size() : p(0) -{ -} - -inline int font_size::operator==(font_size fs) -{ - return p == fs.p; -} - -inline int font_size::operator!=(font_size fs) -{ - return p != fs.p; -} - -inline int font_size::to_scaled_points() -{ - return p; -} - -inline int font_size::to_points() -{ - return p/sizescale; -} - -struct environment; - -hunits env_digit_width(environment *); -hunits env_space_width(environment *); -hunits env_sentence_space_width(environment *); -hunits env_narrow_space_width(environment *); -hunits env_half_narrow_space_width(environment *); - -struct tab; - -enum tab_type { TAB_NONE, TAB_LEFT, TAB_CENTER, TAB_RIGHT }; - -class tab_stops { - tab *initial_list; - tab *repeated_list; -public: - tab_stops(); - tab_stops(hunits distance, tab_type type); - tab_stops(const tab_stops &); - ~tab_stops(); - void operator=(const tab_stops &); - tab_type distance_to_next_tab(hunits pos, hunits *distance); - void clear(); - void add_tab(hunits pos, tab_type type, int repeated); - const char *to_string(); -}; - -const unsigned MARGIN_CHARACTER_ON = 1; -const unsigned MARGIN_CHARACTER_NEXT = 2; - -struct charinfo; -struct node; -struct breakpoint; -struct font_family; -struct pending_output_line; - -class environment { - int dummy; // dummy environment used for \w - hunits prev_line_length; - hunits line_length; - hunits prev_title_length; - hunits title_length; - font_size prev_size; - font_size size; - int requested_size; - int prev_requested_size; - int char_height; - int char_slant; - int prev_fontno; - int fontno; - font_family *prev_family; - font_family *family; - int space_size; // in 36ths of an em - int sentence_space_size; // same but for spaces at the end of sentences - int adjust_mode; - int fill; - int interrupted; - int prev_line_interrupted; - int center_lines; - int right_justify_lines; - vunits prev_vertical_spacing; - vunits vertical_spacing; - vunits prev_post_vertical_spacing; - vunits post_vertical_spacing; - int prev_line_spacing; - int line_spacing; - hunits prev_indent; - hunits indent; - hunits temporary_indent; - int have_temporary_indent; - hunits saved_indent; - hunits target_text_length; - int pre_underline_fontno; - int underline_lines; - symbol input_trap; - int input_trap_count; - node *line; // in reverse order - hunits prev_text_length; - hunits width_total; - int space_total; - hunits input_line_start; - tab_stops tabs; - node *tab_contents; - hunits tab_width; - hunits tab_distance; - tab_type current_tab; - node *leader_node; - charinfo *tab_char; - charinfo *leader_char; - int current_field; // is there a current field? - hunits field_distance; - hunits pre_field_width; - int field_spaces; - int tab_field_spaces; - int tab_precedes_field; - int discarding; - int spread_flag; // set by \p - unsigned margin_character_flags; - node *margin_character_node; - hunits margin_character_distance; - node *numbering_nodes; - hunits line_number_digit_width; - int number_text_separation; // in digit spaces - int line_number_indent; // in digit spaces - int line_number_multiple; - int no_number_count; - unsigned hyphenation_flags; - int hyphen_line_count; - int hyphen_line_max; - hunits hyphenation_space; - hunits hyphenation_margin; - int composite; // used for construction of composite char? - pending_output_line *pending_lines; -#ifdef WIDOW_CONTROL - int widow_control; -#endif /* WIDOW_CONTROL */ - - tab_type distance_to_next_tab(hunits *); - void start_line(); - void output_line(node *, hunits); - void output(node *nd, int retain_size, vunits vs, vunits post_vs, - hunits width); - void output_title(node *nd, int retain_size, vunits vs, vunits post_vs, - hunits width); -#ifdef WIDOW_CONTROL - void mark_last_line(); -#endif /* WIDOW_CONTROL */ - void possibly_break_line(int forced = 0); - breakpoint *choose_breakpoint(); - void hyphenate_line(); - void start_field(); - void wrap_up_field(); - void add_padding(); - node *make_tab_node(hunits d, node *next = 0); - node *get_prev_char(); -public: - const symbol name; - unsigned char control_char; - unsigned char no_break_control_char; - charinfo *hyphen_indicator_char; - - environment(symbol); - environment(const environment *); // for temporary environment - ~environment(); - void copy(const environment *); - int is_dummy() { return dummy; } - int is_empty(); - int is_composite() { return composite; } - void set_composite() { composite = 1; } - vunits get_vertical_spacing(); // .v - vunits get_post_vertical_spacing(); // .pvs - int get_line_spacing(); // .L - vunits total_post_vertical_spacing(); - int get_point_size() { return size.to_scaled_points(); } - font_size get_font_size() { return size; } - int get_size() { return size.to_units(); } - int get_requested_point_size() { return requested_size; } - int get_char_height() { return char_height; } - int get_char_slant() { return char_slant; } - hunits get_digit_width(); - int get_font() { return fontno; }; // .f - font_family *get_family() { return family; } - int get_bold(); // .b - int get_adjust_mode(); // .j - int get_fill(); // .u - hunits get_indent(); // .i - hunits get_temporary_indent(); - hunits get_line_length(); // .l - hunits get_saved_line_length(); // .ll - hunits get_saved_indent(); // .in - hunits get_title_length(); - hunits get_prev_char_width(); // .w - hunits get_prev_char_skew(); - vunits get_prev_char_height(); - vunits get_prev_char_depth(); - hunits get_text_length(); // .k - hunits get_prev_text_length(); // .n - hunits get_space_width() { return env_space_width(this); } - int get_space_size() { return space_size; } // in ems/36 - int get_sentence_space_size() { return sentence_space_size; } - hunits get_narrow_space_width() { return env_narrow_space_width(this); } - hunits get_half_narrow_space_width() - { return env_half_narrow_space_width(this); } - hunits get_input_line_position(); - const char *get_tabs(); - int get_hyphenation_flags(); - int get_hyphen_line_max(); - int get_hyphen_line_count(); - hunits get_hyphenation_space(); - hunits get_hyphenation_margin(); - int get_center_lines(); - int get_right_justify_lines(); - int get_prev_line_interrupted() { return prev_line_interrupted; } - node *make_char_node(charinfo *); - node *extract_output_line(); - void width_registers(); - void wrap_up_tab(); - void set_font(int); - void set_font(symbol); - void set_family(symbol); - void set_size(int); - void set_char_height(int); - void set_char_slant(int); - void set_input_line_position(hunits); // used by \n(hp - void interrupt(); - void spread() { spread_flag = 1; } - void do_break(); // .br - void final_break(); - void newline(); - void handle_tab(int is_leader = 0); // do a tab or leader - void add_node(node *); - void add_char(charinfo *); - void add_hyphen_indicator(); - void add_italic_correction(); - void space(); - void space_newline(); - const char *get_font_family_string(); - const char *get_name_string(); - const char *get_point_size_string(); - const char *get_requested_point_size_string(); - void output_pending_lines(); - - friend void title_length(); - friend void space_size(); - friend void fill(); - friend void no_fill(); - friend void adjust(); - friend void no_adjust(); - friend void center(); - friend void right_justify(); - friend void vertical_spacing(); - friend void post_vertical_spacing(); - friend void line_spacing(); - friend void line_length(); - friend void indent(); - friend void temporary_indent(); - friend void underline(); - friend void input_trap(); - friend void set_tabs(); - friend void margin_character(); - friend void no_number(); - friend void number_lines(); - friend void leader_character(); - friend void tab_character(); - friend void hyphenate_request(); - friend void no_hyphenate(); - friend void hyphen_line_max_request(); - friend void hyphenation_space_request(); - friend void hyphenation_margin_request(); - friend void line_width(); -#if 0 - friend void tabs_save(); - friend void tabs_restore(); -#endif - friend void title(); -#ifdef WIDOW_CONTROL - friend void widow_control_request(); -#endif /* WIDOW_CONTROL */ -}; - -extern environment *curenv; -extern void pop_env(); -extern void push_env(int); - -void init_environments(); -void read_hyphen_file(const char *name); - -extern int break_flag; -extern symbol default_family; -extern int translate_space_to_dummy; diff --git a/contrib/groff/troff/hvunits.h b/contrib/groff/troff/hvunits.h deleted file mode 100644 index 8efb5ab..0000000 --- a/contrib/groff/troff/hvunits.h +++ /dev/null @@ -1,340 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -class vunits { - int n; -public: - vunits(); - vunits(units); - units to_units(); - int is_zero(); - vunits& operator+=(const vunits&); - vunits& operator-=(const vunits&); - friend inline vunits scale(vunits n, units x, units y); // scale n by x/y - friend inline vunits scale(vunits n, vunits x, vunits y); - friend inline vunits operator +(const vunits&, const vunits&); - friend inline vunits operator -(const vunits&, const vunits&); - friend inline vunits operator -(const vunits&); - friend inline int operator /(const vunits&, const vunits&); - friend inline vunits operator /(const vunits&, int); - friend inline vunits operator *(const vunits&, int); - friend inline vunits operator *(int, const vunits&); - friend inline int operator <(const vunits&, const vunits&); - friend inline int operator >(const vunits&, const vunits&); - friend inline int operator <=(const vunits&, const vunits&); - friend inline int operator >=(const vunits&, const vunits&); - friend inline int operator ==(const vunits&, const vunits&); - friend inline int operator !=(const vunits&, const vunits&); -}; - -extern vunits V0; - - -class hunits { - int n; -public: - hunits(); - hunits(units); - units to_units(); - int is_zero(); - hunits& operator+=(const hunits&); - hunits& operator-=(const hunits&); - friend inline hunits scale(hunits n, units x, units y); // scale n by x/y - friend inline hunits scale(hunits n, double x); - friend inline hunits operator +(const hunits&, const hunits&); - friend inline hunits operator -(const hunits&, const hunits&); - friend inline hunits operator -(const hunits&); - friend inline int operator /(const hunits&, const hunits&); - friend inline hunits operator /(const hunits&, int); - friend inline hunits operator *(const hunits&, int); - friend inline hunits operator *(int, const hunits&); - friend inline int operator <(const hunits&, const hunits&); - friend inline int operator >(const hunits&, const hunits&); - friend inline int operator <=(const hunits&, const hunits&); - friend inline int operator >=(const hunits&, const hunits&); - friend inline int operator ==(const hunits&, const hunits&); - friend inline int operator !=(const hunits&, const hunits&); -}; - -extern hunits H0; - -extern int get_vunits(vunits *, unsigned char si); -extern int get_hunits(hunits *, unsigned char si); -extern int get_vunits(vunits *, unsigned char si, vunits prev_value); -extern int get_hunits(hunits *, unsigned char si, hunits prev_value); - -inline vunits:: vunits() : n(0) -{ -} - -inline units vunits::to_units() -{ - return n*vresolution; -} - -inline int vunits::is_zero() -{ - return n == 0; -} - -inline vunits operator +(const vunits & x, const vunits & y) -{ - vunits r; - r = x; - r.n += y.n; - return r; -} - -inline vunits operator -(const vunits & x, const vunits & y) -{ - vunits r; - r = x; - r.n -= y.n; - return r; -} - -inline vunits operator -(const vunits & x) -{ - vunits r; - r.n = -x.n; - return r; -} - -inline int operator /(const vunits & x, const vunits & y) -{ - return x.n/y.n; -} - -inline vunits operator /(const vunits & x, int n) -{ - vunits r; - r = x; - r.n /= n; - return r; -} - -inline vunits operator *(const vunits & x, int n) -{ - vunits r; - r = x; - r.n *= n; - return r; -} - -inline vunits operator *(int n, const vunits & x) -{ - vunits r; - r = x; - r.n *= n; - return r; -} - -inline int operator <(const vunits & x, const vunits & y) -{ - return x.n < y.n; -} - -inline int operator >(const vunits & x, const vunits & y) -{ - return x.n > y.n; -} - -inline int operator <=(const vunits & x, const vunits & y) -{ - return x.n <= y.n; -} - -inline int operator >=(const vunits & x, const vunits & y) -{ - return x.n >= y.n; -} - -inline int operator ==(const vunits & x, const vunits & y) -{ - return x.n == y.n; -} - -inline int operator !=(const vunits & x, const vunits & y) -{ - return x.n != y.n; -} - - -inline vunits& vunits::operator+=(const vunits & x) -{ - n += x.n; - return *this; -} - -inline vunits& vunits::operator-=(const vunits & x) -{ - n -= x.n; - return *this; -} - -inline hunits:: hunits() : n(0) -{ -} - -inline units hunits::to_units() -{ - return n*hresolution; -} - -inline int hunits::is_zero() -{ - return n == 0; -} - -inline hunits operator +(const hunits & x, const hunits & y) -{ - hunits r; - r = x; - r.n += y.n; - return r; -} - -inline hunits operator -(const hunits & x, const hunits & y) -{ - hunits r; - r = x; - r.n -= y.n; - return r; -} - -inline hunits operator -(const hunits & x) -{ - hunits r; - r = x; - r.n = -x.n; - return r; -} - -inline int operator /(const hunits & x, const hunits & y) -{ - return x.n/y.n; -} - -inline hunits operator /(const hunits & x, int n) -{ - hunits r; - r = x; - r.n /= n; - return r; -} - -inline hunits operator *(const hunits & x, int n) -{ - hunits r; - r = x; - r.n *= n; - return r; -} - -inline hunits operator *(int n, const hunits & x) -{ - hunits r; - r = x; - r.n *= n; - return r; -} - -inline int operator <(const hunits & x, const hunits & y) -{ - return x.n < y.n; -} - -inline int operator >(const hunits & x, const hunits & y) -{ - return x.n > y.n; -} - -inline int operator <=(const hunits & x, const hunits & y) -{ - return x.n <= y.n; -} - -inline int operator >=(const hunits & x, const hunits & y) -{ - return x.n >= y.n; -} - -inline int operator ==(const hunits & x, const hunits & y) -{ - return x.n == y.n; -} - -inline int operator !=(const hunits & x, const hunits & y) -{ - return x.n != y.n; -} - - -inline hunits& hunits::operator+=(const hunits & x) -{ - n += x.n; - return *this; -} - -inline hunits& hunits::operator-=(const hunits & x) -{ - n -= x.n; - return *this; -} - -inline hunits scale(hunits n, units x, units y) -{ - hunits r; - r.n = scale(n.n, x, y); - return r; -} - -inline vunits scale(vunits n, units x, units y) -{ - vunits r; - r.n = scale(n.n, x, y); - return r; -} - -inline vunits scale(vunits n, vunits x, vunits y) -{ - vunits r; - r.n = scale(n.n, x.n, y.n); - return r; -} - -inline hunits scale(hunits n, double x) -{ - hunits r; - r.n = int(n.n*x); - return r; -} - -inline units scale(units n, double x) -{ - return int(n*x); -} - -inline units points_to_units(units n) -{ - return scale(n, units_per_inch, 72); -} - diff --git a/contrib/groff/troff/hyphen.us b/contrib/groff/troff/hyphen.us deleted file mode 100644 index d86c3d5..0000000 --- a/contrib/groff/troff/hyphen.us +++ /dev/null @@ -1,4449 +0,0 @@ -% Hyphenation patterns for US English. -% These are the standard Plain TeX hyphenation patterns (in hyphen.tex). -.ach4 -.ad4der -.af1t -.al3t -.am5at -.an5c -.ang4 -.ani5m -.ant4 -.an3te -.anti5s -.ar5s -.ar4tie -.ar4ty -.as3c -.as1p -.as1s -.aster5 -.atom5 -.au1d -.av4i -.awn4 -.ba4g -.ba5na -.bas4e -.ber4 -.be5ra -.be3sm -.be5sto -.bri2 -.but4ti -.cam4pe -.can5c -.capa5b -.car5ol -.ca4t -.ce4la -.ch4 -.chill5i -.ci2 -.cit5r -.co3e -.co4r -.cor5ner -.de4moi -.de3o -.de3ra -.de3ri -.des4c -.dictio5 -.do4t -.du4c -.dumb5 -.earth5 -.eas3i -.eb4 -.eer4 -.eg2 -.el5d -.el3em -.enam3 -.en3g -.en3s -.eq5ui5t -.er4ri -.es3 -.eu3 -.eye5 -.fes3 -.for5mer -.ga2 -.ge2 -.gen3t4 -.ge5og -.gi5a -.gi4b -.go4r -.hand5i -.han5k -.he2 -.hero5i -.hes3 -.het3 -.hi3b -.hi3er -.hon5ey -.hon3o -.hov5 -.id4l -.idol3 -.im3m -.im5pin -.in1 -.in3ci -.ine2 -.in2k -.in3s -.ir5r -.is4i -.ju3r -.la4cy -.la4m -.lat5er -.lath5 -.le2 -.leg5e -.len4 -.lep5 -.lev1 -.li4g -.lig5a -.li2n -.li3o -.li4t -.mag5a5 -.mal5o -.man5a -.mar5ti -.me2 -.mer3c -.me5ter -.mis1 -.mist5i -.mon3e -.mo3ro -.mu5ta -.muta5b -.ni4c -.od2 -.odd5 -.of5te -.or5ato -.or3c -.or1d -.or3t -.os3 -.os4tl -.oth3 -.out3 -.ped5al -.pe5te -.pe5tit -.pi4e -.pio5n -.pi2t -.pre3m -.ra4c -.ran4t -.ratio5na -.ree2 -.re5mit -.res2 -.re5stat -.ri4g -.rit5u -.ro4q -.ros5t -.row5d -.ru4d -.sci3e -.self5 -.sell5 -.se2n -.se5rie -.sh2 -.si2 -.sing4 -.st4 -.sta5bl -.sy2 -.ta4 -.te4 -.ten5an -.th2 -.ti2 -.til4 -.tim5o5 -.ting4 -.tin5k -.ton4a -.to4p -.top5i -.tou5s -.trib5ut -.un1a -.un3ce -.under5 -.un1e -.un5k -.un5o -.un3u -.up3 -.ure3 -.us5a -.ven4de -.ve5ra -.wil5i -.ye4 -4ab. -a5bal -a5ban -abe2 -ab5erd -abi5a -ab5it5ab -ab5lat -ab5o5liz -4abr -ab5rog -ab3ul -a4car -ac5ard -ac5aro -a5ceou -ac1er -a5chet -4a2ci -a3cie -ac1in -a3cio -ac5rob -act5if -ac3ul -ac4um -a2d -ad4din -ad5er. -2adi -a3dia -ad3ica -adi4er -a3dio -a3dit -a5diu -ad4le -ad3ow -ad5ran -ad4su -4adu -a3duc -ad5um -ae4r -aeri4e -a2f -aff4 -a4gab -aga4n -ag5ell -age4o -4ageu -ag1i -4ag4l -ag1n -a2go -3agog -ag3oni -a5guer -ag5ul -a4gy -a3ha -a3he -ah4l -a3ho -ai2 -a5ia -a3ic. -ai5ly -a4i4n -ain5in -ain5o -ait5en -a1j -ak1en -al5ab -al3ad -a4lar -4aldi -2ale -al3end -a4lenti -a5le5o -al1i -al4ia. -ali4e -al5lev -4allic -4alm -a5log. -a4ly. -4alys -5a5lyst -5alyt -3alyz -4ama -am5ab -am3ag -ama5ra -am5asc -a4matis -a4m5ato -am5era -am3ic -am5if -am5ily -am1in -ami4no -a2mo -a5mon -amor5i -amp5en -a2n -an3age -3analy -a3nar -an3arc -anar4i -a3nati -4and -ande4s -an3dis -an1dl -an4dow -a5nee -a3nen -an5est. -a3neu -2ang -ang5ie -an1gl -a4n1ic -a3nies -an3i3f -an4ime -a5nimi -a5nine -an3io -a3nip -an3ish -an3it -a3niu -an4kli -5anniz -ano4 -an5ot -anoth5 -an2sa -an4sco -an4sn -an2sp -ans3po -an4st -an4sur -antal4 -an4tie -4anto -an2tr -an4tw -an3ua -an3ul -a5nur -4ao -apar4 -ap5at -ap5ero -a3pher -4aphi -a4pilla -ap5illar -ap3in -ap3ita -a3pitu -a2pl -apoc5 -ap5ola -apor5i -apos3t -aps5es -a3pu -aque5 -2a2r -ar3act -a5rade -ar5adis -ar3al -a5ramete -aran4g -ara3p -ar4at -a5ratio -ar5ativ -a5rau -ar5av4 -araw4 -arbal4 -ar4chan -ar5dine -ar4dr -ar5eas -a3ree -ar3ent -a5ress -ar4fi -ar4fl -ar1i -ar5ial -ar3ian -a3riet -ar4im -ar5inat -ar3io -ar2iz -ar2mi -ar5o5d -a5roni -a3roo -ar2p -ar3q -arre4 -ar4sa -ar2sh -4as. -as4ab -as3ant -ashi4 -a5sia. -a3sib -a3sic -5a5si4t -ask3i -as4l -a4soc -as5ph -as4sh -as3ten -as1tr -asur5a -a2ta -at3abl -at5ac -at3alo -at5ap -ate5c -at5ech -at3ego -at3en. -at3era -ater5n -a5terna -at3est -at5ev -4ath -ath5em -a5then -at4ho -ath5om -4ati. -a5tia -at5i5b -at1ic -at3if -ation5ar -at3itu -a4tog -a2tom -at5omiz -a4top -a4tos -a1tr -at5rop -at4sk -at4tag -at5te -at4th -a2tu -at5ua -at5ue -at3ul -at3ura -a2ty -au4b -augh3 -au3gu -au4l2 -aun5d -au3r -au5sib -aut5en -au1th -a2va -av3ag -a5van -ave4no -av3era -av5ern -av5ery -av1i -avi4er -av3ig -av5oc -a1vor -3away -aw3i -aw4ly -aws4 -ax4ic -ax4id -ay5al -aye4 -ays4 -azi4er -azz5i -5ba. -bad5ger -ba4ge -bal1a -ban5dag -ban4e -ban3i -barbi5 -bari4a -bas4si -1bat -ba4z -2b1b -b2be -b3ber -bbi4na -4b1d -4be. -beak4 -beat3 -4be2d -be3da -be3de -be3di -be3gi -be5gu -1bel -be1li -be3lo -4be5m -be5nig -be5nu -4bes4 -be3sp -be5str -3bet -bet5iz -be5tr -be3tw -be3w -be5yo -2bf -4b3h -bi2b -bi4d -3bie -bi5en -bi4er -2b3if -1bil -bi3liz -bina5r4 -bin4d -bi5net -bi3ogr -bi5ou -bi2t -3bi3tio -bi3tr -3bit5ua -b5itz -b1j -bk4 -b2l2 -blath5 -b4le. -blen4 -5blesp -b3lis -b4lo -blun4t -4b1m -4b3n -bne5g -3bod -bod3i -bo4e -bol3ic -bom4bi -bon4a -bon5at -3boo -5bor. -4b1ora -bor5d -5bore -5bori -5bos4 -b5ota -both5 -bo4to -bound3 -4bp -4brit -broth3 -2b5s2 -bsor4 -2bt -bt4l -b4to -b3tr -buf4fer -bu4ga -bu3li -bumi4 -bu4n -bunt4i -bu3re -bus5ie -buss4e -5bust -4buta -3butio -b5uto -b1v -4b5w -5by. -bys4 -1ca -cab3in -ca1bl -cach4 -ca5den -4cag4 -2c5ah -ca3lat -cal4la -call5in -4calo -can5d -can4e -can4ic -can5is -can3iz -can4ty -cany4 -ca5per -car5om -cast5er -cas5tig -4casy -ca4th -4cativ -cav5al -c3c -ccha5 -cci4a -ccompa5 -ccon4 -ccou3t -2ce. -4ced. -4ceden -3cei -5cel. -3cell -1cen -3cenc -2cen4e -4ceni -3cent -3cep -ce5ram -4cesa -3cessi -ces5si5b -ces5t -cet4 -c5e4ta -cew4 -2ch -4ch. -4ch3ab -5chanic -ch5a5nis -che2 -cheap3 -4ched -che5lo -3chemi -ch5ene -ch3er. -ch3ers -4ch1in -5chine. -ch5iness -5chini -5chio -3chit -chi2z -3cho2 -ch4ti -1ci -3cia -ci2a5b -cia5r -ci5c -4cier -5cific. -4cii -ci4la -3cili -2cim -2cin -c4ina -3cinat -cin3em -c1ing -c5ing. -5cino -cion4 -4cipe -ci3ph -4cipic -4cista -4cisti -2c1it -cit3iz -5ciz -ck1 -ck3i -1c4l4 -4clar -c5laratio -5clare -cle4m -4clic -clim4 -cly4 -c5n -1co -co5ag -coe2 -2cog -co4gr -coi4 -co3inc -col5i -5colo -col3or -com5er -con4a -c4one -con3g -con5t -co3pa -cop3ic -co4pl -4corb -coro3n -cos4e -cov1 -cove4 -cow5a -coz5e -co5zi -c1q -cras5t -5crat. -5cratic -cre3at -5cred -4c3reta -cre4v -cri2 -cri5f -c4rin -cris4 -5criti -cro4pl -crop5o -cros4e -cru4d -4c3s2 -2c1t -cta4b -ct5ang -c5tant -c2te -c3ter -c4ticu -ctim3i -ctu4r -c4tw -cud5 -c4uf -c4ui -cu5ity -5culi -cul4tis -3cultu -cu2ma -c3ume -cu4mi -3cun -cu3pi -cu5py -cur5a4b -cu5ria -1cus -cuss4i -3c4ut -cu4tie -4c5utiv -4cutr -1cy -cze4 -1d2a -5da. -2d3a4b -dach4 -4daf -2dag -da2m2 -dan3g -dard5 -dark5 -4dary -3dat -4dativ -4dato -5dav4 -dav5e -5day -d1b -d5c -d1d4 -2de. -deaf5 -deb5it -de4bon -decan4 -de4cil -de5com -2d1ed -4dee. -de5if -deli4e -del5i5q -de5lo -d4em -5dem. -3demic -dem5ic. -de5mil -de4mons -demor5 -1den -de4nar -de3no -denti5f -de3nu -de1p -de3pa -depi4 -de2pu -d3eq -d4erh -5derm -dern5iz -der5s -des2 -d2es. -de1sc -de2s5o -des3ti -de3str -de4su -de1t -de2to -de1v -dev3il -4dey -4d1f -d4ga -d3ge4t -dg1i -d2gy -d1h2 -5di. -1d4i3a -dia5b -di4cam -d4ice -3dict -3did -5di3en -d1if -di3ge -di4lato -d1in -1dina -3dine. -5dini -di5niz -1dio -dio5g -di4pl -dir2 -di1re -dirt5i -dis1 -5disi -d4is3t -d2iti -1di1v -d1j -d5k2 -4d5la -3dle. -3dled -3dles. -4dless -2d3lo -4d5lu -2dly -d1m -4d1n4 -1do -3do. -do5de -5doe -2d5of -d4og -do4la -doli4 -do5lor -dom5iz -do3nat -doni4 -doo3d -dop4p -d4or -3dos -4d5out -do4v -3dox -d1p -1dr -drag5on -4drai -dre4 -drea5r -5dren -dri4b -dril4 -dro4p -4drow -5drupli -4dry -2d1s2 -ds4p -d4sw -d4sy -d2th -1du -d1u1a -du2c -d1uca -duc5er -4duct. -4ducts -du5el -du4g -d3ule -dum4be -du4n -4dup -du4pe -d1v -d1w -d2y -5dyn -dy4se -dys5p -e1a4b -e3act -ead1 -ead5ie -ea4ge -ea5ger -ea4l -eal5er -eal3ou -eam3er -e5and -ear3a -ear4c -ear5es -ear4ic -ear4il -ear5k -ear2t -eart3e -ea5sp -e3ass -east3 -ea2t -eat5en -eath3i -e5atif -e4a3tu -ea2v -eav3en -eav5i -eav5o -2e1b -e4bel. -e4bels -e4ben -e4bit -e3br -e4cad -ecan5c -ecca5 -e1ce -ec5essa -ec2i -e4cib -ec5ificat -ec5ifie -ec5ify -ec3im -eci4t -e5cite -e4clam -e4clus -e2col -e4comm -e4compe -e4conc -e2cor -ec3ora -eco5ro -e1cr -e4crem -ec4tan -ec4te -e1cu -e4cul -ec3ula -2e2da -4ed3d -e4d1er -ede4s -4edi -e3dia -ed3ib -ed3ica -ed3im -ed1it -edi5z -4edo -e4dol -edon2 -e4dri -e4dul -ed5ulo -ee2c -eed3i -ee2f -eel3i -ee4ly -ee2m -ee4na -ee4p1 -ee2s4 -eest4 -ee4ty -e5ex -e1f -e4f3ere -1eff -e4fic -5efici -efil4 -e3fine -ef5i5nite -3efit -efor5es -e4fuse. -4egal -eger4 -eg5ib -eg4ic -eg5ing -e5git5 -eg5n -e4go. -e4gos -eg1ul -e5gur -5egy -e1h4 -eher4 -ei2 -e5ic -ei5d -eig2 -ei5gl -e3imb -e3inf -e1ing -e5inst -eir4d -eit3e -ei3th -e5ity -e1j -e4jud -ej5udi -eki4n -ek4la -e1la -e4la. -e4lac -elan4d -el5ativ -e4law -elaxa4 -e3lea -el5ebra -5elec -e4led -el3ega -e5len -e4l1er -e1les -el2f -el2i -e3libe -e4l5ic. -el3ica -e3lier -el5igib -e5lim -e4l3ing -e3lio -e2lis -el5ish -e3liv3 -4ella -el4lab -ello4 -e5loc -el5og -el3op. -el2sh -el4ta -e5lud -el5ug -e4mac -e4mag -e5man -em5ana -em5b -e1me -e2mel -e4met -em3ica -emi4e -em5igra -em1in2 -em5ine -em3i3ni -e4mis -em5ish -e5miss -em3iz -5emniz -emo4g -emoni5o -em3pi -e4mul -em5ula -emu3n -e3my -en5amo -e4nant -ench4er -en3dic -e5nea -e5nee -en3em -en5ero -en5esi -en5est -en3etr -e3new -en5ics -e5nie -e5nil -e3nio -en3ish -en3it -e5niu -5eniz -4enn -4eno -eno4g -e4nos -en3ov -en4sw -ent5age -4enthes -en3ua -en5uf -e3ny. -4en3z -e5of -eo2g -e4oi4 -e3ol -eop3ar -e1or -eo3re -eo5rol -eos4 -e4ot -eo4to -e5out -e5ow -e2pa -e3pai -ep5anc -e5pel -e3pent -ep5etitio -ephe4 -e4pli -e1po -e4prec -ep5reca -e4pred -ep3reh -e3pro -e4prob -ep4sh -ep5ti5b -e4put -ep5uta -e1q -equi3l -e4q3ui3s -er1a -era4b -4erand -er3ar -4erati. -2erb -er4bl -er3ch -er4che -2ere. -e3real -ere5co -ere3in -er5el. -er3emo -er5ena -er5ence -4erene -er3ent -ere4q -er5ess -er3est -eret4 -er1h -er1i -e1ria4 -5erick -e3rien -eri4er -er3ine -e1rio -4erit -er4iu -eri4v -e4riva -er3m4 -er4nis -4ernit -5erniz -er3no -2ero -er5ob -e5roc -ero4r -er1ou -er1s -er3set -ert3er -4ertl -er3tw -4eru -eru4t -5erwau -e1s4a -e4sage. -e4sages -es2c -e2sca -es5can -e3scr -es5cu -e1s2e -e2sec -es5ecr -es5enc -e4sert. -e4serts -e4serva -4esh -e3sha -esh5en -e1si -e2sic -e2sid -es5iden -es5igna -e2s5im -es4i4n -esis4te -esi4u -e5skin -es4mi -e2sol -es3olu -e2son -es5ona -e1sp -es3per -es5pira -es4pre -2ess -es4si4b -estan4 -es3tig -es5tim -4es2to -e3ston -2estr -e5stro -estruc5 -e2sur -es5urr -es4w -eta4b -eten4d -e3teo -ethod3 -et1ic -e5tide -etin4 -eti4no -e5tir -e5titio -et5itiv -4etn -et5ona -e3tra -e3tre -et3ric -et5rif -et3rog -et5ros -et3ua -et5ym -et5z -4eu -e5un -e3up -eu3ro -eus4 -eute4 -euti5l -eu5tr -eva2p5 -e2vas -ev5ast -e5vea -ev3ell -evel3o -e5veng -even4i -ev1er -e5verb -e1vi -ev3id -evi4l -e4vin -evi4v -e5voc -e5vu -e1wa -e4wag -e5wee -e3wh -ewil5 -ew3ing -e3wit -1exp -5eyc -5eye. -eys4 -1fa -fa3bl -fab3r -fa4ce -4fag -fain4 -fall5e -4fa4ma -fam5is -5far -far5th -fa3ta -fa3the -4fato -fault5 -4f5b -4fd -4fe. -feas4 -feath3 -fe4b -4feca -5fect -2fed -fe3li -fe4mo -fen2d -fend5e -fer1 -5ferr -fev4 -4f1f -f4fes -f4fie -f5fin. -f2f5is -f4fly -f2fy -4fh -1fi -fi3a -2f3ic. -4f3ical -f3ican -4ficate -f3icen -fi3cer -fic4i -5ficia -5ficie -4fics -fi3cu -fi5del -fight5 -fil5i -fill5in -4fily -2fin -5fina -fin2d5 -fi2ne -f1in3g -fin4n -fis4ti -f4l2 -f5less -flin4 -flo3re -f2ly5 -4fm -4fn -1fo -5fon -fon4de -fon4t -fo2r -fo5rat -for5ay -fore5t -for4i -fort5a -fos5 -4f5p -fra4t -f5rea -fres5c -fri2 -fril4 -frol5 -2f3s -2ft -f4to -f2ty -3fu -fu5el -4fug -fu4min -fu5ne -fu3ri -fusi4 -fus4s -4futa -1fy -1ga -gaf4 -5gal. -3gali -ga3lo -2gam -ga5met -g5amo -gan5is -ga3niz -gani5za -4gano -gar5n4 -gass4 -gath3 -4gativ -4gaz -g3b -gd4 -2ge. -2ged -geez4 -gel4in -ge5lis -ge5liz -4gely -1gen -ge4nat -ge5niz -4geno -4geny -1geo -ge3om -g4ery -5gesi -geth5 -4geto -ge4ty -ge4v -4g1g2 -g2ge -g3ger -gglu5 -ggo4 -gh3in -gh5out -gh4to -5gi. -1gi4a -gia5r -g1ic -5gicia -g4ico -gien5 -5gies. -gil4 -g3imen -3g4in. -gin5ge -5g4ins -5gio -3gir -gir4l -g3isl -gi4u -5giv -3giz -gl2 -gla4 -glad5i -5glas -1gle -gli4b -g3lig -3glo -glo3r -g1m -g4my -gn4a -g4na. -gnet4t -g1ni -g2nin -g4nio -g1no -g4non -1go -3go. -gob5 -5goe -3g4o4g -go3is -gon2 -4g3o3na -gondo5 -go3ni -5goo -go5riz -gor5ou -5gos. -gov1 -g3p -1gr -4grada -g4rai -gran2 -5graph. -g5rapher -5graphic -4graphy -4gray -gre4n -4gress. -4grit -g4ro -gruf4 -gs2 -g5ste -gth3 -gu4a -3guard -2gue -5gui5t -3gun -3gus -4gu4t -g3w -1gy -2g5y3n -gy5ra -h3ab4l -hach4 -hae4m -hae4t -h5agu -ha3la -hala3m -ha4m -han4ci -han4cy -5hand. -han4g -hang5er -hang5o -h5a5niz -han4k -han4te -hap3l -hap5t -ha3ran -ha5ras -har2d -hard3e -har4le -harp5en -har5ter -has5s -haun4 -5haz -haz3a -h1b -1head -3hear -he4can -h5ecat -h4ed -he5do5 -he3l4i -hel4lis -hel4ly -h5elo -hem4p -he2n -hena4 -hen5at -heo5r -hep5 -h4era -hera3p -her4ba -here5a -h3ern -h5erou -h3ery -h1es -he2s5p -he4t -het4ed -heu4 -h1f -h1h -hi5an -hi4co -high5 -h4il2 -himer4 -h4ina -hion4e -hi4p -hir4l -hi3ro -hir4p -hir4r -his3el -his4s -hith5er -hi2v -4hk -4h1l4 -hlan4 -h2lo -hlo3ri -4h1m -hmet4 -2h1n -h5odiz -h5ods -ho4g -hoge4 -hol5ar -3hol4e -ho4ma -home3 -hon4a -ho5ny -3hood -hoon4 -hor5at -ho5ris -hort3e -ho5ru -hos4e -ho5sen -hos1p -1hous -house3 -hov5el -4h5p -4hr4 -hree5 -hro5niz -hro3po -4h1s2 -h4sh -h4tar -ht1en -ht5es -h4ty -hu4g -hu4min -hun5ke -hun4t -hus3t4 -hu4t -h1w -h4wart -hy3pe -hy3ph -hy2s -2i1a -i2al -iam4 -iam5ete -i2an -4ianc -ian3i -4ian4t -ia5pe -iass4 -i4ativ -ia4tric -i4atu -ibe4 -ib3era -ib5ert -ib5ia -ib3in -ib5it. -ib5ite -i1bl -ib3li -i5bo -i1br -i2b5ri -i5bun -4icam -5icap -4icar -i4car. -i4cara -icas5 -i4cay -iccu4 -4iceo -4ich -2ici -i5cid -ic5ina -i2cip -ic3ipa -i4cly -i2c5oc -4i1cr -5icra -i4cry -ic4te -ictu2 -ic4t3ua -ic3ula -ic4um -ic5uo -i3cur -2id -i4dai -id5anc -id5d -ide3al -ide4s -i2di -id5ian -idi4ar -i5die -id3io -idi5ou -id1it -id5iu -i3dle -i4dom -id3ow -i4dr -i2du -id5uo -2ie4 -ied4e -5ie5ga -ield3 -ien5a4 -ien4e -i5enn -i3enti -i1er. -i3esc -i1est -i3et -4if. -if5ero -iff5en -if4fr -4ific. -i3fie -i3fl -4ift -2ig -iga5b -ig3era -ight3i -4igi -i3gib -ig3il -ig3in -ig3it -i4g4l -i2go -ig3or -ig5ot -i5gre -igu5i -ig1ur -i3h -4i5i4 -i3j -4ik -i1la -il3a4b -i4lade -i2l5am -ila5ra -i3leg -il1er -ilev4 -il5f -il1i -il3ia -il2ib -il3io -il4ist -2ilit -il2iz -ill5ab -4iln -il3oq -il4ty -il5ur -il3v -i4mag -im3age -ima5ry -imenta5r -4imet -im1i -im5ida -imi5le -i5mini -4imit -im4ni -i3mon -i2mu -im3ula -2in. -i4n3au -4inav -incel4 -in3cer -4ind -in5dling -2ine -i3nee -iner4ar -i5ness -4inga -4inge -in5gen -4ingi -in5gling -4ingo -4ingu -2ini -i5ni. -i4nia -in3io -in1is -i5nite. -5initio -in3ity -4ink -4inl -2inn -2i1no -i4no4c -ino4s -i4not -2ins -in3se -insur5a -2int. -2in4th -in1u -i5nus -4iny -2io -4io. -ioge4 -io2gr -i1ol -io4m -ion3at -ion4ery -ion3i -io5ph -ior3i -i4os -io5th -i5oti -io4to -i4our -2ip -ipe4 -iphras4 -ip3i -ip4ic -ip4re4 -ip3ul -i3qua -iq5uef -iq3uid -iq3ui3t -4ir -i1ra -ira4b -i4rac -ird5e -ire4de -i4ref -i4rel4 -i4res -ir5gi -ir1i -iri5de -ir4is -iri3tu -5i5r2iz -ir4min -iro4g -5iron. -ir5ul -2is. -is5ag -is3ar -isas5 -2is1c -is3ch -4ise -is3er -3isf -is5han -is3hon -ish5op -is3ib -isi4d -i5sis -is5itiv -4is4k -islan4 -4isms -i2so -iso5mer -is1p -is2pi -is4py -4is1s -is4sal -issen4 -is4ses -is4ta. -is1te -is1ti -ist4ly -4istral -i2su -is5us -4ita. -ita4bi -i4tag -4ita5m -i3tan -i3tat -2ite -it3era -i5teri -it4es -2ith -i1ti -4itia -4i2tic -it3ica -5i5tick -it3ig -it5ill -i2tim -2itio -4itis -i4tism -i2t5o5m -4iton -i4tram -it5ry -4itt -it3uat -i5tud -it3ul -4itz. -i1u -2iv -iv3ell -iv3en. -i4v3er. -i4vers. -iv5il. -iv5io -iv1it -i5vore -iv3o3ro -i4v3ot -4i5w -ix4o -4iy -4izar -izi4 -5izont -5ja -jac4q -ja4p -1je -jer5s -4jestie -4jesty -jew3 -jo4p -5judg -3ka. -k3ab -k5ag -kais4 -kal4 -k1b -k2ed -1kee -ke4g -ke5li -k3en4d -k1er -kes4 -k3est. -ke4ty -k3f -kh4 -k1i -5ki. -5k2ic -k4ill -kilo5 -k4im -k4in. -kin4de -k5iness -kin4g -ki4p -kis4 -k5ish -kk4 -k1l -4kley -4kly -k1m -k5nes -1k2no -ko5r -kosh4 -k3ou -kro5n -4k1s2 -k4sc -ks4l -k4sy -k5t -k1w -lab3ic -l4abo -laci4 -l4ade -la3dy -lag4n -lam3o -3land -lan4dl -lan5et -lan4te -lar4g -lar3i -las4e -la5tan -4lateli -4lativ -4lav -la4v4a -2l1b -lbin4 -4l1c2 -lce4 -l3ci -2ld -l2de -ld4ere -ld4eri -ldi4 -ld5is -l3dr -l4dri -le2a -le4bi -left5 -5leg. -5legg -le4mat -lem5atic -4len. -3lenc -5lene. -1lent -le3ph -le4pr -lera5b -ler4e -3lerg -3l4eri -l4ero -les2 -le5sco -5lesq -3less -5less. -l3eva -lev4er. -lev4era -lev4ers -3ley -4leye -2lf -l5fr -4l1g4 -l5ga -lgar3 -l4ges -lgo3 -2l3h -li4ag -li2am -liar5iz -li4as -li4ato -li5bi -5licio -li4cor -4lics -4lict. -l4icu -l3icy -l3ida -lid5er -3lidi -lif3er -l4iff -li4fl -5ligate -3ligh -li4gra -3lik -4l4i4l -lim4bl -lim3i -li4mo -l4im4p -l4ina -1l4ine -lin3ea -lin3i -link5er -li5og -4l4iq -lis4p -l1it -l2it. -5litica -l5i5tics -liv3er -l1iz -4lj -lka3 -l3kal -lka4t -l1l -l4law -l2le -l5lea -l3lec -l3leg -l3lel -l3le4n -l3le4t -ll2i -l2lin4 -l5lina -ll4o -lloqui5 -ll5out -l5low -2lm -l5met -lm3ing -l4mod -lmon4 -2l1n2 -3lo. -lob5al -lo4ci -4lof -3logic -l5ogo -3logu -lom3er -5long -lon4i -l3o3niz -lood5 -5lope. -lop3i -l3opm -lora4 -lo4rato -lo5rie -lor5ou -5los. -los5et -5losophiz -5losophy -los4t -lo4ta -loun5d -2lout -4lov -2lp -lpa5b -l3pha -l5phi -lp5ing -l3pit -l4pl -l5pr -4l1r -2l1s2 -l4sc -l2se -l4sie -4lt -lt5ag -ltane5 -l1te -lten4 -ltera4 -lth3i -l5ties. -ltis4 -l1tr -ltu2 -ltur3a -lu5a -lu3br -luch4 -lu3ci -lu3en -luf4 -lu5id -lu4ma -5lumi -l5umn. -5lumnia -lu3o -luo3r -4lup -luss4 -lus3te -1lut -l5ven -l5vet4 -2l1w -1ly -4lya -4lyb -ly5me -ly3no -2lys4 -l5yse -1ma -2mab -ma2ca -ma5chine -ma4cl -mag5in -5magn -2mah -maid5 -4mald -ma3lig -ma5lin -mal4li -mal4ty -5mania -man5is -man3iz -4map -ma5rine. -ma5riz -mar4ly -mar3v -ma5sce -mas4e -mas1t -5mate -math3 -ma3tis -4matiza -4m1b -mba4t5 -m5bil -m4b3ing -mbi4v -4m5c -4me. -2med -4med. -5media -me3die -m5e5dy -me2g -mel5on -mel4t -me2m -mem1o3 -1men -men4a -men5ac -men4de -4mene -men4i -mens4 -mensu5 -3ment -men4te -me5on -m5ersa -2mes -3mesti -me4ta -met3al -me1te -me5thi -m4etr -5metric -me5trie -me3try -me4v -4m1f -2mh -5mi. -mi3a -mid4a -mid4g -mig4 -3milia -m5i5lie -m4ill -min4a -3mind -m5inee -m4ingl -min5gli -m5ingly -min4t -m4inu -miot4 -m2is -mis4er. -mis5l -mis4ti -m5istry -4mith -m2iz -4mk -4m1l -m1m -mma5ry -4m1n -mn4a -m4nin -mn4o -1mo -4mocr -5mocratiz -mo2d1 -mo4go -mois2 -moi5se -4mok -mo5lest -mo3me -mon5et -mon5ge -moni3a -mon4ism -mon4ist -mo3niz -monol4 -mo3ny. -mo2r -4mora. -mos2 -mo5sey -mo3sp -moth3 -m5ouf -3mous -mo2v -4m1p -mpara5 -mpa5rab -mpar5i -m3pet -mphas4 -m2pi -mpi4a -mp5ies -m4p1in -m5pir -mp5is -mpo3ri -mpos5ite -m4pous -mpov5 -mp4tr -m2py -4m3r -4m1s2 -m4sh -m5si -4mt -1mu -mula5r4 -5mult -multi3 -3mum -mun2 -4mup -mu4u -4mw -1na -2n1a2b -n4abu -4nac. -na4ca -n5act -nag5er. -nak4 -na4li -na5lia -4nalt -na5mit -n2an -nanci4 -nan4it -nank4 -nar3c -4nare -nar3i -nar4l -n5arm -n4as -nas4c -nas5ti -n2at -na3tal -nato5miz -n2au -nau3se -3naut -nav4e -4n1b4 -ncar5 -n4ces. -n3cha -n5cheo -n5chil -n3chis -nc1in -nc4it -ncour5a -n1cr -n1cu -n4dai -n5dan -n1de -nd5est. -ndi4b -n5d2if -n1dit -n3diz -n5duc -ndu4r -nd2we -2ne. -n3ear -ne2b -neb3u -ne2c -5neck -2ned -ne4gat -neg5ativ -5nege -ne4la -nel5iz -ne5mi -ne4mo -1nen -4nene -3neo -ne4po -ne2q -n1er -nera5b -n4erar -n2ere -n4er5i -ner4r -1nes -2nes. -4nesp -2nest -4nesw -3netic -ne4v -n5eve -ne4w -n3f -n4gab -n3gel -nge4n4e -n5gere -n3geri -ng5ha -n3gib -ng1in -n5git -n4gla -ngov4 -ng5sh -n1gu -n4gum -n2gy -4n1h4 -nha4 -nhab3 -nhe4 -3n4ia -ni3an -ni4ap -ni3ba -ni4bl -ni4d -ni5di -ni4er -ni2fi -ni5ficat -n5igr -nik4 -n1im -ni3miz -n1in -5nine. -nin4g -ni4o -5nis. -nis4ta -n2it -n4ith -3nitio -n3itor -ni3tr -n1j -4nk2 -n5kero -n3ket -nk3in -n1kl -4n1l -n5m -nme4 -nmet4 -4n1n2 -nne4 -nni3al -nni4v -nob4l -no3ble -n5ocl -4n3o2d -3noe -4nog -noge4 -nois5i -no5l4i -5nologis -3nomic -n5o5miz -no4mo -no3my -no4n -non4ag -non5i -n5oniz -4nop -5nop5o5li -nor5ab -no4rary -4nosc -nos4e -nos5t -no5ta -1nou -3noun -nov3el3 -nowl3 -n1p4 -npi4 -npre4c -n1q -n1r -nru4 -2n1s2 -ns5ab -nsati4 -ns4c -n2se -n4s3es -nsid1 -nsig4 -n2sl -ns3m -n4soc -ns4pe -n5spi -nsta5bl -n1t -nta4b -nter3s -nt2i -n5tib -nti4er -nti2f -n3tine -n4t3ing -nti4p -ntrol5li -nt4s -ntu3me -nu1a -nu4d -nu5en -nuf4fe -n3uin -3nu3it -n4um -nu1me -n5umi -3nu4n -n3uo -nu3tr -n1v2 -n1w4 -nym4 -nyp4 -4nz -n3za -4oa -oad3 -o5a5les -oard3 -oas4e -oast5e -oat5i -ob3a3b -o5bar -obe4l -o1bi -o2bin -ob5ing -o3br -ob3ul -o1ce -och4 -o3chet -ocif3 -o4cil -o4clam -o4cod -oc3rac -oc5ratiz -ocre3 -5ocrit -octor5a -oc3ula -o5cure -od5ded -od3ic -odi3o -o2do4 -odor3 -od5uct. -od5ucts -o4el -o5eng -o3er -oe4ta -o3ev -o2fi -of5ite -ofit4t -o2g5a5r -og5ativ -o4gato -o1ge -o5gene -o5geo -o4ger -o3gie -1o1gis -og3it -o4gl -o5g2ly -3ogniz -o4gro -ogu5i -1ogy -2ogyn -o1h2 -ohab5 -oi2 -oic3es -oi3der -oiff4 -oig4 -oi5let -o3ing -oint5er -o5ism -oi5son -oist5en -oi3ter -o5j -2ok -o3ken -ok5ie -o1la -o4lan -olass4 -ol2d -old1e -ol3er -o3lesc -o3let -ol4fi -ol2i -o3lia -o3lice -ol5id. -o3li4f -o5lil -ol3ing -o5lio -o5lis. -ol3ish -o5lite -o5litio -o5liv -olli4e -ol5ogiz -olo4r -ol5pl -ol2t -ol3ub -ol3ume -ol3un -o5lus -ol2v -o2ly -om5ah -oma5l -om5atiz -om2be -om4bl -o2me -om3ena -om5erse -o4met -om5etry -o3mia -om3ic. -om3ica -o5mid -om1in -o5mini -5ommend -omo4ge -o4mon -om3pi -ompro5 -o2n -on1a -on4ac -o3nan -on1c -3oncil -2ond -on5do -o3nen -on5est -on4gu -on1ic -o3nio -on1is -o5niu -on3key -on4odi -on3omy -on3s -onspi4 -onspir5a -onsu4 -onten4 -on3t4i -ontif5 -on5um -onva5 -oo2 -ood5e -ood5i -oo4k -oop3i -o3ord -oost5 -o2pa -ope5d -op1er -3opera -4operag -2oph -o5phan -o5pher -op3ing -o3pit -o5pon -o4posi -o1pr -op1u -opy5 -o1q -o1ra -o5ra. -o4r3ag -or5aliz -or5ange -ore5a -o5real -or3ei -ore5sh -or5est. -orew4 -or4gu -4o5ria -or3ica -o5ril -or1in -o1rio -or3ity -o3riu -or2mi -orn2e -o5rof -or3oug -or5pe -3orrh -or4se -ors5en -orst4 -or3thi -or3thy -or4ty -o5rum -o1ry -os3al -os2c -os4ce -o3scop -4oscopi -o5scr -os4i4e -os5itiv -os3ito -os3ity -osi4u -os4l -o2so -os4pa -os4po -os2ta -o5stati -os5til -os5tit -o4tan -otele4g -ot3er. -ot5ers -o4tes -4oth -oth5esi -oth3i4 -ot3ic. -ot5ica -o3tice -o3tif -o3tis -oto5s -ou2 -ou3bl -ouch5i -ou5et -ou4l -ounc5er -oun2d -ou5v -ov4en -over4ne -over3s -ov4ert -o3vis -oviti4 -o5v4ol -ow3der -ow3el -ow5est -ow1i -own5i -o4wo -oy1a -1pa -pa4ca -pa4ce -pac4t -p4ad -5pagan -p3agat -p4ai -pain4 -p4al -pan4a -pan3el -pan4ty -pa3ny -pa1p -pa4pu -para5bl -par5age -par5di -3pare -par5el -p4a4ri -par4is -pa2te -pa5ter -5pathic -pa5thy -pa4tric -pav4 -3pay -4p1b -pd4 -4pe. -3pe4a -pear4l -pe2c -2p2ed -3pede -3pedi -pedia4 -ped4ic -p4ee -pee4d -pek4 -pe4la -peli4e -pe4nan -p4enc -pen4th -pe5on -p4era. -pera5bl -p4erag -p4eri -peri5st -per4mal -perme5 -p4ern -per3o -per3ti -pe5ru -per1v -pe2t -pe5ten -pe5tiz -4pf -4pg -4ph. -phar5i -phe3no -ph4er -ph4es. -ph1ic -5phie -ph5ing -5phisti -3phiz -ph2l -3phob -3phone -5phoni -pho4r -4phs -ph3t -5phu -1phy -pi3a -pian4 -pi4cie -pi4cy -p4id -p5ida -pi3de -5pidi -3piec -pi3en -pi4grap -pi3lo -pi2n -p4in. -pind4 -p4ino -3pi1o -pion4 -p3ith -pi5tha -pi2tu -2p3k2 -1p2l2 -3plan -plas5t -pli3a -pli5er -4plig -pli4n -ploi4 -plu4m -plum4b -4p1m -2p3n -po4c -5pod. -po5em -po3et5 -5po4g -poin2 -5point -poly5t -po4ni -po4p -1p4or -po4ry -1pos -pos1s -p4ot -po4ta -5poun -4p1p -ppa5ra -p2pe -p4ped -p5pel -p3pen -p3per -p3pet -ppo5site -pr2 -pray4e -5preci -pre5co -pre3em -pref5ac -pre4la -pre3r -p3rese -3press -pre5ten -pre3v -5pri4e -prin4t3 -pri4s -pris3o -p3roca -prof5it -pro3l -pros3e -pro1t -2p1s2 -p2se -ps4h -p4sib -2p1t -pt5a4b -p2te -p2th -pti3m -ptu4r -p4tw -pub3 -pue4 -puf4 -pul3c -pu4m -pu2n -pur4r -5pus -pu2t -5pute -put3er -pu3tr -put4ted -put4tin -p3w -qu2 -qua5v -2que. -3quer -3quet -2rab -ra3bi -rach4e -r5acl -raf5fi -raf4t -r2ai -ra4lo -ram3et -r2ami -rane5o -ran4ge -r4ani -ra5no -rap3er -3raphy -rar5c -rare4 -rar5ef -4raril -r2as -ration4 -rau4t -ra5vai -rav3el -ra5zie -r1b -r4bab -r4bag -rbi2 -rbi4f -r2bin -r5bine -rb5ing. -rb4o -r1c -r2ce -rcen4 -r3cha -rch4er -r4ci4b -rc4it -rcum3 -r4dal -rd2i -rdi4a -rdi4er -rdin4 -rd3ing -2re. -re1al -re3an -re5arr -5reav -re4aw -r5ebrat -rec5oll -rec5ompe -re4cre -2r2ed -re1de -re3dis -red5it -re4fac -re2fe -re5fer. -re3fi -re4fy -reg3is -re5it -re1li -re5lu -r4en4ta -ren4te -re1o -re5pin -re4posi -re1pu -r1er4 -r4eri -rero4 -re5ru -r4es. -re4spi -ress5ib -res2t -re5stal -re3str -re4ter -re4ti4z -re3tri -reu2 -re5uti -rev2 -re4val -rev3el -r5ev5er. -re5vers -re5vert -re5vil -rev5olu -re4wh -r1f -rfu4 -r4fy -rg2 -rg3er -r3get -r3gic -rgi4n -rg3ing -r5gis -r5git -r1gl -rgo4n -r3gu -rh4 -4rh. -4rhal -ri3a -ria4b -ri4ag -r4ib -rib3a -ric5as -r4ice -4rici -5ricid -ri4cie -r4ico -rid5er -ri3enc -ri3ent -ri1er -ri5et -rig5an -5rigi -ril3iz -5riman -rim5i -3rimo -rim4pe -r2ina -5rina. -rin4d -rin4e -rin4g -ri1o -5riph -riph5e -ri2pl -rip5lic -r4iq -r2is -r4is. -ris4c -r3ish -ris4p -ri3ta3b -r5ited. -rit5er. -rit5ers -rit3ic -ri2tu -rit5ur -riv5el -riv3et -riv3i -r3j -r3ket -rk4le -rk4lin -r1l -rle4 -r2led -r4lig -r4lis -rl5ish -r3lo4 -r1m -rma5c -r2me -r3men -rm5ers -rm3ing -r4ming. -r4mio -r3mit -r4my -r4nar -r3nel -r4ner -r5net -r3ney -r5nic -r1nis4 -r3nit -r3niv -rno4 -r4nou -r3nu -rob3l -r2oc -ro3cr -ro4e -ro1fe -ro5fil -rok2 -ro5ker -5role. -rom5ete -rom4i -rom4p -ron4al -ron4e -ro5n4is -ron4ta -1room -5root -ro3pel -rop3ic -ror3i -ro5ro -ros5per -ros4s -ro4the -ro4ty -ro4va -rov5el -rox5 -r1p -r4pea -r5pent -rp5er. -r3pet -rp4h4 -rp3ing -r3po -r1r4 -rre4c -rre4f -r4reo -rre4st -rri4o -rri4v -rron4 -rros4 -rrys4 -4rs2 -r1sa -rsa5ti -rs4c -r2se -r3sec -rse4cr -rs5er. -rs3es -rse5v2 -r1sh -r5sha -r1si -r4si4b -rson3 -r1sp -r5sw -rtach4 -r4tag -r3teb -rten4d -rte5o -r1ti -rt5ib -rti4d -r4tier -r3tig -rtil3i -rtil4l -r4tily -r4tist -r4tiv -r3tri -rtroph4 -rt4sh -ru3a -ru3e4l -ru3en -ru4gl -ru3in -rum3pl -ru2n -runk5 -run4ty -r5usc -ruti5n -rv4e -rvel4i -r3ven -rv5er. -r5vest -r3vey -r3vic -rvi4v -r3vo -r1w -ry4c -5rynge -ry3t -sa2 -2s1ab -5sack -sac3ri -s3act -5sai -salar4 -sal4m -sa5lo -sal4t -3sanc -san4de -s1ap -sa5ta -5sa3tio -sat3u -sau4 -sa5vor -5saw -4s5b -scan4t5 -sca4p -scav5 -s4ced -4scei -s4ces -sch2 -s4cho -3s4cie -5scin4d -scle5 -s4cli -scof4 -4scopy -scour5a -s1cu -4s5d -4se. -se4a -seas4 -sea5w -se2c3o -3sect -4s4ed -se4d4e -s5edl -se2g -seg3r -5sei -se1le -5self -5selv -4seme -se4mol -sen5at -4senc -sen4d -s5ened -sen5g -s5enin -4sentd -4sentl -sep3a3 -4s1er. -s4erl -ser4o -4servo -s1e4s -se5sh -ses5t -5se5um -5sev -sev3en -sew4i -5sex -4s3f -2s3g -s2h -2sh. -sh1er -5shev -sh1in -sh3io -3ship -shiv5 -sho4 -sh5old -shon3 -shor4 -short5 -4shw -si1b -s5icc -3side. -5sides -5sidi -si5diz -4signa -sil4e -4sily -2s1in -s2ina -5sine. -s3ing -1sio -5sion -sion5a -si2r -sir5a -1sis -3sitio -5siu -1siv -5siz -sk2 -4ske -s3ket -sk5ine -sk5ing -s1l2 -s3lat -s2le -slith5 -2s1m -s3ma -small3 -sman3 -smel4 -s5men -5smith -smol5d4 -s1n4 -1so -so4ce -soft3 -so4lab -sol3d2 -so3lic -5solv -3som -3s4on. -sona4 -son4g -s4op -5sophic -s5ophiz -s5ophy -sor5c -sor5d -4sov -so5vi -2spa -5spai -spa4n -spen4d -2s5peo -2sper -s2phe -3spher -spho5 -spil4 -sp5ing -4spio -s4ply -s4pon -spor4 -4spot -squal4l -s1r -2ss -s1sa -ssas3 -s2s5c -s3sel -s5seng -s4ses. -s5set -s1si -s4sie -ssi4er -ss5ily -s4sl -ss4li -s4sn -sspend4 -ss2t -ssur5a -ss5w -2st. -s2tag -s2tal -stam4i -5stand -s4ta4p -5stat. -s4ted -stern5i -s5tero -ste2w -stew5a -s3the -st2i -s4ti. -s5tia -s1tic -5stick -s4tie -s3tif -st3ing -5stir -s1tle -5stock -stom3a -5stone -s4top -3store -st4r -s4trad -5stratu -s4tray -s4trid -4stry -4st3w -s2ty -1su -su1al -su4b3 -su2g3 -su5is -suit3 -s4ul -su2m -sum3i -su2n -su2r -4sv -sw2 -4swo -s4y -4syc -3syl -syn5o -sy5rin -1ta -3ta. -2tab -ta5bles -5taboliz -4taci -ta5do -4taf4 -tai5lo -ta2l -ta5la -tal5en -tal3i -4talk -tal4lis -ta5log -ta5mo -tan4de -tanta3 -ta5per -ta5pl -tar4a -4tarc -4tare -ta3riz -tas4e -ta5sy -4tatic -ta4tur -taun4 -tav4 -2taw -tax4is -2t1b -4tc -t4ch -tch5et -4t1d -4te. -tead4i -4teat -tece4 -5tect -2t1ed -te5di -1tee -teg4 -te5ger -te5gi -3tel. -teli4 -5tels -te2ma2 -tem3at -3tenan -3tenc -3tend -4tenes -1tent -ten4tag -1teo -te4p -te5pe -ter3c -5ter3d -1teri -ter5ies -ter3is -teri5za -5ternit -ter5v -4tes. -4tess -t3ess. -teth5e -3teu -3tex -4tey -2t1f -4t1g -2th. -than4 -th2e -4thea -th3eas -the5at -the3is -3thet -th5ic. -th5ica -4thil -5think -4thl -th5ode -5thodic -4thoo -thor5it -tho5riz -2ths -1tia -ti4ab -ti4ato -2ti2b -4tick -t4ico -t4ic1u -5tidi -3tien -tif2 -ti5fy -2tig -5tigu -till5in -1tim -4timp -tim5ul -2t1in -t2ina -3tine. -3tini -1tio -ti5oc -tion5ee -5tiq -ti3sa -3tise -tis4m -ti5so -tis4p -5tistica -ti3tl -ti4u -1tiv -tiv4a -1tiz -ti3za -ti3zen -2tl -t5la -tlan4 -3tle. -3tled -3tles. -t5let. -t5lo -4t1m -tme4 -2t1n2 -1to -to3b -to5crat -4todo -2tof -to2gr -to5ic -to2ma -tom4b -to3my -ton4ali -to3nat -4tono -4tony -to2ra -to3rie -tor5iz -tos2 -5tour -4tout -to3war -4t1p -1tra -tra3b -tra5ch -traci4 -trac4it -trac4te -tras4 -tra5ven -trav5es5 -tre5f -tre4m -trem5i -5tria -tri5ces -5tricia -4trics -2trim -tri4v -tro5mi -tron5i -4trony -tro5phe -tro3sp -tro3v -tru5i -trus4 -4t1s2 -t4sc -tsh4 -t4sw -4t3t2 -t4tes -t5to -ttu4 -1tu -tu1a -tu3ar -tu4bi -tud2 -4tue -4tuf4 -5tu3i -3tum -tu4nis -2t3up. -3ture -5turi -tur3is -tur5o -tu5ry -3tus -4tv -tw4 -4t1wa -twis4 -4two -1ty -4tya -2tyl -type3 -ty5ph -4tz -tz4e -4uab -uac4 -ua5na -uan4i -uar5ant -uar2d -uar3i -uar3t -u1at -uav4 -ub4e -u4bel -u3ber -u4bero -u1b4i -u4b5ing -u3ble. -u3ca -uci4b -uc4it -ucle3 -u3cr -u3cu -u4cy -ud5d -ud3er -ud5est -udev4 -u1dic -ud3ied -ud3ies -ud5is -u5dit -u4don -ud4si -u4du -u4ene -uens4 -uen4te -uer4il -3ufa -u3fl -ugh3en -ug5in -2ui2 -uil5iz -ui4n -u1ing -uir4m -uita4 -uiv3 -uiv4er. -u5j -4uk -u1la -ula5b -u5lati -ulch4 -5ulche -ul3der -ul4e -u1len -ul4gi -ul2i -u5lia -ul3ing -ul5ish -ul4lar -ul4li4b -ul4lis -4ul3m -u1l4o -4uls -uls5es -ul1ti -ultra3 -4ultu -u3lu -ul5ul -ul5v -um5ab -um4bi -um4bly -u1mi -u4m3ing -umor5o -um2p -unat4 -u2ne -un4er -u1ni -un4im -u2nin -un5ish -uni3v -un3s4 -un4sw -unt3ab -un4ter. -un4tes -unu4 -un5y -un5z -u4ors -u5os -u1ou -u1pe -uper5s -u5pia -up3ing -u3pl -up3p -upport5 -upt5ib -uptu4 -u1ra -4ura. -u4rag -u4ras -ur4be -urc4 -ur1d -ure5at -ur4fer -ur4fr -u3rif -uri4fic -ur1in -u3rio -u1rit -ur3iz -ur2l -url5ing. -ur4no -uros4 -ur4pe -ur4pi -urs5er -ur5tes -ur3the -urti4 -ur4tie -u3ru -2us -u5sad -u5san -us4ap -usc2 -us3ci -use5a -u5sia -u3sic -us4lin -us1p -us5sl -us5tere -us1tr -u2su -usur4 -uta4b -u3tat -4ute. -4utel -4uten -uten4i -4u1t2i -uti5liz -u3tine -ut3ing -ution5a -u4tis -5u5tiz -u4t1l -ut5of -uto5g -uto5matic -u5ton -u4tou -uts4 -u3u -uu4m -u1v2 -uxu3 -uz4e -1va -5va. -2v1a4b -vac5il -vac3u -vag4 -va4ge -va5lie -val5o -val1u -va5mo -va5niz -va5pi -var5ied -3vat -4ve. -4ved -veg3 -v3el. -vel3li -ve4lo -v4ely -ven3om -v5enue -v4erd -5vere. -v4erel -v3eren -ver5enc -v4eres -ver3ie -vermi4n -3verse -ver3th -v4e2s -4ves. -ves4te -ve4te -vet3er -ve4ty -vi5ali -5vian -5vide. -5vided -4v3iden -5vides -5vidi -v3if -vi5gn -vik4 -2vil -5vilit -v3i3liz -v1in -4vi4na -v2inc -vin5d -4ving -vio3l -v3io4r -vi1ou -vi4p -vi5ro -vis3it -vi3so -vi3su -4viti -vit3r -4vity -3viv -5vo. -voi4 -3vok -vo4la -v5ole -5volt -3volv -vom5i -vor5ab -vori4 -vo4ry -vo4ta -4votee -4vv4 -v4y -w5abl -2wac -wa5ger -wag5o -wait5 -w5al. -wam4 -war4t -was4t -wa1te -wa5ver -w1b -wea5rie -weath3 -wed4n -weet3 -wee5v -wel4l -w1er -west3 -w3ev -whi4 -wi2 -wil2 -will5in -win4de -win4g -wir4 -3wise -with3 -wiz5 -w4k -wl4es -wl3in -w4no -1wo2 -wom1 -wo5ven -w5p -wra4 -wri4 -writa4 -w3sh -ws4l -ws4pe -w5s4t -4wt -wy4 -x1a -xac5e -x4ago -xam3 -x4ap -xas5 -x3c2 -x1e -xe4cuto -x2ed -xer4i -xe5ro -x1h -xhi2 -xhil5 -xhu4 -x3i -xi5a -xi5c -xi5di -x4ime -xi5miz -x3o -x4ob -x3p -xpan4d -xpecto5 -xpe3d -x1t2 -x3ti -x1u -xu3a -xx4 -y5ac -3yar4 -y5at -y1b -y1c -y2ce -yc5er -y3ch -ych4e -ycom4 -ycot4 -y1d -y5ee -y1er -y4erf -yes4 -ye4t -y5gi -4y3h -y1i -y3la -ylla5bl -y3lo -y5lu -ymbol5 -yme4 -ympa3 -yn3chr -yn5d -yn5g -yn5ic -5ynx -y1o4 -yo5d -y4o5g -yom4 -yo5net -y4ons -y4os -y4ped -yper5 -yp3i -y3po -y4poc -yp2ta -y5pu -yra5m -yr5ia -y3ro -yr4r -ys4c -y3s2e -ys3ica -ys3io -3ysis -y4so -yss4 -ys1t -ys3ta -ysur4 -y3thin -yt3ic -y1w -za1 -z5a2b -zar2 -4zb -2ze -ze4n -ze4p -z1er -ze3ro -zet4 -2z1i -z4il -z4is -5zl -4zm -1zo -zo4m -zo5ol -zte4 -4z1z2 -z4zy diff --git a/contrib/groff/troff/input.cc b/contrib/groff/troff/input.cc deleted file mode 100644 index 529a70f..0000000 --- a/contrib/groff/troff/input.cc +++ /dev/null @@ -1,6406 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "reg.h" -#include "token.h" -#include "div.h" -#include "charinfo.h" -#include "font.h" -#include "searchpath.h" -#include "macropath.h" -#include "defs.h" - -// Needed for getpid(). -#include "posix.h" - -#include "nonposix.h" - -#ifdef ISATTY_MISSING -#undef isatty -#define isatty(n) (1) -#else /* not ISATTY_MISSING */ -#ifndef isatty -extern "C" { - int isatty(int); -} -#endif /* not isatty */ -#endif /* not ISATTY_MISSING */ - -#define USAGE_EXIT_CODE 1 -#define MACRO_PREFIX "tmac." -#define INITIAL_STARTUP_FILE "troffrc" -#define FINAL_STARTUP_FILE "troffrc-end" -#define DEFAULT_INPUT_STACK_LIMIT 1000 - -#ifndef DEFAULT_WARNING_MASK -// warnings that are enabled by default -#define DEFAULT_WARNING_MASK \ - (WARN_CHAR|WARN_NUMBER|WARN_BREAK|WARN_SPACE|WARN_FONT) -#endif - -// initial size of buffer for reading names; expanded as necessary -#define ABUF_SIZE 16 - -#ifdef COLUMN -void init_column_requests(); -#endif /* COLUMN */ - -static node *read_draw_node(); -void handle_first_page_transition(); -static void push_token(const token &); -void copy_file(); -#ifdef COLUMN -void vjustify(); -#endif /* COLUMN */ -void transparent(); -void transparent_file(); - -const char *program_name = 0; -token tok; -int break_flag = 0; -static int backtrace_flag = 0; -#ifndef POPEN_MISSING -char *pipe_command = 0; -#endif -charinfo *charset_table[256]; - -static int warning_mask = DEFAULT_WARNING_MASK; -static int inhibit_errors = 0; -static int ignoring = 0; - -static void enable_warning(const char *); -static void disable_warning(const char *); - -static int escape_char = '\\'; -static symbol end_macro_name; -static symbol blank_line_macro_name; -static int compatible_flag = 0; -int ascii_output_flag = 0; -int suppress_output_flag = 0; - -int tcommand_flag = 0; - -static int get_copy(node**, int = 0); -static void copy_mode_error(const char *, - const errarg & = empty_errarg, - const errarg & = empty_errarg, - const errarg & = empty_errarg); - -static symbol read_escape_name(); -static void interpolate_string(symbol); -static void interpolate_macro(symbol); -static void interpolate_number_format(symbol); -static void interpolate_environment_variable(symbol); - -static void interpolate_arg(symbol); -static request_or_macro *lookup_request(symbol); -static int get_delim_number(units *, int); -static int get_delim_number(units *, int, units); -static int get_line_arg(units *res, int si, charinfo **cp); -static int read_size(int *); -static symbol get_delim_name(); -static void init_registers(); -static void trapping_blank_line(); - -struct input_iterator; -input_iterator *make_temp_iterator(const char *); -const char *input_char_description(int); - -#ifndef IS_EBCDIC_HOST - -const int ESCAPE_QUESTION = 015; -const int BEGIN_TRAP = 016; -const int END_TRAP = 017; -const int PAGE_EJECTOR = 020; -const int ESCAPE_NEWLINE = 021; -const int ESCAPE_AMPERSAND = 022; -const int ESCAPE_UNDERSCORE = 023; -const int ESCAPE_BAR = 024; -const int ESCAPE_CIRCUMFLEX = 025; -const int ESCAPE_LEFT_BRACE = 026; -const int ESCAPE_RIGHT_BRACE = 027; -const int ESCAPE_LEFT_QUOTE = 030; -const int ESCAPE_RIGHT_QUOTE = 031; -const int ESCAPE_HYPHEN = 032; -const int ESCAPE_BANG = 033; -const int ESCAPE_c = 034; -const int ESCAPE_e = 035; -const int ESCAPE_PERCENT = 036; -const int ESCAPE_SPACE = 037; - -const int TITLE_REQUEST = 0200; -const int COPY_FILE_REQUEST = 0201; -const int TRANSPARENT_FILE_REQUEST = 0202; -#ifdef COLUMN -const int VJUSTIFY_REQUEST = 0203; -#endif /* COLUMN */ -const int ESCAPE_E = 0204; -const int LAST_PAGE_EJECTOR = 0205; -const int ESCAPE_RIGHT_PARENTHESIS = 0206; - -#else /* IS_EBCDIC_HOST */ - -const int ESCAPE_QUESTION = 010; -const int BEGIN_TRAP = 011; -const int END_TRAP = 013; -const int PAGE_EJECTOR = 015; -const int ESCAPE_NEWLINE = 016; -const int ESCAPE_AMPERSAND = 017; -const int ESCAPE_UNDERSCORE = 020; -const int ESCAPE_BAR = 021; -const int ESCAPE_CIRCUMFLEX = 022; -const int ESCAPE_LEFT_BRACE = 023; -const int ESCAPE_RIGHT_BRACE = 024; -const int ESCAPE_LEFT_QUOTE = 027; -const int ESCAPE_RIGHT_QUOTE = 030; -const int ESCAPE_HYPHEN = 031; -const int ESCAPE_BANG = 032; -const int ESCAPE_c = 033; -const int ESCAPE_e = 034; -const int ESCAPE_PERCENT = 035; -const int ESCAPE_SPACE = 036; - -const int TITLE_REQUEST = 060; -const int COPY_FILE_REQUEST = 061; -const int TRANSPARENT_FILE_REQUEST = 062; -#ifdef COLUMN -const int VJUSTIFY_REQUEST = 063; -#endif /* COLUMN */ -const int ESCAPE_E = 064; -const int LAST_PAGE_EJECTOR = 065; -const int ESCAPE_RIGHT_PARENTHESIS = 066; - -#endif /* IS_EBCDIC_HOST */ - - -void set_escape_char() -{ - if (has_arg()) { - if (tok.ch() == 0) { - error("bad escape character"); - escape_char = '\\'; - } - else - escape_char = tok.ch(); - } - else - escape_char = '\\'; - skip_line(); -} - -void escape_off() -{ - escape_char = 0; - skip_line(); -} - -class input_iterator { -public: - input_iterator(); - virtual ~input_iterator(); - int get(node **); - friend class input_stack; -protected: - const unsigned char *ptr; - const unsigned char *eptr; - input_iterator *next; -private: - virtual int fill(node **); - virtual int peek(); - virtual int has_args() { return 0; } - virtual int nargs() { return 0; } - virtual input_iterator *get_arg(int) { return NULL; } - virtual int get_location(int, const char **, int *) - { return 0; } - virtual void backtrace() {} - virtual int set_location(const char *, int) - { return 0; } - virtual int next_file(FILE *, const char *) { return 0; } - virtual void shift(int) {} - virtual int is_boundary(); - virtual int internal_level() { return 0; } - virtual int is_file() { return 0; } -}; - -input_iterator::input_iterator() -: ptr(0), eptr(0) -{ -} - -input_iterator::~input_iterator() -{ -} - -int input_iterator::fill(node **) -{ - return EOF; -} - -int input_iterator::peek() -{ - return EOF; -} - -int input_iterator::is_boundary() -{ - return 0; -} - -inline int input_iterator::get(node **p) -{ - return ptr < eptr ? *ptr++ : fill(p); -} - - -class input_boundary : public input_iterator { -public: - int is_boundary() { return 1; } -}; - -class file_iterator : public input_iterator { - FILE *fp; - int lineno; - const char *filename; - int popened; - int newline_flag; - enum { BUF_SIZE = 512 }; - unsigned char buf[BUF_SIZE]; - void close(); -public: - file_iterator(FILE *, const char *, int = 0); - ~file_iterator(); - int fill(node **); - int peek(); - int get_location(int, const char **, int *); - void backtrace(); - int set_location(const char *, int); - int next_file(FILE *, const char *); - int is_file(); -}; - -file_iterator::file_iterator(FILE *f, const char *fn, int po) -: fp(f), lineno(1), filename(fn), popened(po), newline_flag(0) -{ - if ((font::use_charnames_in_special) && (fn != 0)) { - if (!the_output) - init_output(); - the_output->put_filename(fn); - } -} - -file_iterator::~file_iterator() -{ - close(); -} - -void file_iterator::close() -{ - if (fp == stdin) - clearerr(stdin); -#ifndef POPEN_MISSING - else if (popened) - pclose(fp); -#endif /* not POPEN_MISSING */ - else - fclose(fp); -} - -int file_iterator::is_file() -{ - return 1; -} - -int file_iterator::next_file(FILE *f, const char *s) -{ - close(); - filename = s; - fp = f; - lineno = 1; - newline_flag = 0; - popened = 0; - ptr = 0; - eptr = 0; - return 1; -} - -int file_iterator::fill(node **) -{ - if (newline_flag) - lineno++; - newline_flag = 0; - unsigned char *p = buf; - ptr = p; - unsigned char *e = p + BUF_SIZE; - while (p < e) { - int c = getc(fp); - if (c == EOF) - break; - if (illegal_input_char(c)) - warning(WARN_INPUT, "illegal input character code %1", int(c)); - else { - *p++ = c; - if (c == '\n') { - newline_flag = 1; - break; - } - } - } - if (p > buf) { - eptr = p; - return *ptr++; - } - else { - eptr = p; - return EOF; - } -} - -int file_iterator::peek() -{ - int c = getc(fp); - while (illegal_input_char(c)) { - warning(WARN_INPUT, "illegal input character code %1", int(c)); - c = getc(fp); - } - if (c != EOF) - ungetc(c, fp); - return c; -} - -int file_iterator::get_location(int /*allow_macro*/, - const char **filenamep, int *linenop) -{ - *linenop = lineno; - if (filename != 0 && strcmp(filename, "-") == 0) - *filenamep = "<standard input>"; - else - *filenamep = filename; - return 1; -} - -void file_iterator::backtrace() -{ - errprint("%1:%2: backtrace: %3 `%1'\n", filename, lineno, - popened ? "process" : "file"); -} - -int file_iterator::set_location(const char *f, int ln) -{ - if (f) { - filename = f; - if (!the_output) - init_output(); - the_output->put_filename(f); - } - lineno = ln; - return 1; -} - -input_iterator nil_iterator; - -class input_stack { -public: - static int get(node **); - static int peek(); - static void push(input_iterator *); - static input_iterator *get_arg(int); - static int nargs(); - static int get_location(int, const char **, int *); - static int set_location(const char *, int); - static void backtrace(); - static void backtrace_all(); - static void next_file(FILE *, const char *); - static void end_file(); - static void shift(int n); - static void add_boundary(); - static void remove_boundary(); - static int get_level(); - static void clear(); - - static int limit; -private: - static input_iterator *top; - static int level; - - static int finish_get(node **); - static int finish_peek(); -}; - -input_iterator *input_stack::top = &nil_iterator; -int input_stack::level = 0; -int input_stack::limit = DEFAULT_INPUT_STACK_LIMIT; - -inline int input_stack::get_level() -{ - return level + top->internal_level(); -} - -inline int input_stack::get(node **np) -{ - return (top->ptr < top->eptr) ? *top->ptr++ : finish_get(np); -} - -int input_stack::finish_get(node **np) -{ - for (;;) { - int c = top->fill(np); - if (c != EOF || top->is_boundary()) - return c; - if (top == &nil_iterator) - break; - input_iterator *tem = top; - top = top->next; - level--; - delete tem; - if (top->ptr < top->eptr) - return *top->ptr++; - } - assert(level == 0); - return EOF; -} - -inline int input_stack::peek() -{ - return (top->ptr < top->eptr) ? *top->ptr : finish_peek(); -} - -int input_stack::finish_peek() -{ - for (;;) { - int c = top->peek(); - if (c != EOF || top->is_boundary()) - return c; - if (top == &nil_iterator) - break; - input_iterator *tem = top; - top = top->next; - level--; - delete tem; - if (top->ptr < top->eptr) - return *top->ptr; - } - assert(level == 0); - return EOF; -} - -void input_stack::add_boundary() -{ - push(new input_boundary); -} - -void input_stack::remove_boundary() -{ - assert(top->is_boundary()); - input_iterator *temp = top->next; - delete top; - top = temp; - level--; -} - -void input_stack::push(input_iterator *in) -{ - if (in == 0) - return; - if (++level > limit && limit > 0) - fatal("input stack limit exceeded (probable infinite loop)"); - in->next = top; - top = in; -} - -input_iterator *input_stack::get_arg(int i) -{ - input_iterator *p; - for (p = top; p != NULL; p = p->next) - if (p->has_args()) - return p->get_arg(i); - return 0; -} - -void input_stack::shift(int n) -{ - for (input_iterator *p = top; p; p = p->next) - if (p->has_args()) { - p->shift(n); - return; - } -} - -int input_stack::nargs() -{ - for (input_iterator *p =top; p != 0; p = p->next) - if (p->has_args()) - return p->nargs(); - return 0; -} - -int input_stack::get_location(int allow_macro, const char **filenamep, int *linenop) -{ - for (input_iterator *p = top; p; p = p->next) - if (p->get_location(allow_macro, filenamep, linenop)) - return 1; - return 0; -} - -void input_stack::backtrace() -{ - const char *f; - int n; - // only backtrace down to (not including) the topmost file - for (input_iterator *p = top; - p && !p->get_location(0, &f, &n); - p = p->next) - p->backtrace(); -} - -void input_stack::backtrace_all() -{ - for (input_iterator *p = top; p; p = p->next) - p->backtrace(); -} - -int input_stack::set_location(const char *filename, int lineno) -{ - for (input_iterator *p = top; p; p = p->next) - if (p->set_location(filename, lineno)) - return 1; - return 0; -} - -void input_stack::next_file(FILE *fp, const char *s) -{ - input_iterator **pp; - for (pp = ⊤ *pp != &nil_iterator; pp = &(*pp)->next) - if ((*pp)->next_file(fp, s)) - return; - if (++level > limit && limit > 0) - fatal("input stack limit exceeded"); - *pp = new file_iterator(fp, s); - (*pp)->next = &nil_iterator; -} - -void input_stack::end_file() -{ - for (input_iterator **pp = ⊤ *pp != &nil_iterator; pp = &(*pp)->next) - if ((*pp)->is_file()) { - input_iterator *tem = *pp; - *pp = (*pp)->next; - delete tem; - level--; - return; - } -} - -void input_stack::clear() -{ - int nboundaries = 0; - while (top != &nil_iterator) { - if (top->is_boundary()) - nboundaries++; - input_iterator *tem = top; - top = top->next; - level--; - delete tem; - } - // Keep while_request happy. - for (; nboundaries > 0; --nboundaries) - add_boundary(); -} - -void backtrace_request() -{ - input_stack::backtrace_all(); - fflush(stderr); - skip_line(); -} - -void next_file() -{ - symbol nm = get_long_name(0); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (nm.is_null()) - input_stack::end_file(); - else { - errno = 0; - FILE *fp = fopen(nm.contents(), "r"); - if (!fp) - error("can't open `%1': %2", nm.contents(), strerror(errno)); - else - input_stack::next_file(fp, nm.contents()); - } - tok.next(); -} - -void shift() -{ - int n; - if (!has_arg() || !get_integer(&n)) - n = 1; - input_stack::shift(n); - skip_line(); -} - -static int get_char_for_escape_name() -{ - int c = get_copy(NULL); - switch (c) { - case EOF: - copy_mode_error("end of input in escape name"); - return '\0'; - default: - if (!illegal_input_char(c)) - break; - // fall through - case '\n': - if (c == '\n') - input_stack::push(make_temp_iterator("\n")); - case ' ': - case '\t': - case '\001': - case '\b': - copy_mode_error("%1 is not allowed in an escape name", - input_char_description(c)); - return '\0'; - } - return c; -} - -static symbol read_two_char_escape_name() -{ - char buf[3]; - buf[0] = get_char_for_escape_name(); - if (buf[0] != '\0') { - buf[1] = get_char_for_escape_name(); - if (buf[1] == '\0') - buf[0] = 0; - else - buf[2] = 0; - } - return symbol(buf); -} - -static symbol read_long_escape_name() -{ - int start_level = input_stack::get_level(); - char abuf[ABUF_SIZE]; - char *buf = abuf; - int buf_size = ABUF_SIZE; - int i = 0; - for (;;) { - int c = get_char_for_escape_name(); - if (c == 0) { - if (buf != abuf) - a_delete buf; - return NULL_SYMBOL; - } - if (i + 2 > buf_size) { - if (buf == abuf) { - buf = new char [ABUF_SIZE*2]; - memcpy(buf, abuf, buf_size); - buf_size = ABUF_SIZE*2; - } - else { - char *old_buf = buf; - buf = new char[buf_size*2]; - memcpy(buf, old_buf, buf_size); - buf_size *= 2; - a_delete old_buf; - } - } - if (c == ']' && input_stack::get_level() == start_level) - break; - buf[i++] = c; - } - buf[i] = 0; - if (buf == abuf) { - if (i == 0) { - copy_mode_error("empty escape name"); - return NULL_SYMBOL; - } - return symbol(abuf); - } - else { - symbol s(buf); - a_delete buf; - return s; - } -} - -static symbol read_escape_name() -{ - int c = get_char_for_escape_name(); - if (c == 0) - return NULL_SYMBOL; - if (c == '(') - return read_two_char_escape_name(); - if (c == '[' && !compatible_flag) - return read_long_escape_name(); - char buf[2]; - buf[0] = c; - buf[1] = '\0'; - return symbol(buf); -} - -static symbol read_increment_and_escape_name(int *incp) -{ - int c = get_char_for_escape_name(); - switch (c) { - case 0: - *incp = 0; - return NULL_SYMBOL; - case '(': - *incp = 0; - return read_two_char_escape_name(); - case '+': - *incp = 1; - return read_escape_name(); - case '-': - *incp = -1; - return read_escape_name(); - case '[': - if (!compatible_flag) { - *incp = 0; - return read_long_escape_name(); - } - break; - } - *incp = 0; - char buf[2]; - buf[0] = c; - buf[1] = '\0'; - return symbol(buf); -} - -static int get_copy(node **nd, int defining) -{ - for (;;) { - int c = input_stack::get(nd); - if (c == ESCAPE_NEWLINE) { - if (defining) - return c; - do { - c = input_stack::get(nd); - } while (c == ESCAPE_NEWLINE); - } - if (c != escape_char || escape_char <= 0) - return c; - c = input_stack::peek(); - switch(c) { - case 0: - return escape_char; - case '"': - (void)input_stack::get(NULL); - while ((c = input_stack::get(NULL)) != '\n' && c != EOF) - ; - return c; - case '#': // Like \" but newline is ignored. - (void)input_stack::get(NULL); - while ((c = input_stack::get(NULL)) != '\n') - if (c == EOF) - return EOF; - break; - case '$': - { - (void)input_stack::get(NULL); - symbol s = read_escape_name(); - if (!s.is_null()) - interpolate_arg(s); - break; - } - case '*': - { - (void)input_stack::get(NULL); - symbol s = read_escape_name(); - if (!s.is_null()) - interpolate_string(s); - break; - } - case 'a': - (void)input_stack::get(NULL); - return '\001'; - case 'e': - (void)input_stack::get(NULL); - return ESCAPE_e; - case 'E': - (void)input_stack::get(NULL); - return ESCAPE_E; - case 'n': - { - (void)input_stack::get(NULL); - int inc; - symbol s = read_increment_and_escape_name(&inc); - if (!s.is_null()) - interpolate_number_reg(s, inc); - break; - } - case 'g': - { - (void)input_stack::get(NULL); - symbol s = read_escape_name(); - if (!s.is_null()) - interpolate_number_format(s); - break; - } - case 't': - (void)input_stack::get(NULL); - return '\t'; - case 'V': - { - (void)input_stack::get(NULL); - symbol s = read_escape_name(); - if (!s.is_null()) - interpolate_environment_variable(s); - break; - } - case '\n': - (void)input_stack::get(NULL); - if (defining) - return ESCAPE_NEWLINE; - break; - case ' ': - (void)input_stack::get(NULL); - return ESCAPE_SPACE; - case '|': - (void)input_stack::get(NULL); - return ESCAPE_BAR; - case '^': - (void)input_stack::get(NULL); - return ESCAPE_CIRCUMFLEX; - case '{': - (void)input_stack::get(NULL); - return ESCAPE_LEFT_BRACE; - case '}': - (void)input_stack::get(NULL); - return ESCAPE_RIGHT_BRACE; - case '`': - (void)input_stack::get(NULL); - return ESCAPE_LEFT_QUOTE; - case '\'': - (void)input_stack::get(NULL); - return ESCAPE_RIGHT_QUOTE; - case '-': - (void)input_stack::get(NULL); - return ESCAPE_HYPHEN; - case '_': - (void)input_stack::get(NULL); - return ESCAPE_UNDERSCORE; - case 'c': - (void)input_stack::get(NULL); - return ESCAPE_c; - case '!': - (void)input_stack::get(NULL); - return ESCAPE_BANG; - case '?': - (void)input_stack::get(NULL); - return ESCAPE_QUESTION; - case '&': - (void)input_stack::get(NULL); - return ESCAPE_AMPERSAND; - case ')': - (void)input_stack::get(NULL); - return ESCAPE_RIGHT_PARENTHESIS; - case '.': - (void)input_stack::get(NULL); - return c; - case '%': - (void)input_stack::get(NULL); - return ESCAPE_PERCENT; - default: - if (c == escape_char) { - (void)input_stack::get(NULL); - return c; - } - else - return escape_char; - } - } -} - -class non_interpreted_char_node : public node { - unsigned char c; -public: - non_interpreted_char_node(unsigned char); - node *copy(); - int interpret(macro *); - int same(node *); - const char *type(); -}; - -int non_interpreted_char_node::same(node *nd) -{ - return c == ((non_interpreted_char_node *)nd)->c; -} - -const char *non_interpreted_char_node::type() -{ - return "non_interpreted_char_node"; -} - -non_interpreted_char_node::non_interpreted_char_node(unsigned char n) : c(n) -{ - assert(n != 0); -} - -node *non_interpreted_char_node::copy() -{ - return new non_interpreted_char_node(c); -} - -int non_interpreted_char_node::interpret(macro *mac) -{ - mac->append(c); - return 1; -} - -static void do_width(); -static node *do_non_interpreted(); -static node *do_special(); -static void do_register(); - -static node *do_overstrike() -{ - token start; - overstrike_node *on = new overstrike_node; - start.next(); - tok.next(); - while (tok != start) { - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - charinfo *ci = tok.get_char(1); - if (ci) { - node *n = curenv->make_char_node(ci); - if (n) - on->overstrike(n); - } - tok.next(); - } - return on; -} - -static node *do_bracket() -{ - token start; - bracket_node *bn = new bracket_node; - start.next(); - tok.next(); - while (tok != start) { - if (tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok.newline()) { - warning(WARN_DELIM, "missing closing delimiter"); - input_stack::push(make_temp_iterator("\n")); - break; - } - charinfo *ci = tok.get_char(1); - if (ci) { - node *n = curenv->make_char_node(ci); - if (n) - bn->bracket(n); - } - tok.next(); - } - return bn; -} - -static int do_name_test() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - int bad_char = 0; - int some_char = 0; - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - if (!tok.ch()) - bad_char = 1; - some_char = 1; - } - return some_char && !bad_char; -} - -#if 0 -static node *do_zero_width() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - environment env(curenv); - environment *oldenv = curenv; - curenv = &env; - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - error("missing closing delimiter"); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - tok.process(); - } - curenv = oldenv; - node *rev = env.extract_output_line(); - node *n = 0; - while (rev) { - node *tem = rev; - rev = rev->next; - tem->next = n; - n = tem; - } - return new zero_width_node(n); -} - -#else - -// It's undesirable for \Z to change environments, because then -// \n(.w won't work as expected. - -static node *do_zero_width() -{ - node *rev = new dummy_node; - token start; - start.next(); - int start_level = input_stack::get_level(); - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - if (!tok.add_to_node_list(&rev)) - error("illegal token in argument to \\Z"); - } - node *n = 0; - while (rev) { - node *tem = rev; - rev = rev->next; - tem->next = n; - n = tem; - } - return new zero_width_node(n); -} - -#endif - -token_node *node::get_token_node() -{ - return 0; -} - -class token_node : public node { -public: - token tk; - token_node(const token &t); - node *copy(); - token_node *get_token_node(); - int same(node *); - const char *type(); -}; - -token_node::token_node(const token &t) : tk(t) -{ -} - -node *token_node::copy() -{ - return new token_node(tk); -} - -token_node *token_node::get_token_node() -{ - return this; -} - -int token_node::same(node *nd) -{ - return tk == ((token_node *)nd)->tk; -} - -const char *token_node::type() -{ - return "token_node"; -} - -token::token() : nd(0), type(TOKEN_EMPTY) -{ -} - -token::~token() -{ - delete nd; -} - -token::token(const token &t) -: nm(t.nm), c(t.c), val(t.val), dim(t.dim), type(t.type) -{ - // Use two statements to work around bug in SGI C++. - node *tem = t.nd; - nd = tem ? tem->copy() : 0; -} - -void token::operator=(const token &t) -{ - delete nd; - nm = t.nm; - // Use two statements to work around bug in SGI C++. - node *tem = t.nd; - nd = tem ? tem->copy() : 0; - c = t.c; - val = t.val; - dim = t.dim; - type = t.type; -} - -void token::skip() -{ - while (space()) - next(); -} - -int has_arg() -{ - while (tok.space()) - tok.next(); - return !tok.newline(); -} - -void token::make_space() -{ - type = TOKEN_SPACE; -} - -void token::make_newline() -{ - type = TOKEN_NEWLINE; -} - -void token::next() -{ - if (nd) { - delete nd; - nd = 0; - } - units x; - for (;;) { - node *n; - int cc = input_stack::get(&n); - if (cc != escape_char || escape_char == 0) { - handle_normal_char: - switch(cc) { - case EOF: - type = TOKEN_EOF; - return; - case TRANSPARENT_FILE_REQUEST: - case TITLE_REQUEST: - case COPY_FILE_REQUEST: -#ifdef COLUMN - case VJUSTIFY_REQUEST: -#endif /* COLUMN */ - type = TOKEN_REQUEST; - c = cc; - return; - case BEGIN_TRAP: - type = TOKEN_BEGIN_TRAP; - return; - case END_TRAP: - type = TOKEN_END_TRAP; - return; - case LAST_PAGE_EJECTOR: - seen_last_page_ejector = 1; - // fall through - case PAGE_EJECTOR: - type = TOKEN_PAGE_EJECTOR; - return; - case ESCAPE_PERCENT: - ESCAPE_PERCENT: - type = TOKEN_HYPHEN_INDICATOR; - return; - case ESCAPE_SPACE: - ESCAPE_SPACE: - type = TOKEN_NODE; - nd = new space_char_hmotion_node(curenv->get_space_width()); - return; - case ESCAPE_e: - ESCAPE_e: - type = TOKEN_ESCAPE; - return; - case ESCAPE_E: - goto handle_escape_char; - case ESCAPE_BAR: - ESCAPE_BAR: - type = TOKEN_NODE; - nd = new hmotion_node(curenv->get_narrow_space_width()); - return; - case ESCAPE_CIRCUMFLEX: - ESCAPE_CIRCUMFLEX: - type = TOKEN_NODE; - nd = new hmotion_node(curenv->get_half_narrow_space_width()); - return; - case ESCAPE_NEWLINE: - break; - case ESCAPE_LEFT_BRACE: - ESCAPE_LEFT_BRACE: - type = TOKEN_LEFT_BRACE; - return; - case ESCAPE_RIGHT_BRACE: - ESCAPE_RIGHT_BRACE: - type = TOKEN_RIGHT_BRACE; - return; - case ESCAPE_LEFT_QUOTE: - ESCAPE_LEFT_QUOTE: - type = TOKEN_SPECIAL; - nm = symbol("ga"); - return; - case ESCAPE_RIGHT_QUOTE: - ESCAPE_RIGHT_QUOTE: - type = TOKEN_SPECIAL; - nm = symbol("aa"); - return; - case ESCAPE_HYPHEN: - ESCAPE_HYPHEN: - type = TOKEN_SPECIAL; - nm = symbol("-"); - return; - case ESCAPE_UNDERSCORE: - ESCAPE_UNDERSCORE: - type = TOKEN_SPECIAL; - nm = symbol("ul"); - return; - case ESCAPE_c: - ESCAPE_c: - type = TOKEN_INTERRUPT; - return; - case ESCAPE_BANG: - ESCAPE_BANG: - type = TOKEN_TRANSPARENT; - return; - case ESCAPE_QUESTION: - ESCAPE_QUESTION: - nd = do_non_interpreted(); - if (nd) { - type = TOKEN_NODE; - return; - } - break; - case ESCAPE_AMPERSAND: - ESCAPE_AMPERSAND: - type = TOKEN_DUMMY; - return; - case ESCAPE_RIGHT_PARENTHESIS: - ESCAPE_RIGHT_PARENTHESIS: - type = TOKEN_NODE; - nd = new transparent_dummy_node; - return; - case '\b': - type = TOKEN_BACKSPACE; - return; - case ' ': - type = TOKEN_SPACE; - return; - case '\t': - type = TOKEN_TAB; - return; - case '\n': - type = TOKEN_NEWLINE; - return; - case '\001': - type = TOKEN_LEADER; - return; - case 0: - { - assert(n != 0); - token_node *tn = n->get_token_node(); - if (tn) { - *this = tn->tk; - delete tn; - } - else { - nd = n; - type = TOKEN_NODE; - } - } - return; - default: - type = TOKEN_CHAR; - c = cc; - return; - } - } - else { - handle_escape_char: - cc = input_stack::get(NULL); - switch(cc) { - case '(': - nm = read_two_char_escape_name(); - type = TOKEN_SPECIAL; - return; - case EOF: - type = TOKEN_EOF; - error("end of input after escape character"); - return; - case '`': - goto ESCAPE_LEFT_QUOTE; - case '\'': - goto ESCAPE_RIGHT_QUOTE; - case '-': - goto ESCAPE_HYPHEN; - case '_': - goto ESCAPE_UNDERSCORE; - case '%': - goto ESCAPE_PERCENT; - case ' ': - goto ESCAPE_SPACE; - case '0': - nd = new hmotion_node(curenv->get_digit_width()); - type = TOKEN_NODE; - return; - case '|': - goto ESCAPE_BAR; - case '^': - goto ESCAPE_CIRCUMFLEX; - case '/': - type = TOKEN_ITALIC_CORRECTION; - return; - case ',': - type = TOKEN_NODE; - nd = new left_italic_corrected_node; - return; - case '&': - goto ESCAPE_AMPERSAND; - case ')': - goto ESCAPE_RIGHT_PARENTHESIS; - case '!': - goto ESCAPE_BANG; - case '?': - goto ESCAPE_QUESTION; - case '~': - nd = new unbreakable_space_node(curenv->get_space_width()); - type = TOKEN_NODE; - return; - case '"': - while ((cc = input_stack::get(NULL)) != '\n' && cc != EOF) - ; - if (cc == '\n') - type = TOKEN_NEWLINE; - else - type = TOKEN_EOF; - return; - case '#': // Like \" but newline is ignored. - while ((cc = input_stack::get(NULL)) != '\n') - if (cc == EOF) { - type = TOKEN_EOF; - return; - } - break; - case '$': - { - symbol nm = read_escape_name(); - if (!nm.is_null()) - interpolate_arg(nm); - break; - } - case '*': - { - symbol nm = read_escape_name(); - if (!nm.is_null()) - interpolate_string(nm); - break; - } - case 'a': - nd = new non_interpreted_char_node('\001'); - type = TOKEN_NODE; - return; - case 'A': - c = '0' + do_name_test(); - type = TOKEN_CHAR; - return; - case 'b': - nd = do_bracket(); - type = TOKEN_NODE; - return; - case 'c': - goto ESCAPE_c; - case 'C': - nm = get_delim_name(); - if (nm.is_null()) - break; - type = TOKEN_SPECIAL; - return; - case 'd': - type = TOKEN_NODE; - nd = new vmotion_node(curenv->get_size()/2); - return; - case 'D': - nd = read_draw_node(); - if (!nd) - break; - type = TOKEN_NODE; - return; - case 'e': - goto ESCAPE_e; - case 'E': - goto handle_escape_char; - case 'f': - { - symbol s = read_escape_name(); - if (s.is_null()) - break; - const char *p; - for (p = s.contents(); *p != '\0'; p++) - if (!csdigit(*p)) - break; - if (*p) - curenv->set_font(s); - else - curenv->set_font(atoi(s.contents())); - break; - } - case 'g': - { - symbol s = read_escape_name(); - if (!s.is_null()) - interpolate_number_format(s); - break; - } - case 'h': - if (!get_delim_number(&x, 'm')) - break; - type = TOKEN_NODE; - nd = new hmotion_node(x); - return; - case 'H': - if (get_delim_number(&x, 'z', curenv->get_requested_point_size())) - curenv->set_char_height(x); - break; - case 'k': - nm = read_escape_name(); - if (nm.is_null()) - break; - type = TOKEN_MARK_INPUT; - return; - case 'l': - case 'L': - { - charinfo *s = 0; - if (!get_line_arg(&x, (cc == 'l' ? 'm': 'v'), &s)) - break; - if (s == 0) - s = get_charinfo(cc == 'l' ? "ru" : "br"); - type = TOKEN_NODE; - node *n = curenv->make_char_node(s); - if (cc == 'l') - nd = new hline_node(x, n); - else - nd = new vline_node(x, n); - return; - } - case 'n': - { - int inc; - symbol nm = read_increment_and_escape_name(&inc); - if (!nm.is_null()) - interpolate_number_reg(nm, inc); - break; - } - case 'N': - if (!get_delim_number(&val, 0)) - break; - type = TOKEN_NUMBERED_CHAR; - return; - case 'o': - nd = do_overstrike(); - type = TOKEN_NODE; - return; - case 'p': - type = TOKEN_SPREAD; - return; - case 'r': - type = TOKEN_NODE; - nd = new vmotion_node(-curenv->get_size()); - return; - case 'R': - do_register(); - break; - case 's': - if (read_size(&x)) - curenv->set_size(x); - break; - case 'S': - if (get_delim_number(&x, 0)) - curenv->set_char_slant(x); - break; - case 't': - type = TOKEN_NODE; - nd = new non_interpreted_char_node('\t'); - return; - case 'u': - type = TOKEN_NODE; - nd = new vmotion_node(-curenv->get_size()/2); - return; - case 'v': - if (!get_delim_number(&x, 'v')) - break; - type = TOKEN_NODE; - nd = new vmotion_node(x); - return; - case 'V': - { - symbol nm = read_escape_name(); - if (!nm.is_null()) - interpolate_environment_variable(nm); - break; - } - case 'w': - do_width(); - break; - case 'x': - if (!get_delim_number(&x, 'v')) - break; - type = TOKEN_NODE; - nd = new extra_size_node(x); - return; - case 'X': - nd = do_special(); - if (!nd) - break; - type = TOKEN_NODE; - return; - case 'Y': - { - symbol s = read_escape_name(); - if (s.is_null()) - break; - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) { - error("can't transparently throughput a request"); - break; - } - nd = new special_node(*m); - type = TOKEN_NODE; - return; - } - case 'z': - { - next(); - if (type == TOKEN_NODE) - nd = new zero_width_node(nd); - else { - charinfo *ci = get_char(1); - if (ci == 0) - break; - node *gn = curenv->make_char_node(ci); - if (gn == 0) - break; - nd = new zero_width_node(gn); - type = TOKEN_NODE; - } - return; - } - case 'Z': - nd = do_zero_width(); - if (nd == 0) - break; - type = TOKEN_NODE; - return; - case '{': - goto ESCAPE_LEFT_BRACE; - case '}': - goto ESCAPE_RIGHT_BRACE; - case '\n': - break; - case '[': - if (!compatible_flag) { - nm = read_long_escape_name(); - if (nm.is_null()) - break; - type = TOKEN_SPECIAL; - return; - } - goto handle_normal_char; - default: - if (cc != escape_char && cc != '.') - warning(WARN_ESCAPE, "escape character ignored before %1", - input_char_description(cc)); - goto handle_normal_char; - } - } - } -} - -int token::operator==(const token &t) -{ - if (type != t.type) - return 0; - switch(type) { - case TOKEN_CHAR: - return c == t.c; - case TOKEN_SPECIAL: - return nm == t.nm; - case TOKEN_NUMBERED_CHAR: - return val == t.val; - default: - return 1; - } -} - -int token::operator!=(const token &t) -{ - return !(*this == t); -} - -// is token a suitable delimiter (like ')? - -int token::delimiter(int err) -{ - switch(type) { - case TOKEN_CHAR: - switch(c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case '/': - case '*': - case '%': - case '<': - case '>': - case '=': - case '&': - case ':': - case '(': - case ')': - case '.': - if (err) - error("cannot use character `%1' as a starting delimiter", char(c)); - return 0; - default: - return 1; - } - case TOKEN_NODE: - case TOKEN_SPACE: - case TOKEN_TAB: - case TOKEN_NEWLINE: - if (err) - error("cannot use %1 as a starting delimiter", description()); - return 0; - default: - return 1; - } -} - -const char *token::description() -{ - static char buf[4]; - switch (type) { - case TOKEN_BACKSPACE: - return "a backspace character"; - case TOKEN_CHAR: - buf[0] = '`'; - buf[1] = c; - buf[2] = '\''; - buf[3] = '\0'; - return buf; - case TOKEN_DUMMY: - return "`\\&'"; - case TOKEN_ESCAPE: - return "`\\e'"; - case TOKEN_HYPHEN_INDICATOR: - return "`\\%'"; - case TOKEN_INTERRUPT: - return "`\\c'"; - case TOKEN_ITALIC_CORRECTION: - return "`\\/'"; - case TOKEN_LEADER: - return "a leader character"; - case TOKEN_LEFT_BRACE: - return "`\\{'"; - case TOKEN_MARK_INPUT: - return "`\\k'"; - case TOKEN_NEWLINE: - return "newline"; - case TOKEN_NODE: - return "a node"; - case TOKEN_NUMBERED_CHAR: - return "`\\N'"; - case TOKEN_RIGHT_BRACE: - return "`\\}'"; - case TOKEN_SPACE: - return "a space"; - case TOKEN_SPECIAL: - return "a special character"; - case TOKEN_SPREAD: - return "`\\p'"; - case TOKEN_TAB: - return "a tab character"; - case TOKEN_TRANSPARENT: - return "`\\!'"; - case TOKEN_EOF: - return "end of input"; - default: - break; - } - return "a magic token"; -} - -void skip_line() -{ - while (!tok.newline()) - if (tok.eof()) - return; - else - tok.next(); - tok.next(); -} - -void compatible() -{ - int n; - if (has_arg() && get_integer(&n)) - compatible_flag = n != 0; - else - compatible_flag = 1; - skip_line(); -} - -static void empty_name_warning(int required) -{ - if (tok.newline() || tok.eof()) { - if (required) - warning(WARN_MISSING, "missing name"); - } - else if (tok.right_brace() || tok.tab()) { - const char *start = tok.description(); - do { - tok.next(); - } while (tok.space() || tok.right_brace() || tok.tab()); - if (!tok.newline() && !tok.eof()) - error("%1 is not allowed before an argument", start); - else if (required) - warning(WARN_MISSING, "missing name"); - } - else if (required) - error("name expected (got %1)", tok.description()); - else - error("name expected (got %1): treated as missing", tok.description()); -} - -static void non_empty_name_warning() -{ - if (!tok.newline() && !tok.eof() && !tok.space() && !tok.tab() - && !tok.right_brace() - // We don't want to give a warning for .el\{ - && !tok.left_brace()) - error("%1 is not allowed in a name", tok.description()); -} - -symbol get_name(int required) -{ - if (compatible_flag) { - char buf[3]; - tok.skip(); - if ((buf[0] = tok.ch()) != 0) { - tok.next(); - if ((buf[1] = tok.ch()) != 0) { - buf[2] = 0; - tok.make_space(); - } - else - non_empty_name_warning(); - return symbol(buf); - } - else { - empty_name_warning(required); - return NULL_SYMBOL; - } - } - else - return get_long_name(required); -} - -symbol get_long_name(int required) -{ - while (tok.space()) - tok.next(); - char abuf[ABUF_SIZE]; - char *buf = abuf; - int buf_size = ABUF_SIZE; - int i = 0; - for (;;) { - if (i + 1 > buf_size) { - if (buf == abuf) { - buf = new char [ABUF_SIZE*2]; - memcpy(buf, abuf, buf_size); - buf_size = ABUF_SIZE*2; - } - else { - char *old_buf = buf; - buf = new char[buf_size*2]; - memcpy(buf, old_buf, buf_size); - buf_size *= 2; - a_delete old_buf; - } - } - if ((buf[i] = tok.ch()) == 0) - break; - i++; - tok.next(); - } - if (i == 0) { - empty_name_warning(required); - return NULL_SYMBOL; - } - non_empty_name_warning(); - if (buf == abuf) - return symbol(buf); - else { - symbol s(buf); - a_delete buf; - return s; - } -} - -void exit_troff() -{ - exit_started = 1; - topdiv->set_last_page(); - if (!end_macro_name.is_null()) { - spring_trap(end_macro_name); - tok.next(); - process_input_stack(); - } - curenv->final_break(); - tok.next(); - process_input_stack(); - end_diversions(); - done_end_macro = 1; - topdiv->set_ejecting(); - static unsigned char buf[2] = { LAST_PAGE_EJECTOR, '\0' }; - input_stack::push(make_temp_iterator((char *)buf)); - topdiv->space(topdiv->get_page_length(), 1); - tok.next(); - process_input_stack(); - seen_last_page_ejector = 1; // should be set already - topdiv->set_ejecting(); - push_page_ejector(); - topdiv->space(topdiv->get_page_length(), 1); - tok.next(); - process_input_stack(); - // This will only happen if a trap-invoked macro starts a diversion, - // or if vertical position traps have been disabled. - cleanup_and_exit(0); -} - -// This implements .ex. The input stack must be cleared before calling -// exit_troff(). - -void exit_request() -{ - input_stack::clear(); - if (exit_started) - tok.next(); - else - exit_troff(); -} - -void end_macro() -{ - end_macro_name = get_name(); - skip_line(); -} - -void blank_line_macro() -{ - blank_line_macro_name = get_name(); - skip_line(); -} - -static void trapping_blank_line() -{ - if (!blank_line_macro_name.is_null()) - spring_trap(blank_line_macro_name); - else - blank_line(); -} - -void do_request() -{ - int saved_compatible_flag = compatible_flag; - compatible_flag = 0; - symbol nm = get_name(); - if (nm.is_null()) - skip_line(); - else - interpolate_macro(nm); - compatible_flag = saved_compatible_flag; -} - -inline int possibly_handle_first_page_transition() -{ - if (topdiv->before_first_page && curdiv == topdiv && !curenv->is_dummy()) { - handle_first_page_transition(); - return 1; - } - else - return 0; -} - -static int transparent_translate(int cc) -{ - if (!illegal_input_char(cc)) { - charinfo *ci = charset_table[cc]; - switch (ci->get_special_translation(1)) { - case charinfo::TRANSLATE_SPACE: - return ' '; - case charinfo::TRANSLATE_DUMMY: - return ESCAPE_AMPERSAND; - case charinfo::TRANSLATE_HYPHEN_INDICATOR: - return ESCAPE_PERCENT; - } - // This is really ugly. - ci = ci->get_translation(1); - if (ci) { - int c = ci->get_ascii_code(); - if (c != '\0') - return c; - error("can't translate %1 to special character `%2'" - " in transparent throughput", - input_char_description(cc), - ci->nm.contents()); - } - } - return cc; -} - -class int_stack { - struct int_stack_element { - int n; - int_stack_element *next; - } *top; -public: - int_stack(); - ~int_stack(); - void push(int); - int is_empty(); - int pop(); -}; - -int_stack::int_stack() -{ - top = 0; -} - -int_stack::~int_stack() -{ - while (top != 0) { - int_stack_element *temp = top; - top = top->next; - delete temp; - } - -} - -int int_stack::is_empty() -{ - return top == 0; -} - -void int_stack::push(int n) -{ - int_stack_element *p = new int_stack_element; - p->next = top; - p->n = n; - top = p; -} - - -int int_stack::pop() -{ - assert(top != 0); - int_stack_element *p = top; - top = top->next; - int n = p->n; - delete p; - return n; -} - -int node::reread(int *) -{ - return 0; -} - -int diverted_space_node::reread(int *bolp) -{ - if (curenv->get_fill()) - trapping_blank_line(); - else - curdiv->space(n); - *bolp = 1; - return 1; -} - -int diverted_copy_file_node::reread(int *bolp) -{ - curdiv->copy_file(filename.contents()); - *bolp = 1; - return 1; -} - -void process_input_stack() -{ - int_stack trap_bol_stack; - int bol = 1; - for (;;) { - int suppress_next = 0; - switch (tok.type) { - case token::TOKEN_CHAR: - { - unsigned char ch = tok.c; - if (bol && - (ch == curenv->control_char - || ch == curenv->no_break_control_char)) { - break_flag = ch == curenv->control_char; - // skip tabs as well as spaces here - do { - tok.next(); - } while (tok.white_space()); - symbol nm = get_name(); - if (nm.is_null()) - skip_line(); - else - interpolate_macro(nm); - suppress_next = 1; - } - else { - if (possibly_handle_first_page_transition()) - ; - else { - for (;;) { - curenv->add_char(charset_table[ch]); - tok.next(); - if (tok.type != token::TOKEN_CHAR) - break; - ch = tok.c; - } - suppress_next = 1; - bol = 0; - } - } - break; - } - case token::TOKEN_TRANSPARENT: - { - if (bol) { - if (possibly_handle_first_page_transition()) - ; - else { - int cc; - do { - node *n; - cc = get_copy(&n); - if (cc != EOF) - if (cc != '\0') - curdiv->transparent_output(transparent_translate(cc)); - else - curdiv->transparent_output(n); - } while (cc != '\n' && cc != EOF); - if (cc == EOF) - curdiv->transparent_output('\n'); - } - } - break; - } - case token::TOKEN_NEWLINE: - { - if (bol && !curenv->get_prev_line_interrupted()) - trapping_blank_line(); - else { - curenv->newline(); - bol = 1; - } - break; - } - case token::TOKEN_REQUEST: - { - int request_code = tok.c; - tok.next(); - switch (request_code) { - case TITLE_REQUEST: - title(); - break; - case COPY_FILE_REQUEST: - copy_file(); - break; - case TRANSPARENT_FILE_REQUEST: - transparent_file(); - break; -#ifdef COLUMN - case VJUSTIFY_REQUEST: - vjustify(); - break; -#endif /* COLUMN */ - default: - assert(0); - break; - } - suppress_next = 1; - break; - } - case token::TOKEN_SPACE: - { - if (possibly_handle_first_page_transition()) - ; - else if (bol && !curenv->get_prev_line_interrupted()) { - int nspaces = 0; - do { - nspaces += tok.nspaces(); - tok.next(); - } while (tok.space()); - if (tok.newline()) - trapping_blank_line(); - else { - push_token(tok); - curenv->do_break(); - curenv->add_node(new hmotion_node(curenv->get_space_width()*nspaces)); - bol = 0; - } - } - else { - curenv->space(); - bol = 0; - } - break; - } - case token::TOKEN_EOF: - return; - case token::TOKEN_NODE: - { - if (possibly_handle_first_page_transition()) - ; - else if (tok.nd->reread(&bol)) { - delete tok.nd; - tok.nd = 0; - } - else { - curenv->add_node(tok.nd); - tok.nd = 0; - bol = 0; - } - break; - } - case token::TOKEN_PAGE_EJECTOR: - { - continue_page_eject(); - // I think we just want to preserve bol. - // bol = 1; - break; - } - case token::TOKEN_BEGIN_TRAP: - { - trap_bol_stack.push(bol); - bol = 1; - break; - } - case token::TOKEN_END_TRAP: - { - if (trap_bol_stack.is_empty()) - error("spurious end trap token detected!"); - else - bol = trap_bol_stack.pop(); - - /* I'm not totally happy about this. But I can't think of any other - way to do it. Doing an output_pending_lines() whenever a - TOKEN_END_TRAP is detected doesn't work: for example, - - .wh -1i x - .de x - 'bp - .. - .wh -.5i y - .de y - .tl ''-%-'' - .. - .br - .ll .5i - .sp |\n(.pu-1i-.5v - a\%very\%very\%long\%word - - will print all but the first lines from the word immediately - after the footer, rather than on the next page. */ - - if (trap_bol_stack.is_empty()) - curenv->output_pending_lines(); - break; - } - default: - { - bol = 0; - tok.process(); - break; - } - } - if (!suppress_next) - tok.next(); - trap_sprung_flag = 0; - } -} - -#ifdef WIDOW_CONTROL - -void flush_pending_lines() -{ - while (!tok.newline() && !tok.eof()) - tok.next(); - curenv->output_pending_lines(); - tok.next(); -} - -#endif /* WIDOW_CONTROL */ - -request_or_macro::request_or_macro() -{ -} - -macro *request_or_macro::to_macro() -{ - return 0; -} - -request::request(REQUEST_FUNCP pp) : p(pp) -{ -} - -void request::invoke(symbol) -{ - (*p)(); -} - -struct char_block { - enum { SIZE = 128 }; - unsigned char s[SIZE]; - char_block *next; - char_block(); -}; - -char_block::char_block() -: next(0) -{ -} - -class char_list { -public: - char_list(); - ~char_list(); - void append(unsigned char); - int length(); -private: - unsigned char *ptr; - int len; - char_block *head; - char_block *tail; - friend class macro_header; - friend class string_iterator; -}; - -char_list::char_list() -: ptr(0), len(0), head(0), tail(0) -{ -} - -char_list::~char_list() -{ - while (head != 0) { - char_block *tem = head; - head = head->next; - delete tem; - } -} - -int char_list::length() -{ - return len; -} - -void char_list::append(unsigned char c) -{ - if (tail == 0) { - head = tail = new char_block; - ptr = tail->s; - } - else { - if (ptr >= tail->s + char_block::SIZE) { - tail->next = new char_block; - tail = tail->next; - ptr = tail->s; - } - } - *ptr++ = c; - len++; -} - -class node_list { - node *head; - node *tail; -public: - node_list(); - ~node_list(); - void append(node *); - int length(); - node *extract(); - - friend class macro_header; - friend class string_iterator; -}; - -void node_list::append(node *n) -{ - if (head == 0) { - n->next = 0; - head = tail = n; - } - else { - n->next = 0; - tail = tail->next = n; - } -} - -int node_list::length() -{ - int total = 0; - for (node *n = head; n != 0; n = n->next) - ++total; - return total; -} - -node_list::node_list() -{ - head = tail = 0; -} - -node *node_list::extract() -{ - node *temp = head; - head = tail = 0; - return temp; -} - - -node_list::~node_list() -{ - delete_node_list(head); -} - -struct macro_header { -public: - int count; - char_list cl; - node_list nl; - macro_header() { count = 1; } - macro_header *copy(int); -}; - - -macro::~macro() -{ - if (p != 0 && --(p->count) <= 0) - delete p; -} - -macro::macro() -{ - if (!input_stack::get_location(1, &filename, &lineno)) { - filename = 0; - lineno = 0; - } - length = 0; - p = 0; -} - -macro::macro(const macro &m) -: p(m.p), filename(m.filename), lineno(m.lineno), length(m.length) -{ - if (p != 0) - p->count++; -} - -macro ¯o::operator=(const macro &m) -{ - // don't assign object - if (m.p != 0) - m.p->count++; - if (p != 0 && --(p->count) <= 0) - delete p; - p = m.p; - filename = m.filename; - lineno = m.lineno; - length = m.length; - return *this; -} - -void macro::append(unsigned char c) -{ - assert(c != 0); - if (p == 0) - p = new macro_header; - if (p->cl.length() != length) { - macro_header *tem = p->copy(length); - if (--(p->count) <= 0) - delete p; - p = tem; - } - p->cl.append(c); - ++length; -} - -void macro::append(node *n) -{ - assert(n != 0); - if (p == 0) - p = new macro_header; - if (p->cl.length() != length) { - macro_header *tem = p->copy(length); - if (--(p->count) <= 0) - delete p; - p = tem; - } - p->cl.append(0); - p->nl.append(n); - ++length; -} - -void macro::print_size() -{ - errprint("%1", length); -} - -// make a copy of the first n bytes - -macro_header *macro_header::copy(int n) -{ - macro_header *p = new macro_header; - char_block *bp = cl.head; - unsigned char *ptr = bp->s; - node *nd = nl.head; - while (--n >= 0) { - if (ptr >= bp->s + char_block::SIZE) { - bp = bp->next; - ptr = bp->s; - } - int c = *ptr++; - p->cl.append(c); - if (c == 0) { - p->nl.append(nd->copy()); - nd = nd->next; - } - } - return p; -} - -void print_macros() -{ - object_dictionary_iterator iter(request_dictionary); - request_or_macro *rm; - symbol s; - while (iter.get(&s, (object **)&rm)) { - assert(!s.is_null()); - macro *m = rm->to_macro(); - if (m) { - errprint("%1\t", s.contents()); - m->print_size(); - errprint("\n"); - } - } - fflush(stderr); - skip_line(); -} - -class string_iterator : public input_iterator { - macro mac; - const char *how_invoked; - int newline_flag; - int lineno; - char_block *bp; - int count; // of characters remaining - node *nd; -protected: - symbol nm; - string_iterator(); -public: - string_iterator(const macro &m, const char *p = 0, symbol s = NULL_SYMBOL); - int fill(node **); - int peek(); - int get_location(int, const char **, int *); - void backtrace(); -}; - -string_iterator::string_iterator(const macro &m, const char *p, symbol s) -: mac(m), how_invoked(p), newline_flag(0), lineno(1), nm(s) -{ - count = mac.length; - if (count != 0) { - bp = mac.p->cl.head; - nd = mac.p->nl.head; - ptr = eptr = bp->s; - } - else { - bp = 0; - nd = 0; - ptr = eptr = 0; - } -} - -string_iterator::string_iterator() -{ - bp = 0; - nd = 0; - ptr = eptr = 0; - newline_flag = 0; - how_invoked = 0; - lineno = 1; - count = 0; -} - -int string_iterator::fill(node **np) -{ - if (newline_flag) - lineno++; - newline_flag = 0; - if (count <= 0) - return EOF; - const unsigned char *p = eptr; - if (p >= bp->s + char_block::SIZE) { - bp = bp->next; - p = bp->s; - } - if (*p == '\0') { - if (np) - *np = nd->copy(); - nd = nd->next; - eptr = ptr = p + 1; - count--; - return 0; - } - const unsigned char *e = bp->s + char_block::SIZE; - if (e - p > count) - e = p + count; - ptr = p; - while (p < e) { - unsigned char c = *p; - if (c == '\n' || c == ESCAPE_NEWLINE) { - newline_flag = 1; - p++; - break; - } - if (c == '\0') - break; - p++; - } - eptr = p; - count -= p - ptr; - return *ptr++; -} - -int string_iterator::peek() -{ - if (count <= 0) - return EOF; - const unsigned char *p = eptr; - if (count <= 0) - return EOF; - if (p >= bp->s + char_block::SIZE) { - p = bp->next->s; - } - return *p; -} - -int string_iterator::get_location(int allow_macro, - const char **filep, int *linep) -{ - if (!allow_macro) - return 0; - if (mac.filename == 0) - return 0; - *filep = mac.filename; - *linep = mac.lineno + lineno - 1; - return 1; -} - -void string_iterator::backtrace() -{ - if (mac.filename) { - errprint("%1:%2: backtrace", mac.filename, mac.lineno + lineno - 1); - if (how_invoked) { - if (!nm.is_null()) - errprint(": %1 `%2'\n", how_invoked, nm.contents()); - else - errprint(": %1\n", how_invoked); - } - else - errprint("\n"); - } -} - -class temp_iterator : public input_iterator { - unsigned char *base; - temp_iterator(const char *, int len); -public: - ~temp_iterator(); - friend input_iterator *make_temp_iterator(const char *); -}; - -#ifdef __GNUG__ -inline -#endif -temp_iterator::temp_iterator(const char *s, int len) -{ - base = new unsigned char[len]; - memcpy(base, s, len); - ptr = base; - eptr = base + len; -} - -temp_iterator::~temp_iterator() -{ - a_delete base; -} - -class small_temp_iterator : public input_iterator { -private: - small_temp_iterator(const char *, int); - ~small_temp_iterator(); - enum { BLOCK = 16 }; - static small_temp_iterator *free_list; - void *operator new(size_t); - void operator delete(void *); - enum { SIZE = 12 }; - unsigned char buf[SIZE]; - friend input_iterator *make_temp_iterator(const char *); -}; - -small_temp_iterator *small_temp_iterator::free_list = 0; - -void *small_temp_iterator::operator new(size_t n) -{ - assert(n == sizeof(small_temp_iterator)); - if (!free_list) { - free_list = (small_temp_iterator *)new char[sizeof(small_temp_iterator)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - small_temp_iterator *p = free_list; - free_list = (small_temp_iterator *)(free_list->next); - p->next = 0; - return p; -} - -#ifdef __GNUG__ -inline -#endif -void small_temp_iterator::operator delete(void *p) -{ - if (p) { - ((small_temp_iterator *)p)->next = free_list; - free_list = (small_temp_iterator *)p; - } -} - -small_temp_iterator::~small_temp_iterator() -{ -} - - -#ifdef __GNUG__ -inline -#endif -small_temp_iterator::small_temp_iterator(const char *s, int len) -{ - for (int i = 0; i < len; i++) - buf[i] = s[i]; - ptr = buf; - eptr = buf + len; -} - -input_iterator *make_temp_iterator(const char *s) -{ - if (s == 0) - return new small_temp_iterator(s, 0); - else { - int n = strlen(s); - if (n <= small_temp_iterator::SIZE) - return new small_temp_iterator(s, n); - else - return new temp_iterator(s, n); - } -} - -// this is used when macros are interpolated using the .macro_name notation - -struct arg_list { - macro mac; - arg_list *next; - arg_list(const macro &); - ~arg_list(); -}; - -arg_list::arg_list(const macro &m) : mac(m), next(0) -{ -} - -arg_list::~arg_list() -{ -} - -class macro_iterator : public string_iterator { - arg_list *args; - int argc; -public: - macro_iterator(symbol, macro &, const char *how_invoked = "macro"); - macro_iterator(); - ~macro_iterator(); - int has_args() { return 1; } - input_iterator *get_arg(int i); - int nargs() { return argc; } - void add_arg(const macro &m); - void shift(int n); -}; - -input_iterator *macro_iterator::get_arg(int i) -{ - if (i == 0) - return make_temp_iterator(nm.contents()); - if (i > 0 && i <= argc) { - arg_list *p = args; - for (int j = 1; j < i; j++) { - assert(p != 0); - p = p->next; - } - return new string_iterator(p->mac); - } - else - return 0; -} - -void macro_iterator::add_arg(const macro &m) -{ - arg_list **p; - for (p = &args; *p; p = &((*p)->next)) - ; - *p = new arg_list(m); - ++argc; -} - -void macro_iterator::shift(int n) -{ - while (n > 0 && argc > 0) { - arg_list *tem = args; - args = args->next; - delete tem; - --argc; - --n; - } -} - -// This gets used by eg .if '\?xxx\?''. - -int operator==(const macro &m1, const macro &m2) -{ - if (m1.length != m2.length) - return 0; - string_iterator iter1(m1); - string_iterator iter2(m2); - int n = m1.length; - while (--n >= 0) { - node *nd1 = 0; - int c1 = iter1.get(&nd1); - assert(c1 != EOF); - node *nd2 = 0; - int c2 = iter2.get(&nd2); - assert(c2 != EOF); - if (c1 != c2) { - if (c1 == 0) - delete nd1; - else if (c2 == 0) - delete nd2; - return 0; - } - if (c1 == 0) { - assert(nd1 != 0); - assert(nd2 != 0); - int are_same = nd1->type() == nd2->type() && nd1->same(nd2); - delete nd1; - delete nd2; - if (!are_same) - return 0; - } - } - return 1; -} - -static void interpolate_macro(symbol nm) -{ - request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm); - if (p == 0) { - int warned = 0; - const char *s = nm.contents(); - if (strlen(s) > 2) { - request_or_macro *r; - char buf[3]; - buf[0] = s[0]; - buf[1] = s[1]; - buf[2] = '\0'; - r = (request_or_macro *)request_dictionary.lookup(symbol(buf)); - if (r) { - macro *m = r->to_macro(); - if (!m || !m->empty()) - warned = warning(WARN_SPACE, - "`%1' not defined (probable missing space after `%2')", - nm.contents(), buf); - } - } - if (!warned) { - warning(WARN_MAC, "`%1' not defined", nm.contents()); - p = new macro; - request_dictionary.define(nm, p); - } - } - if (p) - p->invoke(nm); - else { - skip_line(); - return; - } -} - -static void decode_args(macro_iterator *mi) -{ - if (!tok.newline() && !tok.eof()) { - node *n; - int c = get_copy(&n); - for (;;) { - while (c == ' ') - c = get_copy(&n); - if (c == '\n' || c == EOF) - break; - macro arg; - int quote_input_level = 0; - int done_tab_warning = 0; - if (c == '\"') { - quote_input_level = input_stack::get_level(); - c = get_copy(&n); - } - while (c != EOF && c != '\n' && !(c == ' ' && quote_input_level == 0)) { - if (quote_input_level > 0 && c == '\"' - && (compatible_flag - || input_stack::get_level() == quote_input_level)) { - c = get_copy(&n); - if (c == '"') { - arg.append(c); - c = get_copy(&n); - } - else - break; - } - else { - if (c == 0) - arg.append(n); - else { - if (c == '\t' && quote_input_level == 0 && !done_tab_warning) { - warning(WARN_TAB, "tab character in unquoted macro argument"); - done_tab_warning = 1; - } - arg.append(c); - } - c = get_copy(&n); - } - } - mi->add_arg(arg); - } - } -} - -void macro::invoke(symbol nm) -{ - macro_iterator *mi = new macro_iterator(nm, *this); - decode_args(mi); - input_stack::push(mi); - tok.next(); -} - -macro *macro::to_macro() -{ - return this; -} - -int macro::empty() -{ - return length == 0; -} - -macro_iterator::macro_iterator(symbol s, macro &m, const char *how_invoked) -: string_iterator(m, how_invoked, s), args(0), argc(0) -{ -} - -macro_iterator::macro_iterator() : args(0), argc(0) -{ -} - -macro_iterator::~macro_iterator() -{ - while (args != 0) { - arg_list *tem = args; - args = args->next; - delete tem; - } -} - -int trap_sprung_flag = 0; -int postpone_traps_flag = 0; -symbol postponed_trap; - -void spring_trap(symbol nm) -{ - assert(!nm.is_null()); - trap_sprung_flag = 1; - if (postpone_traps_flag) { - postponed_trap = nm; - return; - } - static char buf[2] = { BEGIN_TRAP, 0 }; - static char buf2[2] = { END_TRAP, '\0' }; - input_stack::push(make_temp_iterator(buf2)); - request_or_macro *p = lookup_request(nm); - macro *m = p->to_macro(); - if (m) - input_stack::push(new macro_iterator(nm, *m, "trap-invoked macro")); - else - error("you can't invoke a request with a trap"); - input_stack::push(make_temp_iterator(buf)); -} - -void postpone_traps() -{ - postpone_traps_flag = 1; -} - -int unpostpone_traps() -{ - postpone_traps_flag = 0; - if (!postponed_trap.is_null()) { - spring_trap(postponed_trap); - postponed_trap = NULL_SYMBOL; - return 1; - } - else - return 0; -} - -void read_request() -{ - macro_iterator *mi = new macro_iterator; - int reading_from_terminal = isatty(fileno(stdin)); - int had_prompt = 0; - if (!tok.newline() && !tok.eof()) { - int c = get_copy(NULL); - while (c == ' ') - c = get_copy(NULL); - while (c != EOF && c != '\n' && c != ' ') { - if (!illegal_input_char(c)) { - if (reading_from_terminal) - fputc(c, stderr); - had_prompt = 1; - } - c = get_copy(NULL); - } - if (c == ' ') { - tok.make_space(); - decode_args(mi); - } - } - if (reading_from_terminal) { - fputc(had_prompt ? ':' : '\a', stderr); - fflush(stderr); - } - input_stack::push(mi); - macro mac; - int nl = 0; - int c; - while ((c = getchar()) != EOF) { - if (illegal_input_char(c)) - warning(WARN_INPUT, "illegal input character code %1", int(c)); - else { - if (c == '\n') { - if (nl) - break; - else - nl = 1; - } - else - nl = 0; - mac.append(c); - } - } - if (reading_from_terminal) - clearerr(stdin); - input_stack::push(new string_iterator(mac)); - tok.next(); -} - -void do_define_string(int append) -{ - symbol nm; - node *n; - int c; - nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - if (tok.newline()) - c = '\n'; - else if (tok.tab()) - c = '\t'; - else if (!tok.space()) { - error("bad string definition"); - skip_line(); - return; - } - else - c = get_copy(&n); - while (c == ' ') - c = get_copy(&n); - if (c == '"') - c = get_copy(&n); - macro mac; - request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm); - macro *mm = rm ? rm->to_macro() : 0; - if (append && mm) - mac = *mm; - while (c != '\n' && c != EOF) { - if (c == 0) - mac.append(n); - else - mac.append((unsigned char)c); - c = get_copy(&n); - } - if (!mm) { - mm = new macro; - request_dictionary.define(nm, mm); - } - *mm = mac; - tok.next(); -} - -void define_string() -{ - do_define_string(0); -} - -void append_string() -{ - do_define_string(1); -} - -void define_character() -{ - node *n; - int c; - tok.skip(); - charinfo *ci = tok.get_char(1); - if (ci == 0) { - skip_line(); - return; - } - tok.next(); - if (tok.newline()) - c = '\n'; - else if (tok.tab()) - c = '\t'; - else if (!tok.space()) { - error("bad character definition"); - skip_line(); - return; - } - else - c = get_copy(&n); - while (c == ' ' || c == '\t') - c = get_copy(&n); - if (c == '"') - c = get_copy(&n); - macro *m = new macro; - while (c != '\n' && c != EOF) { - if (c == 0) - m->append(n); - else - m->append((unsigned char)c); - c = get_copy(&n); - } - m = ci->set_macro(m); - if (m) - delete m; - tok.next(); -} - - -static void remove_character() -{ - tok.skip(); - while (!tok.newline() && !tok.eof()) { - if (!tok.space() && !tok.tab()) { - charinfo *ci = tok.get_char(1); - if (!ci) - break; - macro *m = ci->set_macro(0); - if (m) - delete m; - } - tok.next(); - } - skip_line(); -} - -static void interpolate_string(symbol nm) -{ - request_or_macro *p = lookup_request(nm); - macro *m = p->to_macro(); - if (!m) - error("you can only invoke a string using \\*"); - else { - string_iterator *si = new string_iterator(*m, "string", nm); - input_stack::push(si); - } -} - -/* This class is used for the implementation of \$@. It is used for -each of the closing double quotes. It artificially increases the -input level by 2, so that the closing double quote will appear to have -the same input level as the opening quote. */ - -class end_quote_iterator : public input_iterator { - unsigned char buf[1]; -public: - end_quote_iterator(); - ~end_quote_iterator() { } - int internal_level() { return 2; } -}; - -end_quote_iterator::end_quote_iterator() -{ - buf[0] = '"'; - ptr = buf; - eptr = buf + 1; -} - -static void interpolate_arg(symbol nm) -{ - const char *s = nm.contents(); - if (!s || *s == '\0') - copy_mode_error("missing argument name"); - else if (s[1] == 0 && csdigit(s[0])) - input_stack::push(input_stack::get_arg(s[0] - '0')); - else if (s[0] == '*' && s[1] == '\0') { - for (int i = input_stack::nargs(); i > 0; i--) { - input_stack::push(input_stack::get_arg(i)); - if (i != 1) - input_stack::push(make_temp_iterator(" ")); - } - } - else if (s[0] == '@' && s[1] == '\0') { - for (int i = input_stack::nargs(); i > 0; i--) { - input_stack::push(new end_quote_iterator); - input_stack::push(input_stack::get_arg(i)); - input_stack::push(make_temp_iterator(i == 1 ? "\"" : " \"")); - } - } - else { - const char *p; - for (p = s; *p && csdigit(*p); p++) - ; - if (*p) - copy_mode_error("bad argument name `%1'", s); - else - input_stack::push(input_stack::get_arg(atoi(s))); - } -} - -void handle_first_page_transition() -{ - push_token(tok); - topdiv->begin_page(); -} - -// We push back a token by wrapping it up in a token_node, and -// wrapping that up in a string_iterator. - -static void push_token(const token &t) -{ - macro m; - m.append(new token_node(t)); - input_stack::push(new string_iterator(m)); -} - -void push_page_ejector() -{ - static char buf[2] = { PAGE_EJECTOR, '\0' }; - input_stack::push(make_temp_iterator(buf)); -} - -void handle_initial_request(unsigned char code) -{ - char buf[2]; - buf[0] = code; - buf[1] = '\0'; - macro mac; - mac.append(new token_node(tok)); - input_stack::push(new string_iterator(mac)); - input_stack::push(make_temp_iterator(buf)); - topdiv->begin_page(); - tok.next(); -} - -void handle_initial_title() -{ - handle_initial_request(TITLE_REQUEST); -} - -// this should be local to define_macro, but cfront 1.2 doesn't support that -static symbol dot_symbol("."); - -enum define_mode { DEFINE_NORMAL, DEFINE_APPEND, DEFINE_IGNORE }; - -void do_define_macro(define_mode mode) -{ - symbol nm; - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - } - symbol term = get_name(); // the request that terminates the definition - if (term.is_null()) - term = dot_symbol; - while (!tok.newline() && !tok.eof()) - tok.next(); - const char *start_filename; - int start_lineno; - int have_start_location = input_stack::get_location(0, &start_filename, - &start_lineno); - node *n; - // doing this here makes the line numbers come out right - int c = get_copy(&n, 1); - macro mac; - macro *mm = 0; - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - request_or_macro *rm = - (request_or_macro *)request_dictionary.lookup(nm); - if (rm) - mm = rm->to_macro(); - if (mm && mode == DEFINE_APPEND) - mac = *mm; - } - int bol = 1; - for (;;) { - while (c == ESCAPE_NEWLINE) { - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) - mac.append(c); - c = get_copy(&n, 1); - } - if (bol && c == '.') { - const char *s = term.contents(); - int d; - // see if it matches term - int i; - for (i = 0; s[i] != 0; i++) { - d = get_copy(&n); - if ((unsigned char)s[i] != d) - break; - } - if (s[i] == 0 - && ((i == 2 && compatible_flag) - || (d = get_copy(&n)) == ' ' - || d == '\n')) { // we found it - if (d == '\n') - tok.make_newline(); - else - tok.make_space(); - if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { - if (!mm) { - mm = new macro; - request_dictionary.define(nm, mm); - } - *mm = mac; - } - if (term != dot_symbol) { - ignoring = 0; - interpolate_macro(term); - } - else - skip_line(); - return; - } - if (mode == DEFINE_APPEND || mode == DEFINE_NORMAL) { - mac.append(c); - for (int j = 0; j < i; j++) - mac.append(s[j]); - } - c = d; - } - if (c == EOF) { - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - if (have_start_location) - error_with_file_and_line(start_filename, start_lineno, - "end of file while defining macro `%1'", - nm.contents()); - else - error("end of file while defining macro `%1'", nm.contents()); - } - else { - if (have_start_location) - error_with_file_and_line(start_filename, start_lineno, - "end of file while ignoring input lines"); - else - error("end of file while ignoring input lines"); - } - tok.next(); - return; - } - if (mode == DEFINE_NORMAL || mode == DEFINE_APPEND) { - if (c == 0) - mac.append(n); - else - mac.append(c); - } - bol = (c == '\n'); - c = get_copy(&n, 1); - } -} - -void define_macro() -{ - do_define_macro(DEFINE_NORMAL); -} - -void append_macro() -{ - do_define_macro(DEFINE_APPEND); -} - -void ignore() -{ - ignoring = 1; - do_define_macro(DEFINE_IGNORE); - ignoring = 0; -} - -void remove_macro() -{ - for (;;) { - symbol s = get_name(); - if (s.is_null()) - break; - request_dictionary.remove(s); - } - skip_line(); -} - -void rename_macro() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) - request_dictionary.rename(s1, s2); - } - skip_line(); -} - -void alias_macro() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) { - if (!request_dictionary.alias(s1, s2)) - warning(WARN_MAC, "`%1' not defined", s2.contents()); - } - } - skip_line(); -} - -void chop_macro() -{ - symbol s = get_name(1); - if (!s.is_null()) { - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot chop request"); - else if (m->length == 0) - error("cannot chop empty macro"); - else - m->length -= 1; - } - skip_line(); -} - -void substring_macro() -{ - int start; - symbol s = get_name(1); - if (!s.is_null() && get_integer(&start)) { - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot substring request"); - else { - if (start <= 0) - start += m->length; - else - start--; - int end = 0; - if (!has_arg() || get_integer(&end)) { - if (end <= 0) - end += m->length; - else - end--; - if (start > end) { - int tem = start; - start = end; - end = tem; - } - if (start >= m->length || start == end) { - m->length = 0; - if (m->p) { - if (--(m->p->count) <= 0) - delete m->p; - m->p = 0; - } - } - else if (start == 0) - m->length = end; - else { - string_iterator iter(*m); - int i; - for (i = 0; i < start; i++) - if (iter.get(0) == EOF) - break; - macro mac; - for (; i < end; i++) { - node *nd; - int c = iter.get(&nd); - if (c == EOF) - break; - if (c == 0) - mac.append(nd); - else - mac.append((unsigned char)c); - } - *m = mac; - } - } - } - } - skip_line(); -} - -void length_macro() -{ - symbol ret; - ret = get_name(1); - if (ret.is_null()) { - skip_line(); - return; - } - int c; - node *n; - if (tok.newline()) - c = '\n'; - else if (tok.tab()) - c = '\t'; - else if (!tok.space()) { - error("bad string definition"); - skip_line(); - return; - } - else - c = get_copy(&n); - while (c == ' ') - c = get_copy(&n); - if (c == '"') - c = get_copy(&n); - int len = 0; - while (c != '\n' && c != EOF) { - ++len; - c = get_copy(&n); - } - tok.next(); - reg *r = (reg*)number_reg_dictionary.lookup(ret); - if (r) - r->set_value(len); - else - set_number_reg(ret, len); -} - -void asciify_macro() -{ - symbol s = get_name(1); - if (!s.is_null()) { - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot asciify request"); - else { - macro am; - string_iterator iter(*m); - for (;;) { - node *nd; - int c = iter.get(&nd); - if (c == EOF) - break; - if (c != 0) - am.append(c); - else - nd->asciify(&am); - } - *m = am; - } - } - skip_line(); -} - -static void interpolate_environment_variable(symbol nm) -{ - const char *s = getenv(nm.contents()); - if (s && *s) - input_stack::push(make_temp_iterator(s)); -} - -void interpolate_number_reg(symbol nm, int inc) -{ - reg *r = lookup_number_reg(nm); - if (inc < 0) - r->decrement(); - else if (inc > 0) - r->increment(); - input_stack::push(make_temp_iterator(r->get_string())); -} - -static void interpolate_number_format(symbol nm) -{ - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r) - input_stack::push(make_temp_iterator(r->get_format())); -} - -static int get_delim_number(units *n, int si, int prev_value) -{ - token start; - start.next(); - if (start.delimiter(1)) { - tok.next(); - if (get_number(n, si, prev_value)) { - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - return 1; - } - } - return 0; -} - -static int get_delim_number(units *n, int si) -{ - token start; - start.next(); - if (start.delimiter(1)) { - tok.next(); - if (get_number(n, si)) { - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - return 1; - } - } - return 0; -} - -static int get_line_arg(units *n, int si, charinfo **cp) -{ - token start; - start.next(); - if (start.delimiter(1)) { - tok.next(); - if (get_number(n, si)) { - if (tok.dummy()) - tok.next(); - if (start != tok) { - *cp = tok.get_char(1); - tok.next(); - } - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - return 1; - } - } - return 0; -} - -static int read_size(int *x) -{ - tok.next(); - int c = tok.ch(); - int inc = 0; - if (c == '-') { - inc = -1; - tok.next(); - c = tok.ch(); - } - else if (c == '+') { - inc = 1; - tok.next(); - c = tok.ch(); - } - int val; - int bad = 0; - if (c == '(') { - tok.next(); - c = tok.ch(); - if (!inc) { - // allow an increment either before or after the left parenthesis - if (c == '-') { - inc = -1; - tok.next(); - c = tok.ch(); - } - else if (c == '+') { - inc = 1; - tok.next(); - c = tok.ch(); - } - } - if (!csdigit(c)) - bad = 1; - else { - val = c - '0'; - tok.next(); - c = tok.ch(); - if (!csdigit(c)) - bad = 1; - else { - val = val*10 + (c - '0'); - val *= sizescale; - } - } - } - else if (csdigit(c)) { - val = c - '0'; - if (!inc && c != '0' && c < '4') { - tok.next(); - c = tok.ch(); - if (!csdigit(c)) - bad = 1; - else - val = val*10 + (c - '0'); - } - val *= sizescale; - } - else if (!tok.delimiter(1)) - return 0; - else { - token start(tok); - tok.next(); - if (!(inc - ? get_number(&val, 'z') - : get_number(&val, 'z', curenv->get_requested_point_size()))) - return 0; - if (!(start.ch() == '[' && tok.ch() == ']') && start != tok) { - if (start.ch() == '[') - error("missing `]'"); - else - error("missing closing delimiter"); - return 0; - } - } - if (!bad) { - switch (inc) { - case 0: - *x = val; - break; - case 1: - *x = curenv->get_requested_point_size() + val; - break; - case -1: - *x = curenv->get_requested_point_size() - val; - break; - default: - assert(0); - } - return 1; - } - else { - error("bad digit in point size"); - return 0; - } -} - -static symbol get_delim_name() -{ - token start; - start.next(); - if (start.eof()) { - error("end of input at start of delimited name"); - return NULL_SYMBOL; - } - if (start.newline()) { - error("can't delimit name with a newline"); - return NULL_SYMBOL; - } - int start_level = input_stack::get_level(); - char abuf[ABUF_SIZE]; - char *buf = abuf; - int buf_size = ABUF_SIZE; - int i = 0; - for (;;) { - if (i + 1 > buf_size) { - if (buf == abuf) { - buf = new char [ABUF_SIZE*2]; - memcpy(buf, abuf, buf_size); - buf_size = ABUF_SIZE*2; - } - else { - char *old_buf = buf; - buf = new char[buf_size*2]; - memcpy(buf, old_buf, buf_size); - buf_size *= 2; - a_delete old_buf; - } - } - tok.next(); - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - if ((buf[i] = tok.ch()) == 0) { - error("missing delimiter (got %1)", tok.description()); - if (buf != abuf) - a_delete buf; - return NULL_SYMBOL; - } - i++; - } - buf[i] = '\0'; - if (buf == abuf) { - if (i == 0) { - error("empty delimited name"); - return NULL_SYMBOL; - } - else - return symbol(buf); - } - else { - symbol s(buf); - a_delete buf; - return s; - } -} - - -// Implement \R - -static void do_register() -{ - token start; - start.next(); - if (!start.delimiter(1)) - return; - tok.next(); - symbol nm = get_long_name(1); - if (nm.is_null()) - return; - while (tok.space()) - tok.next(); - reg *r = (reg *)number_reg_dictionary.lookup(nm); - int prev_value; - if (!r || !r->get_value(&prev_value)) - prev_value = 0; - int val; - if (!get_number(&val, 'u', prev_value)) - return; - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - if (r) - r->set_value(val); - else - set_number_reg(nm, val); -} - -// this implements the \w escape sequence - -static void do_width() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - environment env(curenv); - environment *oldenv = curenv; - curenv = &env; - for (;;) { - tok.next(); - if (tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - if (tok.newline()) { - warning(WARN_DELIM, "missing closing delimiter"); - input_stack::push(make_temp_iterator("\n")); - break; - } - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) - break; - tok.process(); - } - env.wrap_up_tab(); - units x = env.get_input_line_position().to_units(); - input_stack::push(make_temp_iterator(i_to_a(x))); - env.width_registers(); - curenv = oldenv; -} - -charinfo *page_character; - -void set_page_character() -{ - page_character = get_optional_char(); - skip_line(); -} - -static const symbol percent_symbol("%"); - -void read_title_parts(node **part, hunits *part_width) -{ - tok.skip(); - if (tok.newline() || tok.eof()) - return; - token start(tok); - int start_level = input_stack::get_level(); - tok.next(); - for (int i = 0; i < 3; i++) { - while (!tok.newline() && !tok.eof()) { - if (tok == start - && (compatible_flag || input_stack::get_level() == start_level)) { - tok.next(); - break; - } - if (page_character != 0 && tok.get_char() == page_character) - interpolate_number_reg(percent_symbol, 0); - else - tok.process(); - tok.next(); - } - curenv->wrap_up_tab(); - part_width[i] = curenv->get_input_line_position(); - part[i] = curenv->extract_output_line(); - } - while (!tok.newline() && !tok.eof()) - tok.next(); -} - -class non_interpreted_node : public node { - macro mac; -public: - non_interpreted_node(const macro &); - int interpret(macro *); - node *copy(); - int same(node *); - const char *type(); -}; - -non_interpreted_node::non_interpreted_node(const macro &m) : mac(m) -{ -} - -int non_interpreted_node::same(node *nd) -{ - return mac == ((non_interpreted_node *)nd)->mac; -} - -const char *non_interpreted_node::type() -{ - return "non_interpreted_node"; -} - -node *non_interpreted_node::copy() -{ - return new non_interpreted_node(mac); -} - -int non_interpreted_node::interpret(macro *m) -{ - string_iterator si(mac); - node *n; - for (;;) { - int c = si.get(&n); - if (c == EOF) - break; - if (c == 0) - m->append(n); - else - m->append(c); - } - return 1; -} - -static node *do_non_interpreted() -{ - node *n; - int c; - macro mac; - while ((c = get_copy(&n)) != ESCAPE_QUESTION && c != EOF && c != '\n') - if (c == 0) - mac.append(n); - else - mac.append(c); - if (c == EOF || c == '\n') { - error("missing \\?"); - return 0; - } - return new non_interpreted_node(mac); -} - -static void encode_char (macro *mac, char c) -{ - if (c == '\0') { - if ((font::use_charnames_in_special) && tok.special()) { - charinfo *ci=tok.get_char(1); - const char *s=ci->get_symbol()->contents(); - - if (s[0] != (char)0) { - mac->append('\\'); - mac->append('('); - int i=0; - while (s[i] != (char)0) { - mac->append(s[i]); - i++; - } - mac->append('\\'); - mac->append(')'); - } - } else { - error("%1 is illegal within \\X", tok.description()); - } - } else { - if ((font::use_charnames_in_special) && (c == '\\')) { - /* - * add escape escape sequence - */ - mac->append(c); - } - mac->append(c); - } -} - -node *do_special() -{ - token start; - start.next(); - int start_level = input_stack::get_level(); - macro mac; - for (tok.next(); - tok != start || input_stack::get_level() != start_level; - tok.next()) { - if (tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - return 0; - } - if (tok.newline()) { - input_stack::push(make_temp_iterator("\n")); - warning(WARN_DELIM, "missing closing delimiter"); - break; - } - unsigned char c; - if (tok.space()) - c = ' '; - else if (tok.tab()) - c = '\t'; - else if (tok.leader()) - c = '\001'; - else if (tok.backspace()) - c = '\b'; - else - c = tok.ch(); - encode_char(&mac, c); - } - return new special_node(mac); -} - -void special_node::tprint(troff_output_file *out) -{ - tprint_start(out); - string_iterator iter(mac); - for (;;) { - int c = iter.get(NULL); - if (c == EOF) - break; - for (const char *s = ::asciify(c); *s; s++) - tprint_char(out, *s); - } - tprint_end(out); -} - -int get_file_line(const char **filename, int *lineno) -{ - return input_stack::get_location(0, filename, lineno); -} - -void line_file() -{ - int n; - if (get_integer(&n)) { - const char *filename = 0; - if (has_arg()) { - symbol s = get_long_name(); - filename = s.contents(); - } - (void)input_stack::set_location(filename, n-1); - } - skip_line(); -} - -static int nroff_mode = 0; - -static void nroff_request() -{ - nroff_mode = 1; - skip_line(); -} - -static void troff_request() -{ - nroff_mode = 0; - skip_line(); -} - -static void skip_alternative() -{ - int level = 0; - // ensure that ``.if 0\{'' works as expected - if (tok.left_brace()) - level++; - int c; - for (;;) { - c = input_stack::get(NULL); - if (c == EOF) - break; - if (c == ESCAPE_LEFT_BRACE) - ++level; - else if (c == ESCAPE_RIGHT_BRACE) - --level; - else if (c == escape_char && escape_char > 0) - switch(input_stack::get(NULL)) { - case '{': - ++level; - break; - case '}': - --level; - break; - case '"': - while ((c = input_stack::get(NULL)) != '\n' && c != EOF) - ; - } - /* - Note that the level can properly be < 0, eg - - .if 1 \{\ - .if 0 \{\ - .\}\} - - So don't give an error message in this case. - */ - if (level <= 0 && c == '\n') - break; - } - tok.next(); -} - -static void begin_alternative() -{ - while (tok.space() || tok.left_brace()) - tok.next(); -} - - -static int_stack if_else_stack; - -int do_if_request() -{ - int invert = 0; - while (tok.space()) - tok.next(); - while (tok.ch() == '!') { - tok.next(); - invert = !invert; - } - int result; - unsigned char c = tok.ch(); - if (c == 't') { - tok.next(); - result = !nroff_mode; - } - else if (c == 'n') { - tok.next(); - result = nroff_mode; - } - else if (c == 'v') { - tok.next(); - result = 0; - } - else if (c == 'o') { - result = (topdiv->get_page_number() & 1); - tok.next(); - } - else if (c == 'e') { - result = !(topdiv->get_page_number() & 1); - tok.next(); - } - else if (c == 'd' || c == 'r') { - tok.next(); - symbol nm = get_name(1); - if (nm.is_null()) { - skip_alternative(); - return 0; - } - result = (c == 'd' - ? request_dictionary.lookup(nm) != 0 - : number_reg_dictionary.lookup(nm) != 0); - } - else if (c == 'c') { - tok.next(); - tok.skip(); - charinfo *ci = tok.get_char(1); - if (ci == 0) { - skip_alternative(); - return 0; - } - result = character_exists(ci, curenv); - tok.next(); - } - else if (tok.space()) - result = 0; - else if (tok.delimiter()) { - token delim = tok; - int delim_level = input_stack::get_level(); - environment env1(curenv); - environment env2(curenv); - environment *oldenv = curenv; - curenv = &env1; - for (int i = 0; i < 2; i++) { - for (;;) { - tok.next(); - if (tok.newline() || tok.eof()) { - warning(WARN_DELIM, "missing closing delimiter"); - tok.next(); - curenv = oldenv; - return 0; - } - if (tok == delim - && (compatible_flag || input_stack::get_level() == delim_level)) - break; - tok.process(); - } - curenv = &env2; - } - node *n1 = env1.extract_output_line(); - node *n2 = env2.extract_output_line(); - result = same_node_list(n1, n2); - delete_node_list(n1); - delete_node_list(n2); - curenv = oldenv; - tok.next(); - } - else { - units n; - if (!get_number(&n, 'u')) { - skip_alternative(); - return 0; - } - else - result = n > 0; - } - if (invert) - result = !result; - if (result) - begin_alternative(); - else - skip_alternative(); - return result; -} - -void if_else_request() -{ - if_else_stack.push(do_if_request()); -} - -void if_request() -{ - do_if_request(); -} - -void else_request() -{ - if (if_else_stack.is_empty()) { - warning(WARN_EL, "unbalanced .el request"); - skip_alternative(); - } - else { - if (if_else_stack.pop()) - skip_alternative(); - else - begin_alternative(); - } -} - -static int while_depth = 0; -static int while_break_flag = 0; - -void while_request() -{ - macro mac; - int escaped = 0; - int level = 0; - mac.append(new token_node(tok)); - for (;;) { - node *n; - int c = input_stack::get(&n); - if (c == EOF) - break; - if (c == 0) { - escaped = 0; - mac.append(n); - } - else if (escaped) { - if (c == '{') - level += 1; - else if (c == '}') - level -= 1; - escaped = 0; - mac.append(c); - } - else { - if (c == ESCAPE_LEFT_BRACE) - level += 1; - else if (c == ESCAPE_RIGHT_BRACE) - level -= 1; - else if (c == escape_char) - escaped = 1; - mac.append(c); - if (c == '\n' && level <= 0) - break; - } - } - if (level != 0) - error("unbalanced \\{ \\}"); - else { - while_depth++; - input_stack::add_boundary(); - for (;;) { - input_stack::push(new string_iterator(mac, "while loop")); - tok.next(); - if (!do_if_request()) { - while (input_stack::get(NULL) != EOF) - ; - break; - } - process_input_stack(); - if (while_break_flag) { - while_break_flag = 0; - break; - } - } - input_stack::remove_boundary(); - while_depth--; - } - tok.next(); -} - -void while_break_request() -{ - if (!while_depth) { - error("no while loop"); - skip_line(); - } - else { - while_break_flag = 1; - while (input_stack::get(NULL) != EOF) - ; - tok.next(); - } -} - -void while_continue_request() -{ - if (!while_depth) { - error("no while loop"); - skip_line(); - } - else { - while (input_stack::get(NULL) != EOF) - ; - tok.next(); - } -} - -// .so - -void source() -{ - symbol nm = get_long_name(1); - if (nm.is_null()) - skip_line(); - else { - while (!tok.newline() && !tok.eof()) - tok.next(); - errno = 0; - FILE *fp = fopen(nm.contents(), "r"); - if (fp) - input_stack::push(new file_iterator(fp, nm.contents())); - else - error("can't open `%1': %2", nm.contents(), strerror(errno)); - tok.next(); - } -} - -// like .so but use popen() - -void pipe_source() -{ -#ifdef POPEN_MISSING - error("pipes not available on this system"); - skip_line(); -#else /* not POPEN_MISSING */ - if (tok.newline() || tok.eof()) - error("missing command"); - else { - int c; - while ((c = get_copy(NULL)) == ' ' || c == '\t') - ; - int buf_size = 24; - char *buf = new char[buf_size]; - int buf_used = 0; - for (; c != '\n' && c != EOF; c = get_copy(NULL)) { - const char *s = asciify(c); - int slen = strlen(s); - if (buf_used + slen + 1> buf_size) { - char *old_buf = buf; - int old_buf_size = buf_size; - buf_size *= 2; - buf = new char[buf_size]; - memcpy(buf, old_buf, old_buf_size); - a_delete old_buf; - } - strcpy(buf + buf_used, s); - buf_used += slen; - } - buf[buf_used] = '\0'; - errno = 0; - FILE *fp = popen(buf, POPEN_RT); - if (fp) - input_stack::push(new file_iterator(fp, symbol(buf).contents(), 1)); - else - error("can't open pipe to process `%1': %2", buf, strerror(errno)); - a_delete buf; - } - tok.next(); -#endif /* not POPEN_MISSING */ -} - - -// .psbb - -static int llx_reg_contents = 0; -static int lly_reg_contents = 0; -static int urx_reg_contents = 0; -static int ury_reg_contents = 0; - -struct bounding_box { - int llx, lly, urx, ury; -}; - -/* Parse the argument to a %%BoundingBox comment. Return 1 if it -contains 4 numbers, 2 if it contains (atend), 0 otherwise. */ - -int parse_bounding_box(char *p, bounding_box *bb) -{ - if (sscanf(p, "%d %d %d %d", - &bb->llx, &bb->lly, &bb->urx, &bb->ury) == 4) - return 1; - else { - /* The Document Structuring Conventions say that the numbers - should be integers. Unfortunately some broken applications - get this wrong. */ - double x1, x2, x3, x4; - if (sscanf(p, "%lf %lf %lf %lf", &x1, &x2, &x3, &x4) == 4) { - bb->llx = (int)x1; - bb->lly = (int)x2; - bb->urx = (int)x3; - bb->ury = (int)x4; - return 1; - } - else { - for (; *p == ' ' || *p == '\t'; p++) - ; - if (strncmp(p, "(atend)", 7) == 0) { - return 2; - } - } - } - bb->llx = bb->lly = bb->urx = bb->ury = 0; - return 0; -} - -// This version is taken from psrm.cc - -#define PS_LINE_MAX 255 -cset white_space("\n\r \t"); - -int ps_get_line(char *buf, FILE *fp, const char* filename) -{ - int c = getc(fp); - if (c == EOF) { - buf[0] = '\0'; - return 0; - } - int i = 0; - int err = 0; - while (c != '\r' && c != '\n' && c != EOF) { - if ((c < 0x1b && !white_space(c)) || c == 0x7f) - error("illegal input character code %1 in `%2'", int(c), filename); - else if (i < PS_LINE_MAX) - buf[i++] = c; - else if (!err) { - err = 1; - error("PostScript file `%1' is non-conforming " - "because length of line exceeds 255", filename); - } - c = getc(fp); - } - buf[i++] = '\n'; - buf[i] = '\0'; - if (c == '\r') { - c = getc(fp); - if (c != EOF && c != '\n') - ungetc(c, fp); - } - return 1; -} - -void do_ps_file(FILE *fp, const char* filename) -{ - bounding_box bb; - int bb_at_end = 0; - char buf[PS_LINE_MAX]; - llx_reg_contents = lly_reg_contents = - urx_reg_contents = ury_reg_contents = 0; - if (!ps_get_line(buf, fp, filename)) { - error("`%1' is empty", filename); - return; - } - if (strncmp("%!PS-Adobe-", buf, 11) != 0) { - error("`%1' is not conforming to the Document Structuring Conventions", - filename); - return; - } - while (ps_get_line(buf, fp, filename) != 0) { - if (buf[0] != '%' || buf[1] != '%' - || strncmp(buf + 2, "EndComments", 11) == 0) - break; - if (strncmp(buf + 2, "BoundingBox:", 12) == 0) { - int res = parse_bounding_box(buf + 14, &bb); - if (res == 1) - goto assign_registers; - else if (res == 2) { - bb_at_end = 1; - break; - } - else { - error("the arguments to the %%%%BoundingBox comment in `%1' are bad", - filename); - return; - } - } - } - if (bb_at_end) { - long offset; - int last_try = 0; - /* in the trailer, the last BoundingBox comment is significant */ - for (offset = 512; !last_try; offset *= 2) { - int had_trailer = 0; - int got_bb = 0; - if (offset > 32768 || fseek(fp, -offset, 2) == -1) { - last_try = 1; - if (fseek(fp, 0L, 0) == -1) - break; - } - while (ps_get_line(buf, fp, filename) != 0) { - if (buf[0] == '%' && buf[1] == '%') { - if (!had_trailer) { - if (strncmp(buf + 2, "Trailer", 7) == 0) - had_trailer = 1; - } - else { - if (strncmp(buf + 2, "BoundingBox:", 12) == 0) { - int res = parse_bounding_box(buf + 14, &bb); - if (res == 1) - got_bb = 1; - else if (res == 2) { - error("`(atend)' not allowed in trailer of `%1'", filename); - return; - } - else { - error("the arguments to the %%%%BoundingBox comment in `%1' are bad", - filename); - return; - } - } - } - } - } - if (got_bb) - goto assign_registers; - } - } - error("%%%%BoundingBox comment not found in `%1'", filename); - return; - -assign_registers: - llx_reg_contents = bb.llx; - lly_reg_contents = bb.lly; - urx_reg_contents = bb.urx; - ury_reg_contents = bb.ury; -} - -void ps_bbox_request() -{ - symbol nm = get_long_name(1); - if (nm.is_null()) - skip_line(); - else { - while (!tok.newline() && !tok.eof()) - tok.next(); - errno = 0; - // PS files might contain non-printable characters, such as ^Z - // and CRs not followed by an LF, so open them in binary mode. - FILE *fp = fopen(nm.contents(), FOPEN_RB); - if (fp) { - do_ps_file(fp, nm.contents()); - fclose(fp); - } - else - error("can't open `%1': %2", nm.contents(), strerror(errno)); - tok.next(); - } -} - -const char *asciify(int c) -{ - static char buf[3]; - buf[0] = escape_char == '\0' ? '\\' : escape_char; - buf[1] = buf[2] = '\0'; - switch (c) { - case ESCAPE_QUESTION: - buf[1] = '?'; - break; - case ESCAPE_AMPERSAND: - buf[1] = '&'; - break; - case ESCAPE_UNDERSCORE: - buf[1] = '_'; - break; - case ESCAPE_BAR: - buf[1] = '|'; - break; - case ESCAPE_CIRCUMFLEX: - buf[1] = '^'; - break; - case ESCAPE_LEFT_BRACE: - buf[1] = '{'; - break; - case ESCAPE_RIGHT_BRACE: - buf[1] = '}'; - break; - case ESCAPE_LEFT_QUOTE: - buf[1] = '`'; - break; - case ESCAPE_RIGHT_QUOTE: - buf[1] = '\''; - break; - case ESCAPE_HYPHEN: - buf[1] = '-'; - break; - case ESCAPE_BANG: - buf[1] = '!'; - break; - case ESCAPE_c: - buf[1] = 'c'; - break; - case ESCAPE_e: - buf[1] = 'e'; - break; - case ESCAPE_E: - buf[1] = 'E'; - break; - case ESCAPE_PERCENT: - buf[1] = '%'; - break; - case ESCAPE_SPACE: - buf[1] = ' '; - break; - default: - if (illegal_input_char(c)) - buf[0] = '\0'; - else - buf[0] = c; - break; - } - return buf; -} - - -const char *input_char_description(int c) -{ - switch (c) { - case '\n': - return "a newline character"; - case '\b': - return "a backspace character"; - case '\001': - return "a leader character"; - case '\t': - return "a tab character"; - case ' ': - return "a space character"; - case '\0': - return "a node"; - } - static char buf[sizeof("magic character code ") + 1 + INT_DIGITS]; - if (illegal_input_char(c)) { - const char *s = asciify(c); - if (*s) { - buf[0] = '`'; - strcpy(buf + 1, s); - strcat(buf, "'"); - return buf; - } - sprintf(buf, "magic character code %d", c); - return buf; - } - if (csprint(c)) { - buf[0] = '`'; - buf[1] = c; - buf[2] = '\''; - return buf; - } - sprintf(buf, "character code %d", c); - return buf; -} - -// .tm - -void terminal() -{ - if (!tok.newline() && !tok.eof()) { - int c; - while ((c = get_copy(NULL)) == ' ' || c == '\t') - ; - for (; c != '\n' && c != EOF; c = get_copy(NULL)) - fputs(asciify(c), stderr); - } - fputc('\n', stderr); - fflush(stderr); - tok.next(); -} - -dictionary stream_dictionary(20); - -void do_open(int append) -{ - symbol stream = get_name(1); - if (!stream.is_null()) { - symbol filename = get_long_name(1); - if (!filename.is_null()) { - errno = 0; - FILE *fp = fopen(filename.contents(), append ? "a" : "w"); - if (!fp) { - error("can't open `%1' for %2: %3", - filename.contents(), - append ? "appending" : "writing", - strerror(errno)); - fp = (FILE *)stream_dictionary.remove(stream); - } - else - fp = (FILE *)stream_dictionary.lookup(stream, fp); - if (fp) - fclose(fp); - } - } - skip_line(); -} - -void open_request() -{ - do_open(0); -} - -void opena_request() -{ - do_open(1); -} - -void close_request() -{ - symbol stream = get_name(1); - if (!stream.is_null()) { - FILE *fp = (FILE *)stream_dictionary.remove(stream); - if (!fp) - error("no stream named `%1'", stream.contents()); - else - fclose(fp); - } - skip_line(); -} - -void write_request() -{ - symbol stream = get_name(1); - if (stream.is_null()) { - skip_line(); - return; - } - FILE *fp = (FILE *)stream_dictionary.lookup(stream); - if (!fp) { - error("no stream named `%1'", stream.contents()); - skip_line(); - return; - } - int c; - while ((c = get_copy(NULL)) == ' ') - ; - if (c == '"') - c = get_copy(NULL); - for (; c != '\n' && c != EOF; c = get_copy(NULL)) - fputs(asciify(c), fp); - fputc('\n', fp); - fflush(fp); - tok.next(); -} - -void write_macro_request() -{ - symbol stream = get_name(1); - if (stream.is_null()) { - skip_line(); - return; - } - FILE *fp = (FILE *)stream_dictionary.lookup(stream); - if (!fp) { - error("no stream named `%1'", stream.contents()); - skip_line(); - return; - } - symbol s = get_name(1); - if (s.is_null()) { - skip_line(); - return; - } - request_or_macro *p = lookup_request(s); - macro *m = p->to_macro(); - if (!m) - error("cannot write request"); - else { - string_iterator iter(*m); - for (;;) { - int c = iter.get(0); - if (c == EOF) - break; - fputs(asciify(c), fp); - } - fflush(fp); - } - skip_line(); -} - -static void init_charset_table() -{ - char buf[16]; - strcpy(buf, "char"); - for (int i = 0; i < 256; i++) { - strcpy(buf + 4, i_to_a(i)); - charset_table[i] = get_charinfo(symbol(buf)); - charset_table[i]->set_ascii_code(i); - if (csalpha(i)) - charset_table[i]->set_hyphenation_code(cmlower(i)); - } - charset_table['.']->set_flags(charinfo::ENDS_SENTENCE); - charset_table['?']->set_flags(charinfo::ENDS_SENTENCE); - charset_table['!']->set_flags(charinfo::ENDS_SENTENCE); - charset_table['-']->set_flags(charinfo::BREAK_AFTER); - charset_table['"']->set_flags(charinfo::TRANSPARENT); - charset_table['\'']->set_flags(charinfo::TRANSPARENT); - charset_table[')']->set_flags(charinfo::TRANSPARENT); - charset_table[']']->set_flags(charinfo::TRANSPARENT); - charset_table['*']->set_flags(charinfo::TRANSPARENT); - get_charinfo(symbol("dg"))->set_flags(charinfo::TRANSPARENT); - get_charinfo(symbol("rq"))->set_flags(charinfo::TRANSPARENT); - get_charinfo(symbol("em"))->set_flags(charinfo::BREAK_AFTER); - get_charinfo(symbol("ul"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("rn"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("radicalex"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("ru"))->set_flags(charinfo::OVERLAPS_HORIZONTALLY); - get_charinfo(symbol("br"))->set_flags(charinfo::OVERLAPS_VERTICALLY); - page_character = charset_table['%']; -} - -static -void do_translate(int translate_transparent) -{ - tok.skip(); - while (!tok.newline() && !tok.eof()) { - if (tok.space()) { - // This is a really bizarre troff feature. - tok.next(); - translate_space_to_dummy = tok.dummy(); - if (tok.newline() || tok.eof()) - break; - tok.next(); - continue; - } - charinfo *ci1 = tok.get_char(1); - if (ci1 == 0) - break; - tok.next(); - if (tok.newline() || tok.eof()) { - ci1->set_special_translation(charinfo::TRANSLATE_SPACE, - translate_transparent); - break; - } - if (tok.space()) - ci1->set_special_translation(charinfo::TRANSLATE_SPACE, - translate_transparent); - else if (tok.dummy()) - ci1->set_special_translation(charinfo::TRANSLATE_DUMMY, - translate_transparent); - else if (tok.hyphen_indicator()) - ci1->set_special_translation(charinfo::TRANSLATE_HYPHEN_INDICATOR, - translate_transparent); - else { - charinfo *ci2 = tok.get_char(1); - if (ci2 == 0) - break; - if (ci1 == ci2) - ci1->set_translation(0, translate_transparent); - else - ci1->set_translation(ci2, translate_transparent); - } - tok.next(); - } - skip_line(); -} - -void translate() -{ - do_translate(1); -} - -void translate_no_transparent() -{ - do_translate(0); -} - -void char_flags() -{ - int flags; - if (get_integer(&flags)) - while (has_arg()) { - charinfo *ci = tok.get_char(1); - if (ci) { - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - ci->set_flags(flags); - } - tok.next(); - } - skip_line(); -} - -void hyphenation_code() -{ - tok.skip(); - while (!tok.newline() && !tok.eof()) { - charinfo *ci = tok.get_char(1); - if (ci == 0) - break; - tok.next(); - tok.skip(); - unsigned char c = tok.ch(); - if (c == 0) { - error("hyphenation code must be ordinary character"); - break; - } - if (csdigit(c)) { - error("hyphenation code cannot be digit"); - break; - } - ci->set_hyphenation_code(c); - tok.next(); - tok.skip(); - } - skip_line(); -} - -charinfo *token::get_char(int required) -{ - if (type == TOKEN_CHAR) - return charset_table[c]; - if (type == TOKEN_SPECIAL) - return get_charinfo(nm); - if (type == TOKEN_NUMBERED_CHAR) - return get_charinfo_by_number(val); - if (type == TOKEN_ESCAPE) { - if (escape_char != 0) - return charset_table[escape_char]; - else { - error("`\\e' used while no current escape character"); - return 0; - } - } - if (required) { - if (type == TOKEN_EOF || type == TOKEN_NEWLINE) - warning(WARN_MISSING, "missing normal or special character"); - else - error("normal or special character expected (got %1)", description()); - } - return 0; -} - -charinfo *get_optional_char() -{ - while (tok.space()) - tok.next(); - charinfo *ci = tok.get_char(); - if (!ci) - check_missing_character(); - else - tok.next(); - return ci; -} - -void check_missing_character() -{ - if (!tok.newline() && !tok.eof() && !tok.right_brace() && !tok.tab()) - error("normal or special character expected (got %1): " - "treated as missing", - tok.description()); -} - -int token::add_to_node_list(node **pp) -{ - hunits w; - node *n = 0; - switch (type) { - case TOKEN_CHAR: - *pp = (*pp)->add_char(charset_table[c], curenv, &w); - break; - case TOKEN_DUMMY: - n = new dummy_node; - break; - case TOKEN_ESCAPE: - if (escape_char != 0) - *pp = (*pp)->add_char(charset_table[escape_char], curenv, &w); - break; - case TOKEN_HYPHEN_INDICATOR: - *pp = (*pp)->add_discretionary_hyphen(); - break; - case TOKEN_ITALIC_CORRECTION: - *pp = (*pp)->add_italic_correction(&w); - break; - case TOKEN_LEFT_BRACE: - break; - case TOKEN_MARK_INPUT: - set_number_reg(nm, curenv->get_input_line_position().to_units()); - break; - case TOKEN_NODE: - n = nd; - nd = 0; - break; - case TOKEN_NUMBERED_CHAR: - *pp = (*pp)->add_char(get_charinfo_by_number(val), curenv, &w); - break; - case TOKEN_RIGHT_BRACE: - break; - case TOKEN_SPACE: - n = new hmotion_node(curenv->get_space_width()); - break; - case TOKEN_SPECIAL: - *pp = (*pp)->add_char(get_charinfo(nm), curenv, &w); - break; - default: - return 0; - } - if (n) { - n->next = *pp; - *pp = n; - } - return 1; -} - -void token::process() -{ - if (possibly_handle_first_page_transition()) - return; - switch (type) { - case TOKEN_BACKSPACE: - curenv->add_node(new hmotion_node(-curenv->get_space_width())); - break; - case TOKEN_CHAR: - curenv->add_char(charset_table[c]); - break; - case TOKEN_DUMMY: - curenv->add_node(new dummy_node); - break; - case TOKEN_EOF: - assert(0); - break; - case TOKEN_EMPTY: - assert(0); - break; - case TOKEN_ESCAPE: - if (escape_char != 0) - curenv->add_char(charset_table[escape_char]); - break; - case TOKEN_BEGIN_TRAP: - case TOKEN_END_TRAP: - case TOKEN_PAGE_EJECTOR: - // these are all handled in process_input_stack() - break; - case TOKEN_HYPHEN_INDICATOR: - curenv->add_hyphen_indicator(); - break; - case TOKEN_INTERRUPT: - curenv->interrupt(); - break; - case TOKEN_ITALIC_CORRECTION: - curenv->add_italic_correction(); - break; - case TOKEN_LEADER: - curenv->handle_tab(1); - break; - case TOKEN_LEFT_BRACE: - break; - case TOKEN_MARK_INPUT: - set_number_reg(nm, curenv->get_input_line_position().to_units()); - break; - case TOKEN_NEWLINE: - curenv->newline(); - break; - case TOKEN_NODE: - curenv->add_node(nd); - nd = 0; - break; - case TOKEN_NUMBERED_CHAR: - curenv->add_char(get_charinfo_by_number(val)); - break; - case TOKEN_REQUEST: - // handled in process_input_stack - break; - case TOKEN_RIGHT_BRACE: - break; - case TOKEN_SPACE: - curenv->space(); - break; - case TOKEN_SPECIAL: - curenv->add_char(get_charinfo(nm)); - break; - case TOKEN_SPREAD: - curenv->spread(); - break; - case TOKEN_TAB: - curenv->handle_tab(0); - break; - case TOKEN_TRANSPARENT: - break; - default: - assert(0); - } -} - -class nargs_reg : public reg { -public: - const char *get_string(); -}; - -const char *nargs_reg::get_string() -{ - return i_to_a(input_stack::nargs()); -} - -class lineno_reg : public reg { -public: - const char *get_string(); -}; - -const char *lineno_reg::get_string() -{ - int line; - const char *file; - if (!input_stack::get_location(0, &file, &line)) - line = 0; - return i_to_a(line); -} - - -class writable_lineno_reg : public general_reg { -public: - writable_lineno_reg(); - void set_value(units); - int get_value(units *); -}; - -writable_lineno_reg::writable_lineno_reg() -{ -} - -int writable_lineno_reg::get_value(units *res) -{ - int line; - const char *file; - if (!input_stack::get_location(0, &file, &line)) - return 0; - *res = line; - return 1; -} - -void writable_lineno_reg::set_value(units n) -{ - input_stack::set_location(0, n); -} - -class filename_reg : public reg { -public: - const char *get_string(); -}; - -const char *filename_reg::get_string() -{ - int line; - const char *file; - if (input_stack::get_location(0, &file, &line)) - return file; - else - return 0; -} - - -class constant_reg : public reg { - const char *s; -public: - constant_reg(const char *); - const char *get_string(); -}; - -constant_reg::constant_reg(const char *p) : s(p) -{ -} - -const char *constant_reg::get_string() -{ - return s; -} - -constant_int_reg::constant_int_reg(int *q) : p(q) -{ -} - -const char *constant_int_reg::get_string() -{ - return i_to_a(*p); -} - -void abort_request() -{ - int c; - if (tok.eof()) - c = EOF; - else if (tok.newline()) - c = '\n'; - else { - while ((c = get_copy(0)) == ' ') - ; - } - if (c == EOF || c == '\n') - fputs("User Abort.", stderr); - else { - for (; c != '\n' && c != EOF; c = get_copy(NULL)) - fputs(asciify(c), stderr); - } - fputc('\n', stderr); - cleanup_and_exit(1); -} - -char *read_string() -{ - int len = 256; - char *s = new char[len]; - int c; - while ((c = get_copy(0)) == ' ') - ; - int i = 0; - while (c != '\n' && c != EOF) { - if (!illegal_input_char(c)) { - if (i + 2 > len) { - char *tem = s; - s = new char[len*2]; - memcpy(s, tem, len); - len *= 2; - a_delete tem; - } - s[i++] = c; - } - c = get_copy(0); - } - s[i] = '\0'; - tok.next(); - if (i == 0) { - a_delete s; - return 0; - } - return s; -} - -void pipe_output() -{ -#ifdef POPEN_MISSING - error("pipes not available on this system"); - skip_line(); -#else /* not POPEN_MISSING */ - if (the_output) { - error("can't pipe: output already started"); - skip_line(); - } - else { - if ((pipe_command = read_string()) == 0) - error("can't pipe to empty command"); - } -#endif /* not POPEN_MISSING */ -} - -static int system_status; - -void system_request() -{ - char *command = read_string(); - if (!command) - error("empty command"); - else { - system_status = system(command); - a_delete command; - } -} - -void copy_file() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_request(COPY_FILE_REQUEST); - return; - } - symbol filename = get_long_name(1); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (!filename.is_null()) - curdiv->copy_file(filename.contents()); - tok.next(); -} - -#ifdef COLUMN - -void vjustify() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_request(VJUSTIFY_REQUEST); - return; - } - symbol type = get_long_name(1); - if (!type.is_null()) - curdiv->vjustify(type); - skip_line(); -} - -#endif /* COLUMN */ - -void transparent_file() -{ - if (curdiv == topdiv && topdiv->before_first_page) { - handle_initial_request(TRANSPARENT_FILE_REQUEST); - return; - } - symbol filename = get_long_name(1); - while (!tok.newline() && !tok.eof()) - tok.next(); - if (break_flag) - curenv->do_break(); - if (!filename.is_null()) { - errno = 0; - FILE *fp = fopen(filename.contents(), "r"); - if (!fp) - error("can't open `%1': %2", filename.contents(), strerror(errno)); - else { - int bol = 1; - for (;;) { - int c = getc(fp); - if (c == EOF) - break; - if (illegal_input_char(c)) - warning(WARN_INPUT, "illegal input character code %1", int(c)); - else { - curdiv->transparent_output(c); - bol = c == '\n'; - } - } - if (!bol) - curdiv->transparent_output('\n'); - fclose(fp); - } - } - tok.next(); -} - -class page_range { - int first; - int last; -public: - page_range *next; - page_range(int, int, page_range *); - int contains(int n); -}; - -page_range::page_range(int i, int j, page_range *p) -: first(i), last(j), next(p) -{ -} - -int page_range::contains(int n) -{ - return n >= first && (last <= 0 || n <= last); -} - -page_range *output_page_list = 0; - -int in_output_page_list(int n) -{ - if (!output_page_list) - return 1; - for (page_range *p = output_page_list; p; p = p->next) - if (p->contains(n)) - return 1; - return 0; -} - -static void parse_output_page_list(char *p) -{ - for (;;) { - int i; - if (*p == '-') - i = 1; - else if (csdigit(*p)) { - i = 0; - do - i = i*10 + *p++ - '0'; - while (csdigit(*p)); - } - else - break; - int j; - if (*p == '-') { - p++; - j = 0; - if (csdigit(*p)) { - do - j = j*10 + *p++ - '0'; - while (csdigit(*p)); - } - } - else - j = i; - if (j == 0) - last_page_number = -1; - else if (last_page_number >= 0 && j > last_page_number) - last_page_number = j; - output_page_list = new page_range(i, j, output_page_list); - if (*p != ',') - break; - ++p; - } - if (*p != '\0') { - error("bad output page list"); - output_page_list = 0; - } -} - -static FILE *open_mac_file(const char *mac, char **path) -{ - char *s = new char[strlen(mac)+strlen(MACRO_PREFIX)+1]; - strcpy(s, MACRO_PREFIX); - strcat(s, mac); - FILE *fp = macro_path.open_file(s, path); - a_delete s; - return fp; -} - -static void process_macro_file(const char *mac) -{ - char *path; - FILE *fp = open_mac_file(mac, &path); - if (!fp) - fatal("can't find macro file %1", mac); - const char *s = symbol(path).contents(); - a_delete path; - input_stack::push(new file_iterator(fp, s)); - tok.next(); - process_input_stack(); -} - -static void process_startup_file(char *filename) -{ - char *path; - FILE *fp = macro_path.open_file(filename, &path); - if (fp) { - input_stack::push(new file_iterator(fp, symbol(path).contents())); - a_delete path; - tok.next(); - process_input_stack(); - } -} - -void macro_source() -{ - symbol nm = get_long_name(1); - if (nm.is_null()) - skip_line(); - else { - while (!tok.newline() && !tok.eof()) - tok.next(); - char *path; - FILE *fp = macro_path.open_file(nm.contents(), &path); - if (fp) { - input_stack::push(new file_iterator(fp, symbol(path).contents())); - a_delete path; - } - else - error("can't find macro file `%1'", nm.contents()); - tok.next(); - } -} - -static void process_input_file(const char *name) -{ - FILE *fp; - if (strcmp(name, "-") == 0) { - clearerr(stdin); - fp = stdin; - } - else { - errno = 0; - fp = fopen(name, "r"); - if (!fp) - fatal("can't open `%1': %2", name, strerror(errno)); - } - input_stack::push(new file_iterator(fp, name)); - tok.next(); - process_input_stack(); -} - -// make sure the_input is empty before calling this - -static int evaluate_expression(const char *expr, units *res) -{ - input_stack::push(make_temp_iterator(expr)); - tok.next(); - int success = get_number(res, 'u'); - while (input_stack::get(NULL) != EOF) - ; - return success; -} - -static void do_register_assignment(const char *s) -{ - const char *p = strchr(s, '='); - if (!p) { - char buf[2]; - buf[0] = s[0]; - buf[1] = 0; - units n; - if (evaluate_expression(s + 1, &n)) - set_number_reg(buf, n); - } - else { - char *buf = new char[p - s + 1]; - memcpy(buf, s, p - s); - buf[p - s] = 0; - units n; - if (evaluate_expression(p + 1, &n)) - set_number_reg(buf, n); - a_delete buf; - } -} - -static void set_string(const char *name, const char *value) -{ - macro *m = new macro; - for (const char *p = value; *p; p++) - if (!illegal_input_char((unsigned char)*p)) - m->append(*p); - request_dictionary.define(name, m); -} - - -static void do_string_assignment(const char *s) -{ - const char *p = strchr(s, '='); - if (!p) { - char buf[2]; - buf[0] = s[0]; - buf[1] = 0; - set_string(buf, s + 1); - } - else { - char *buf = new char[p - s + 1]; - memcpy(buf, s, p - s); - buf[p - s] = 0; - set_string(buf, p + 1); - a_delete buf; - } -} - -struct string_list { - const char *s; - string_list *next; - string_list(const char *ss) : s(ss), next(0) {} -}; - -static void prepend_string(const char *s, string_list **p) -{ - string_list *l = new string_list(s); - l->next = *p; - *p = l; -} - -static void add_string(const char *s, string_list **p) -{ - while (*p) - p = &((*p)->next); - *p = new string_list(s); -} - -void usage(const char *prog) -{ - errprint( -"usage: %1 -abivzCERU -wname -Wname -dcs -ffam -mname -nnum -olist\n" -" -rcn -Tname -Fdir -Mdir [files...]\n", - prog); - exit(USAGE_EXIT_CODE); -} - -int main(int argc, char **argv) -{ - program_name = argv[0]; - static char stderr_buf[BUFSIZ]; - setbuf(stderr, stderr_buf); - int c; - string_list *macros = 0; - string_list *register_assignments = 0; - string_list *string_assignments = 0; - int iflag = 0; - int tflag = 0; - int fflag = 0; - int nflag = 0; - int safer_flag = 1; // safer by default - int no_rc = 0; // don't process troffrc and troffrc-end - int next_page_number; - opterr = 0; - hresolution = vresolution = 1; - while ((c = getopt(argc, argv, "abivw:W:zCEf:m:n:o:r:d:F:M:T:tqs:RU")) - != EOF) - switch(c) { - case 'v': - { - extern const char *Version_string; - fprintf(stderr, "GNU troff version %s\n", Version_string); - fflush(stderr); - break; - } - case 'T': - device = optarg; - tflag = 1; - break; - case 'C': - compatible_flag = 1; - break; - case 'M': - macro_path.command_line_dir(optarg); - break; - case 'F': - font::command_line_font_dir(optarg); - break; - case 'm': - add_string(optarg, ¯os); - break; - case 'E': - inhibit_errors = 1; - break; - case 'R': - no_rc = 1; - break; - case 'w': - enable_warning(optarg); - break; - case 'W': - disable_warning(optarg); - break; - case 'i': - iflag = 1; - break; - case 'b': - backtrace_flag = 1; - break; - case 'a': - ascii_output_flag = 1; - break; - case 'z': - suppress_output_flag = 1; - break; - case 'n': - if (sscanf(optarg, "%d", &next_page_number) == 1) - nflag++; - else - error("bad page number"); - break; - case 'o': - parse_output_page_list(optarg); - break; - case 'd': - if (*optarg == '\0') - error("`-d' requires non-empty argument"); - else - add_string(optarg, &string_assignments); - break; - case 'r': - if (*optarg == '\0') - error("`-r' requires non-empty argument"); - else - add_string(optarg, ®ister_assignments); - break; - case 'f': - default_family = symbol(optarg); - fflag = 1; - break; - case 'q': - case 's': - case 't': - // silently ignore these - break; - case 'U': - safer_flag = 0; // unsafe behaviour - break; - case '?': - usage(argv[0]); - default: - assert(0); - } - set_string(".T", device); - init_charset_table(); - if (!font::load_desc()) - fatal("sorry, I can't continue"); - units_per_inch = font::res; - hresolution = font::hor; - vresolution = font::vert; - sizescale = font::sizescale; - tcommand_flag = font::tcommand; - if (!fflag && font::family != 0 && *font::family != '\0') - default_family = symbol(font::family); - font_size::init_size_table(font::sizes); - int i; - int j = 1; - if (font::style_table) { - for (i = 0; font::style_table[i]; i++) - mount_style(j++, symbol(font::style_table[i])); - } - for (i = 0; font::font_name_table[i]; i++, j++) - // In the DESC file a font name of 0 (zero) means leave this - // position empty. - if (strcmp(font::font_name_table[i], "0") != 0) - mount_font(j, symbol(font::font_name_table[i])); - curdiv = topdiv = new top_level_diversion; - if (nflag) - topdiv->set_next_page_number(next_page_number); - init_input_requests(); - init_env_requests(); - init_div_requests(); -#ifdef COLUMN - init_column_requests(); -#endif /* COLUMN */ - init_node_requests(); - number_reg_dictionary.define(".T", new constant_reg(tflag ? "1" : "0")); - init_registers(); - init_reg_requests(); - init_hyphen_requests(); - init_environments(); - while (string_assignments) { - do_string_assignment(string_assignments->s); - string_list *tem = string_assignments; - string_assignments = string_assignments->next; - delete tem; - } - while (register_assignments) { - do_register_assignment(register_assignments->s); - string_list *tem = register_assignments; - register_assignments = register_assignments->next; - delete tem; - } - if (!no_rc) - process_startup_file(INITIAL_STARTUP_FILE); - if (safer_flag) - prepend_string("safer", ¯os); - while (macros) { - process_macro_file(macros->s); - string_list *tem = macros; - macros = macros->next; - delete tem; - } - if (!no_rc) - process_startup_file(FINAL_STARTUP_FILE); - for (i = optind; i < argc; i++) - process_input_file(argv[i]); - if (optind >= argc || iflag) - process_input_file("-"); - exit_troff(); - return 0; // not reached -} - -void warn_request() -{ - int n; - if (has_arg() && get_integer(&n)) { - if (n & ~WARN_TOTAL) { - warning(WARN_RANGE, "warning mask must be between 0 and %1", WARN_TOTAL); - n &= WARN_TOTAL; - } - warning_mask = n; - } - else - warning_mask = WARN_TOTAL; - skip_line(); -} - -static void init_registers() -{ -#ifdef LONG_FOR_TIME_T - long -#else /* not LONG_FOR_TIME_T */ - time_t -#endif /* not LONG_FOR_TIME_T */ - t = time(0); - // Use struct here to work around misfeature in old versions of g++. - struct tm *tt = localtime(&t); - set_number_reg("dw", int(tt->tm_wday + 1)); - set_number_reg("dy", int(tt->tm_mday)); - set_number_reg("mo", int(tt->tm_mon + 1)); - set_number_reg("year", int(1900 + tt->tm_year)); - set_number_reg("yr", int(tt->tm_year)); - set_number_reg("$$", getpid()); - number_reg_dictionary.define(".A", - new constant_reg(ascii_output_flag - ? "1" - : "0")); -} - -void init_input_requests() -{ - init_request("ds", define_string); - init_request("as", append_string); - init_request("de", define_macro); - init_request("am", append_macro); - init_request("ig", ignore); - init_request("rm", remove_macro); - init_request("rn", rename_macro); - init_request("if", if_request); - init_request("ie", if_else_request); - init_request("el", else_request); - init_request("so", source); - init_request("nx", next_file); - init_request("pm", print_macros); - init_request("eo", escape_off); - init_request("ec", set_escape_char); - init_request("pc", set_page_character); - init_request("tm", terminal); - init_request("ex", exit_request); - init_request("em", end_macro); - init_request("blm", blank_line_macro); - init_request("tr", translate); - init_request("trnt", translate_no_transparent); - init_request("ab", abort_request); - init_request("pi", pipe_output); - init_request("cf", copy_file); - init_request("sy", system_request); - init_request("lf", line_file); - init_request("cflags", char_flags); - init_request("shift", shift); - init_request("rd", read_request); - init_request("cp", compatible); - init_request("char", define_character); - init_request("rchar", remove_character); - init_request("hcode", hyphenation_code); - init_request("while", while_request); - init_request("break", while_break_request); - init_request("continue", while_continue_request); - init_request("als", alias_macro); - init_request("backtrace", backtrace_request); - init_request("chop", chop_macro); - init_request("substring", substring_macro); - init_request("length", length_macro); - init_request("asciify", asciify_macro); - init_request("warn", warn_request); - init_request("open", open_request); - init_request("opena", opena_request); - init_request("close", close_request); - init_request("write", write_request); - init_request("writem", write_macro_request); - init_request("trf", transparent_file); -#ifdef WIDOW_CONTROL - init_request("fpl", flush_pending_lines); -#endif /* WIDOW_CONTROL */ - init_request("nroff", nroff_request); - init_request("troff", troff_request); -#ifdef COLUMN - init_request("vj", vjustify); -#endif /* COLUMN */ - init_request("mso", macro_source); - init_request("do", do_request); -#ifndef POPEN_MISSING - init_request("pso", pipe_source); -#endif /* not POPEN_MISSING */ - init_request("psbb", ps_bbox_request); - number_reg_dictionary.define("systat", new variable_reg(&system_status)); - number_reg_dictionary.define("slimit", - new variable_reg(&input_stack::limit)); - number_reg_dictionary.define(".$", new nargs_reg); - number_reg_dictionary.define(".c", new lineno_reg); - number_reg_dictionary.define("c.", new writable_lineno_reg); - number_reg_dictionary.define(".F", new filename_reg); - number_reg_dictionary.define(".C", new constant_int_reg(&compatible_flag)); - number_reg_dictionary.define(".H", new constant_int_reg(&hresolution)); - number_reg_dictionary.define(".V", new constant_int_reg(&vresolution)); - number_reg_dictionary.define(".R", new constant_reg("10000")); - extern const char *major_version; - number_reg_dictionary.define(".x", new constant_reg(major_version)); - extern const char *minor_version; - number_reg_dictionary.define(".y", new constant_reg(minor_version)); - extern const char *revision; - number_reg_dictionary.define(".Y", new constant_reg(revision)); - number_reg_dictionary.define(".g", new constant_reg("1")); - number_reg_dictionary.define(".warn", new constant_int_reg(&warning_mask)); - number_reg_dictionary.define("llx", new variable_reg(&llx_reg_contents)); - number_reg_dictionary.define("lly", new variable_reg(&lly_reg_contents)); - number_reg_dictionary.define("urx", new variable_reg(&urx_reg_contents)); - number_reg_dictionary.define("ury", new variable_reg(&ury_reg_contents)); -} - -object_dictionary request_dictionary(501); - -void init_request(const char *s, REQUEST_FUNCP f) -{ - request_dictionary.define(s, new request(f)); -} - -static request_or_macro *lookup_request(symbol nm) -{ - assert(!nm.is_null()); - request_or_macro *p = (request_or_macro *)request_dictionary.lookup(nm); - if (p == 0) { - warning(WARN_MAC, "`%1' not defined", nm.contents()); - p = new macro; - request_dictionary.define(nm, p); - } - return p; -} - - -node *charinfo_to_node_list(charinfo *ci, const environment *envp) -{ - // Don't interpret character definitions in compatible mode. - int old_compatible_flag = compatible_flag; - compatible_flag = 0; - int old_escape_char = escape_char; - escape_char = '\\'; - macro *mac = ci->set_macro(0); - assert(mac != 0); - environment *oldenv = curenv; - environment env(envp); - curenv = &env; - curenv->set_composite(); - token old_tok = tok; - input_stack::add_boundary(); - string_iterator *si = new string_iterator(*mac, "composite character", ci->nm); - input_stack::push(si); - // we don't use process_input_stack, because we don't want to recognise - // requests - for (;;) { - tok.next(); - if (tok.eof()) - break; - if (tok.newline()) { - error("composite character mustn't contain newline"); - while (!tok.eof()) - tok.next(); - break; - } - else - tok.process(); - } - node *n = curenv->extract_output_line(); - input_stack::remove_boundary(); - ci->set_macro(mac); - tok = old_tok; - curenv = oldenv; - compatible_flag = old_compatible_flag; - escape_char = old_escape_char; - return n; -} - -static node *read_draw_node() -{ - token start; - start.next(); - if (!start.delimiter(1)){ - do { - tok.next(); - } while (tok != start && !tok.newline() && !tok.eof()); - } - else { - tok.next(); - if (tok == start) - error("missing argument"); - else { - unsigned char type = tok.ch(); - tok.next(); - int maxpoints = 10; - hvpair *point = new hvpair[maxpoints]; - int npoints = 0; - int no_last_v = 0; - int err = 0; - int i; - for (i = 0; tok != start; i++) { - if (i == maxpoints) { - hvpair *oldpoint = point; - point = new hvpair[maxpoints*2]; - for (int j = 0; j < maxpoints; j++) - point[j] = oldpoint[j]; - maxpoints *= 2; - a_delete oldpoint; - } - if (!get_hunits(&point[i].h, - type == 'f' || type == 't' ? 'u' : 'm')) { - err = 1; - break; - } - ++npoints; - tok.skip(); - point[i].v = V0; - if (tok == start) { - no_last_v = 1; - break; - } - if (!get_vunits(&point[i].v, 'v')) { - err = 1; - break; - } - tok.skip(); - } - while (tok != start && !tok.newline() && !tok.eof()) - tok.next(); - if (!err) { - switch (type) { - case 'l': - if (npoints != 1 || no_last_v) { - error("two arguments needed for line"); - npoints = 1; - } - break; - case 'c': - if (npoints != 1 || !no_last_v) { - error("one argument needed for circle"); - npoints = 1; - point[0].v = V0; - } - break; - case 'e': - if (npoints != 1 || no_last_v) { - error("two arguments needed for ellipse"); - npoints = 1; - } - break; - case 'a': - if (npoints != 2 || no_last_v) { - error("four arguments needed for arc"); - npoints = 2; - } - break; - case '~': - if (no_last_v) - error("even number of arguments needed for spline"); - break; - default: - // silently pass it through - break; - } - draw_node *dn = new draw_node(type, point, npoints, - curenv->get_font_size()); - a_delete point; - return dn; - } - else { - a_delete point; - } - } - } - return 0; -} - -static struct { - const char *name; - int mask; -} warning_table[] = { - { "char", WARN_CHAR }, - { "range", WARN_RANGE }, - { "break", WARN_BREAK }, - { "delim", WARN_DELIM }, - { "el", WARN_EL }, - { "scale", WARN_SCALE }, - { "number", WARN_NUMBER }, - { "syntax", WARN_SYNTAX }, - { "tab", WARN_TAB }, - { "right-brace", WARN_RIGHT_BRACE }, - { "missing", WARN_MISSING }, - { "input", WARN_INPUT }, - { "escape", WARN_ESCAPE }, - { "space", WARN_SPACE }, - { "font", WARN_FONT }, - { "di", WARN_DI }, - { "mac", WARN_MAC }, - { "reg", WARN_REG }, - { "ig", WARN_IG }, - { "all", WARN_TOTAL & ~(WARN_DI | WARN_MAC | WARN_REG) }, - { "w", WARN_TOTAL }, - { "default", DEFAULT_WARNING_MASK }, -}; - -static int lookup_warning(const char *name) -{ - for (int i = 0; - i < sizeof(warning_table)/sizeof(warning_table[0]); - i++) - if (strcmp(name, warning_table[i].name) == 0) - return warning_table[i].mask; - return 0; -} - -static void enable_warning(const char *name) -{ - int mask = lookup_warning(name); - if (mask) - warning_mask |= mask; - else - error("unknown warning `%1'", name); -} - -static void disable_warning(const char *name) -{ - int mask = lookup_warning(name); - if (mask) - warning_mask &= ~mask; - else - error("unknown warning `%1'", name); -} - -static void copy_mode_error(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - if (ignoring) { - static const char prefix[] = "(in ignored input) "; - char *s = new char[sizeof(prefix) + strlen(format)]; - strcpy(s, prefix); - strcat(s, format); - warning(WARN_IG, s, arg1, arg2, arg3); - a_delete s; - } - else - error(format, arg1, arg2, arg3); -} - -enum error_type { WARNING, ERROR, FATAL }; - -static void do_error(error_type type, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - const char *filename; - int lineno; - if (inhibit_errors && type < FATAL) - return; - if (backtrace_flag) - input_stack::backtrace(); - if (!get_file_line(&filename, &lineno)) - filename = 0; - if (filename) - errprint("%1:%2: ", filename, lineno); - else if (program_name) - fprintf(stderr, "%s: ", program_name); - switch (type) { - case FATAL: - fputs("fatal error: ", stderr); - break; - case ERROR: - break; - case WARNING: - fputs("warning: ", stderr); - break; - } - errprint(format, arg1, arg2, arg3); - fputc('\n', stderr); - fflush(stderr); - if (type == FATAL) - cleanup_and_exit(1); -} - -int warning(warning_type t, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - if ((t & warning_mask) != 0) { - do_error(WARNING, format, arg1, arg2, arg3); - return 1; - } - else - return 0; -} - -void error(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error(ERROR, format, arg1, arg2, arg3); -} - -void fatal(const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - do_error(FATAL, format, arg1, arg2, arg3); -} - -void fatal_with_file_and_line(const char *filename, int lineno, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - fprintf(stderr, "%s:%d: fatal error: ", filename, lineno); - errprint(format, arg1, arg2, arg3); - fputc('\n', stderr); - fflush(stderr); - cleanup_and_exit(1); -} - -void error_with_file_and_line(const char *filename, int lineno, - const char *format, - const errarg &arg1, - const errarg &arg2, - const errarg &arg3) -{ - fprintf(stderr, "%s:%d: error: ", filename, lineno); - errprint(format, arg1, arg2, arg3); - fputc('\n', stderr); - fflush(stderr); -} - -dictionary charinfo_dictionary(501); - -charinfo *get_charinfo(symbol nm) -{ - void *p = charinfo_dictionary.lookup(nm); - if (p != 0) - return (charinfo *)p; - charinfo *cp = new charinfo(nm); - (void)charinfo_dictionary.lookup(nm, cp); - return cp; -} - -int charinfo::next_index = 0; - -charinfo::charinfo(symbol s) -: translation(0), mac(0), special_translation(TRANSLATE_NONE), - hyphenation_code(0), flags(0), ascii_code(0), not_found(0), - transparent_translate(1), nm(s) -{ - index = next_index++; -} - -void charinfo::set_hyphenation_code(unsigned char c) -{ - hyphenation_code = c; -} - -void charinfo::set_translation(charinfo *ci, int tt) -{ - translation = ci; - special_translation = TRANSLATE_NONE; - transparent_translate = tt; -} - -void charinfo::set_special_translation(int c, int tt) -{ - special_translation = c; - translation = 0; - transparent_translate = tt; -} - -void charinfo::set_ascii_code(unsigned char c) -{ - ascii_code = c; -} - -macro *charinfo::set_macro(macro *m) -{ - macro *tem = mac; - mac = m; - return tem; -} - -void charinfo::set_number(int n) -{ - number = n; - flags |= NUMBERED; -} - -int charinfo::get_number() -{ - assert(flags & NUMBERED); - return number; -} - -symbol UNNAMED_SYMBOL("---"); - -// For numbered characters not between 0 and 255, we make a symbol out -// of the number and store them in this dictionary. - -dictionary numbered_charinfo_dictionary(11); - -charinfo *get_charinfo_by_number(int n) -{ - static charinfo *number_table[256]; - - if (n >= 0 && n < 256) { - charinfo *ci = number_table[n]; - if (!ci) { - ci = new charinfo(UNNAMED_SYMBOL); - ci->set_number(n); - number_table[n] = ci; - } - return ci; - } - else { - symbol ns(i_to_a(n)); - charinfo *ci = (charinfo *)numbered_charinfo_dictionary.lookup(ns); - if (!ci) { - ci = new charinfo(UNNAMED_SYMBOL); - ci->set_number(n); - numbered_charinfo_dictionary.lookup(ns, ci); - } - return ci; - } -} - -int font::name_to_index(const char *nm) -{ - charinfo *ci; - if (nm[1] == 0) - ci = charset_table[nm[0] & 0xff]; - else if (nm[0] == '\\' && nm[2] == 0) - ci = get_charinfo(symbol(nm + 1)); - else - ci = get_charinfo(symbol(nm)); - if (ci == 0) - return -1; - else - return ci->get_index(); -} - -int font::number_to_index(int n) -{ - return get_charinfo_by_number(n)->get_index(); -} diff --git a/contrib/groff/troff/node.cc b/contrib/groff/troff/node.cc deleted file mode 100644 index d53bf33..0000000 --- a/contrib/groff/troff/node.cc +++ /dev/null @@ -1,4920 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "hvunits.h" -#include "env.h" -#include "request.h" -#include "node.h" -#include "token.h" -#include "charinfo.h" -#include "font.h" -#include "reg.h" - -#include "nonposix.h" - -#ifdef _POSIX_VERSION - -#include <sys/wait.h> - -#else /* not _POSIX_VERSION */ - -/* traditional Unix */ - -#define WIFEXITED(s) (((s) & 0377) == 0) -#define WEXITSTATUS(s) (((s) >> 8) & 0377) -#define WTERMSIG(s) ((s) & 0177) -#define WIFSTOPPED(s) (((s) & 0377) == 0177) -#define WSTOPSIG(s) (((s) >> 8) & 0377) -#define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177)) - -#endif /* not _POSIX_VERSION */ - -#define STORE_WIDTH 1 - -symbol HYPHEN_SYMBOL("hy"); - -// Character used when a hyphen is inserted at a line break. -static charinfo *soft_hyphen_char; - -enum constant_space_type { - CONSTANT_SPACE_NONE, - CONSTANT_SPACE_RELATIVE, - CONSTANT_SPACE_ABSOLUTE - }; - -struct special_font_list { - int n; - special_font_list *next; -}; - -special_font_list *global_special_fonts; -static int global_ligature_mode = 1; -static int global_kern_mode = 1; - -class track_kerning_function { - int non_zero; - units min_size; - hunits min_amount; - units max_size; - hunits max_amount; -public: - track_kerning_function(); - track_kerning_function(units, hunits, units, hunits); - int operator==(const track_kerning_function &); - int operator!=(const track_kerning_function &); - hunits compute(int point_size); -}; - -// embolden fontno when this is the current font - -struct conditional_bold { - conditional_bold *next; - int fontno; - hunits offset; - conditional_bold(int, hunits, conditional_bold * = 0); -}; - -struct tfont; - -class font_info { - tfont *last_tfont; - int number; - font_size last_size; - int last_height; - int last_slant; - symbol internal_name; - symbol external_name; - font *fm; - char is_bold; - hunits bold_offset; - track_kerning_function track_kern; - constant_space_type is_constant_spaced; - units constant_space; - int last_ligature_mode; - int last_kern_mode; - conditional_bold *cond_bold_list; - void flush(); -public: - special_font_list *sf; - - font_info(symbol nm, int n, symbol enm, font *f); - int contains(charinfo *); - void set_bold(hunits); - void unbold(); - void set_conditional_bold(int, hunits); - void conditional_unbold(int); - void set_track_kern(track_kerning_function &); - void set_constant_space(constant_space_type, units = 0); - int is_named(symbol); - symbol get_name(); - tfont *get_tfont(font_size, int, int, int); - hunits get_space_width(font_size, int); - hunits get_narrow_space_width(font_size); - hunits get_half_narrow_space_width(font_size); - int get_bold(hunits *); - int is_special(); - int is_style(); -}; - -class tfont_spec { -protected: - symbol name; - int input_position; - font *fm; - font_size size; - char is_bold; - char is_constant_spaced; - int ligature_mode; - int kern_mode; - hunits bold_offset; - hunits track_kern; // add this to the width - hunits constant_space_width; - int height; - int slant; -public: - tfont_spec(symbol nm, int pos, font *, font_size, int, int); - tfont_spec(const tfont_spec &spec) { *this = spec; } - tfont_spec plain(); - int operator==(const tfont_spec &); - friend tfont *font_info::get_tfont(font_size fs, int, int, int); -}; - -class tfont : public tfont_spec { - static tfont *tfont_list; - tfont *next; - tfont *plain_version; -public: - tfont(tfont_spec &); - int contains(charinfo *); - hunits get_width(charinfo *c); - int get_bold(hunits *); - int get_constant_space(hunits *); - hunits get_track_kern(); - tfont *get_plain(); - font_size get_size(); - symbol get_name(); - charinfo *get_lig(charinfo *c1, charinfo *c2); - int get_kern(charinfo *c1, charinfo *c2, hunits *res); - int get_input_position(); - int get_character_type(charinfo *); - int get_height(); - int get_slant(); - vunits get_char_height(charinfo *); - vunits get_char_depth(charinfo *); - hunits get_char_skew(charinfo *); - hunits get_italic_correction(charinfo *); - hunits get_left_italic_correction(charinfo *); - hunits get_subscript_correction(charinfo *); - friend tfont *make_tfont(tfont_spec &); -}; - -inline int env_definite_font(environment *env) -{ - return env->get_family()->make_definite(env->get_font()); -} - -/* font_info functions */ - -static font_info **font_table = 0; -static int font_table_size = 0; - -font_info::font_info(symbol nm, int n, symbol enm, font *f) -: last_tfont(0), number(n), last_size(0), - internal_name(nm), external_name(enm), fm(f), - is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1), - last_kern_mode(1), cond_bold_list(0), sf(0) -{ -} - -inline int font_info::contains(charinfo *ci) -{ - return fm != 0 && fm->contains(ci->get_index()); -} - -inline int font_info::is_special() -{ - return fm != 0 && fm->is_special(); -} - -inline int font_info::is_style() -{ - return fm == 0; -} - -// this is the current_font, fontno is where we found the character, -// presumably a special font - -tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno) -{ - if (last_tfont == 0 || fs != last_size - || height != last_height || slant != last_slant - || global_ligature_mode != last_ligature_mode - || global_kern_mode != last_kern_mode - || fontno != number) { - font_info *f = font_table[fontno]; - tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant); - for (conditional_bold *p = cond_bold_list; p; p = p->next) - if (p->fontno == fontno) { - spec.is_bold = 1; - spec.bold_offset = p->offset; - break; - } - if (!spec.is_bold && is_bold) { - spec.is_bold = 1; - spec.bold_offset = bold_offset; - } - spec.track_kern = track_kern.compute(fs.to_scaled_points()); - spec.ligature_mode = global_ligature_mode; - spec.kern_mode = global_kern_mode; - switch (is_constant_spaced) { - case CONSTANT_SPACE_NONE: - break; - case CONSTANT_SPACE_ABSOLUTE: - spec.is_constant_spaced = 1; - spec.constant_space_width = constant_space; - break; - case CONSTANT_SPACE_RELATIVE: - spec.is_constant_spaced = 1; - spec.constant_space_width - = scale(constant_space*fs.to_scaled_points(), - units_per_inch, - 36*72*sizescale); - break; - default: - assert(0); - } - if (fontno != number) - return make_tfont(spec); - last_tfont = make_tfont(spec); - last_size = fs; - last_height = height; - last_slant = slant; - last_ligature_mode = global_ligature_mode; - last_kern_mode = global_kern_mode; - } - return last_tfont; -} - -int font_info::get_bold(hunits *res) -{ - if (is_bold) { - *res = bold_offset; - return 1; - } - else - return 0; -} - -void font_info::unbold() -{ - if (is_bold) { - is_bold = 0; - flush(); - } -} - -void font_info::set_bold(hunits offset) -{ - if (!is_bold || offset != bold_offset) { - is_bold = 1; - bold_offset = offset; - flush(); - } -} - -void font_info::set_conditional_bold(int fontno, hunits offset) -{ - for (conditional_bold *p = cond_bold_list; p; p = p->next) - if (p->fontno == fontno) { - if (offset != p->offset) { - p->offset = offset; - flush(); - } - return; - } - cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list); -} - -conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x) - : next(x), fontno(f), offset(h) -{ -} - -void font_info::conditional_unbold(int fontno) -{ - for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next) - if ((*p)->fontno == fontno) { - conditional_bold *tem = *p; - *p = (*p)->next; - delete tem; - flush(); - return; - } -} - -void font_info::set_constant_space(constant_space_type type, units x) -{ - if (type != is_constant_spaced - || (type != CONSTANT_SPACE_NONE && x != constant_space)) { - flush(); - is_constant_spaced = type; - constant_space = x; - } -} - -void font_info::set_track_kern(track_kerning_function &tk) -{ - if (track_kern != tk) { - track_kern = tk; - flush(); - } -} - -void font_info::flush() -{ - last_tfont = 0; -} - -int font_info::is_named(symbol s) -{ - return internal_name == s; -} - -symbol font_info::get_name() -{ - return internal_name; -} - -hunits font_info::get_space_width(font_size fs, int space_size) -{ - if (is_constant_spaced == CONSTANT_SPACE_NONE) - return scale(hunits(fm->get_space_width(fs.to_scaled_points())), - space_size, 12); - else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE) - return constant_space; - else - return scale(constant_space*fs.to_scaled_points(), - units_per_inch, 36*72*sizescale); -} - -hunits font_info::get_narrow_space_width(font_size fs) -{ - charinfo *ci = get_charinfo(symbol("|")); - if (fm->contains(ci->get_index())) - return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); - else - return hunits(fs.to_units()/6); -} - -hunits font_info::get_half_narrow_space_width(font_size fs) -{ - charinfo *ci = get_charinfo(symbol("^")); - if (fm->contains(ci->get_index())) - return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); - else - return hunits(fs.to_units()/12); -} - -/* tfont */ - -tfont_spec::tfont_spec(symbol nm, int n, font *f, - font_size s, int h, int sl) - : name(nm), input_position(n), fm(f), size(s), - is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1), - height(h), slant(sl) -{ - if (height == size.to_scaled_points()) - height = 0; -} - -int tfont_spec::operator==(const tfont_spec &spec) -{ - if (fm == spec.fm - && size == spec.size - && input_position == spec.input_position - && name == spec.name - && height == spec.height - && slant == spec.slant - && (is_bold - ? (spec.is_bold && bold_offset == spec.bold_offset) - : !spec.is_bold) - && track_kern == spec.track_kern - && (is_constant_spaced - ? (spec.is_constant_spaced - && constant_space_width == spec.constant_space_width) - : !spec.is_constant_spaced) - && ligature_mode == spec.ligature_mode - && kern_mode == spec.kern_mode) - return 1; - else - return 0; -} - -tfont_spec tfont_spec::plain() -{ - return tfont_spec(name, input_position, fm, size, height, slant); -} - -hunits tfont::get_width(charinfo *c) -{ - if (is_constant_spaced) - return constant_space_width; - else if (is_bold) - return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) - + track_kern + bold_offset); - else - return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + track_kern); -} - -vunits tfont::get_char_height(charinfo *c) -{ - vunits v = fm->get_height(c->get_index(), size.to_scaled_points()); - if (height != 0 && height != size.to_scaled_points()) - return scale(v, height, size.to_scaled_points()); - else - return v; -} - -vunits tfont::get_char_depth(charinfo *c) -{ - vunits v = fm->get_depth(c->get_index(), size.to_scaled_points()); - if (height != 0 && height != size.to_scaled_points()) - return scale(v, height, size.to_scaled_points()); - else - return v; -} - -hunits tfont::get_char_skew(charinfo *c) -{ - return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant)); -} - -hunits tfont::get_italic_correction(charinfo *c) -{ - return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points())); -} - -hunits tfont::get_left_italic_correction(charinfo *c) -{ - return hunits(fm->get_left_italic_correction(c->get_index(), - size.to_scaled_points())); -} - -hunits tfont::get_subscript_correction(charinfo *c) -{ - return hunits(fm->get_subscript_correction(c->get_index(), - size.to_scaled_points())); -} - -inline int tfont::get_input_position() -{ - return input_position; -} - -inline int tfont::contains(charinfo *ci) -{ - return fm->contains(ci->get_index()); -} - -inline int tfont::get_character_type(charinfo *ci) -{ - return fm->get_character_type(ci->get_index()); -} - -inline int tfont::get_bold(hunits *res) -{ - if (is_bold) { - *res = bold_offset; - return 1; - } - else - return 0; -} - -inline int tfont::get_constant_space(hunits *res) -{ - if (is_constant_spaced) { - *res = constant_space_width; - return 1; - } - else - return 0; -} - -inline hunits tfont::get_track_kern() -{ - return track_kern; -} - -inline tfont *tfont::get_plain() -{ - return plain_version; -} - -inline font_size tfont::get_size() -{ - return size; -} - -inline symbol tfont::get_name() -{ - return name; -} - -inline int tfont::get_height() -{ - return height; -} - -inline int tfont::get_slant() -{ - return slant; -} - -symbol SYMBOL_ff("ff"); -symbol SYMBOL_fi("fi"); -symbol SYMBOL_fl("fl"); -symbol SYMBOL_Fi("Fi"); -symbol SYMBOL_Fl("Fl"); - -charinfo *tfont::get_lig(charinfo *c1, charinfo *c2) -{ - if (ligature_mode == 0) - return 0; - charinfo *ci = 0; - if (c1->get_ascii_code() == 'f') { - switch (c2->get_ascii_code()) { - case 'f': - if (fm->has_ligature(font::LIG_ff)) - ci = get_charinfo(SYMBOL_ff); - break; - case 'i': - if (fm->has_ligature(font::LIG_fi)) - ci = get_charinfo(SYMBOL_fi); - break; - case 'l': - if (fm->has_ligature(font::LIG_fl)) - ci = get_charinfo(SYMBOL_fl); - break; - } - } - else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) { - switch (c2->get_ascii_code()) { - case 'i': - if (fm->has_ligature(font::LIG_ffi)) - ci = get_charinfo(SYMBOL_Fi); - break; - case 'l': - if (fm->has_ligature(font::LIG_ffl)) - ci = get_charinfo(SYMBOL_Fl); - break; - } - } - if (ci != 0 && fm->contains(ci->get_index())) - return ci; - return 0; -} - -inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res) -{ - if (kern_mode == 0) - return 0; - else { - int n = fm->get_kern(c1->get_index(), - c2->get_index(), - size.to_scaled_points()); - if (n) { - *res = hunits(n); - return 1; - } - else - return 0; - } -} - -tfont *make_tfont(tfont_spec &spec) -{ - for (tfont *p = tfont::tfont_list; p; p = p->next) - if (*p == spec) - return p; - return new tfont(spec); -} - -tfont *tfont::tfont_list = 0; - -tfont::tfont(tfont_spec &spec) : tfont_spec(spec) -{ - next = tfont_list; - tfont_list = this; - tfont_spec plain_spec = plain(); - tfont *p; - for (p = tfont_list; p; p = p->next) - if (*p == plain_spec) { - plain_version = p; - break; - } - if (!p) - plain_version = new tfont(plain_spec); -} - -/* output_file */ - -class real_output_file : public output_file { -#ifndef POPEN_MISSING - int piped; -#endif - int printing; - virtual void really_transparent_char(unsigned char) = 0; - virtual void really_print_line(hunits x, vunits y, node *n, - vunits before, vunits after) = 0; - virtual void really_begin_page(int pageno, vunits page_length) = 0; - virtual void really_copy_file(hunits x, vunits y, const char *filename); - virtual void really_put_filename(const char *filename); -protected: - FILE *fp; -public: - real_output_file(); - ~real_output_file(); - void flush(); - void transparent_char(unsigned char); - void print_line(hunits x, vunits y, node *n, vunits before, vunits after); - void begin_page(int pageno, vunits page_length); - void put_filename(const char *filename); - int is_printing(); - void copy_file(hunits x, vunits y, const char *filename); -}; - -class suppress_output_file : public real_output_file { -public: - suppress_output_file(); - void really_transparent_char(unsigned char); - void really_print_line(hunits x, vunits y, node *n, vunits, vunits); - void really_begin_page(int pageno, vunits page_length); -}; - -class ascii_output_file : public real_output_file { -public: - ascii_output_file(); - void really_transparent_char(unsigned char); - void really_print_line(hunits x, vunits y, node *n, vunits, vunits); - void really_begin_page(int pageno, vunits page_length); - void outc(unsigned char c); - void outs(const char *s); -}; - -void ascii_output_file::outc(unsigned char c) -{ - fputc(c, fp); -} - -void ascii_output_file::outs(const char *s) -{ - fputc('<', fp); - if (s) - fputs(s, fp); - fputc('>', fp); -} - -struct hvpair; - -class troff_output_file : public real_output_file { - units hpos; - units vpos; - units output_vpos; - units output_hpos; - int force_motion; - int current_size; - int current_slant; - int current_height; - tfont *current_tfont; - int current_font_number; - symbol *font_position; - int nfont_positions; - enum { TBUF_SIZE = 256 }; - char tbuf[TBUF_SIZE]; - int tbuf_len; - int tbuf_kern; - int begun_page; - void do_motion(); - void put(char c); - void put(unsigned char c); - void put(int i); - void put(const char *s); - void set_font(tfont *tf); - void flush_tbuf(); -public: - troff_output_file(); - ~troff_output_file(); - void trailer(vunits page_length); - void put_char(charinfo *ci, tfont *tf); - void put_char_width(charinfo *ci, tfont *tf, hunits w, hunits k); - void right(hunits); - void down(vunits); - void moveto(hunits, vunits); - void start_special(); - void special_char(unsigned char c); - void end_special(); - void word_marker(); - void really_transparent_char(unsigned char c); - void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after); - void really_begin_page(int pageno, vunits page_length); - void really_copy_file(hunits x, vunits y, const char *filename); - void really_put_filename(const char *filename); - void draw(char, hvpair *, int, font_size); - int get_hpos() { return hpos; } - int get_vpos() { return vpos; } -}; - -static void put_string(const char *s, FILE *fp) -{ - for (; *s != '\0'; ++s) - putc(*s, fp); -} - -inline void troff_output_file::put(char c) -{ - putc(c, fp); -} - -inline void troff_output_file::put(unsigned char c) -{ - putc(c, fp); -} - -inline void troff_output_file::put(const char *s) -{ - put_string(s, fp); -} - -inline void troff_output_file::put(int i) -{ - put_string(i_to_a(i), fp); -} - -void troff_output_file::start_special() -{ - flush_tbuf(); - do_motion(); - put("x X "); -} - -void troff_output_file::special_char(unsigned char c) -{ - put(c); - if (c == '\n') - put('+'); -} - -void troff_output_file::end_special() -{ - put('\n'); -} - -inline void troff_output_file::moveto(hunits h, vunits v) -{ - hpos = h.to_units(); - vpos = v.to_units(); -} - -void troff_output_file::really_print_line(hunits x, vunits y, node *n, - vunits before, vunits after) -{ - moveto(x, y); - while (n != 0) { - n->tprint(this); - n = n->next; - } - flush_tbuf(); - // This ensures that transparent throughput will have a more predictable - // position. - do_motion(); - force_motion = 1; - hpos = 0; - put('n'); - put(before.to_units()); - put(' '); - put(after.to_units()); - put('\n'); -} - -inline void troff_output_file::word_marker() -{ - flush_tbuf(); - put('w'); -} - -inline void troff_output_file::right(hunits n) -{ - hpos += n.to_units(); -} - -inline void troff_output_file::down(vunits n) -{ - vpos += n.to_units(); -} - -void troff_output_file::do_motion() -{ - if (force_motion) { - put('V'); - put(vpos); - put('\n'); - put('H'); - put(hpos); - put('\n'); - } - else { - if (hpos != output_hpos) { - units n = hpos - output_hpos; - if (n > 0 && n < hpos) { - put('h'); - put(n); - } - else { - put('H'); - put(hpos); - } - put('\n'); - } - if (vpos != output_vpos) { - units n = vpos - output_vpos; - if (n > 0 && n < vpos) { - put('v'); - put(n); - } - else { - put('V'); - put(vpos); - } - put('\n'); - } - } - output_vpos = vpos; - output_hpos = hpos; - force_motion = 0; -} - -void troff_output_file::flush_tbuf() -{ - if (tbuf_len == 0) - return; - if (tbuf_kern == 0) - put('t'); - else { - put('u'); - put(tbuf_kern); - put(' '); - } - for (int i = 0; i < tbuf_len; i++) - put(tbuf[i]); - put('\n'); - tbuf_len = 0; -} - -void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w, - hunits k) -{ - if (tf != current_tfont) { - flush_tbuf(); - set_font(tf); - } - char c = ci->get_ascii_code(); - int kk = k.to_units(); - if (c == '\0') { - flush_tbuf(); - do_motion(); - if (ci->numbered()) { - put('N'); - put(ci->get_number()); - } - else { - put('C'); - const char *s = ci->nm.contents(); - if (s[1] == 0) { - put('\\'); - put(s[0]); - } - else - put(s); - } - put('\n'); - hpos += w.to_units() + kk; - } - else if (tcommand_flag) { - if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos - && kk == tbuf_kern - && tbuf_len < TBUF_SIZE) { - tbuf[tbuf_len++] = c; - output_hpos += w.to_units() + kk; - hpos = output_hpos; - return; - } - flush_tbuf(); - do_motion(); - tbuf[tbuf_len++] = c; - output_hpos += w.to_units() + kk; - tbuf_kern = kk; - hpos = output_hpos; - } - else { - // flush_tbuf(); - int n = hpos - output_hpos; - if (vpos == output_vpos && n > 0 && n < 100 && !force_motion) { - put(char(n/10 + '0')); - put(char(n%10 + '0')); - put(c); - output_hpos = hpos; - } - else { - do_motion(); - put('c'); - put(c); - } - hpos += w.to_units() + kk; - } -} - -void troff_output_file::put_char(charinfo *ci, tfont *tf) -{ - flush_tbuf(); - if (tf != current_tfont) - set_font(tf); - char c = ci->get_ascii_code(); - if (c == '\0') { - do_motion(); - if (ci->numbered()) { - put('N'); - put(ci->get_number()); - } - else { - put('C'); - const char *s = ci->nm.contents(); - if (s[1] == 0) { - put('\\'); - put(s[0]); - } - else - put(s); - } - put('\n'); - } - else { - int n = hpos - output_hpos; - if (vpos == output_vpos && n > 0 && n < 100) { - put(char(n/10 + '0')); - put(char(n%10 + '0')); - put(c); - output_hpos = hpos; - } - else { - do_motion(); - put('c'); - put(c); - } - } -} - -void troff_output_file::set_font(tfont *tf) -{ - if (current_tfont == tf) - return; - int n = tf->get_input_position(); - symbol nm = tf->get_name(); - if (n >= nfont_positions || font_position[n] != nm) { - put("x font "); - put(n); - put(' '); - put(nm.contents()); - put('\n'); - if (n >= nfont_positions) { - int old_nfont_positions = nfont_positions; - symbol *old_font_position = font_position; - nfont_positions *= 3; - nfont_positions /= 2; - if (nfont_positions <= n) - nfont_positions = n + 10; - font_position = new symbol[nfont_positions]; - memcpy(font_position, old_font_position, - old_nfont_positions*sizeof(symbol)); - a_delete old_font_position; - } - font_position[n] = nm; - } - if (current_font_number != n) { - put('f'); - put(n); - put('\n'); - current_font_number = n; - } - int size = tf->get_size().to_scaled_points(); - if (current_size != size) { - put('s'); - put(size); - put('\n'); - current_size = size; - } - int slant = tf->get_slant(); - if (current_slant != slant) { - put("x Slant "); - put(slant); - put('\n'); - current_slant = slant; - } - int height = tf->get_height(); - if (current_height != height) { - put("x Height "); - put(height == 0 ? current_size : height); - put('\n'); - current_height = height; - } - current_tfont = tf; -} - -void troff_output_file::draw(char code, hvpair *point, int npoints, - font_size fsize) -{ - flush_tbuf(); - do_motion(); - int size = fsize.to_scaled_points(); - if (current_size != size) { - put('s'); - put(size); - put('\n'); - current_size = size; - current_tfont = 0; - } - put('D'); - put(code); - int i; - if (code == 'c') { - put(' '); - put(point[0].h.to_units()); - } - else - for (i = 0; i < npoints; i++) { - put(' '); - put(point[i].h.to_units()); - put(' '); - put(point[i].v.to_units()); - } - for (i = 0; i < npoints; i++) - output_hpos += point[i].h.to_units(); - hpos = output_hpos; - if (code != 'e') { - for (i = 0; i < npoints; i++) - output_vpos += point[i].v.to_units(); - vpos = output_vpos; - } - put('\n'); -} - -void troff_output_file::really_put_filename(const char *filename) -{ - flush_tbuf(); - put("F "); - put(filename); - put('\n'); -} - -void troff_output_file::really_begin_page(int pageno, vunits page_length) -{ - flush_tbuf(); - if (begun_page) { - if (page_length > V0) { - put('V'); - put(page_length.to_units()); - put('\n'); - } - } - else - begun_page = 1; - current_tfont = 0; - current_font_number = -1; - current_size = 0; - // current_height = 0; - // current_slant = 0; - hpos = 0; - vpos = 0; - output_hpos = 0; - output_vpos = 0; - force_motion = 1; - for (int i = 0; i < nfont_positions; i++) - font_position[i] = NULL_SYMBOL; - put('p'); - put(pageno); - put('\n'); -} - -void troff_output_file::really_copy_file(hunits x, vunits y, const char *filename) -{ - moveto(x, y); - flush_tbuf(); - do_motion(); - errno = 0; - FILE *ifp = fopen(filename, "r"); - if (ifp == 0) - error("can't open `%1': %2", filename, strerror(errno)); - else { - int c; - while ((c = getc(ifp)) != EOF) - put(char(c)); - fclose(ifp); - } - force_motion = 1; - current_size = 0; - current_tfont = 0; - current_font_number = -1; - for (int i = 0; i < nfont_positions; i++) - font_position[i] = NULL_SYMBOL; -} - -void troff_output_file::really_transparent_char(unsigned char c) -{ - put(c); -} - -troff_output_file::~troff_output_file() -{ - a_delete font_position; -} - -void troff_output_file::trailer(vunits page_length) -{ - flush_tbuf(); - if (page_length > V0) { - put("x trailer\n"); - put('V'); - put(page_length.to_units()); - put('\n'); - } - put("x stop\n"); -} - -troff_output_file::troff_output_file() -: current_slant(0), current_height(0), nfont_positions(10), tbuf_len(0), - begun_page(0) -{ - font_position = new symbol[nfont_positions]; - put("x T "); - put(device); - put('\n'); - put("x res "); - put(units_per_inch); - put(' '); - put(hresolution); - put(' '); - put(vresolution); - put('\n'); - put("x init\n"); -} - -/* output_file */ - -output_file *the_output = 0; - -output_file::output_file() -{ -} - -output_file::~output_file() -{ -} - -void output_file::trailer(vunits) -{ -} - - -void output_file::put_filename(const char *filename) -{ -} - -real_output_file::real_output_file() -: printing(0) -{ -#ifndef POPEN_MISSING - if (pipe_command) { - if ((fp = popen(pipe_command, POPEN_WT)) != 0) { - piped = 1; - return; - } - error("pipe open failed: %1", strerror(errno)); - } - piped = 0; -#endif /* not POPEN_MISSING */ - fp = stdout; -} - -real_output_file::~real_output_file() -{ - if (!fp) - return; - // To avoid looping, set fp to 0 before calling fatal(). - if (ferror(fp) || fflush(fp) < 0) { - fp = 0; - fatal("error writing output file"); - } -#ifndef POPEN_MISSING - if (piped) { - int result = pclose(fp); - fp = 0; - if (result < 0) - fatal("pclose failed"); - if (!WIFEXITED(result)) - error("output process `%1' got fatal signal %2", - pipe_command, - WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result)); - else { - int exit_status = WEXITSTATUS(result); - if (exit_status != 0) - error("output process `%1' exited with status %2", - pipe_command, exit_status); - } - } - else -#endif /* not POPEN MISSING */ - if (fclose(fp) < 0) { - fp = 0; - fatal("error closing output file"); - } -} - -void real_output_file::flush() -{ - if (fflush(fp) < 0) - fatal("error writing output file"); -} - -int real_output_file::is_printing() -{ - return printing; -} - -void real_output_file::begin_page(int pageno, vunits page_length) -{ - printing = in_output_page_list(pageno); - if (printing) - really_begin_page(pageno, page_length); -} - -void real_output_file::copy_file(hunits x, vunits y, const char *filename) -{ - if (printing) - really_copy_file(x, y, filename); -} - -void real_output_file::transparent_char(unsigned char c) -{ - if (printing) - really_transparent_char(c); -} - -void real_output_file::print_line(hunits x, vunits y, node *n, - vunits before, vunits after) -{ - if (printing) - really_print_line(x, y, n, before, after); - delete_node_list(n); -} - -void real_output_file::really_copy_file(hunits, vunits, const char *) -{ - // do nothing -} - -void real_output_file::put_filename(const char *filename) -{ - really_put_filename(filename); -} - -void real_output_file::really_put_filename(const char *filename) -{ -} - -/* ascii_output_file */ - -void ascii_output_file::really_transparent_char(unsigned char c) -{ - putc(c, fp); -} - -void ascii_output_file::really_print_line(hunits, vunits, node *n, vunits, vunits) -{ - while (n != 0) { - n->ascii_print(this); - n = n->next; - } - fputc('\n', fp); -} - -void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/) -{ - fputs("<beginning of page>\n", fp); -} - -ascii_output_file::ascii_output_file() -{ -} - -/* suppress_output_file */ - -suppress_output_file::suppress_output_file() -{ -} - -void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits) -{ -} - -void suppress_output_file::really_begin_page(int, vunits) -{ -} - -void suppress_output_file::really_transparent_char(unsigned char) -{ -} - -/* glyphs, ligatures, kerns, discretionary breaks */ - -class charinfo_node : public node { -protected: - charinfo *ci; -public: - charinfo_node(charinfo *, node * = 0); - int ends_sentence(); - int overlaps_vertically(); - int overlaps_horizontally(); -}; - -charinfo_node::charinfo_node(charinfo *c, node *x) -: node(x), ci(c) -{ -} - -int charinfo_node::ends_sentence() -{ - if (ci->ends_sentence()) - return 1; - else if (ci->transparent()) - return 2; - else - return 0; -} - -int charinfo_node::overlaps_horizontally() -{ - return ci->overlaps_horizontally(); -} - -int charinfo_node::overlaps_vertically() -{ - return ci->overlaps_vertically(); -} - -class glyph_node : public charinfo_node { - static glyph_node *free_list; -protected: - tfont *tf; -#ifdef STORE_WIDTH - hunits wid; - glyph_node(charinfo *, tfont *, hunits, node * = 0); -#endif -public: - void *operator new(size_t); - void operator delete(void *); - glyph_node(charinfo *, tfont *, node * = 0); - ~glyph_node() {} - node *copy(); - node *merge_glyph_node(glyph_node *); - node *merge_self(node *); - hunits width(); - node *last_char_node(); - units size(); - void vertical_extent(vunits *, vunits *); - hunits subscript_correction(); - hunits italic_correction(); - hunits left_italic_correction(); - hunits skew(); - hyphenation_type get_hyphenation_type(); - tfont *get_tfont(); - void tprint(troff_output_file *); - void zero_width_tprint(troff_output_file *); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - node *add_self(node *, hyphen_list **); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int character_type(); - int same(node *); - const char *type(); -}; - -glyph_node *glyph_node::free_list = 0; - -class ligature_node : public glyph_node { - node *n1; - node *n2; -#ifdef STORE_WIDTH - ligature_node(charinfo *, tfont *, hunits, node *gn1, node *gn2, node *x = 0); -#endif -public: - void *operator new(size_t); - void operator delete(void *); - ligature_node(charinfo *, tfont *, node *gn1, node *gn2, node *x = 0); - ~ligature_node(); - node *copy(); - node *add_self(node *, hyphen_list **); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int same(node *); - const char *type(); -}; - -class kern_pair_node : public node { - hunits amount; - node *n1; - node *n2; -public: - kern_pair_node(hunits n, node *first, node *second, node *x = 0); - ~kern_pair_node(); - node *copy(); - node *merge_glyph_node(glyph_node *); - node *add_self(node *, hyphen_list **); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - node *add_discretionary_hyphen(); - hunits width(); - node *last_char_node(); - hunits italic_correction(); - hunits subscript_correction(); - void tprint(troff_output_file *); - hyphenation_type get_hyphenation_type(); - int ends_sentence(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int same(node *); - const char *type(); - void vertical_extent(vunits *, vunits *); -}; - -class dbreak_node : public node { - node *none; - node *pre; - node *post; -public: - dbreak_node(node *n, node *p, node *x = 0); - ~dbreak_node(); - node *copy(); - node *merge_glyph_node(glyph_node *); - node *add_discretionary_hyphen(); - hunits width(); - node *last_char_node(); - hunits italic_correction(); - hunits subscript_correction(); - void tprint(troff_output_file *); - breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0, - int is_inner = 0); - int nbreaks(); - int ends_sentence(); - void split(int, node **, node **); - hyphenation_type get_hyphenation_type(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int same(node *); - const char *type(); -}; - -void *glyph_node::operator new(size_t n) -{ - assert(n == sizeof(glyph_node)); - if (!free_list) { - const int BLOCK = 1024; - free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - glyph_node *p = free_list; - free_list = (glyph_node *)(free_list->next); - p->next = 0; - return p; -} - -void *ligature_node::operator new(size_t n) -{ - return new char[n]; -} - -void glyph_node::operator delete(void *p) -{ - if (p) { - ((glyph_node *)p)->next = free_list; - free_list = (glyph_node *)p; - } -} - -void ligature_node::operator delete(void *p) -{ - delete[] (char *)p; -} - -glyph_node::glyph_node(charinfo *c, tfont *t, node *x) -: charinfo_node(c, x), tf(t) -{ -#ifdef STORE_WIDTH - wid = tf->get_width(ci); -#endif -} - -#ifdef STORE_WIDTH -glyph_node::glyph_node(charinfo *c, tfont *t, hunits w, node *x) -: charinfo_node(c, x), tf(t), wid(w) -{ -} -#endif - -node *glyph_node::copy() -{ -#ifdef STORE_WIDTH - return new glyph_node(ci, tf, wid); -#else - return new glyph_node(ci, tf); -#endif -} - -node *glyph_node::merge_self(node *nd) -{ - return nd->merge_glyph_node(this); -} - -int glyph_node::character_type() -{ - return tf->get_character_type(ci); -} - -node *glyph_node::add_self(node *n, hyphen_list **p) -{ - assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); - next = 0; - node *nn; - if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) { - next = n; - nn = this; - } - if ((*p)->hyphen) - nn = nn->add_discretionary_hyphen(); - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return nn; -} - -units glyph_node::size() -{ - return tf->get_size().to_units(); -} - -hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(ci->get_hyphenation_code(), tail); -} - - -tfont *node::get_tfont() -{ - return 0; -} - -tfont *glyph_node::get_tfont() -{ - return tf; -} - -node *node::merge_glyph_node(glyph_node * /*gn*/) -{ - return 0; -} - -node *glyph_node::merge_glyph_node(glyph_node *gn) -{ - if (tf == gn->tf) { - charinfo *lig; - if ((lig = tf->get_lig(ci, gn->ci)) != 0) { - node *next1 = next; - next = 0; - return new ligature_node(lig, tf, this, gn, next1); - } - hunits kern; - if (tf->get_kern(ci, gn->ci, &kern)) { - node *next1 = next; - next = 0; - return new kern_pair_node(kern, this, gn, next1); - } - } - return 0; -} - -#ifdef STORE_WIDTH -inline -#endif -hunits glyph_node::width() -{ -#ifdef STORE_WIDTH - return wid; -#else - return tf->get_width(ci); -#endif -} - -node *glyph_node::last_char_node() -{ - return this; -} - -void glyph_node::vertical_extent(vunits *min, vunits *max) -{ - *min = -tf->get_char_height(ci); - *max = tf->get_char_depth(ci); -} - -hunits glyph_node::skew() -{ - return tf->get_char_skew(ci); -} - -hunits glyph_node::subscript_correction() -{ - return tf->get_subscript_correction(ci); -} - -hunits glyph_node::italic_correction() -{ - return tf->get_italic_correction(ci); -} - -hunits glyph_node::left_italic_correction() -{ - return tf->get_left_italic_correction(ci); -} - -hyphenation_type glyph_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -void glyph_node::ascii_print(ascii_output_file *ascii) -{ - unsigned char c = ci->get_ascii_code(); - if (c != 0) - ascii->outc(c); - else - ascii->outs(ci->nm.contents()); -} - -ligature_node::ligature_node(charinfo *c, tfont *t, - node *gn1, node *gn2, node *x) - : glyph_node(c, t, x), n1(gn1), n2(gn2) -{ -} - -#ifdef STORE_WIDTH -ligature_node::ligature_node(charinfo *c, tfont *t, hunits w, - node *gn1, node *gn2, node *x) - : glyph_node(c, t, w, x), n1(gn1), n2(gn2) -{ -} -#endif - -ligature_node::~ligature_node() -{ - delete n1; - delete n2; -} - -node *ligature_node::copy() -{ -#ifdef STORE_WIDTH - return new ligature_node(ci, tf, wid, n1->copy(), n2->copy()); -#else - return new ligature_node(ci, tf, n1->copy(), n2->copy()); -#endif -} - -void ligature_node::ascii_print(ascii_output_file *ascii) -{ - n1->ascii_print(ascii); - n2->ascii_print(ascii); -} - -hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail) -{ - return n1->get_hyphen_list(n2->get_hyphen_list(tail)); -} - -node *ligature_node::add_self(node *n, hyphen_list **p) -{ - n = n1->add_self(n, p); - n = n2->add_self(n, p); - n1 = n2 = 0; - delete this; - return n; -} - -kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x) - : node(x), amount(n), n1(first), n2(second) -{ -} - -dbreak_node::dbreak_node(node *n, node *p, node *x) - : node(x), none(n), pre(p), post(0) -{ -} - -node *dbreak_node::merge_glyph_node(glyph_node *gn) -{ - glyph_node *gn2 = (glyph_node *)gn->copy(); - node *new_none = none ? none->merge_glyph_node(gn) : 0; - node *new_post = post ? post->merge_glyph_node(gn2) : 0; - if (new_none == 0 && new_post == 0) { - delete gn2; - return 0; - } - if (new_none != 0) - none = new_none; - else { - gn->next = none; - none = gn; - } - if (new_post != 0) - post = new_post; - else { - gn2->next = post; - post = gn2; - } - return this; -} - -node *kern_pair_node::merge_glyph_node(glyph_node *gn) -{ - node *nd = n2->merge_glyph_node(gn); - if (nd == 0) - return 0; - n2 = nd; - nd = n2->merge_self(n1); - if (nd) { - nd->next = next; - n1 = 0; - n2 = 0; - delete this; - return nd; - } - return this; -} - - -hunits kern_pair_node::italic_correction() -{ - return n2->italic_correction(); -} - -hunits kern_pair_node::subscript_correction() -{ - return n2->subscript_correction(); -} - -void kern_pair_node::vertical_extent(vunits *min, vunits *max) -{ - n1->vertical_extent(min, max); - vunits min2, max2; - n2->vertical_extent(&min2, &max2); - if (min2 < *min) - *min = min2; - if (max2 > *max) - *max = max2; -} - -node *kern_pair_node::add_discretionary_hyphen() -{ - tfont *tf = n2->get_tfont(); - if (tf) { - if (tf->contains(soft_hyphen_char)) { - node *next1 = next; - next = 0; - node *n = copy(); - glyph_node *gn = new glyph_node(soft_hyphen_char, tf); - node *nn = n->merge_glyph_node(gn); - if (nn == 0) { - gn->next = n; - nn = gn; - } - return new dbreak_node(this, nn, next1); - } - } - return this; -} - - -kern_pair_node::~kern_pair_node() -{ - if (n1 != 0) - delete n1; - if (n2 != 0) - delete n2; -} - -dbreak_node::~dbreak_node() -{ - delete_node_list(pre); - delete_node_list(post); - delete_node_list(none); -} - -node *kern_pair_node::copy() -{ - return new kern_pair_node(amount, n1->copy(), n2->copy()); -} - -node *copy_node_list(node *n) -{ - node *p = 0; - while (n != 0) { - node *nn = n->copy(); - nn->next = p; - p = nn; - n = n->next; - } - while (p != 0) { - node *pp = p->next; - p->next = n; - n = p; - p = pp; - } - return n; -} - -void delete_node_list(node *n) -{ - while (n != 0) { - node *tem = n; - n = n->next; - delete tem; - } -} - -node *dbreak_node::copy() -{ - dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre)); - p->post = copy_node_list(post); - return p; -} - -hyphen_list *node::get_hyphen_list(hyphen_list *tail) -{ - return tail; -} - - -hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail) -{ - return n1->get_hyphen_list(n2->get_hyphen_list(tail)); -} - -class hyphen_inhibitor_node : public node { -public: - hyphen_inhibitor_node(node *nd = 0); - node *copy(); - int same(node *); - const char *type(); - hyphenation_type get_hyphenation_type(); -}; - -hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd) -{ -} - -node *hyphen_inhibitor_node::copy() -{ - return new hyphen_inhibitor_node; -} - -int hyphen_inhibitor_node::same(node *) -{ - return 1; -} - -const char *hyphen_inhibitor_node::type() -{ - return "hyphen_inhibitor_node"; -} - -hyphenation_type hyphen_inhibitor_node::get_hyphenation_type() -{ - return HYPHEN_INHIBIT; -} - -/* add_discretionary_hyphen methods */ - -node *dbreak_node::add_discretionary_hyphen() -{ - if (post) - post = post->add_discretionary_hyphen(); - if (none) - none = none->add_discretionary_hyphen(); - return this; -} - - -node *node::add_discretionary_hyphen() -{ - tfont *tf = get_tfont(); - if (!tf) - return new hyphen_inhibitor_node(this); - if (tf->contains(soft_hyphen_char)) { - node *next1 = next; - next = 0; - node *n = copy(); - glyph_node *gn = new glyph_node(soft_hyphen_char, tf); - node *n1 = n->merge_glyph_node(gn); - if (n1 == 0) { - gn->next = n; - n1 = gn; - } - return new dbreak_node(this, n1, next1); - } - return this; -} - - -node *node::merge_self(node *) -{ - return 0; -} - -node *node::add_self(node *n, hyphen_list ** /*p*/) -{ - next = n; - return this; -} - -node *kern_pair_node::add_self(node *n, hyphen_list **p) -{ - n = n1->add_self(n, p); - n = n2->add_self(n, p); - n1 = n2 = 0; - delete this; - return n; -} - - -hunits node::width() -{ - return H0; -} - -node *node::last_char_node() -{ - return 0; -} - -hunits hmotion_node::width() -{ - return n; -} - -units node::size() -{ - return points_to_units(10); -} - -hunits kern_pair_node::width() -{ - return n1->width() + n2->width() + amount; -} - -node *kern_pair_node::last_char_node() -{ - node *nd = n2->last_char_node(); - if (nd) - return nd; - return n1->last_char_node(); -} - -hunits dbreak_node::width() -{ - hunits x = H0; - for (node *n = none; n != 0; n = n->next) - x += n->width(); - return x; -} - -node *dbreak_node::last_char_node() -{ - for (node *n = none; n; n = n->next) { - node *last = n->last_char_node(); - if (last) - return last; - } - return 0; -} - -hunits dbreak_node::italic_correction() -{ - return none ? none->italic_correction() : H0; -} - -hunits dbreak_node::subscript_correction() -{ - return none ? none->subscript_correction() : H0; -} - -class italic_corrected_node : public node { - node *n; - hunits x; -public: - italic_corrected_node(node *, hunits, node * = 0); - ~italic_corrected_node(); - node *copy(); - void ascii_print(ascii_output_file *); - void asciify(macro *m); - hunits width(); - node *last_char_node(); - void vertical_extent(vunits *, vunits *); - int ends_sentence(); - int overlaps_horizontally(); - int overlaps_vertically(); - int same(node *); - hyphenation_type get_hyphenation_type(); - tfont *get_tfont(); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - int character_type(); - void tprint(troff_output_file *); - hunits subscript_correction(); - hunits skew(); - node *add_self(node *, hyphen_list **); - const char *type(); -}; - -node *node::add_italic_correction(hunits *width) -{ - hunits ic = italic_correction(); - if (ic.is_zero()) - return this; - else { - node *next1 = next; - next = 0; - *width += ic; - return new italic_corrected_node(this, ic, next1); - } -} - -italic_corrected_node::italic_corrected_node(node *nn, hunits xx, node *p) -: node(p), n(nn), x(xx) -{ - assert(n != 0); -} - -italic_corrected_node::~italic_corrected_node() -{ - delete n; -} - -node *italic_corrected_node::copy() -{ - return new italic_corrected_node(n->copy(), x); -} - -hunits italic_corrected_node::width() -{ - return n->width() + x; -} - -void italic_corrected_node::vertical_extent(vunits *min, vunits *max) -{ - n->vertical_extent(min, max); -} - -void italic_corrected_node::tprint(troff_output_file *out) -{ - n->tprint(out); - out->right(x); -} - -hunits italic_corrected_node::skew() -{ - return n->skew() - x/2; -} - -hunits italic_corrected_node::subscript_correction() -{ - return n->subscript_correction() - x; -} - -void italic_corrected_node::ascii_print(ascii_output_file *out) -{ - n->ascii_print(out); -} - -int italic_corrected_node::ends_sentence() -{ - return n->ends_sentence(); -} - -int italic_corrected_node::overlaps_horizontally() -{ - return n->overlaps_horizontally(); -} - -int italic_corrected_node::overlaps_vertically() -{ - return n->overlaps_vertically(); -} - -node *italic_corrected_node::last_char_node() -{ - return n->last_char_node(); -} - -tfont *italic_corrected_node::get_tfont() -{ - return n->get_tfont(); -} - -hyphenation_type italic_corrected_node::get_hyphenation_type() -{ - return n->get_hyphenation_type(); -} - -node *italic_corrected_node::add_self(node *nd, hyphen_list **p) -{ - nd = n->add_self(nd, p); - hunits not_interested; - nd = nd->add_italic_correction(¬_interested); - n = 0; - delete this; - return nd; -} - -hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail) -{ - return n->get_hyphen_list(tail); -} - -int italic_corrected_node::character_type() -{ - return n->character_type(); -} - -class break_char_node : public node { - node *ch; - char break_code; -public: - break_char_node(node *, int, node * = 0); - ~break_char_node(); - node *copy(); - hunits width(); - vunits vertical_width(); - node *last_char_node(); - int character_type(); - int ends_sentence(); - node *add_self(node *, hyphen_list **); - hyphen_list *get_hyphen_list(hyphen_list *s = 0); - void tprint(troff_output_file *); - void zero_width_tprint(troff_output_file *); - void ascii_print(ascii_output_file *); - void asciify(macro *m); - hyphenation_type get_hyphenation_type(); - int overlaps_vertically(); - int overlaps_horizontally(); - units size(); - tfont *get_tfont(); - int same(node *); - const char *type(); -}; - -break_char_node::break_char_node(node *n, int c, node *x) -: node(x), ch(n), break_code(c) -{ -} - -break_char_node::~break_char_node() -{ - delete ch; -} - -node *break_char_node::copy() -{ - return new break_char_node(ch->copy(), break_code); -} - -hunits break_char_node::width() -{ - return ch->width(); -} - -vunits break_char_node::vertical_width() -{ - return ch->vertical_width(); -} - -node *break_char_node::last_char_node() -{ - return ch->last_char_node(); -} - -int break_char_node::character_type() -{ - return ch->character_type(); -} - -int break_char_node::ends_sentence() -{ - return ch->ends_sentence(); -} - -node *break_char_node::add_self(node *n, hyphen_list **p) -{ - assert((*p)->hyphenation_code == 0); - if ((*p)->breakable && (break_code & 1)) { - n = new space_node(H0, n); - n->freeze_space(); - } - next = n; - n = this; - if ((*p)->breakable && (break_code & 2)) { - n = new space_node(H0, n); - n->freeze_space(); - } - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return n; -} - -hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(0, tail); -} - -hyphenation_type break_char_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -void break_char_node::ascii_print(ascii_output_file *ascii) -{ - ch->ascii_print(ascii); -} - -int break_char_node::overlaps_vertically() -{ - return ch->overlaps_vertically(); -} - -int break_char_node::overlaps_horizontally() -{ - return ch->overlaps_horizontally(); -} - -units break_char_node::size() -{ - return ch->size(); -} - -tfont *break_char_node::get_tfont() -{ - return ch->get_tfont(); -} - -node *extra_size_node::copy() -{ - return new extra_size_node(n); -} - -node *vertical_size_node::copy() -{ - return new vertical_size_node(n); -} - -node *hmotion_node::copy() -{ - return new hmotion_node(n); -} - -node *space_char_hmotion_node::copy() -{ - return new space_char_hmotion_node(n); -} - -node *vmotion_node::copy() -{ - return new vmotion_node(n); -} - -node *dummy_node::copy() -{ - return new dummy_node; -} - -node *transparent_dummy_node::copy() -{ - return new transparent_dummy_node; -} - -hline_node::~hline_node() -{ - if (n) - delete n; -} - -node *hline_node::copy() -{ - return new hline_node(x, n ? n->copy() : 0); -} - -hunits hline_node::width() -{ - return x < H0 ? H0 : x; -} - - -vline_node::~vline_node() -{ - if (n) - delete n; -} - -node *vline_node::copy() -{ - return new vline_node(x, n ? n->copy() : 0); -} - -hunits vline_node::width() -{ - return n == 0 ? H0 : n->width(); -} - - -zero_width_node::zero_width_node(node *nd) : n(nd) -{ -} - -zero_width_node::~zero_width_node() -{ - delete_node_list(n); -} - -node *zero_width_node::copy() -{ - return new zero_width_node(copy_node_list(n)); -} - -int node_list_character_type(node *p) -{ - int t = 0; - for (; p; p = p->next) - t |= p->character_type(); - return t; -} - -int zero_width_node::character_type() -{ - return node_list_character_type(n); -} - -void node_list_vertical_extent(node *p, vunits *min, vunits *max) -{ - *min = V0; - *max = V0; - vunits cur_vpos = V0; - vunits v1, v2; - for (; p; p = p->next) { - p->vertical_extent(&v1, &v2); - v1 += cur_vpos; - if (v1 < *min) - *min = v1; - v2 += cur_vpos; - if (v2 > *max) - *max = v2; - cur_vpos += p->vertical_width(); - } -} - -void zero_width_node::vertical_extent(vunits *min, vunits *max) -{ - node_list_vertical_extent(n, min, max); -} - -overstrike_node::overstrike_node() : list(0), max_width(H0) -{ -} - -overstrike_node::~overstrike_node() -{ - delete_node_list(list); -} - -node *overstrike_node::copy() -{ - overstrike_node *on = new overstrike_node; - for (node *tem = list; tem; tem = tem->next) - on->overstrike(tem->copy()); - return on; -} - -void overstrike_node::overstrike(node *n) -{ - if (n == 0) - return; - hunits w = n->width(); - if (w > max_width) - max_width = w; - node **p; - for (p = &list; *p; p = &(*p)->next) - ; - n->next = 0; - *p = n; -} - -hunits overstrike_node::width() -{ - return max_width; -} - -bracket_node::bracket_node() : list(0), max_width(H0) -{ -} - -bracket_node::~bracket_node() -{ - delete_node_list(list); -} - -node *bracket_node::copy() -{ - bracket_node *on = new bracket_node; - node *last = 0; - node *tem; - for (tem = list; tem; tem = tem->next) { - if (tem->next) - tem->next->last = tem; - last = tem; - } - for (tem = last; tem; tem = tem->last) - on->bracket(tem->copy()); - return on; -} - - -void bracket_node::bracket(node *n) -{ - if (n == 0) - return; - hunits w = n->width(); - if (w > max_width) - max_width = w; - n->next = list; - list = n; -} - -hunits bracket_node::width() -{ - return max_width; -} - -int node::nspaces() -{ - return 0; -} - -int node::merge_space(hunits) -{ - return 0; -} - -#if 0 -space_node *space_node::free_list = 0; - -void *space_node::operator new(size_t n) -{ - assert(n == sizeof(space_node)); - if (!free_list) { - free_list = (space_node *)new char[sizeof(space_node)*BLOCK]; - for (int i = 0; i < BLOCK - 1; i++) - free_list[i].next = free_list + i + 1; - free_list[BLOCK-1].next = 0; - } - space_node *p = free_list; - free_list = (space_node *)(free_list->next); - p->next = 0; - return p; -} - -inline void space_node::operator delete(void *p) -{ - if (p) { - ((space_node *)p)->next = free_list; - free_list = (space_node *)p; - } -} -#endif - -space_node::space_node(hunits nn, node *p) : node(p), n(nn), set(0) -{ -} - -space_node::space_node(hunits nn, int s, node *p) : node(p), n(nn), set(s) -{ -} - -#if 0 -space_node::~space_node() -{ -} -#endif - -node *space_node::copy() -{ - return new space_node(n, set); -} - -int space_node::nspaces() -{ - return set ? 0 : 1; -} - -int space_node::merge_space(hunits h) -{ - n += h; - return 1; -} - -hunits space_node::width() -{ - return n; -} - -void node::spread_space(int*, hunits*) -{ -} - -void space_node::spread_space(int *nspaces, hunits *desired_space) -{ - if (!set) { - assert(*nspaces > 0); - if (*nspaces == 1) { - n += *desired_space; - *desired_space = H0; - } - else { - hunits extra = *desired_space / *nspaces; - *desired_space -= extra; - n += extra; - } - *nspaces -= 1; - set = 1; - } -} - -void node::freeze_space() -{ -} - -void space_node::freeze_space() -{ - set = 1; -} - -diverted_space_node::diverted_space_node(vunits d, node *p) -: node(p), n(d) -{ -} - -node *diverted_space_node::copy() -{ - return new diverted_space_node(n); -} - -diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p) -: node(p), filename(s) -{ -} - -node *diverted_copy_file_node::copy() -{ - return new diverted_copy_file_node(filename); -} - -int node::ends_sentence() -{ - return 0; -} - -int kern_pair_node::ends_sentence() -{ - switch (n2->ends_sentence()) { - case 0: - return 0; - case 1: - return 1; - case 2: - break; - default: - assert(0); - } - return n1->ends_sentence(); -} - -int node_list_ends_sentence(node *n) -{ - for (; n != 0; n = n->next) - switch (n->ends_sentence()) { - case 0: - return 0; - case 1: - return 1; - case 2: - break; - default: - assert(0); - } - return 2; -} - - -int dbreak_node::ends_sentence() -{ - return node_list_ends_sentence(none); -} - - -int node::overlaps_horizontally() -{ - return 0; -} - -int node::overlaps_vertically() -{ - return 0; -} - -int node::discardable() -{ - return 0; -} - -int space_node::discardable() -{ - return set ? 0 : 1; -} - - -vunits node::vertical_width() -{ - return V0; -} - -vunits vline_node::vertical_width() -{ - return x; -} - -vunits vmotion_node::vertical_width() -{ - return n; -} - -int node::character_type() -{ - return 0; -} - -hunits node::subscript_correction() -{ - return H0; -} - -hunits node::italic_correction() -{ - return H0; -} - -hunits node::left_italic_correction() -{ - return H0; -} - -hunits node::skew() -{ - return H0; -} - - -/* vertical_extent methods */ - -void node::vertical_extent(vunits *min, vunits *max) -{ - vunits v = vertical_width(); - if (v < V0) { - *min = v; - *max = V0; - } - else { - *max = v; - *min = V0; - } -} - -void vline_node::vertical_extent(vunits *min, vunits *max) -{ - if (n == 0) - node::vertical_extent(min, max); - else { - vunits cmin, cmax; - n->vertical_extent(&cmin, &cmax); - vunits h = n->size(); - if (x < V0) { - if (-x < h) { - *min = x; - *max = V0; - } - else { - // we print the first character and then move up, so - *max = cmax; - // we print the last character and then move up h - *min = cmin + h; - if (*min > V0) - *min = V0; - *min += x; - } - } - else { - if (x < h) { - *max = x; - *min = V0; - } - else { - // we move down by h and then print the first character, so - *min = cmin + h; - if (*min > V0) - *min = V0; - *max = x + cmax; - } - } - } -} - -/* ascii_print methods */ - - -static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n) -{ - if (n == 0) - return; - ascii_print_reverse_node_list(ascii, n->next); - n->ascii_print(ascii); -} - -void dbreak_node::ascii_print(ascii_output_file *ascii) -{ - ascii_print_reverse_node_list(ascii, none); -} - -void kern_pair_node::ascii_print(ascii_output_file *ascii) -{ - n1->ascii_print(ascii); - n2->ascii_print(ascii); -} - - -void node::ascii_print(ascii_output_file *) -{ -} - -void space_node::ascii_print(ascii_output_file *ascii) -{ - if (!n.is_zero()) - ascii->outc(' '); -} - -void hmotion_node::ascii_print(ascii_output_file *ascii) -{ - // this is pretty arbitrary - if (n >= points_to_units(2)) - ascii->outc(' '); -} - -void space_char_hmotion_node::ascii_print(ascii_output_file *ascii) -{ - ascii->outc(' '); -} - -/* asciify methods */ - -void node::asciify(macro *m) -{ - m->append(this); -} - -void glyph_node::asciify(macro *m) -{ - unsigned char c = ci->get_ascii_code(); - if (c != 0) { - m->append(c); - delete this; - } - else - m->append(this); -} - -void kern_pair_node::asciify(macro *m) -{ - n1->asciify(m); - n2->asciify(m); - n1 = n2 = 0; - delete this; -} - -static void asciify_reverse_node_list(macro *m, node *n) -{ - if (n == 0) - return; - asciify_reverse_node_list(m, n->next); - n->asciify(m); -} - -void dbreak_node::asciify(macro *m) -{ - asciify_reverse_node_list(m, none); - none = 0; - delete this; -} - -void ligature_node::asciify(macro *m) -{ - n1->asciify(m); - n2->asciify(m); - n1 = n2 = 0; - delete this; -} - -void break_char_node::asciify(macro *m) -{ - ch->asciify(m); - ch = 0; - delete this; -} - -void italic_corrected_node::asciify(macro *m) -{ - n->asciify(m); - n = 0; - delete this; -} - -void left_italic_corrected_node::asciify(macro *m) -{ - if (n) { - n->asciify(m); - n = 0; - } - delete this; -} - -space_char_hmotion_node::space_char_hmotion_node(hunits i, node *next) -: hmotion_node(i, next) -{ -} - -void space_char_hmotion_node::asciify(macro *m) -{ - m->append(' '); - delete this; -} - -void line_start_node::asciify(macro *) -{ - delete this; -} - -void vertical_size_node::asciify(macro *) -{ - delete this; -} - -breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/, - breakpoint *rest, int /*is_inner*/) -{ - return rest; -} - -int node::nbreaks() -{ - return 0; -} - -breakpoint *space_node::get_breakpoints(hunits width, int ns, breakpoint *rest, - int is_inner) -{ - if (next->discardable()) - return rest; - breakpoint *bp = new breakpoint; - bp->next = rest; - bp->width = width; - bp->nspaces = ns; - bp->hyphenated = 0; - if (is_inner) { - assert(rest != 0); - bp->index = rest->index + 1; - bp->nd = rest->nd; - } - else { - bp->nd = this; - bp->index = 0; - } - return bp; -} - -int space_node::nbreaks() -{ - if (next->discardable()) - return 0; - else - return 1; -} - -static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp, - int ns, breakpoint *rest) -{ - if (p != 0) { - rest = p->get_breakpoints(*widthp, - ns, - node_list_get_breakpoints(p->next, widthp, ns, - rest), - 1); - *widthp += p->width(); - } - return rest; -} - - -breakpoint *dbreak_node::get_breakpoints(hunits width, int ns, - breakpoint *rest, int is_inner) -{ - breakpoint *bp = new breakpoint; - bp->next = rest; - bp->width = width; - for (node *tem = pre; tem != 0; tem = tem->next) - bp->width += tem->width(); - bp->nspaces = ns; - bp->hyphenated = 1; - if (is_inner) { - assert(rest != 0); - bp->index = rest->index + 1; - bp->nd = rest->nd; - } - else { - bp->nd = this; - bp->index = 0; - } - return node_list_get_breakpoints(none, &width, ns, bp); -} - -int dbreak_node::nbreaks() -{ - int i = 1; - for (node *tem = none; tem != 0; tem = tem->next) - i += tem->nbreaks(); - return i; -} - -void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/) -{ - assert(0); -} - -void space_node::split(int where, node **pre, node **post) -{ - assert(where == 0); - *pre = next; - *post = 0; - delete this; -} - -static void node_list_split(node *p, int *wherep, node **prep, node **postp) -{ - if (p == 0) - return; - int nb = p->nbreaks(); - node_list_split(p->next, wherep, prep, postp); - if (*wherep < 0) { - p->next = *postp; - *postp = p; - } - else if (*wherep < nb) { - p->next = *prep; - p->split(*wherep, prep, postp); - } - else { - p->next = *prep; - *prep = p; - } - *wherep -= nb; -} - -void dbreak_node::split(int where, node **prep, node **postp) -{ - assert(where >= 0); - if (where == 0) { - *postp = post; - post = 0; - if (pre == 0) - *prep = next; - else { - node *tem; - for (tem = pre; tem->next != 0; tem = tem->next) - ; - tem->next = next; - *prep = pre; - } - pre = 0; - delete this; - } - else { - *prep = next; - where -= 1; - node_list_split(none, &where, prep, postp); - none = 0; - delete this; - } -} - - -hyphenation_type node::get_hyphenation_type() -{ - return HYPHEN_BOUNDARY; -} - - -hyphenation_type dbreak_node::get_hyphenation_type() -{ - return HYPHEN_INHIBIT; -} - -hyphenation_type kern_pair_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type dummy_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -hyphenation_type transparent_dummy_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -int node::interpret(macro *) -{ - return 0; -} - -special_node::special_node(const macro &m) -: mac(m) -{ -} - -int special_node::same(node *n) -{ - return mac == ((special_node *)n)->mac; -} - -const char *special_node::type() -{ - return "special_node"; -} - -node *special_node::copy() -{ - return new special_node(mac); -} - -void special_node::tprint_start(troff_output_file *out) -{ - out->start_special(); -} - -void special_node::tprint_char(troff_output_file *out, unsigned char c) -{ - out->special_char(c); -} - -void special_node::tprint_end(troff_output_file *out) -{ - out->end_special(); -} - -/* composite_node */ - -class composite_node : public charinfo_node { - node *n; - tfont *tf; -public: - composite_node(node *, charinfo *, tfont *, node * = 0); - ~composite_node(); - node *copy(); - hunits width(); - node *last_char_node(); - units size(); - void tprint(troff_output_file *); - hyphenation_type get_hyphenation_type(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - hyphen_list *get_hyphen_list(hyphen_list *tail); - node *add_self(node *, hyphen_list **); - tfont *get_tfont(); - int same(node *); - const char *type(); - void vertical_extent(vunits *, vunits *); - vunits vertical_width(); -}; - -composite_node::composite_node(node *p, charinfo *c, tfont *t, node *x) -: charinfo_node(c, x), n(p), tf(t) -{ -} - -composite_node::~composite_node() -{ - delete_node_list(n); -} - -node *composite_node::copy() -{ - return new composite_node(copy_node_list(n), ci, tf); -} - -hunits composite_node::width() -{ - hunits x; - if (tf->get_constant_space(&x)) - return x; - x = H0; - for (node *tem = n; tem; tem = tem->next) - x += tem->width(); - hunits offset; - if (tf->get_bold(&offset)) - x += offset; - x += tf->get_track_kern(); - return x; -} - -node *composite_node::last_char_node() -{ - return this; -} - -vunits composite_node::vertical_width() -{ - vunits v = V0; - for (node *tem = n; tem; tem = tem->next) - v += tem->vertical_width(); - return v; -} - -units composite_node::size() -{ - return tf->get_size().to_units(); -} - -hyphenation_type composite_node::get_hyphenation_type() -{ - return HYPHEN_MIDDLE; -} - -void composite_node::asciify(macro *m) -{ - unsigned char c = ci->get_ascii_code(); - if (c != 0) { - m->append(c); - delete this; - } - else - m->append(this); -} - -void composite_node::ascii_print(ascii_output_file *ascii) -{ - unsigned char c = ci->get_ascii_code(); - if (c != 0) - ascii->outc(c); - else - ascii->outs(ci->nm.contents()); - -} - -hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail) -{ - return new hyphen_list(ci->get_hyphenation_code(), tail); - -} - -node *composite_node::add_self(node *nn, hyphen_list **p) -{ - assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); - next = nn; - nn = this; - if ((*p)->hyphen) - nn = nn->add_discretionary_hyphen(); - hyphen_list *pp = *p; - *p = (*p)->next; - delete pp; - return nn; -} - -tfont *composite_node::get_tfont() -{ - return tf; -} - -node *reverse_node_list(node *n) -{ - node *r = 0; - while (n) { - node *tem = n; - n = n->next; - tem->next = r; - r = tem; - } - return r; -} - -void composite_node::vertical_extent(vunits *min, vunits *max) -{ - n = reverse_node_list(n); - node_list_vertical_extent(n, min, max); - n = reverse_node_list(n); -} - -word_space_node::word_space_node(hunits d, node *x) : space_node(d, x) -{ -} - -word_space_node::word_space_node(hunits d, int s, node *x) -: space_node(d, s, x) -{ -} - -node *word_space_node::copy() -{ - return new word_space_node(n, set); -} - -void word_space_node::tprint(troff_output_file *out) -{ - out->word_marker(); - space_node::tprint(out); -} - -unbreakable_space_node::unbreakable_space_node(hunits d, node *x) -: word_space_node(d, x) -{ -} - -unbreakable_space_node::unbreakable_space_node(hunits d, int s, node *x) -: word_space_node(d, s, x) -{ -} - -node *unbreakable_space_node::copy() -{ - return new unbreakable_space_node(n, set); -} - -breakpoint *unbreakable_space_node::get_breakpoints(hunits, int, - breakpoint *rest, int) -{ - return rest; -} - -int unbreakable_space_node::nbreaks() -{ - return 0; -} - -void unbreakable_space_node::split(int, node **, node **) -{ - assert(0); -} - -int unbreakable_space_node::merge_space(hunits) -{ - return 0; -} - -hvpair::hvpair() -{ -} - -draw_node::draw_node(char c, hvpair *p, int np, font_size s) - : npoints(np), sz(s), code(c) -{ - point = new hvpair[npoints]; - for (int i = 0; i < npoints; i++) - point[i] = p[i]; -} - -int draw_node::same(node *n) -{ - draw_node *nd = (draw_node *)n; - if (code != nd->code || npoints != nd->npoints || sz != nd->sz) - return 0; - for (int i = 0; i < npoints; i++) - if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v) - return 0; - return 1; -} - -const char *draw_node::type() -{ - return "draw_node"; -} - -draw_node::~draw_node() -{ - if (point) - a_delete point; -} - -hunits draw_node::width() -{ - hunits x = H0; - for (int i = 0; i < npoints; i++) - x += point[i].h; - return x; -} - -vunits draw_node::vertical_width() -{ - if (code == 'e') - return V0; - vunits x = V0; - for (int i = 0; i < npoints; i++) - x += point[i].v; - return x; -} - -node *draw_node::copy() -{ - return new draw_node(code, point, npoints, sz); -} - -void draw_node::tprint(troff_output_file *out) -{ - out->draw(code, point, npoints, sz); -} - -/* tprint methods */ - -void glyph_node::tprint(troff_output_file *out) -{ - tfont *ptf = tf->get_plain(); - if (ptf == tf) - out->put_char_width(ci, ptf, width(), H0); - else { - hunits offset; - int bold = tf->get_bold(&offset); - hunits w = ptf->get_width(ci); - hunits k = H0; - hunits x; - int cs = tf->get_constant_space(&x); - if (cs) { - x -= w; - if (bold) - x -= offset; - hunits x2 = x/2; - out->right(x2); - k = x - x2; - } - else - k = tf->get_track_kern(); - if (bold) { - out->put_char(ci, ptf); - out->right(offset); - } - out->put_char_width(ci, ptf, w, k); - } -} - -void glyph_node::zero_width_tprint(troff_output_file *out) -{ - tfont *ptf = tf->get_plain(); - hunits offset; - int bold = tf->get_bold(&offset); - hunits x; - int cs = tf->get_constant_space(&x); - if (cs) { - x -= ptf->get_width(ci); - if (bold) - x -= offset; - x = x/2; - out->right(x); - } - out->put_char(ci, ptf); - if (bold) { - out->right(offset); - out->put_char(ci, ptf); - out->right(-offset); - } - if (cs) - out->right(-x); -} - -void break_char_node::tprint(troff_output_file *t) -{ - ch->tprint(t); -} - -void break_char_node::zero_width_tprint(troff_output_file *t) -{ - ch->zero_width_tprint(t); -} - -void hline_node::tprint(troff_output_file *out) -{ - if (x < H0) { - out->right(x); - x = -x; - } - if (n == 0) { - out->right(x); - return; - } - hunits w = n->width(); - if (w <= H0) { - error("horizontal line drawing character must have positive width"); - out->right(x); - return; - } - int i = int(x/w); - if (i == 0) { - hunits xx = x - w; - hunits xx2 = xx/2; - out->right(xx2); - n->tprint(out); - out->right(xx - xx2); - } - else { - hunits rem = x - w*i; - if (rem > H0) - if (n->overlaps_horizontally()) { - n->tprint(out); - out->right(rem - w); - } - else - out->right(rem); - while (--i >= 0) - n->tprint(out); - } -} - -void vline_node::tprint(troff_output_file *out) -{ - if (n == 0) { - out->down(x); - return; - } - vunits h = n->size(); - int overlaps = n->overlaps_vertically(); - vunits y = x; - if (y < V0) { - y = -y; - int i = y / h; - vunits rem = y - i*h; - if (i == 0) { - out->right(n->width()); - out->down(-rem); - } - else { - while (--i > 0) { - n->zero_width_tprint(out); - out->down(-h); - } - if (overlaps) { - n->zero_width_tprint(out); - out->down(-rem); - n->tprint(out); - out->down(-h); - } - else { - n->tprint(out); - out->down(-h - rem); - } - } - } - else { - int i = y / h; - vunits rem = y - i*h; - if (i == 0) { - out->down(rem); - out->right(n->width()); - } - else { - out->down(h); - if (overlaps) - n->zero_width_tprint(out); - out->down(rem); - while (--i > 0) { - n->zero_width_tprint(out); - out->down(h); - } - n->tprint(out); - } - } -} - -void zero_width_node::tprint(troff_output_file *out) -{ - if (!n) - return; - if (!n->next) { - n->zero_width_tprint(out); - return; - } - int hpos = out->get_hpos(); - int vpos = out->get_vpos(); - node *tem = n; - while (tem) { - tem->tprint(out); - tem = tem->next; - } - out->moveto(hpos, vpos); -} - -void overstrike_node::tprint(troff_output_file *out) -{ - hunits pos = H0; - for (node *tem = list; tem; tem = tem->next) { - hunits x = (max_width - tem->width())/2; - out->right(x - pos); - pos = x; - tem->zero_width_tprint(out); - } - out->right(max_width - pos); -} - -void bracket_node::tprint(troff_output_file *out) -{ - if (list == 0) - return; - int npieces = 0; - node *tem; - for (tem = list; tem; tem = tem->next) - ++npieces; - vunits h = list->size(); - vunits totalh = h*npieces; - vunits y = (totalh - h)/2; - out->down(y); - for (tem = list; tem; tem = tem->next) { - tem->zero_width_tprint(out); - out->down(-h); - } - out->right(max_width); - out->down(totalh - y); -} - -void node::tprint(troff_output_file *) -{ -} - -void node::zero_width_tprint(troff_output_file *out) -{ - int hpos = out->get_hpos(); - int vpos = out->get_vpos(); - tprint(out); - out->moveto(hpos, vpos); -} - -void space_node::tprint(troff_output_file *out) -{ - out->right(n); -} - -void hmotion_node::tprint(troff_output_file *out) -{ - out->right(n); -} - -void vmotion_node::tprint(troff_output_file *out) -{ - out->down(n); -} - -void kern_pair_node::tprint(troff_output_file *out) -{ - n1->tprint(out); - out->right(amount); - n2->tprint(out); -} - -static void tprint_reverse_node_list(troff_output_file *out, node *n) -{ - if (n == 0) - return; - tprint_reverse_node_list(out, n->next); - n->tprint(out); -} - -void dbreak_node::tprint(troff_output_file *out) -{ - tprint_reverse_node_list(out, none); -} - -void composite_node::tprint(troff_output_file *out) -{ - hunits bold_offset; - int is_bold = tf->get_bold(&bold_offset); - hunits track_kern = tf->get_track_kern(); - hunits constant_space; - int is_constant_spaced = tf->get_constant_space(&constant_space); - hunits x = H0; - if (is_constant_spaced) { - x = constant_space; - for (node *tem = n; tem; tem = tem->next) - x -= tem->width(); - if (is_bold) - x -= bold_offset; - hunits x2 = x/2; - out->right(x2); - x -= x2; - } - if (is_bold) { - int hpos = out->get_hpos(); - int vpos = out->get_vpos(); - tprint_reverse_node_list(out, n); - out->moveto(hpos, vpos); - out->right(bold_offset); - } - tprint_reverse_node_list(out, n); - if (is_constant_spaced) - out->right(x); - else - out->right(track_kern); -} - -node *make_composite_node(charinfo *s, environment *env) -{ - int fontno = env_definite_font(env); - if (fontno < 0) { - error("no current font"); - return 0; - } - assert(fontno < font_table_size && font_table[fontno] != 0); - node *n = charinfo_to_node_list(s, env); - font_size fs = env->get_font_size(); - int char_height = env->get_char_height(); - int char_slant = env->get_char_slant(); - tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, - fontno); - if (env->is_composite()) - tf = tf->get_plain(); - return new composite_node(n, s, tf); -} - -node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0) -{ - int fontno = env_definite_font(env); - if (fontno < 0) { - error("no current font"); - return 0; - } - assert(fontno < font_table_size && font_table[fontno] != 0); - int fn = fontno; - int found = font_table[fontno]->contains(s); - if (!found) { - if (s->numbered()) { - if (!no_error_message) - warning(WARN_CHAR, "can't find numbered character %1", - s->get_number()); - return 0; - } - special_font_list *sf = font_table[fontno]->sf; - while (sf != 0 && !found) { - fn = sf->n; - if (font_table[fn]) - found = font_table[fn]->contains(s); - sf = sf->next; - } - if (!found) { - sf = global_special_fonts; - while (sf != 0 && !found) { - fn = sf->n; - if (font_table[fn]) - found = font_table[fn]->contains(s); - sf = sf->next; - } - } - if (!found -#if 0 - && global_special_fonts == 0 && font_table[fontno]->sf == 0 -#endif - ) { - for (fn = 0; fn < font_table_size; fn++) - if (font_table[fn] - && font_table[fn]->is_special() - && font_table[fn]->contains(s)) { - found = 1; - break; - } - } - if (!found) { - if (!no_error_message && s->first_time_not_found()) { - unsigned char input_code = s->get_ascii_code(); - if (input_code != 0) { - if (csgraph(input_code)) - warning(WARN_CHAR, "can't find character `%1'", input_code); - else - warning(WARN_CHAR, "can't find character with input code %1", - int(input_code)); - } - else - warning(WARN_CHAR, "can't find special character `%1'", - s->nm.contents()); - } - return 0; - } - } - font_size fs = env->get_font_size(); - int char_height = env->get_char_height(); - int char_slant = env->get_char_slant(); - tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn); - if (env->is_composite()) - tf = tf->get_plain(); - return new glyph_node(s, tf); -} - -node *make_node(charinfo *ci, environment *env) -{ - switch (ci->get_special_translation()) { - case charinfo::TRANSLATE_SPACE: - return new space_char_hmotion_node(env->get_space_width()); - case charinfo::TRANSLATE_DUMMY: - return new dummy_node; - case charinfo::TRANSLATE_HYPHEN_INDICATOR: - error("translation to \\% ignored in this context"); - break; - } - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - macro *mac = ci->get_macro(); - if (mac) - return make_composite_node(ci, env); - else - return make_glyph_node(ci, env); -} - -int character_exists(charinfo *ci, environment *env) -{ - if (ci->get_special_translation() != charinfo::TRANSLATE_NONE) - return 1; - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - if (ci->get_macro()) - return 1; - node *nd = make_glyph_node(ci, env, 1); - if (nd) { - delete nd; - return 1; - } - return 0; -} - -node *node::add_char(charinfo *ci, environment *env, hunits *widthp) -{ - node *res; - switch (ci->get_special_translation()) { - case charinfo::TRANSLATE_SPACE: - res = new space_char_hmotion_node(env->get_space_width(), this); - *widthp += res->width(); - return res; - case charinfo::TRANSLATE_DUMMY: - return new dummy_node(this); - case charinfo::TRANSLATE_HYPHEN_INDICATOR: - return add_discretionary_hyphen(); - } - charinfo *tem = ci->get_translation(); - if (tem) - ci = tem; - macro *mac = ci->get_macro(); - if (mac) { - res = make_composite_node(ci, env); - if (res) { - res->next = this; - *widthp += res->width(); - } - else - return this; - } - else { - node *gn = make_glyph_node(ci, env); - if (gn == 0) - return this; - else { - hunits old_width = width(); - node *p = gn->merge_self(this); - if (p == 0) { - *widthp += gn->width(); - gn->next = this; - res = gn; - } - else { - *widthp += p->width() - old_width; - res = p; - } - } - } - int break_code = 0; - if (ci->can_break_before()) - break_code = 1; - if (ci->can_break_after()) - break_code |= 2; - if (break_code) { - node *next1 = res->next; - res->next = 0; - res = new break_char_node(res, break_code, next1); - } - return res; -} - - -#ifdef __GNUG__ -inline -#endif -int same_node(node *n1, node *n2) -{ - if (n1 != 0) { - if (n2 != 0) - return n1->type() == n2->type() && n1->same(n2); - else - return 0; - } - else - return n2 == 0; -} - -int same_node_list(node *n1, node *n2) -{ - while (n1 && n2) { - if (n1->type() != n2->type() || !n1->same(n2)) - return 0; - n1 = n1->next; - n2 = n2->next; - } - return !n1 && !n2; -} - -int extra_size_node::same(node *nd) -{ - return n == ((extra_size_node *)nd)->n; -} - -const char *extra_size_node::type() -{ - return "extra_size_node"; -} - -int vertical_size_node::same(node *nd) -{ - return n == ((vertical_size_node *)nd)->n; -} - -const char *vertical_size_node::type() -{ - return "vertical_size_node"; -} - -int hmotion_node::same(node *nd) -{ - return n == ((hmotion_node *)nd)->n; -} - -const char *hmotion_node::type() -{ - return "hmotion_node"; -} - -int space_char_hmotion_node::same(node *nd) -{ - return n == ((space_char_hmotion_node *)nd)->n; -} - -const char *space_char_hmotion_node::type() -{ - return "space_char_hmotion_node"; -} - -int vmotion_node::same(node *nd) -{ - return n == ((vmotion_node *)nd)->n; -} - -const char *vmotion_node::type() -{ - return "vmotion_node"; -} - -int hline_node::same(node *nd) -{ - return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n); -} - -const char *hline_node::type() -{ - return "hline_node"; -} - -int vline_node::same(node *nd) -{ - return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n); -} - -const char *vline_node::type() -{ - return "vline_node"; -} - -int dummy_node::same(node * /*nd*/) -{ - return 1; -} - -const char *dummy_node::type() -{ - return "dummy_node"; -} - -int transparent_dummy_node::same(node * /*nd*/) -{ - return 1; -} - -const char *transparent_dummy_node::type() -{ - return "transparent_dummy_node"; -} - -int transparent_dummy_node::ends_sentence() -{ - return 2; -} - -int zero_width_node::same(node *nd) -{ - return same_node_list(n, ((zero_width_node *)nd)->n); -} - -const char *zero_width_node::type() -{ - return "zero_width_node"; -} - -int italic_corrected_node::same(node *nd) -{ - return (x == ((italic_corrected_node *)nd)->x - && same_node(n, ((italic_corrected_node *)nd)->n)); -} - -const char *italic_corrected_node::type() -{ - return "italic_corrected_node"; -} - - -left_italic_corrected_node::left_italic_corrected_node(node *x) -: node(x), n(0) -{ -} - -left_italic_corrected_node::~left_italic_corrected_node() -{ - delete n; -} - -node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn) -{ - if (n == 0) { - hunits lic = gn->left_italic_correction(); - if (!lic.is_zero()) { - x = lic; - n = gn; - return this; - } - } - else { - node *nd = n->merge_glyph_node(gn); - if (nd) { - n = nd; - x = n->left_italic_correction(); - return this; - } - } - return 0; -} - -node *left_italic_corrected_node::copy() -{ - left_italic_corrected_node *nd = new left_italic_corrected_node; - if (n) { - nd->n = n->copy(); - nd->x = x; - } - return nd; -} - -void left_italic_corrected_node::tprint(troff_output_file *out) -{ - if (n) { - out->right(x); - n->tprint(out); - } -} - -const char *left_italic_corrected_node::type() -{ - return "left_italic_corrected_node"; -} - -int left_italic_corrected_node::same(node *nd) -{ - return (x == ((left_italic_corrected_node *)nd)->x - && same_node(n, ((left_italic_corrected_node *)nd)->n)); -} - -void left_italic_corrected_node::ascii_print(ascii_output_file *out) -{ - if (n) - n->ascii_print(out); -} - -hunits left_italic_corrected_node::width() -{ - return n ? n->width() + x : H0; -} - -void left_italic_corrected_node::vertical_extent(vunits *min, vunits *max) -{ - if (n) - n->vertical_extent(min, max); - else - node::vertical_extent(min, max); -} - -hunits left_italic_corrected_node::skew() -{ - return n ? n->skew() + x/2 : H0; -} - -hunits left_italic_corrected_node::subscript_correction() -{ - return n ? n->subscript_correction() : H0; -} - -hunits left_italic_corrected_node::italic_correction() -{ - return n ? n->italic_correction() : H0; -} - -int left_italic_corrected_node::ends_sentence() -{ - return n ? n->ends_sentence() : 0; -} - -int left_italic_corrected_node::overlaps_horizontally() -{ - return n ? n->overlaps_horizontally() : 0; -} - -int left_italic_corrected_node::overlaps_vertically() -{ - return n ? n->overlaps_vertically() : 0; -} - -node *left_italic_corrected_node::last_char_node() -{ - return n ? n->last_char_node() : 0; -} - -tfont *left_italic_corrected_node::get_tfont() -{ - return n ? n->get_tfont() : 0; -} - -hyphenation_type left_italic_corrected_node::get_hyphenation_type() -{ - if (n) - return n->get_hyphenation_type(); - else - return HYPHEN_MIDDLE; -} - -hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail) -{ - return n ? n->get_hyphen_list(tail) : tail; -} - -node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p) -{ - if (n) { - nd = new left_italic_corrected_node(nd); - nd = n->add_self(nd, p); - n = 0; - delete this; - } - return nd; -} - -int left_italic_corrected_node::character_type() -{ - return n ? n->character_type() : 0; -} - -int overstrike_node::same(node *nd) -{ - return same_node_list(list, ((overstrike_node *)nd)->list); -} - -const char *overstrike_node::type() -{ - return "overstrike_node"; -} - -int bracket_node::same(node *nd) -{ - return same_node_list(list, ((bracket_node *)nd)->list); -} - -const char *bracket_node::type() -{ - return "bracket_node"; -} - -int composite_node::same(node *nd) -{ - return ci == ((composite_node *)nd)->ci - && same_node_list(n, ((composite_node *)nd)->n); -} - -const char *composite_node::type() -{ - return "composite_node"; -} - -int glyph_node::same(node *nd) -{ - return ci == ((glyph_node *)nd)->ci && tf == ((glyph_node *)nd)->tf; -} - -const char *glyph_node::type() -{ - return "glyph_node"; -} - -int ligature_node::same(node *nd) -{ - return (same_node(n1, ((ligature_node *)nd)->n1) - && same_node(n2, ((ligature_node *)nd)->n2) - && glyph_node::same(nd)); -} - -const char *ligature_node::type() -{ - return "ligature_node"; -} - -int kern_pair_node::same(node *nd) -{ - return (amount == ((kern_pair_node *)nd)->amount - && same_node(n1, ((kern_pair_node *)nd)->n1) - && same_node(n2, ((kern_pair_node *)nd)->n2)); -} - -const char *kern_pair_node::type() -{ - return "kern_pair_node"; -} - -int dbreak_node::same(node *nd) -{ - return (same_node_list(none, ((dbreak_node *)nd)->none) - && same_node_list(pre, ((dbreak_node *)nd)->pre) - && same_node_list(post, ((dbreak_node *)nd)->post)); -} - -const char *dbreak_node::type() -{ - return "dbreak_node"; -} - -int break_char_node::same(node *nd) -{ - return (break_code == ((break_char_node *)nd)->break_code - && same_node(ch, ((break_char_node *)nd)->ch)); -} - -const char *break_char_node::type() -{ - return "break_char_node"; -} - -int line_start_node::same(node * /*nd*/) -{ - return 1; -} - -const char *line_start_node::type() -{ - return "line_start_node"; -} - -int space_node::same(node *nd) -{ - return n == ((space_node *)nd)->n && set == ((space_node *)nd)->set; -} - -const char *space_node::type() -{ - return "space_node"; -} - -int word_space_node::same(node *nd) -{ - return (n == ((word_space_node *)nd)->n - && set == ((word_space_node *)nd)->set); -} - -const char *word_space_node::type() -{ - return "word_space_node"; -} - -int unbreakable_space_node::same(node *nd) -{ - return (n == ((unbreakable_space_node *)nd)->n - && set == ((unbreakable_space_node *)nd)->set); -} - -const char *unbreakable_space_node::type() -{ - return "unbreakable_space_node"; -} - -int diverted_space_node::same(node *nd) -{ - return n == ((diverted_space_node *)nd)->n; -} - -const char *diverted_space_node::type() -{ - return "diverted_space_node"; -} - -int diverted_copy_file_node::same(node *nd) -{ - return filename == ((diverted_copy_file_node *)nd)->filename; -} - -const char *diverted_copy_file_node::type() -{ - return "diverted_copy_file_node"; -} - -// Grow the font_table so that its size is > n. - -static void grow_font_table(int n) -{ - assert(n >= font_table_size); - font_info **old_font_table = font_table; - int old_font_table_size = font_table_size; - font_table_size = font_table_size ? (font_table_size*3)/2 : 10; - if (font_table_size <= n) - font_table_size = n + 10; - font_table = new font_info *[font_table_size]; - if (old_font_table_size) - memcpy(font_table, old_font_table, - old_font_table_size*sizeof(font_info *)); - a_delete old_font_table; - for (int i = old_font_table_size; i < font_table_size; i++) - font_table[i] = 0; -} - -dictionary font_translation_dictionary(17); - -static symbol get_font_translation(symbol nm) -{ - void *p = font_translation_dictionary.lookup(nm); - return p ? symbol((char *)p) : nm; -} - -dictionary font_dictionary(50); - -static int mount_font_no_translate(int n, symbol name, symbol external_name) -{ - assert(n >= 0); - // We store the address of this char in font_dictionary to indicate - // that we've previously tried to mount the font and failed. - static char a_char; - font *fm = 0; - void *p = font_dictionary.lookup(external_name); - if (p == 0) { - int not_found; - fm = font::load_font(external_name.contents(), ¬_found); - if (!fm) { - if (not_found) - warning(WARN_FONT, "can't find font `%1'", external_name.contents()); - font_dictionary.lookup(external_name, &a_char); - return 0; - } - font_dictionary.lookup(name, fm); - } - else if (p == &a_char) { -#if 0 - error("invalid font `%1'", external_name.contents()); -#endif - return 0; - } - else - fm = (font*)p; - if (n >= font_table_size) { - if (n - font_table_size > 1000) { - error("font position too much larger than first unused position"); - return 0; - } - grow_font_table(n); - } - else if (font_table[n] != 0) - delete font_table[n]; - font_table[n] = new font_info(name, n, external_name, fm); - font_family::invalidate_fontno(n); - return 1; -} - -int mount_font(int n, symbol name, symbol external_name) -{ - assert(n >= 0); - name = get_font_translation(name); - if (external_name.is_null()) - external_name = name; - else - external_name = get_font_translation(external_name); - return mount_font_no_translate(n, name, external_name); -} - -void mount_style(int n, symbol name) -{ - assert(n >= 0); - if (n >= font_table_size) { - if (n - font_table_size > 1000) { - error("font position too much larger than first unused position"); - return; - } - grow_font_table(n); - } - else if (font_table[n] != 0) - delete font_table[n]; - font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0); - font_family::invalidate_fontno(n); -} - -/* global functions */ - -void font_translate() -{ - symbol from = get_name(1); - if (!from.is_null()) { - symbol to = get_name(); - if (to.is_null() || from == to) - font_translation_dictionary.remove(from); - else - font_translation_dictionary.lookup(from, (void *)to.contents()); - } - skip_line(); -} - -void font_position() -{ - int n; - if (get_integer(&n)) { - if (n < 0) - error("negative font position"); - else { - symbol internal_name = get_name(1); - if (!internal_name.is_null()) { - symbol external_name = get_long_name(0); - mount_font(n, internal_name, external_name); // ignore error - } - } - } - skip_line(); -} - -font_family::font_family(symbol s) -: map_size(10), nm(s) -{ - map = new int[map_size]; - for (int i = 0; i < map_size; i++) - map[i] = -1; -} - -font_family::~font_family() -{ - a_delete map; -} - -int font_family::make_definite(int i) -{ - if (i >= 0) { - if (i < map_size && map[i] >= 0) - return map[i]; - else { - if (i < font_table_size && font_table[i] != 0) { - if (i >= map_size) { - int old_map_size = map_size; - int *old_map = map; - map_size *= 3; - map_size /= 2; - if (i >= map_size) - map_size = i + 10; - map = new int[map_size]; - memcpy(map, old_map, old_map_size*sizeof(int)); - a_delete old_map; - for (int j = old_map_size; j < map_size; j++) - map[j] = -1; - } - if (font_table[i]->is_style()) { - symbol sty = font_table[i]->get_name(); - symbol f = concat(nm, sty); - int n; - // don't use symbol_fontno, because that might return a style - // and because we don't want to translate the name - for (n = 0; n < font_table_size; n++) - if (font_table[n] != 0 && font_table[n]->is_named(f) - && !font_table[n]->is_style()) - break; - if (n >= font_table_size) { - n = next_available_font_position(); - if (!mount_font_no_translate(n, f, f)) - return -1; - } - return map[i] = n; - } - else - return map[i] = i; - } - else - return -1; - } - } - else - return -1; -} - -dictionary family_dictionary(5); - -font_family *lookup_family(symbol nm) -{ - font_family *f = (font_family *)family_dictionary.lookup(nm); - if (!f) { - f = new font_family(nm); - (void)family_dictionary.lookup(nm, f); - } - return f; -} - -void font_family::invalidate_fontno(int n) -{ - assert(n >= 0 && n < font_table_size); - dictionary_iterator iter(family_dictionary); - symbol nm; - font_family *fam; - while (iter.get(&nm, (void **)&fam)) { - int map_size = fam->map_size; - if (n < map_size) - fam->map[n] = -1; - for (int i = 0; i < map_size; i++) - if (fam->map[i] == n) - fam->map[i] = -1; - } -} - -void style() -{ - int n; - if (get_integer(&n)) { - if (n < 0) - error("negative font position"); - else { - symbol internal_name = get_name(1); - if (!internal_name.is_null()) - mount_style(n, internal_name); - } - } - skip_line(); -} - -static int get_fontno() -{ - int n; - tok.skip(); - if (tok.delimiter()) { - symbol s = get_name(1); - if (!s.is_null()) { - n = symbol_fontno(s); - if (n < 0) { - n = next_available_font_position(); - if (!mount_font(n, s)) - return -1; - } - return curenv->get_family()->make_definite(n); - } - } - else if (get_integer(&n)) { - if (n < 0 || n >= font_table_size || font_table[n] == 0) - error("bad font number"); - else - return curenv->get_family()->make_definite(n); - } - return -1; -} - -static int underline_fontno = 2; - -void underline_font() -{ - int n = get_fontno(); - if (n >= 0) - underline_fontno = n; - skip_line(); -} - -int get_underline_fontno() -{ - return underline_fontno; -} - -static void read_special_fonts(special_font_list **sp) -{ - special_font_list *s = *sp; - *sp = 0; - while (s != 0) { - special_font_list *tem = s; - s = s->next; - delete tem; - } - special_font_list **p = sp; - while (has_arg()) { - int i = get_fontno(); - if (i >= 0) { - special_font_list *tem = new special_font_list; - tem->n = i; - tem->next = 0; - *p = tem; - p = &(tem->next); - } - } -} - -void font_special_request() -{ - int n = get_fontno(); - if (n >= 0) - read_special_fonts(&font_table[n]->sf); - skip_line(); -} - - -void special_request() -{ - read_special_fonts(&global_special_fonts); - skip_line(); -} - -int next_available_font_position() -{ - int i; - for (i = 1; i < font_table_size && font_table[i] != 0; i++) - ; - return i; -} - -int symbol_fontno(symbol s) -{ - s = get_font_translation(s); - for (int i = 0; i < font_table_size; i++) - if (font_table[i] != 0 && font_table[i]->is_named(s)) - return i; - return -1; -} - -int is_good_fontno(int n) -{ - return n >= 0 && n < font_table_size && font_table[n] != NULL; -} - -int get_bold_fontno(int n) -{ - if (n >= 0 && n < font_table_size && font_table[n] != 0) { - hunits offset; - if (font_table[n]->get_bold(&offset)) - return offset.to_units() + 1; - else - return 0; - } - else - return 0; -} - -hunits env_digit_width(environment *env) -{ - node *n = make_glyph_node(charset_table['0'], env); - if (n) { - hunits x = n->width(); - delete n; - return x; - } - else - return H0; -} - -hunits env_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return scale(fs.to_units()/3, env->get_space_size(), 12); - else - return font_table[fn]->get_space_width(fs, env->get_space_size()); -} - -hunits env_sentence_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return scale(fs.to_units()/3, env->get_sentence_space_size(), 12); - else - return font_table[fn]->get_space_width(fs, env->get_sentence_space_size()); -} - -hunits env_half_narrow_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return 0; - else - return font_table[fn]->get_half_narrow_space_width(fs); -} - -hunits env_narrow_space_width(environment *env) -{ - int fn = env_definite_font(env); - font_size fs = env->get_font_size(); - if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) - return 0; - else - return font_table[fn]->get_narrow_space_width(fs); -} - -void bold_font() -{ - int n = get_fontno(); - if (n >= 0) { - if (has_arg()) { - if (tok.delimiter()) { - int f = get_fontno(); - if (f >= 0) { - units offset; - if (has_arg() && get_number(&offset, 'u') && offset >= 1) - font_table[f]->set_conditional_bold(n, hunits(offset - 1)); - else - font_table[f]->conditional_unbold(n); - } - } - else { - units offset; - if (get_number(&offset, 'u') && offset >= 1) - font_table[n]->set_bold(hunits(offset - 1)); - else - font_table[n]->unbold(); - } - } - else - font_table[n]->unbold(); - } - skip_line(); -} - -track_kerning_function::track_kerning_function() : non_zero(0) -{ -} - -track_kerning_function::track_kerning_function(int min_s, hunits min_a, - int max_s, hunits max_a) - : non_zero(1), - min_size(min_s), min_amount(min_a), - max_size(max_s), max_amount(max_a) -{ -} - -int track_kerning_function::operator==(const track_kerning_function &tk) -{ - if (non_zero) - return (tk.non_zero - && min_size == tk.min_size - && min_amount == tk.min_amount - && max_size == tk.max_size - && max_amount == tk.max_amount); - else - return !tk.non_zero; -} - -int track_kerning_function::operator!=(const track_kerning_function &tk) -{ - if (non_zero) - return (!tk.non_zero - || min_size != tk.min_size - || min_amount != tk.min_amount - || max_size != tk.max_size - || max_amount != tk.max_amount); - else - return tk.non_zero; -} - -hunits track_kerning_function::compute(int size) -{ - if (non_zero) { - if (max_size <= min_size) - return min_amount; - else if (size <= min_size) - return min_amount; - else if (size >= max_size) - return max_amount; - else - return (scale(max_amount, size - min_size, max_size - min_size) - + scale(min_amount, max_size - size, max_size - min_size)); - } - else - return H0; -} - -void track_kern() -{ - int n = get_fontno(); - if (n >= 0) { - int min_s, max_s; - hunits min_a, max_a; - if (has_arg() - && get_number(&min_s, 'z') - && get_hunits(&min_a, 'p') - && get_number(&max_s, 'z') - && get_hunits(&max_a, 'p')) { - track_kerning_function tk(min_s, min_a, max_s, max_a); - font_table[n]->set_track_kern(tk); - } - else { - track_kerning_function tk; - font_table[n]->set_track_kern(tk); - } - } - skip_line(); -} - -void constant_space() -{ - int n = get_fontno(); - if (n >= 0) { - int x, y; - if (!has_arg() || !get_integer(&x)) - font_table[n]->set_constant_space(CONSTANT_SPACE_NONE); - else { - if (!has_arg() || !get_number(&y, 'z')) - font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x); - else - font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE, - scale(y*x, - units_per_inch, - 36*72*sizescale)); - } - } - skip_line(); -} - -void ligature() -{ - int lig; - if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2) - global_ligature_mode = lig; - else - global_ligature_mode = 1; - skip_line(); -} - -void kern_request() -{ - int k; - if (has_arg() && get_integer(&k)) - global_kern_mode = k != 0; - else - global_kern_mode = 1; - skip_line(); -} - -void set_soft_hyphen_char() -{ - soft_hyphen_char = get_optional_char(); - if (!soft_hyphen_char) - soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); - skip_line(); -} - -void init_output() -{ - if (suppress_output_flag) - the_output = new suppress_output_file; - else if (ascii_output_flag) - the_output = new ascii_output_file; - else - the_output = new troff_output_file; -} - -class next_available_font_position_reg : public reg { -public: - const char *get_string(); -}; - -const char *next_available_font_position_reg::get_string() -{ - return i_to_a(next_available_font_position()); -} - -class printing_reg : public reg { -public: - const char *get_string(); -}; - -const char *printing_reg::get_string() -{ - if (the_output) - return the_output->is_printing() ? "1" : "0"; - else - return "0"; -} - -void init_node_requests() -{ - init_request("fp", font_position); - init_request("sty", style); - init_request("cs", constant_space); - init_request("bd", bold_font); - init_request("uf", underline_font); - init_request("lg", ligature); - init_request("kern", kern_request); - init_request("tkf", track_kern); - init_request("special", special_request); - init_request("fspecial", font_special_request); - init_request("ftr", font_translate); - init_request("shc", set_soft_hyphen_char); - number_reg_dictionary.define(".fp", new next_available_font_position_reg); - number_reg_dictionary.define(".kern", - new constant_int_reg(&global_kern_mode)); - number_reg_dictionary.define(".lg", - new constant_int_reg(&global_ligature_mode)); - number_reg_dictionary.define(".P", new printing_reg); - soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); -} diff --git a/contrib/groff/troff/node.h b/contrib/groff/troff/node.h deleted file mode 100644 index b509557..0000000 --- a/contrib/groff/troff/node.h +++ /dev/null @@ -1,495 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -struct hyphen_list { - unsigned char hyphen; - unsigned char breakable; - unsigned char hyphenation_code; - hyphen_list *next; - hyphen_list(unsigned char code, hyphen_list *p = 0); -}; - -void hyphenate(hyphen_list *, unsigned); - -enum hyphenation_type { HYPHEN_MIDDLE, HYPHEN_BOUNDARY, HYPHEN_INHIBIT }; - -class ascii_output_file; - -struct breakpoint; -struct vertical_size; -struct charinfo; - -class macro; - -class troff_output_file; -class tfont; -class environment; - -class glyph_node; -class diverted_space_node; -class token_node; - -struct node { - node *next; - node *last; - node(); - node(node *n); - node *add_char(charinfo *c, environment *, hunits *widthp); - - virtual ~node(); - virtual node *copy() = 0; - virtual hunits width(); - virtual hunits subscript_correction(); - virtual hunits italic_correction(); - virtual hunits left_italic_correction(); - virtual hunits skew(); - virtual int nspaces(); - virtual int merge_space(hunits); - virtual vunits vertical_width(); - virtual node *last_char_node(); - virtual void vertical_extent(vunits *min, vunits *max); - virtual int character_type(); - virtual void set_vertical_size(vertical_size *); - virtual int ends_sentence(); - virtual node *merge_self(node *); - virtual node *add_discretionary_hyphen(); - virtual node *add_self(node *, hyphen_list **); - virtual hyphen_list *get_hyphen_list(hyphen_list *s = 0); - virtual void ascii_print(ascii_output_file *); - virtual void asciify(macro *); - virtual int discardable(); - virtual void spread_space(int *, hunits *); - virtual void freeze_space(); - virtual breakpoint *get_breakpoints(hunits width, int nspaces, - breakpoint *rest = 0, - int is_inner = 0); - virtual int nbreaks(); - virtual void split(int, node **, node **); - virtual hyphenation_type get_hyphenation_type(); - virtual int reread(int *); - virtual token_node *get_token_node(); - virtual int overlaps_vertically(); - virtual int overlaps_horizontally(); - virtual units size(); - virtual int interpret(macro *); - - virtual node *merge_glyph_node(glyph_node *); - virtual tfont *get_tfont(); - virtual void tprint(troff_output_file *); - virtual void zero_width_tprint(troff_output_file *); - - node *add_italic_correction(hunits *); - - virtual int same(node *) = 0; - virtual const char *type() = 0; -}; - -inline node::node() : next(0) -{ -} - -inline node::node(node *n) : next(n) -{ -} - -inline node::~node() -{ -} - -// 0 means it doesn't, 1 means it does, 2 means it's transparent - -int node_list_ends_sentence(node *); - -struct breakpoint { - breakpoint *next; - hunits width; - int nspaces; - node *nd; - int index; - char hyphenated; -}; - -class line_start_node : public node { -public: - line_start_node() {} - node *copy() { return new line_start_node; } - int same(node *); - const char *type(); - void asciify(macro *); -}; - -class space_node : public node { -private: -#if 0 - enum { BLOCK = 1024 }; - static space_node *free_list; - void operator delete(void *); -#endif -protected: - hunits n; - char set; - space_node(hunits, int, node * = 0); -public: - space_node(hunits d, node *p = 0); -#if 0 - ~space_node(); - void *operator new(size_t); -#endif - node *copy(); - int nspaces(); - hunits width(); - int discardable(); - int merge_space(hunits); - void freeze_space(); - void spread_space(int*, hunits*); - void tprint(troff_output_file *); - breakpoint *get_breakpoints(hunits width, int nspaces, breakpoint *rest = 0, - int is_inner = 0); - int nbreaks(); - void split(int, node **, node **); - void ascii_print(ascii_output_file *); - int same(node *); - const char *type(); -}; - -class word_space_node : public space_node { -protected: - word_space_node(hunits, int, node * = 0); -public: - word_space_node(hunits, node * = 0); - node *copy(); - void tprint(troff_output_file *); - int same(node *); - const char *type(); -}; - -class unbreakable_space_node : public word_space_node { - unbreakable_space_node(hunits, int, node * = 0); -public: - unbreakable_space_node(hunits, node * = 0); - node *copy(); - int same(node *); - const char *type(); - breakpoint *get_breakpoints(hunits width, int nspaces, breakpoint *rest = 0, - int is_inner = 0); - int nbreaks(); - void split(int, node **, node **); - int merge_space(hunits); -}; - -class diverted_space_node : public node { -public: - vunits n; - diverted_space_node(vunits d, node *p = 0); - node *copy(); - int reread(int *); - int same(node *); - const char *type(); -}; - -class diverted_copy_file_node : public node { - symbol filename; -public: - vunits n; - diverted_copy_file_node(symbol s, node *p = 0); - node *copy(); - int reread(int *); - int same(node *); - const char *type(); -}; - -class extra_size_node : public node { - vunits n; - public: - extra_size_node(vunits i) : n(i) {} - void set_vertical_size(vertical_size *); - node *copy(); - int same(node *); - const char *type(); -}; - -class vertical_size_node : public node { - vunits n; - public: - vertical_size_node(vunits i) : n(i) {} - void set_vertical_size(vertical_size *); - void asciify(macro *); - node *copy(); - int same(node *); - const char *type(); -}; - -class hmotion_node : public node { -protected: - hunits n; -public: - hmotion_node(hunits i, node *next = 0) : node(next), n(i) {} - node *copy(); - void tprint(troff_output_file *); - hunits width(); - void ascii_print(ascii_output_file *); - int same(node *); - const char *type(); -}; - -class space_char_hmotion_node : public hmotion_node { -public: - space_char_hmotion_node(hunits i, node *next = 0); - node *copy(); - void ascii_print(ascii_output_file *); - void asciify(macro *); - int same(node *); - const char *type(); -}; - -class vmotion_node : public node { - vunits n; - public: - vmotion_node(vunits i) : n(i) {} - void tprint(troff_output_file *); - node *copy(); - vunits vertical_width(); - int same(node *); - const char *type(); -}; - - -class hline_node : public node { - hunits x; - node *n; - public: - hline_node(hunits i, node *c, node *next = 0) : node(next), x(i), n(c) {} - ~hline_node(); - node *copy(); - hunits width(); - void tprint(troff_output_file *); - int same(node *); - const char *type(); -}; - -class vline_node : public node { - vunits x; - node *n; - public: - vline_node(vunits i, node *c, node *next= 0) : node(next), x(i), n(c) {} - ~vline_node(); - node *copy(); - void tprint(troff_output_file *); - hunits width(); - vunits vertical_width(); - void vertical_extent(vunits *, vunits *); - int same(node *); - const char *type(); -}; - - -class dummy_node : public node { - public: - dummy_node(node *nd = 0) : node(nd) {} - node *copy(); - int same(node *); - const char *type(); - hyphenation_type get_hyphenation_type(); -}; - -class transparent_dummy_node : public node { -public: - transparent_dummy_node() {} - node *copy(); - int same(node *); - const char *type(); - int ends_sentence(); - hyphenation_type get_hyphenation_type(); -}; - -class zero_width_node : public node { - node *n; - public: - zero_width_node(node *gn); - ~zero_width_node(); - node *copy(); - void tprint(troff_output_file *); - int same(node *); - const char *type(); - void append(node *); - int character_type(); - void vertical_extent(vunits *min, vunits *max); -}; - -class left_italic_corrected_node : public node { - node *n; - hunits x; -public: - left_italic_corrected_node(node * = 0); - ~left_italic_corrected_node(); - void tprint(troff_output_file *); - void ascii_print(ascii_output_file *); - void asciify(macro *); - node *copy(); - int same(node *); - const char *type(); - hunits width(); - node *last_char_node(); - void vertical_extent(vunits *, vunits *); - int ends_sentence(); - int overlaps_horizontally(); - int overlaps_vertically(); - hyphenation_type get_hyphenation_type(); - tfont *get_tfont(); - int character_type(); - hunits skew(); - hunits italic_correction(); - hunits subscript_correction(); - hyphen_list *get_hyphen_list(hyphen_list *ss = 0); - node *add_self(node *, hyphen_list **); - node *merge_glyph_node(glyph_node *); -}; - -class overstrike_node : public node { - node *list; - hunits max_width; -public: - overstrike_node(); - ~overstrike_node(); - node *copy(); - void tprint(troff_output_file *); - void overstrike(node *); // add another node to be overstruck - hunits width(); - int same(node *); - const char *type(); -}; - -class bracket_node : public node { - node *list; - hunits max_width; -public: - bracket_node(); - ~bracket_node(); - node *copy(); - void tprint(troff_output_file *); - void bracket(node *); // add another node to be overstruck - hunits width(); - int same(node *); - const char *type(); -}; - -class special_node : public node { - macro mac; - void tprint_start(troff_output_file *); - void tprint_char(troff_output_file *, unsigned char); - void tprint_end(troff_output_file *); -public: - special_node(const macro &); - node *copy(); - void tprint(troff_output_file *); - int same(node *); - const char *type(); -}; - - -struct hvpair { - hunits h; - vunits v; - - hvpair(); -}; - -class draw_node : public node { - int npoints; - font_size sz; - char code; - hvpair *point; -public: - draw_node(char, hvpair *, int, font_size); - ~draw_node(); - hunits width(); - vunits vertical_width(); - node *copy(); - void tprint(troff_output_file *); - int same(node *); - const char *type(); -}; - -class charinfo; -node *make_node(charinfo *ci, environment *); -int character_exists(charinfo *, environment *); - -int same_node_list(node *n1, node *n2); -node *reverse_node_list(node *n); -void delete_node_list(node *); -node *copy_node_list(node *); - -int get_bold_fontno(int f); - -inline hyphen_list::hyphen_list(unsigned char code, hyphen_list *p) -: hyphen(0), breakable(0), hyphenation_code(code), next(p) -{ -} - -extern void read_desc(); -extern int mount_font(int n, symbol, symbol = NULL_SYMBOL); -extern void mount_style(int n, symbol); -extern int is_good_fontno(int n); -extern int symbol_fontno(symbol); -extern int next_available_font_position(); -extern void init_size_table(int *); -extern int get_underline_fontno(); - -class output_file { - char make_g_plus_plus_shut_up; -public: - output_file(); - virtual ~output_file(); - virtual void trailer(vunits page_length); - virtual void flush() = 0; - virtual void transparent_char(unsigned char) = 0; - virtual void print_line(hunits x, vunits y, node *n, - vunits before, vunits after) = 0; - virtual void begin_page(int pageno, vunits page_length) = 0; - virtual void copy_file(hunits x, vunits y, const char *filename) = 0; - virtual int is_printing() = 0; - virtual void put_filename (const char *filename); -#ifdef COLUMN - virtual void vjustify(vunits, symbol); -#endif /* COLUMN */ -}; - -#ifndef POPEN_MISSING -extern char *pipe_command; -#endif - -extern output_file *the_output; -extern void init_output(); -int in_output_page_list(int n); - -class font_family { - int *map; - int map_size; -public: - const symbol nm; - - font_family(symbol); - ~font_family(); - int make_definite(int); - static void invalidate_fontno(int); -}; - -font_family *lookup_family(symbol); diff --git a/contrib/groff/troff/number.cc b/contrib/groff/troff/number.cc deleted file mode 100644 index b4e3d1d..0000000 --- a/contrib/groff/troff/number.cc +++ /dev/null @@ -1,669 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -#include "troff.h" -#include "symbol.h" -#include "hvunits.h" -#include "env.h" -#include "token.h" -#include "div.h" - -vunits V0; -hunits H0; - -int hresolution = 1; -int vresolution = 1; -int units_per_inch; -int sizescale; - -static int parse_expr(units *v, int scale_indicator, int parenthesised); -static int start_number(); - -int get_vunits(vunits *res, unsigned char si) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, si, 0)) { - *res = vunits(x); - return 1; - } - else - return 0; -} - -int get_hunits(hunits *res, unsigned char si) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, si, 0)) { - *res = hunits(x); - return 1; - } - else - return 0; -} - -int get_number(units *res, unsigned char si) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, si, 0)) { - *res = x; - return 1; - } - else - return 0; -} - -int get_integer(int *res) -{ - if (!start_number()) - return 0; - units x; - if (parse_expr(&x, 0, 0)) { - *res = x; - return 1; - } - else - return 0; -} - -enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT }; - -static incr_number_result get_incr_number(units *res, unsigned char); - -int get_vunits(vunits *res, unsigned char si, vunits prev_value) -{ - units v; - switch (get_incr_number(&v, si)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + v; - break; - case DECREMENT: - *res = prev_value - v; - break; - default: - assert(0); - } - return 1; -} - -int get_hunits(hunits *res, unsigned char si, hunits prev_value) -{ - units v; - switch (get_incr_number(&v, si)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + v; - break; - case DECREMENT: - *res = prev_value - v; - break; - default: - assert(0); - } - return 1; -} - -int get_number(units *res, unsigned char si, units prev_value) -{ - units v; - switch (get_incr_number(&v, si)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + v; - break; - case DECREMENT: - *res = prev_value - v; - break; - default: - assert(0); - } - return 1; -} - -int get_integer(int *res, int prev_value) -{ - units v; - switch (get_incr_number(&v, 0)) { - case BAD: - return 0; - case ABSOLUTE: - *res = v; - break; - case INCREMENT: - *res = prev_value + int(v); - break; - case DECREMENT: - *res = prev_value - int(v); - break; - default: - assert(0); - } - return 1; -} - - -static incr_number_result get_incr_number(units *res, unsigned char si) -{ - if (!start_number()) - return BAD; - incr_number_result result = ABSOLUTE; - if (tok.ch() == '+') { - tok.next(); - result = INCREMENT; - } - else if (tok.ch() == '-') { - tok.next(); - result = DECREMENT; - } - if (parse_expr(res, si, 0)) - return result; - else - return BAD; -} - -static int start_number() -{ - while (tok.space()) - tok.next(); - if (tok.newline()) { - warning(WARN_MISSING, "missing number"); - return 0; - } - if (tok.tab()) { - warning(WARN_TAB, "tab character where number expected"); - return 0; - } - if (tok.right_brace()) { - warning(WARN_RIGHT_BRACE, "`\\}' where number expected"); - return 0; - } - return 1; -} - -enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' }; - -#define SCALE_INDICATOR_CHARS "icPmnpuvMsz" - -static int parse_term(units *v, int scale_indicator, int parenthesised); - -static int parse_expr(units *v, int scale_indicator, int parenthesised) -{ - int result = parse_term(v, scale_indicator, parenthesised); - while (result) { - if (parenthesised) - tok.skip(); - int op = tok.ch(); - switch (op) { - case '+': - case '-': - case '/': - case '*': - case '%': - case ':': - case '&': - tok.next(); - break; - case '>': - tok.next(); - if (tok.ch() == '=') { - tok.next(); - op = OP_GEQ; - } - else if (tok.ch() == '?') { - tok.next(); - op = OP_MAX; - } - break; - case '<': - tok.next(); - if (tok.ch() == '=') { - tok.next(); - op = OP_LEQ; - } - else if (tok.ch() == '?') { - tok.next(); - op = OP_MIN; - } - break; - case '=': - tok.next(); - if (tok.ch() == '=') - tok.next(); - break; - default: - return result; - } - units v2; - if (!parse_term(&v2, scale_indicator, parenthesised)) - return 0; - int overflow = 0; - switch (op) { - case '<': - *v = *v < v2; - break; - case '>': - *v = *v > v2; - break; - case OP_LEQ: - *v = *v <= v2; - break; - case OP_GEQ: - *v = *v >= v2; - break; - case OP_MIN: - if (*v > v2) - *v = v2; - break; - case OP_MAX: - if (*v < v2) - *v = v2; - break; - case '=': - *v = *v == v2; - break; - case '&': - *v = *v > 0 && v2 > 0; - break; - case ':': - *v = *v > 0 || v2 > 0; - case '+': - if (v2 < 0) { - if (*v < INT_MIN - v2) - overflow = 1; - } - else if (v2 > 0) { - if (*v > INT_MAX - v2) - overflow = 1; - } - if (overflow) { - error("addition overflow"); - return 0; - } - *v += v2; - break; - case '-': - if (v2 < 0) { - if (*v > INT_MAX + v2) - overflow = 1; - } - else if (v2 > 0) { - if (*v < INT_MIN + v2) - overflow = 1; - } - if (overflow) { - error("subtraction overflow"); - return 0; - } - *v -= v2; - break; - case '*': - if (v2 < 0) { - if (*v > 0) { - if (*v > -(unsigned)INT_MIN / -(unsigned)v2) - overflow = 1; - } - else if (-(unsigned)*v > INT_MAX / -(unsigned)v2) - overflow = 1; - } - else if (v2 > 0) { - if (*v > 0) { - if (*v > INT_MAX / v2) - overflow = 1; - } - else if (-(unsigned)*v > -(unsigned)INT_MIN / v2) - overflow = 1; - } - if (overflow) { - error("multiplication overflow"); - return 0; - } - *v *= v2; - break; - case '/': - if (v2 == 0) { - error("division by zero"); - return 0; - } - *v /= v2; - break; - case '%': - if (v2 == 0) { - error("modulus by zero"); - return 0; - } - *v %= v2; - break; - default: - assert(0); - } - } - return result; -} - -static int parse_term(units *v, int scale_indicator, int parenthesised) -{ - int negative = 0; - for (;;) - if (parenthesised && tok.space()) - tok.next(); - else if (tok.ch() == '+') - tok.next(); - else if (tok.ch() == '-') { - tok.next(); - negative = !negative; - } - else - break; - unsigned char c = tok.ch(); - switch (c) { - case '|': - // | is not restricted to the outermost level - // tbl uses this - tok.next(); - if (!parse_term(v, scale_indicator, parenthesised)) - return 0; - int tem; - tem = (scale_indicator == 'v' - ? curdiv->get_vertical_position().to_units() - : curenv->get_input_line_position().to_units()); - if (tem >= 0) { - if (*v < INT_MIN + tem) { - error("numeric overflow"); - return 0; - } - } - else { - if (*v > INT_MAX + tem) { - error("numeric overflow"); - return 0; - } - } - *v -= tem; - if (negative) { - if (*v == INT_MIN) { - error("numeric overflow"); - return 0; - } - *v = -*v; - } - return 1; - case '(': - tok.next(); - c = tok.ch(); - if (c == ')') { - warning(WARN_SYNTAX, "empty parentheses"); - tok.next(); - *v = 0; - return 1; - } - else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { - tok.next(); - if (tok.ch() == ';') { - tok.next(); - scale_indicator = c; - } - else { - error("expected `;' after scale-indicator (got %1)", - tok.description()); - return 0; - } - } - else if (c == ';') { - scale_indicator = 0; - tok.next(); - } - if (!parse_expr(v, scale_indicator, 1)) - return 0; - tok.skip(); - if (tok.ch() != ')') { - warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description()); - } - else - tok.next(); - if (negative) { - if (*v == INT_MIN) { - error("numeric overflow"); - return 0; - } - *v = -*v; - } - return 1; - case '.': - *v = 0; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - *v = 0; - do { - if (*v > INT_MAX/10) { - error("numeric overflow"); - return 0; - } - *v *= 10; - if (*v > INT_MAX - (int(c) - '0')) { - error("numeric overflow"); - return 0; - } - *v += c - '0'; - tok.next(); - c = tok.ch(); - } while (csdigit(c)); - break; - case '/': - case '*': - case '%': - case ':': - case '&': - case '>': - case '<': - case '=': - warning(WARN_SYNTAX, "empty left operand"); - *v = 0; - return 1; - default: - warning(WARN_NUMBER, "numeric expression expected (got %1)", - tok.description()); - return 0; - } - int divisor = 1; - if (tok.ch() == '.') { - tok.next(); - for (;;) { - c = tok.ch(); - if (!csdigit(c)) - break; - // we may multiply the divisor by 254 later on - if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) { - *v *= 10; - *v += c - '0'; - divisor *= 10; - } - tok.next(); - } - } - int si = scale_indicator; - int do_next = 0; - if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { - switch (scale_indicator) { - case 'z': - if (c != 'u' && c != 'z') { - warning(WARN_SCALE, - "only `z' and `u' scale indicators valid in this context"); - break; - } - si = c; - break; - case 0: - warning(WARN_SCALE, "scale indicator invalid in this context"); - break; - case 'u': - si = c; - break; - default: - if (c == 'z') { - warning(WARN_SCALE, "`z' scale indicator invalid in this context"); - break; - } - si = c; - break; - } - // Don't do tok.next() here because the next token might be \s, which - // would affect the interpretation of m. - do_next = 1; - } - switch (si) { - case 'i': - *v = scale(*v, units_per_inch, divisor); - break; - case 'c': - *v = scale(*v, units_per_inch*100, divisor*254); - break; - case 0: - case 'u': - if (divisor != 1) - *v /= divisor; - break; - case 'p': - *v = scale(*v, units_per_inch, divisor*72); - break; - case 'P': - *v = scale(*v, units_per_inch, divisor*6); - break; - case 'm': - { - // Convert to hunits so that with -Tascii `m' behaves as in nroff. - hunits em = curenv->get_size(); - *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor); - } - break; - case 'M': - { - hunits em = curenv->get_size(); - *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100); - } - break; - case 'n': - { - // Convert to hunits so that with -Tascii `n' behaves as in nroff. - hunits en = curenv->get_size()/2; - *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor); - } - break; - case 'v': - *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor); - break; - case 's': - while (divisor > INT_MAX/(sizescale*72)) { - divisor /= 10; - *v /= 10; - } - *v = scale(*v, units_per_inch, divisor*sizescale*72); - break; - case 'z': - *v = scale(*v, sizescale, divisor); - break; - default: - assert(0); - } - if (do_next) - tok.next(); - if (negative) { - if (*v == INT_MIN) { - error("numeric overflow"); - return 0; - } - *v = -*v; - } - return 1; -} - -units scale(units n, units x, units y) -{ - assert(x >= 0 && y > 0); - if (x == 0) - return 0; - if (n >= 0) { - if (n <= INT_MAX/x) - return (n*x)/y; - } - else { - if (-(unsigned)n <= -(unsigned)INT_MIN/x) - return (n*x)/y; - } - double res = n*double(x)/double(y); - if (res > INT_MAX) { - error("numeric overflow"); - return INT_MAX; - } - else if (res < INT_MIN) { - error("numeric overflow"); - return INT_MIN; - } - return int(res); -} - -vunits::vunits(units x) -{ - // don't depend on the rounding direction for division of negative integers - if (vresolution == 1) - n = x; - else - n = (x < 0 - ? -((-x + vresolution/2 - 1)/vresolution) - : (x + vresolution/2 - 1)/vresolution); -} - -hunits::hunits(units x) -{ - // don't depend on the rounding direction for division of negative integers - if (hresolution == 1) - n = x; - else - n = (x < 0 - ? -((-x + hresolution/2 - 1)/hresolution) - : (x + hresolution/2 - 1)/hresolution); -} diff --git a/contrib/groff/troff/reg.cc b/contrib/groff/troff/reg.cc deleted file mode 100644 index 79e7806..0000000 --- a/contrib/groff/troff/reg.cc +++ /dev/null @@ -1,473 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "troff.h" -#include "symbol.h" -#include "dictionary.h" -#include "token.h" -#include "request.h" -#include "reg.h" - -object_dictionary number_reg_dictionary(101); - -int reg::get_value(units * /*d*/) -{ - return 0; -} - -void reg::increment() -{ - error("can't increment read-only register"); -} - -void reg::decrement() -{ - error("can't decrement read-only register"); -} - -void reg::set_increment(units /*n*/) -{ - error("can't auto increment read-only register"); -} - -void reg::alter_format(char /*f*/, int /*w*/) -{ - error("can't alter format of read-only register"); -} - -const char *reg::get_format() -{ - return "0"; -} - -void reg::set_value(units /*n*/) -{ - error("can't write read-only register"); -} - -general_reg::general_reg() : format('1'), width(0), inc(0) -{ -} - -static char uppercase_array[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', -}; - -static char lowercase_array[] = { - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', -}; - -static const char *number_value_to_ascii(int value, char format, int width) -{ - static char buf[128]; // must be at least 21 - switch(format) { - case '1': - if (width <= 0) - return i_to_a(value); - else if (width > sizeof(buf) - 2) - sprintf(buf, "%.*d", int(sizeof(buf) - 2), int(value)); - else - sprintf(buf, "%.*d", width, int(value)); - break; - case 'i': - case 'I': - { - char *p = buf; - // troff uses z and w to represent 10000 and 5000 in Roman - // numerals; I can find no historical basis for this usage - const char *s = format == 'i' ? "zwmdclxvi" : "ZWMDCLXVI"; - int n = int(value); - if (n >= 40000 || n <= -40000) { - error("magnitude of `%1' too big for i or I format", n); - return i_to_a(n); - } - if (n == 0) { - *p++ = '0'; - *p = 0; - break; - } - if (n < 0) { - *p++ = '-'; - n = -n; - } - while (n >= 10000) { - *p++ = s[0]; - n -= 10000; - } - for (int i = 1000; i > 0; i /= 10, s += 2) { - int m = n/i; - n -= m*i; - switch (m) { - case 3: - *p++ = s[2]; - /* falls through */ - case 2: - *p++ = s[2]; - /* falls through */ - case 1: - *p++ = s[2]; - break; - case 4: - *p++ = s[2]; - *p++ = s[1]; - break; - case 8: - *p++ = s[1]; - *p++ = s[2]; - *p++ = s[2]; - *p++ = s[2]; - break; - case 7: - *p++ = s[1]; - *p++ = s[2]; - *p++ = s[2]; - break; - case 6: - *p++ = s[1]; - *p++ = s[2]; - break; - case 5: - *p++ = s[1]; - break; - case 9: - *p++ = s[2]; - *p++ = s[0]; - } - } - *p = 0; - break; - } - case 'a': - case 'A': - { - int n = value; - char *p = buf; - if (n == 0) { - *p++ = '0'; - *p = 0; - } - else { - if (n < 0) { - n = -n; - *p++ = '-'; - } - // this is a bit tricky - while (n > 0) { - int d = n % 26; - if (d == 0) - d = 26; - n -= d; - n /= 26; - *p++ = format == 'a' ? lowercase_array[d - 1] : - uppercase_array[d - 1]; - } - *p-- = 0; - char *q = buf[0] == '-' ? buf + 1 : buf; - while (q < p) { - char temp = *q; - *q = *p; - *p = temp; - --p; - ++q; - } - } - break; - } - default: - assert(0); - break; - } - return buf; -} - -const char *general_reg::get_string() -{ - units n; - if (!get_value(&n)) - return ""; - return number_value_to_ascii(n, format, width); -} - - -void general_reg::increment() -{ - int n; - if (get_value(&n)) - set_value(n + inc); -} - -void general_reg::decrement() -{ - int n; - if (get_value(&n)) - set_value(n - inc); -} - -void general_reg::set_increment(units n) -{ - inc = n; -} - -void general_reg::alter_format(char f, int w) -{ - format = f; - width = w; -} - -static const char *number_format_to_ascii(char format, int width) -{ - static char buf[24]; - if (format == '1') { - if (width > 0) { - int n = width; - if (n > int(sizeof(buf)) - 1) - n = int(sizeof(buf)) - 1; - sprintf(buf, "%.*d", n, 0); - return buf; - } - else - return "0"; - } - else { - buf[0] = format; - buf[1] = '\0'; - return buf; - } -} - -const char *general_reg::get_format() -{ - return number_format_to_ascii(format, width); -} - -class number_reg : public general_reg { - units value; -public: - number_reg(); - int get_value(units *); - void set_value(units); -}; - -number_reg::number_reg() : value(0) -{ -} - -int number_reg::get_value(units *res) -{ - *res = value; - return 1; -} - -void number_reg::set_value(units n) -{ - value = n; -} - -variable_reg::variable_reg(units *p) : ptr(p) -{ -} - -void variable_reg::set_value(units n) -{ - *ptr = n; -} - -int variable_reg::get_value(units *res) -{ - *res = *ptr; - return 1; -} - -void define_number_reg() -{ - symbol nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - reg *r = (reg *)number_reg_dictionary.lookup(nm); - units v; - units prev_value; - if (!r || !r->get_value(&prev_value)) - prev_value = 0; - if (get_number(&v, 'u', prev_value)) { - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - r->set_value(v); - if (tok.space() && has_arg() && get_number(&v, 'u')) - r->set_increment(v); - } - skip_line(); -} - -#if 0 -void inline_define_reg() -{ - token start; - start.next(); - if (!start.delimiter(1)) - return; - tok.next(); - symbol nm = get_name(1); - if (nm.is_null()) - return; - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - units v; - units prev_value; - if (!r->get_value(&prev_value)) - prev_value = 0; - if (get_number(&v, 'u', prev_value)) { - r->set_value(v); - if (start != tok) { - if (get_number(&v, 'u')) { - r->set_increment(v); - if (start != tok) - warning(WARN_DELIM, "closing delimiter does not match"); - } - } - } -} -#endif - -void set_number_reg(symbol nm, units n) -{ - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - r->set_value(n); -} - -reg *lookup_number_reg(symbol nm) -{ - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - warning(WARN_REG, "number register `%1' not defined", nm.contents()); - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - return r; -} - -void alter_format() -{ - symbol nm = get_name(1); - if (nm.is_null()) { - skip_line(); - return; - } - reg *r = (reg *)number_reg_dictionary.lookup(nm); - if (r == 0) { - r = new number_reg; - number_reg_dictionary.define(nm, r); - } - tok.skip(); - char c = tok.ch(); - if (csdigit(c)) { - int n = 0; - do { - ++n; - tok.next(); - } while (csdigit(tok.ch())); - r->alter_format('1', n); - } - else if (c == 'i' || c == 'I' || c == 'a' || c == 'A') - r->alter_format(c); - else if (tok.newline() || tok.eof()) - warning(WARN_MISSING, "missing number register format"); - else - error("bad number register format (got %1)", tok.description()); - skip_line(); -} - -void remove_reg() -{ - for (;;) { - symbol s = get_name(); - if (s.is_null()) - break; - number_reg_dictionary.remove(s); - } - skip_line(); -} - -void alias_reg() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) { - if (!number_reg_dictionary.alias(s1, s2)) - warning(WARN_REG, "number register `%1' not defined", s2.contents()); - } - } - skip_line(); -} - -void rename_reg() -{ - symbol s1 = get_name(1); - if (!s1.is_null()) { - symbol s2 = get_name(1); - if (!s2.is_null()) - number_reg_dictionary.rename(s1, s2); - } - skip_line(); -} - -void print_number_regs() -{ - object_dictionary_iterator iter(number_reg_dictionary); - reg *r; - symbol s; - while (iter.get(&s, (object **)&r)) { - assert(!s.is_null()); - errprint("%1\t", s.contents()); - const char *p = r->get_string(); - if (p) - errprint(p); - errprint("\n"); - } - fflush(stderr); - skip_line(); -} - -void init_reg_requests() -{ - init_request("rr", remove_reg); - init_request("nr", define_number_reg); - init_request("af", alter_format); - init_request("aln", alias_reg); - init_request("rnn", rename_reg); - init_request("pnr", print_number_regs); -} diff --git a/contrib/groff/troff/reg.h b/contrib/groff/troff/reg.h deleted file mode 100644 index 51d5b9a..0000000 --- a/contrib/groff/troff/reg.h +++ /dev/null @@ -1,73 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -class reg : public object { -public: - virtual const char *get_string() = 0; - virtual int get_value(units *); - virtual void increment(); - virtual void decrement(); - virtual void set_increment(units); - virtual void alter_format(char f, int w = 0); - virtual const char *get_format(); - virtual void set_value(units); -}; - -class constant_int_reg : public reg { - int *p; -public: - constant_int_reg(int *); - const char *get_string(); -}; - -class general_reg : public reg { - char format; - int width; - int inc; -public: - general_reg(); - const char *get_string(); - void increment(); - void decrement(); - void alter_format(char f, int w = 0); - void set_increment(units); - const char *get_format(); - void add_value(units); - - void set_value(units) = 0; - int get_value(units *) = 0; -}; - -class variable_reg : public general_reg { - units *ptr; -public: - variable_reg(int *); - void set_value(units); - int get_value(units *); -}; - -extern object_dictionary number_reg_dictionary; -extern void set_number_reg(symbol nm, units n); - -reg *lookup_number_reg(symbol); -#if 0 -void inline_define_reg(); -#endif diff --git a/contrib/groff/troff/request.h b/contrib/groff/troff/request.h deleted file mode 100644 index 5703175..0000000 --- a/contrib/groff/troff/request.h +++ /dev/null @@ -1,79 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -typedef void (*REQUEST_FUNCP)(); - -class macro; - -class request_or_macro : public object { -public: - request_or_macro(); - virtual void invoke(symbol s) = 0; - virtual macro *to_macro(); -}; - -class request : public request_or_macro { - REQUEST_FUNCP p; -public: - void invoke(symbol); - request(REQUEST_FUNCP); -}; - -void delete_request_or_macro(request_or_macro *); - -extern object_dictionary request_dictionary; - -struct macro_header; -struct node; - -class macro : public request_or_macro { - macro_header *p; - const char *filename; // where was it defined? - int lineno; - int length; -public: - macro(); - ~macro(); - macro(const macro &); - macro &operator=(const macro &); - void append(unsigned char); - void append(node *); - void invoke(symbol); - macro *to_macro(); - void print_size(); - int empty(); - friend class string_iterator; - friend void chop_macro(); - friend void substring_macro(); - friend int operator==(const macro &, const macro &); -}; - -extern void init_input_requests(); -extern void init_div_requests(); -extern void init_node_requests(); -extern void init_reg_requests(); -extern void init_env_requests(); -extern void init_hyphen_requests(); -extern void init_request(const char *s, REQUEST_FUNCP f); - -class charinfo; -class environment; - -node *charinfo_to_node_list(charinfo *, const environment *); diff --git a/contrib/groff/troff/symbol.cc b/contrib/groff/troff/symbol.cc deleted file mode 100644 index ce09e39..0000000 --- a/contrib/groff/troff/symbol.cc +++ /dev/null @@ -1,150 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -#include "troff.h" -#include "symbol.h" - -const char **symbol::table = 0; -int symbol::table_used = 0; -int symbol::table_size = 0; -char *symbol::block = 0; -int symbol::block_size = 0; - -const symbol NULL_SYMBOL; - -#ifdef BLOCK_SIZE -#undef BLOCK_SIZE -#endif - -const int BLOCK_SIZE = 1024; -// the table will increase in size as necessary -// the size will be chosen from the following array -// add some more if you want -// I think it unlikely that we'll need more than a million symbols -static const unsigned int table_sizes[] = { -101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, 160001, 500009, 1000003, 0 -}; -const double FULL_MAX = 0.3; // don't let the table get more than this full - -static unsigned int hash_string(const char *p) -{ - // compute a hash code; this assumes 32-bit unsigned ints - // see p436 of Compilers by Aho, Sethi & Ullman - // give special treatment to two-character names - unsigned int hc = 0, g; - if (*p != 0) { - hc = *p++; - if (*p != 0) { - hc <<= 7; - hc += *p++; - for (; *p != 0; p++) { - hc <<= 4; - hc += *p; - if ((g = (hc & 0xf0000000)) == 0) { - hc ^= g >> 24; - hc ^= g; - } - } - } - } - return hc; -} - -// Tell compiler that a variable is intentionally unused. -inline void unused(void *) { } - -symbol::symbol(const char *p, int how) -{ - if (p == 0 || *p == 0) { - s = 0; - return; - } - if (table == 0) { - table_size = table_sizes[0]; - table = (const char **)new char*[table_size]; - for (int i = 0; i < table_size; i++) - table[i] = 0; - table_used = 0; - } - unsigned int hc = hash_string(p); - const char **pp; - for (pp = table + hc % table_size; - *pp != 0; - (pp == table ? pp = table + table_size - 1 : --pp)) - if (strcmp(p, *pp) == 0) { - s = *pp; - return; - } - if (how == MUST_ALREADY_EXIST) { - s = 0; - return; - } - if (table_used >= table_size - 1 || table_used >= table_size*FULL_MAX) { - const char **old_table = table; - unsigned int old_table_size = table_size; - int i; - for (i = 1; table_sizes[i] <= old_table_size; i++) - if (table_sizes[i] == 0) - fatal("too many symbols"); - table_size = table_sizes[i]; - table_used = 0; - table = (const char **)new char*[table_size]; - for (i = 0; i < table_size; i++) - table[i] = 0; - for (pp = old_table + old_table_size - 1; - pp >= old_table; - --pp) { - symbol temp(*pp, 1); /* insert it into the new table */ - unused(&temp); - } - a_delete old_table; - for (pp = table + hc % table_size; - *pp != 0; - (pp == table ? pp = table + table_size - 1 : --pp)) - ; - } - ++table_used; - if (how == DONT_STORE) { - s = *pp = p; - } - else { - int len = strlen(p)+1; - if (block == 0 || block_size < len) { - block_size = len > BLOCK_SIZE ? len : BLOCK_SIZE; - block = new char [block_size]; - } - (void)strcpy(block, p); - s = *pp = block; - block += len; - block_size -= len; - } -} - -symbol concat(symbol s1, symbol s2) -{ - char *buf = new char [strlen(s1.contents()) + strlen(s2.contents()) + 1]; - strcpy(buf, s1.contents()); - strcat(buf, s2.contents()); - symbol res(buf); - a_delete buf; - return res; -} - diff --git a/contrib/groff/troff/symbol.h b/contrib/groff/troff/symbol.h deleted file mode 100644 index 88e0fff..0000000 --- a/contrib/groff/troff/symbol.h +++ /dev/null @@ -1,73 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#define DONT_STORE 1 -#define MUST_ALREADY_EXIST 2 - -class symbol { - static const char **table; - static int table_used; - static int table_size; - static char *block; - static int block_size; - const char *s; -public: - symbol(const char *p, int how = 0); - symbol(); - unsigned long hash() const; - int operator ==(symbol) const; - int operator !=(symbol) const; - const char *contents() const; - int is_null() const; -}; - - -extern const symbol NULL_SYMBOL; - -inline symbol::symbol() : s(0) -{ -} - -inline int symbol::operator==(symbol p) const -{ - return s == p.s; -} - -inline int symbol::operator!=(symbol p) const -{ - return s != p.s; -} - -inline unsigned long symbol::hash() const -{ - return (unsigned long)s; -} - -inline const char *symbol::contents() const -{ - return s; -} - -inline int symbol::is_null() const -{ - return s == 0; -} - -symbol concat(symbol, symbol); diff --git a/contrib/groff/troff/token.h b/contrib/groff/troff/token.h deleted file mode 100644 index f6707f2..0000000 --- a/contrib/groff/troff/token.h +++ /dev/null @@ -1,201 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -struct charinfo; -struct node; -struct vunits; - -class token { - symbol nm; - node *nd; - unsigned char c; - int val; - units dim; - enum token_type { - TOKEN_BACKSPACE, - TOKEN_BEGIN_TRAP, - TOKEN_CHAR, // a normal printing character - TOKEN_DUMMY, - TOKEN_EMPTY, // this is the initial value - TOKEN_END_TRAP, - TOKEN_ESCAPE, // \e - TOKEN_HYPHEN_INDICATOR, - TOKEN_INTERRUPT, // \c - TOKEN_ITALIC_CORRECTION, // \/ - TOKEN_LEADER, // ^A - TOKEN_LEFT_BRACE, - TOKEN_MARK_INPUT, // \k -- `nm' is the name of the register - TOKEN_NEWLINE, // newline - TOKEN_NODE, - TOKEN_NUMBERED_CHAR, - TOKEN_PAGE_EJECTOR, - TOKEN_REQUEST, - TOKEN_RIGHT_BRACE, - TOKEN_SPACE, // ` ' -- ordinary space - TOKEN_SPECIAL, // a special character -- \' \` \- \(xx - TOKEN_SPREAD, // \p -- break and spread output line - TOKEN_TAB, // tab - TOKEN_TRANSPARENT, // \! - TOKEN_EOF // end of file - } type; -public: - token(); - ~token(); - token(const token &); - void operator=(const token &); - void next(); - void process(); - void skip(); - int eof(); - int nspaces(); // 1 if space, 2 if double space, 0 otherwise - int space(); // is it a space or double space? - int white_space(); // is the current token space or tab? - int special(); // is the current token a special character? - int newline(); // is the current token a newline? - int tab(); // is the current token a tab? - int leader(); - int backspace(); - int delimiter(int warn = 0); // is it suitable for use as a delimiter? - int dummy(); - int transparent(); - int left_brace(); - int right_brace(); - int page_ejector(); - int hyphen_indicator(); - int operator==(const token &); // need this for delimiters, and for conditions - int operator!=(const token &); // ditto - unsigned char ch(); - charinfo *get_char(int required = 0); - int add_to_node_list(node **); - int title(); - void make_space(); - void make_newline(); - const char *description(); - - friend void process_input_stack(); -}; - -extern token tok; // the current token - -extern symbol get_name(int required = 0); -extern symbol get_long_name(int required = 0); -extern charinfo *get_optional_char(); -extern void check_missing_character(); -extern void skip_line(); -extern void handle_initial_title(); - -struct hunits; -extern void read_title_parts(node **part, hunits *part_width); - -extern int get_number(units *result, unsigned char si); -extern int get_integer(int *result); - -extern int get_number(units *result, unsigned char si, units prev_value); -extern int get_integer(int *result, int prev_value); - -void interpolate_number_reg(symbol, int); - -const char *asciify(int c); - -inline int token::newline() -{ - return type == TOKEN_NEWLINE; -} - -inline int token::space() -{ - return type == TOKEN_SPACE; -} - -inline int token::special() -{ - return type == TOKEN_SPECIAL; -} - -inline int token::nspaces() -{ - if (type == TOKEN_SPACE) - return 1; - else - return 0; -} - -inline int token::white_space() -{ - return type == TOKEN_SPACE || type == TOKEN_TAB; -} - -inline int token::transparent() -{ - return type == TOKEN_TRANSPARENT; -} - -inline int token::page_ejector() -{ - return type == TOKEN_PAGE_EJECTOR; -} - -inline unsigned char token::ch() -{ - return type == TOKEN_CHAR ? c : 0; -} - -inline int token::eof() -{ - return type == TOKEN_EOF; -} - -inline int token::dummy() -{ - return type == TOKEN_DUMMY; -} - -inline int token::left_brace() -{ - return type == TOKEN_LEFT_BRACE; -} - -inline int token::right_brace() -{ - return type == TOKEN_RIGHT_BRACE; -} - -inline int token::tab() -{ - return type == TOKEN_TAB; -} - -inline int token::leader() -{ - return type == TOKEN_LEADER; -} - -inline int token::backspace() -{ - return type == TOKEN_BACKSPACE; -} - -inline int token::hyphen_indicator() -{ - return type == TOKEN_HYPHEN_INDICATOR; -} - -int has_arg(); diff --git a/contrib/groff/troff/troff.h b/contrib/groff/troff/troff.h deleted file mode 100644 index c558501..0000000 --- a/contrib/groff/troff/troff.h +++ /dev/null @@ -1,83 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - - -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <time.h> -#include <stddef.h> -#include <stdlib.h> -#include <errno.h> - -#include "lib.h" -#include "assert.h" -#include "device.h" - -void cleanup_and_exit(int n); - -typedef int units; - -extern units scale(units n, units x, units y); // scale n by x/y - -extern units units_per_inch; - -extern int ascii_output_flag; -extern int suppress_output_flag; - -extern int tcommand_flag; -extern int vresolution; -extern int hresolution; -extern int sizescale; - -#include "cset.h" -#include "cmap.h" -#include "errarg.h" -#include "error.h" - -enum warning_type { - WARN_CHAR = 01, - WARN_NUMBER = 02, - WARN_BREAK = 04, - WARN_DELIM = 010, - WARN_EL = 020, - WARN_SCALE = 040, - WARN_RANGE = 0100, - WARN_SYNTAX = 0200, - WARN_DI = 0400, - WARN_MAC = 01000, - WARN_REG = 02000, - WARN_TAB = 04000, - WARN_RIGHT_BRACE = 010000, - WARN_MISSING = 020000, - WARN_INPUT = 040000, - WARN_ESCAPE = 0100000, - WARN_SPACE = 0200000, - WARN_FONT = 0400000, - WARN_IG = 01000000 - // change WARN_TOTAL if you add more warning types -}; - -const int WARN_TOTAL = 01777777; - -int warning(warning_type, const char *, - const errarg & = empty_errarg, - const errarg & = empty_errarg, - const errarg & = empty_errarg); |