|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: D T
Length: 77816 (0x12ff8) Types: TextFile Names: »Document.c«
└─⟦8648bda34⟧ Bits:30007244 EUUGD5_II: X11R5 └─⟦87c3ac0e0⟧ »./contrib-3/contrib-3.00« └─⟦de8ce1454⟧ └─⟦this⟧ »contrib/lib/iv/src/bin/doc/Document.c«
/* * Copyright (c) 1991 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Stanford not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Stanford makes no representations about * the suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Document */ #include "Document.h" #include "Application.h" #include "DocViewer.h" #include "CounterItem.h" #include "LabelItem.h" #include "RefItem.h" #include "PSFigItem.h" #include "TabularItem.h" #include "TextItem.h" #include "FloatItem.h" #include "PagenoItem.h" #include "codes.h" #include "properties.h" #include <InterViews/character.h> #include <InterViews/color.h> #include <InterViews/compositor.h> #include <InterViews/discretion.h> #include <InterViews/font.h> #include <InterViews/glue.h> #include <InterViews/psfont.h> #include <InterViews/rule.h> #include <InterViews/shapeof.h> #include <InterViews/space.h> #include <InterViews/strut.h> #include <InterViews/world.h> #include <fstream.h> #include <strstream.h> #include <stdio.h> #include <string.h> #include <ctype.h> const int END = -2; const int LINE = -3; const int FIELD = -4; const int COMMAND = -5; const int BLOCK = -6; const int COMMENT = -7; const int VERBATIM = -8; const int IMPORT = -9; const int MACRO = -10; const int PARAMETER = -11; const int PARBOX = -12; const int FLOAT = -13; const int TABULAR = -14; const int PSFIG = -15; const int COUNTER = -16; const int LABEL = -17; const int REF = -18; const int COLOR = -19; const int FONT = -20; const int SIZE = -21; const int ALIGN = -22; const int PAGENUMBER = -23; int FOLDCOLUMN = 65; static int column = 0; static istream* parameter = nil; static FloatItem* expecting_position = nil; class CounterFormat { public: const char* _name; void (*_formatter)(long, char*); }; void arabic_formatter (long value, char* buffer) { sprintf(buffer, "%d", value); } void alph_formatter (long value, char* buffer) { sprintf(buffer, "%c", 'a' + value - 1); } void Alph_formatter (long value, char* buffer) { sprintf(buffer, "%c", 'A' + value - 1); } CounterFormat counter_format [] = { {"arabic", &arabic_formatter }, {"alph", &alph_formatter }, {"Alph", &Alph_formatter }, {"", &arabic_formatter }, {nil, nil } }; class MetricUnit { public: const char* _name; float _conversion; }; MetricUnit metric_unit[] = { {"pt", 1.0 }, {"pts", 1.0 }, {"point", 1.0 }, {"points", 1.0 }, {"in", 72.0 }, {"ins", 72.0 }, {"inch", 72.0 }, {"inches", 72.0 }, {"cm", 72.0 / 2.54 }, {"mm", 72.0 / 25.4 }, {"pc", 72.0 / 12 }, {"pica", 72.0 / 12 }, {nil, 0 } }; class DefaultParameterInfo { public: const char* _name; const char* _value; }; DefaultParameterInfo default_parameter[] = { {"face", "Times-Roman"}, {"pointsize", "10pt"}, {"color", "black"}, {"alignment", "justify"}, {"textwidth", "6in"}, {"textheight", "8.5in"}, {"leftsidemargin", "0.25in"}, {"rightsidemargin", "0.25in"}, {"bottommargin", "0.25in"}, {"topmargin", "0.25in"}, {"baselineskip", "0.1"}, {"baselinestretch", "0"}, {"parskip", "0.2"}, {"parstretch", "0.5"}, {"bigskip", "2.0"}, {"bigstretch", "2.0"}, {"medskip", "1.0"}, {"medstretch", "1.0"}, {"smallskip", "0.5"}, {"smallstretch", "0.5"}, {"gutter", "0.25in"}, {"columns", "1"}, {"hyphenpenalty", "50"}, {"parbreakpenalty", "-500"}, {"skippenalty", "-1000"}, {"linepenalty", "10"}, {"pagepenalty", "100"}, {"floatrepelright", "0.1in"}, {"floatrepelleft", "0.1in"}, {"floatrepeltop", "0.15in"}, {"floatrepelbottom", "0.15in"}, {nil, nil} }; class DefaultMacroInfo { public: const char* _name; const char* _def; }; DefaultMacroInfo default_macro[] = { {"verbatim", "\\font{Courier}\\align{left}"}, {"figure", "\\align{center}\\float{figure}{#}"}, {"figure*", "\\align{center}\\float{figure}{#}"}, {"table", "\\align{center}\\float{table}{#}"}, {"table*", "\\align{center}\\float{table}{#}"}, {nil, nil} }; const char* quoted_characters = " $&%#_{}~"; class TextParseInfo { public: const char* _format; long _code; long _fold; }; TextParseInfo text_map[] = { {"hfil", hfil, -1}, {"hfill", hfill, -1}, {"vfil", vfil, -1}, {"hrule", hrule, -1}, {"smallskip", smallskip, -1}, {"medskip", medskip, -1}, {"bigskip", bigskip, -1}, {"smallvspace", smallvspace, -1}, {"medvspace", medvspace, -1}, {"bigvspace", bigvspace, -1}, {"newpage", newpage, -1}, {"pagebreak", pagebreak, -1}, {"parbreak", parbreak, -1}, {"linebreak", linebreak -1}, {"nobreakspace", nobreakspace, 1}, {"wordspace", wordspace, 0}, {"sentencespace", sentencespace, 1}, {"quad", quadspace, 0}, {"discretionaryhyphen", discretionaryhyphen, 1}, {"visiblehyphen", visiblehyphen, 1}, {"anchor", anchor, 1}, {"thinspace", thinspace, 0}, {"negthinspace", negthinspace, 0}, {"S", section, 0}, {"section", section, 0}, {"P", paragraph, 0}, {"paragraph", paragraph, 0}, {"endash", endash, 0}, {"emdash", emdash, 0}, {"bullet", bullet, 0}, {"dag", dag, 0}, {"ddag", ddag, 0}, {"cdot", cdot, 0}, {"backslash", '\\', 0}, {nil, 0} }; TextParseInfo special_map[] = { {"-", visiblehyphen, 1}, {"--", endash, 1}, {"---", emdash, 1}, {"\\-", discretionaryhyphen, 1}, {"~", nobreakspace, 1}, {" ", sentencespace, 1}, {"\n", parbreak, -1}, {"\\\\", linebreak, -1}, {"\\,", thinspace, 1}, {"\\!", negthinspace, 1}, {"", wordspace, 0}, {nil, 0} }; class StyleInfo { public: TextStyle _style; const Font* _font; const Color* _color; Glyph* _begin_line_strut; Glyph* _end_line_strut; Glyph* _begin_par_strut; Glyph* _end_par_strut; Glyph* _line_strut; Glyph* _fil_strut; Glyph* _hyphen; Glyph* _interline_glue; Glyph* _interpar_glue; Glyph* _hfil_glue; Glyph* _hfill_glue; Glyph* _vfil_glue; Glyph* _bigskip_glue; Glyph* _medskip_glue; Glyph* _smallskip_glue; Glyph* _word_space; Glyph* _sentence_space; Glyph* _glyph[256]; }; class SourceInfo { public: TextSource _source; long _enclosing; long _style; }; class FloatInfo { public: Item* _item; float _x; float _y; long _page; }; class LabelInfo { public: char* _name; char* _text; boolean _save; }; class MacroInfo { public: char* _name; char* _def; boolean _save; }; class CounterInfo { public: char* _name; char* _within; char* _format; long _initial; long _value; boolean _save; }; class DocumentParameterInfo { public: char* _name; char* _value; boolean _save; }; class DocumentViewerInfo { public: DocumentViewer* _viewer; }; class FontFamilyInfo { public: char* _name; FontFamily* _family; }; #include "list.h" declareList(StyleInfo_List,StyleInfo) implementList(StyleInfo_List,StyleInfo) declareList(SourceInfo_List,SourceInfo) implementList(SourceInfo_List,SourceInfo) declareList(MacroInfo_List,MacroInfo) implementList(MacroInfo_List,MacroInfo) declareList(FloatInfo_List,FloatInfo) implementList(FloatInfo_List,FloatInfo) declareList(CounterInfo_List,CounterInfo) implementList(CounterInfo_List,CounterInfo) declareList(LabelInfo_List,LabelInfo) implementList(LabelInfo_List,LabelInfo) declareList(DocumentParameterInfo_List,DocumentParameterInfo) implementList(DocumentParameterInfo_List,DocumentParameterInfo) declareList(DocumentViewerInfo_List,DocumentViewerInfo) implementList(DocumentViewerInfo_List,DocumentViewerInfo) declareList(FontFamilyInfo_List,FontFamilyInfo) implementList(FontFamilyInfo_List,FontFamilyInfo) FontFamily* find_font_family (const char* name) { static FontFamilyInfo_List* _families; if (_families == nil) { _families = new FontFamilyInfo_List(); } if (strlen(name) == 0) { return nil; } else { long count = _families->count(); for (long i = 0; i < count; ++i) { FontFamilyInfo& info = _families->item(0); if (strcmp(info._name, name) == 0) { break; } } if (i == count) { FontFamilyInfo info; info._name = strcpy(new char[strlen(name) + 1], name); info._family = new FontFamily(name); _families->append(info); } return _families->item(i)._family; } } Document::Document (Application* application, int size_hint) { _application = application; _touched = false; _name = nil; _relabel = false; _size_hint = size_hint; _body = nil; _style_name = nil; _style = new StyleInfo_List(); _source = new SourceInfo_List(); _macro = new MacroInfo_List(); _counter = new CounterInfo_List(); _label = new LabelInfo_List(); _float = new FloatInfo_List(); _parameter = new DocumentParameterInfo_List(20); _viewer = new DocumentViewerInfo_List(); long i = 0; while (default_parameter[i]._name != nil) { DefaultParameterInfo& info = default_parameter[i]; define_parameter(find_parameter(info._name), info._value, false); ++i; }; i = 0; while (default_macro[i]._name != nil) { DefaultMacroInfo& info = default_macro[i]; define_macro(find_macro(info._name), info._def, false); ++i; }; find_style(-1, "", "", "10", ""); find_source(-1, 1, "document", "", true, true); } Document::~Document () { delete _name; if (_body != nil) { _body->unref(); _body = nil; } while (_float->count() > 0) { cleanup_float(0); _float->remove(0); } delete _float; while (_style->count() > 0) { cleanup_style(0); _style->remove(0); } delete _style; while (_source->count() > 0) { cleanup_source(0); _source->remove(0); } delete _source; while (_macro->count() > 0) { cleanup_macro(0); _macro->remove(0); } delete _macro; while (_counter->count() > 0) { cleanup_counter(0); _counter->remove(0); } delete _counter; while (_label->count() > 0) { cleanup_label(0); _label->remove(0); } delete _label; while (_parameter->count() > 0) { cleanup_parameter(0); _parameter->remove(0); } delete _parameter; if (_style_name != nil) { delete _style_name; } } void Document::touch (boolean touched) { _touched = touched; } boolean Document::touched () { return _touched; } const char* Document::name () { return _name; } void Document::name (const char* name) { delete _name; if (name != nil) { _name = strcpy(new char[strlen(name)+1], name); } else { _name = nil; } } TextItem* Document::body () { return _body; } void Document::insert_float (Item* item) { FloatInfo info; info._x = 0; info._y = 0; info._page = -3; touch(true); long count = _viewer->count(); for (long i = 0; i < count; ++i) { DocumentViewerInfo& vinfo = _viewer->item(i); vinfo._viewer->float_inserted(item); } } void Document::remove_float (Item* item) { touch(true); long count = _viewer->count(); for (long i = 0; i < count; ++i) { DocumentViewerInfo& info = _viewer->item(i); info._viewer->float_removed(item); } i = find_float(item); cleanup_float(i); _float->remove(i); } void Document::change_float (Item* item ) { FloatInfo& info = _float->item(find_float(item)); touch(true); long count = _viewer->count(); for (long i = 0; i < count; ++i) { DocumentViewerInfo& viewer = _viewer->item(i); viewer._viewer->float_changed(item); } } void Document::adjust_float (Item* item, float x, float y, long page) { FloatInfo& info = _float->item(find_float(item)); info._x = x; info._y = y; info._page = page; touch(true); long count = _viewer->count(); for (long i = 0; i < count; ++i) { DocumentViewerInfo& info = _viewer->item(i); info._viewer->float_adjusted(item, x, y, page); } } const char* Document::document_parameter (const char* name) { DocumentParameterInfo& info = _parameter->item(find_parameter(name)); const char* value = info._value; if (value != nil) { while (*value == ' ' || *value == '\t') ++value; } return value; } float Document::document_metric (const char* name) { DocumentParameterInfo& info = _parameter->item(find_parameter(name)); return convert_metric(info._value); } float Document::convert_metric (const char* value) { if (value == nil || strlen(value) == 0) { return 0; } float f; char unit[100]; /* copy value into local buffer to workaround silly sscanf */ char buf[100]; strncpy(buf, value, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; if (sscanf(buf, "%g %s", &f, unit) == 2) { int i = 0; while (metric_unit[i]._name != nil) { if (strcmp(metric_unit[i]._name, unit) == 0) { return f * metric_unit[i]._conversion; } ++i; } return 0; } else if (sscanf(buf, "%g", &f) == 1) { return f; } else { return 0; } } TextStyle& Document::text_style (long index) { return _style->item(index)._style; } TextSource& Document::text_source (long index) { return _source->item(index)._source; } long Document::common_source (long s1, long s2) { while ( _source->item(s1)._source._depth > _source->item(s2)._source._depth ) { s1 = _source->item(s1)._enclosing; } while ( _source->item(s2)._source._depth > _source->item(s1)._source._depth ) { s2 = _source->item(s2)._enclosing; } while (s1 != s2) { s1 = _source->item(s1)._enclosing; s2 = _source->item(s2)._enclosing; } return s1; } Glyph* Document::character (long code, long style) { StyleInfo& info = _style->item(style); if (info._glyph[code] == nil) { switch (code) { case '\0': info._glyph[code] = info._line_strut; break; case '\n': info._glyph[code] = new Discretionary( PenaltyGood, info._end_par_strut, info._end_par_strut, new Discretionary( 0, nil, info._vfil_glue, nil, nil ), info._begin_par_strut ); break; case hfil: info._glyph[code] = info._hfil_glue; break; case hfill: info._glyph[code] = info._hfill_glue; break; case visiblehyphen: info._glyph[code] = new Discretionary( int(document_metric("hyphenpenalty")), info._hyphen, info._hyphen, info._interline_glue, info._begin_line_strut ); break; case discretionaryhyphen: info._glyph[code] = new Discretionary( int(document_metric("hyphenpenalty")), info._line_strut, info._hyphen, info._interline_glue, info._begin_line_strut ); break; case hrule: info._glyph[code] = new Discretionary( PenaltyGood, nil, nil, new HRule(info._color, 1), nil ); break; case parbreak: info._glyph[code] = new Discretionary( PenaltyGood, info._fil_strut, info._end_par_strut, new Discretionary( int(document_metric("parbreakpenalty")), info._interpar_glue, info._vfil_glue, nil, nil ), info._begin_par_strut ); break; case linebreak: info._glyph[code] = new Discretionary( PenaltyGood, info._line_strut, info._end_line_strut, info._interline_glue, info._begin_line_strut ); break; case bigvspace: info._glyph[code] = new Discretionary( PenaltyGood, nil, nil, info._bigskip_glue, nil ); break; case bigskip: info._glyph[code] = new Discretionary( PenaltyGood, info._fil_strut, info._end_par_strut, new Discretionary( int(document_metric("skippenalty")), info._bigskip_glue, info._vfil_glue, nil, nil ), info._begin_par_strut ); break; case medvspace: info._glyph[code] = new Discretionary( PenaltyGood, nil, nil, info._medskip_glue, nil ); break; case medskip: info._glyph[code] = new Discretionary( PenaltyGood, info._fil_strut, info._end_par_strut, new Discretionary( int(document_metric("skippenalty")), info._medskip_glue, info._vfil_glue, nil, nil ), info._begin_par_strut ); break; case smallvspace: info._glyph[code] = new Discretionary( PenaltyGood, nil, nil, info._smallskip_glue, nil ); break; case smallskip: info._glyph[code] = new Discretionary( PenaltyGood, info._fil_strut, info._end_par_strut, new Discretionary( int(document_metric("skippenalty")), info._smallskip_glue, info._vfil_glue, nil, nil ), info._begin_par_strut ); break; case vfil: info._glyph[code] = new Discretionary( PenaltyGood, info._line_strut, info._end_par_strut, info._vfil_glue, info._begin_par_strut ); break; case newpage: info._glyph[code] = new Discretionary( PenaltyGood, info._fil_strut, info._end_par_strut, new Discretionary( PenaltyGood, info._vfil_glue, info._vfil_glue, nil, nil ), info._begin_par_strut ); break; case pagebreak: info._glyph[code] = new Discretionary( PenaltyGood, info._fil_strut, info._end_par_strut, new Discretionary( PenaltyGood, nil, nil, nil, nil ), info._begin_par_strut ); break; case wordspace: info._glyph[code] = new Discretionary( 0, info._word_space, info._end_line_strut, new Discretionary( 0, info._interline_glue, info._vfil_glue, nil, nil ), info._begin_line_strut ); break; case sentencespace: info._glyph[code] = new Discretionary( 0, info._sentence_space, info._end_line_strut, new Discretionary( 0, info._interline_glue, info._vfil_glue, nil, nil ), info._begin_line_strut ); break; case nobreakspace: info._glyph[code] = info._word_space; break; case quadspace: info._glyph[code] = new ShapeOf( new Character('M', info._font, info._color) ); break; case thinspace: info._glyph[code] = new HGlue(1, 0, 0); break; case negthinspace: info._glyph[code] = new HGlue(-1, 0, 0); break; default: info._glyph[code] = new Character(code, info._font, info._color); break; } info._glyph[code]->ref(); } return info._glyph[code]; } long Document::paste ( istream& in, TextItem* text, long index, long style, long source ) { expecting_position = nil; index = read_encoded_text(in, text, index, style, source, END); if (expecting_position != nil) { Coord x = document_metric("textwidth") / 2; Coord y = - (document_metric("textheight") / 2); long page = -1; adjust_float(expecting_position->item(), x, y, page); expecting_position = nil; } return index; } void Document::copy ( ostream& out, TextItem* text, long index, long count, long style, long source ) { column = 0; write_encoded_text(out, text, index, count, style, source); } void Document::read (istream& in) { static boolean reading_style = false; World* world = World::current(); const char* style_path = world->property_value(STYLE_PATH); const char* style_ext = world->property_value(STYLE_FILE_EXTENSION); char line[1000]; while (in.getline(line, 1000)) { if (strchr(line, '\n') != nil) { *strchr(line, '\n') = '\0'; } if (strcmp(line, "") == 0) { ; } else if (strncmp(line, "\\begin{document}", 16) == 0) { break; } else if (strncmp(line, "\\documentstyle", 14) == 0) { char* beginname = strchr(line, '{') + 1; char* endname = strchr(beginname, '}'); int namelen = endname - beginname; char name[256]; strncpy(name, beginname, namelen); name[namelen] = '\0'; if (!reading_style) { _style_name = strcpy(new char[namelen + 1], name); } char path[256]; if (_application->file_path(name, style_ext, style_path, path)) { ifstream style(path); if (!reading_style) { reading_style = true; read(style); reading_style = false; } else { read(style); } } else { fprintf(stderr, "Can't find style %s\n", name); } } else if (strncmp(line, "%macro", 6) == 0) { char name[100], def[1000]; char* beginname = strchr(line, '{') + 1; char* endname = strchr(beginname, '}'); strcpy(name, ""); strncat(name, beginname, endname - beginname); char* begindef = strchr(endname, '{') + 1; char* enddef = strrchr(line, '}'); strcpy(def, ""); strncat(def, begindef, enddef - begindef); define_macro(find_macro(name), def, !reading_style); } else if (strncmp(line, "%counter", 8) == 0) { char name[100], within[100], format[100]; int initial; char* p = line; char* beginname = strchr(p, '{') + 1; char* endname = strchr(beginname, '}'); strcpy(name, ""); strncat(name, beginname, endname - beginname); p = endname + 1; if (strchr(p, '{') != nil) { char* beginwithin = strchr(p, '{') + 1; char* endwithin = strchr(beginwithin, '}'); p = endwithin + 1; strcpy(within, ""); strncat(within, beginwithin, endwithin - beginwithin); } else { strcpy(within, ""); } if (strchr(p, '[') != nil) { char* beginformat = strchr(p, '[') + 1; char* endformat = strchr(beginformat, ']'); p = endformat + 1; strcpy(format, ""); strncat(format, beginformat, endformat - beginformat); } else { strcpy(format, ""); } if (strchr(p, '=') != nil) { sscanf(strchr(p, '=') + 1, "%d", &initial); } else { initial = 0; } define_counter( find_counter(name), within, format, initial, !reading_style ); } else if (strncmp(line, "%label", 6) == 0) { char name[100], text[100]; char* beginname = strchr(line, '{') + 1; char* endname = strchr(beginname, '}'); strcpy(name, ""); strncat(name, beginname, endname - beginname); if (strchr(endname, '{') != nil) { char* begintext = strchr(endname, '{') + 1; char* endtext = strrchr(line, '}'); strcpy(text, ""); strncat(text, begintext, endtext - begintext); } else { strcpy(text, ""); } define_label(find_label(name), text, !reading_style); } else if (strchr(line, '%') != nil) { char name[100]; char* beginname = strchr(line, '%') + 1; char* endname = strchr(beginname, ' '); if (endname == nil) { endname = strchr(beginname, '\0'); } strcpy(name, ""); strncat(name, beginname, endname - beginname); define_parameter(find_parameter(name), endname, !reading_style); } } if (!reading_style) { float format_width = document_metric("formatwidth"); if (format_width == 0) { long column_count = long(document_metric("columns")); format_width = ( (document_metric("textwidth") - (column_count - 1) * document_metric("gutter")) / column_count ); char buf[100]; sprintf(buf, "%gpt", format_width); define_parameter(find_parameter("formatwidth"), buf, false); } find_style( 0, document_parameter("face"), document_parameter("color"), document_parameter("pointsize"), document_parameter("alignment") ); if (_body == nil) { _body = new TextItem( this, nil, 1, 0, document_parameter("formatwidth"), _size_hint ); _body->ref(); } expecting_position = nil; read_encoded_text(in, _body, 0, 1, 0, END); if (expecting_position != nil) { Coord x = document_metric("textwidth") / 2; Coord y = - (document_metric("textheight") / 2); long page = -1; adjust_float(expecting_position->item(), x, y, page); expecting_position = nil; } while (in.getline(line, 256)) { if (strcmp(line, "\\end{document}\n") == 0) { break; } } notify(); } } void Document::write (ostream& out) { out << "\\documentstyle{" << _style_name << "}\n\n"; long count, i; count = _parameter->count(); for (i = 0; i < count; ++i) { DocumentParameterInfo& info = _parameter->item(i); if (info._save && info._value != nil) { out << "%" << info._name << info._value << "\n"; } } count = _macro->count(); for (i = 0; i < count; ++i) { MacroInfo& info = _macro->item(i); if (info._save && info._def != nil) { out << "%macro{" << info._name << "}"; out << "{" << info._def << "}\n"; } } count = _counter->count(); for (i = 0; i < count; ++i) { CounterInfo& info = _counter->item(i); if (info._save) { out << "%counter{" << info._name << "}"; if (info._within != nil && strlen(info._within) > 0) { out << "{" << info._within << "}"; } if (info._format != nil && strlen(info._format) > 0) { out << "[" << info._format << "]"; } if (info._initial != 0) { out << " = " << info._initial; } out << "\n"; } } count = _label->count(); for (i = 0; i < count; ++i) { LabelInfo& info = _label->item(i); if (info._save) { out << "%label{" << info._name << "}"; out << "{" << info._text << "}\n"; } } column = 0; out << "\n\\begin{document}\n"; write_encoded_text(out, _body, 0, _body->item_count(), 1, 0); out << "%\n\\end{document}\n"; } void Document::read (istream& in, TextItem* text, long style, long source) { read_encoded_text(in, text, 0, style, source, END); } void Document::write (ostream& out, TextItem* text, long style, long source) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "\\parbox{" << text->parameters() << "}{"; } write_encoded_text(out, text, 0, text->item_count(), style, source); if (info._source._editable) { out << "}"; }; } void Document::read ( istream& in, TabularItem* tabular, long style, long source ) { int c; RowSeparator rsep = RowSeparatorOff; ColumnSeparator csep = ColumnSeparatorOff; if ((c = in.get()) == '{') { int column = 0; while ((c = in.get()) != '}') { if (c == 'l') { tabular->insert_column(column, "", ColumnAlignLeft); tabular->change_column_separator(column, csep); ++column; csep = ColumnSeparatorOff; } else if (c == 'c') { tabular->insert_column(column, "", ColumnAlignCenter); tabular->change_column_separator(column, csep); ++column; csep = ColumnSeparatorOff; } else if (c == 'r') { tabular->insert_column(column, "", ColumnAlignRight); tabular->change_column_separator(column, csep); ++column; csep = ColumnSeparatorOff; } else if (c == '|') { csep = ColumnSeparatorSingle; } } while ((c = in.get()) == '\n') { } in.putback(c); tabular->change_column_separator(column, csep); } else { tabular->change_row_separator(0, RowSeparatorSingle); tabular->insert_column(0, "", ColumnAlignLeft); tabular->change_column_separator(0, ColumnSeparatorSingle); rsep = RowSeparatorSingle; } int column = 0; int row = 0; char buffer [1000]; while (true) { streampos tell = in.tellg(); c = token(in, buffer); if (c == EOF) { break; } else if (c == END) { in.seekg(tell); break; } else if (c == COMMENT) { ; } else if (c == LINE) { rsep = RowSeparatorOff; column = 0; row += 1; } else if (c == FIELD) { column += 1; } else if (c == COMMAND && strcmp(buffer, "hline") == 0) { rsep = RowSeparatorSingle; } else { if (row >= tabular->row_count()) { tabular->insert_row(row, ""); tabular->change_row_separator(row, rsep); } TextItem* text = tabular->cell(row, column); in.seekg(tell); if (column < tabular->column_count() - 1) { read_encoded_text(in, text, 0, style, source, FIELD); } else { read_encoded_text(in, text, 0, style, source, LINE); } } } tabular->change_row_separator(row, rsep); } void Document::write ( ostream& out, TabularItem* tabular, long style, long source ) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "\\begin{tabular}"; long i; long column_count = tabular->column_count(); out << "{"; for (i = 0; i < column_count + 1; ++i) { if (tabular->column_separator(i) == ColumnSeparatorSingle) { out << "|"; } if (i < column_count) { ColumnAlignment a = tabular->column_alignment(i); if (a == ColumnAlignLeft) { out << "l"; } else if (a == ColumnAlignCenter) { out << "c"; } else if (a == ColumnAlignRight) { out << "r"; } } } out << "}\n"; long row_count = tabular->row_count(); for (i = 0; i < row_count + 1; ++i) { if (tabular->row_separator(i) == RowSeparatorSingle) { out << "\\hline\n"; } if (i < row_count) { for (long j = 0; j < column_count; ++j) { TextItem* text = tabular->cell(i, j); write_encoded_text( out, text, 0, text->item_count(), style, source ); if (j < column_count - 1) { out << "&\n"; } else { out << "\\\\\n"; } } } } out << "\\end{tabular}%\n"; column = 0; }; } void Document::read (istream& in, PSFigItem* psfig, long, long) { char params[256]; in.get(params, 256, '}'); psfig->parameters(params); } void Document::write (ostream& out, PSFigItem* psfig, long, long source) { SourceInfo& info = _source->item(source); if (info._source._editable) { if (column > 0) { out << "%\n"; } out << "\\psfig{"; out << psfig->parameters(); out << "}%\n"; column = 0; } } void Document::read (istream& in, CounterItem* counter, long, long) { char name[100]; in.get(name, 100, '}'); counter->name(name); } void Document::write ( ostream& out, CounterItem* counter, long, long source ) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "\\counter{"; out << counter->name(); out << "}"; column += strlen(counter->name()) + 10; } } void Document::read (istream& in, LabelItem* label, long, long) { char name[100]; in.get(name, 100, '}'); define_label(find_label(name), "", true); label->name(name); } void Document::write (ostream& out, LabelItem* label, long, long source) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "\\label{"; out << label->name(); out << "}"; column += strlen(label->name()) + 8; } } void Document::read (istream& in, RefItem* ref, long, long) { char label[100]; in.get(label, 100, '}'); ref->name(label); } void Document::write (ostream& out, RefItem* ref, long, long source) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "\\ref{"; out << ref->name(); out << "}"; column += strlen(ref->name()) + 6; } } void Document::read (istream& in, FloatItem* f, long style, long source) { char context[100]; in.getline(context, 100, '}'); in.ignore(1); f->context(context); TextItem* text = new TextItem(this, f, style, source, ""); f->item(text); read_encoded_text(in, text, 0, style, source, END); } void Document::write (ostream& out, FloatItem* f, long, long source) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "\\float{" << f->context() << "}"; out << "{"; column += strlen(f->context()) + 9; } TextItem* text = f->item(); write_encoded_text( out, text, 0, text->item_count(), text->style(), text->source() ); if (info._source._editable) { out << "}"; column += 1; } FloatInfo& finfo = _float->item(find_float(f->item())); out << "%" << finfo._x << " " << finfo._y << " " << finfo._page << "\n"; column = 0; } void Document::read (istream& in, PagenumberItem* p, long, long) { char sample[100]; in.get(sample, 100, '}'); p->sample(sample); } void Document::write (ostream& out, PagenumberItem* p, long, long source) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "\\pagenumber{"; out << p->sample(); out << "}"; column += strlen(p->sample()) + 13; } } long Document::parse_text (const char* buffer) { if (buffer == nil) { return 0; } for (long i = 0; text_map[i]._format != nil; ++i) { if (strcmp(buffer, text_map[i]._format) == 0) { return text_map[i]._code; } } if (isdigit(buffer[0])) { int i = buffer[0] - '0'; if (isdigit(buffer[1])) { i = i * 8 + (buffer[1] - '0'); } if (isdigit(buffer[2])) { i = i * 8 + (buffer[2] - '0'); } return i; } else { return 0; } } long Document::unparse_text (char* buffer, long code) { char ch = char(code); if (ch == '\\') { sprintf(buffer, "\\backslash"); return 0; } else if (ch == '\n') { sprintf(buffer, "\\"); return -1; } else if (strchr(quoted_characters, ch) != NULL) { sprintf(buffer, "\\%c", ch); return 1; } else if (isascii(ch)) { sprintf(buffer, "%c", ch); return 1; } else { long i; for (i = 0; special_map[i]._format != nil; ++i) { if (code == special_map[i]._code) { sprintf(buffer, special_map[i]._format); return special_map[i]._fold; } } for (i = 0; text_map[i]._format != nil; ++i) { if (code == text_map[i]._code) { sprintf(buffer, "\\%s", text_map[i]._format); return text_map[i]._fold; } } sprintf(buffer, "\\%0o", ch); return 1; } } long Document::parse_style (const char* buffer, long current_style) { char font[100]; font[0] = '\0'; char color[100]; color[0] = '\0'; char size[100]; size[0] = '\0'; char alignment[100]; alignment[0] = '\0'; char def[1000]; strcpy(def, buffer); istrstream in(def); char name[100]; while (in) { int c = token(in, name); if (c == EOF) { ; } else if (c == FONT) { strcpy(font, name); } else if (c == SIZE) { strcpy(size, name); } else if (c == COLOR) { strcpy(color, name); } else if (c == ALIGN) { strcpy(alignment, name); } else if (c == COMMAND) { current_style = find_style( current_style, font, color, size, alignment ); strcpy(font, ""); strcpy(color, ""); strcpy(size, ""); strcpy(alignment, ""); MacroInfo& info = _macro->item(find_macro(name)); current_style = parse_style(info._def, current_style); } else { ; } } return find_style(current_style, font, color, size, alignment); } void Document::unparse_style (char* buffer, long style, long old) { TextStyle& new_style = _style->item(style)._style; TextStyle& old_style = _style->item(old)._style; buffer[0] = '\0'; if (strcmp(new_style._font, old_style._font) != 0) { strcat(buffer, "\\font{"); strcat(buffer, new_style._font); strcat(buffer, "}"); } if (strcmp(new_style._color, old_style._color) != 0) { strcat(buffer, "\\color{"); strcat(buffer, new_style._color); strcat(buffer, "}"); } if (strcmp(new_style._size, old_style._size) != 0) { strcat(buffer, "\\size{"); strcat(buffer, new_style._size); strcat(buffer, "}"); } if (strcmp(new_style._alignment, old_style._alignment) != 0) { strcat(buffer, "\\align{"); strcat(buffer, new_style._alignment); strcat(buffer, "}"); } } long Document::read_verbatim_text ( istream& in, TextItem* text, long index, long style, long source ) { source = find_source(source, style, "verbatim", "", true, true); style = parse_style(_macro->item(find_macro("verbatim"))._def, style); char line[1000]; boolean done = false; const char* term = "\\end{verbatim}"; int termlength = strlen(term); in.getline(line, 1000); do { streampos bol = in.tellg(); if (!in.getline(line, 1000)) { done = true; } else if (strncmp(line, term, termlength) == 0) { in.seekg(bol); done = true; } else { int length = strlen(line); for (int i = 0; i < length; ++i) { index = text->insert(index, line[i], style, source, nil); } index = text->insert(index, '\n', style, source, nil); } } while (!done); return index; } void Document::write_verbatim_text ( ostream& out, TextItem* text, long index, long count, long style, long source ) { SourceInfo& info = _source->item(source); if (info._source._editable) { if (info._style != style) { char buffer[100]; unparse_style(buffer, style, info._style); out << "{" << buffer; } out << "%\n\\begin{verbatim}\n"; column = 0; for (long i = index; i < index + count; ++i) { out.put(char(text->item_code(i))); } out << "\\end{verbatim}%\n"; column = 0; if (info._style != style) { out << "}"; column += 1; } } } long Document::read_import_text ( istream&, TextItem* text, long index, long style, long source, const char* filename ) { source = find_source(source, style, "import", filename, false, true); style = parse_style(_macro->item(find_macro("verbatim"))._def, style); boolean done = false; ifstream file(filename); char line[1000]; while (file) { file.getline(line, 1000); if (file) { int length = strlen(line); for (int i = 0; i < length; ++i) { index = text->insert(index, line[i], style, source, nil); } index = text->insert(index, '\n', style, source, nil); } } return index; } void Document::write_import_text ( ostream& out, TextItem*, long, long, long style, long source, const char* filename ) { SourceInfo& info = _source->item(source); if (info._source._editable) { if (info._style != style) { char buffer[100]; unparse_style(buffer, style, info._style); out << "{" << buffer; } out << "%\n\\import{" << filename << "}%\n"; column = 0; if (info._style != style) { out << "}"; column += 1; } } } long Document::read_macro_text ( istream& in, TextItem* text, long index, long style, long source, const char* name ) { source = find_source(source, style, "macro", name, false, true); istrstream def(_macro->item(find_macro(name))._def); parameter = ∈ index = read_encoded_text(def, text, index, style, source, END); return index; } void Document::write_macro_text ( ostream& out, TextItem* text, long index, long count, long, long source, const char* name ) { SourceInfo& info = _source->item(source); if (info._source._editable) { out << "%\n%\n\\" << name << "{"; column = strlen(name) + 2; } source = nested_source(source, text->item_source(index)); write_encoded_text( out, text, index, count, _source->item(source)._style, source ); if (info._source._editable) { out << "}%\n%\n"; column = 0; } } long Document::read_parameter_text ( istream& in, TextItem* text, long index, long style, long source ) { source = find_source(source, style, "parameter", "", true, true); index = read_encoded_text(in, text, index, style, source, END); return index; } void Document::write_parameter_text ( ostream& out, TextItem* text, long index, long count, long, long source ) { SourceInfo& info = _source->item(source); source = nested_source(source, text->item_source(index)); write_encoded_text( out, text, index, count, _source->item(source)._style, source ); } void Document::write_styled_text ( ostream& out, TextItem* text, long index, long count, long style, long source, const char* name ) { SourceInfo& info = _source->item(source); source = nested_source(source, text->item_source(index)); style = parse_style(_macro->item(find_macro(name))._def, style); if (info._source._editable) { out << "{\\" << name << " "; column += strlen(name) + 3; } write_encoded_text(out, text, index, count, style, source); if (info._source._editable) { out << "}"; column += 1; } } long Document::read_encoded_text ( istream& in, TextItem* text, long index, long style, long source, long terminator ) { boolean done = false; char buffer[1000]; long i = index; do { streampos tell = in.tellg(); int c = token(in, buffer); if (c < 0 && c >= terminator) { in.seekg(tell); done = true; } else if (c == COMMENT) { if (expecting_position != nil) { float x, y; long page; if (sscanf(buffer, "%g %g %d", &x, &y, &page) == 3) { adjust_float(expecting_position->item(), x, y, page); expecting_position = nil; } } } else if (c == BLOCK) { i = read_encoded_text(in, text, i, style, source, END); if (token(in, buffer) != END) { ; // error } } else if (c == FIELD) { ; // error } else if (c == LINE) { i = text->insert(i, linebreak, style, source, nil); } else if (c == FONT) { style = find_style(style, buffer, "", "", ""); } else if (c == SIZE) { style = find_style(style, "", "", buffer, ""); } else if (c == COLOR) { style = find_style(style, "", buffer, "", ""); } else if (c == ALIGN) { style = find_style(style, "", "", "", buffer); } else if (c == COMMAND) { long j; if ((j = parse_text(buffer)) > 0) { i = text->insert(i, j, style, source, nil); } else { MacroInfo& info = _macro->item(find_macro(buffer)); SourceInfo& sourceinfo = _source->item(source); if (i == index && sourceinfo._source._editable) { source = find_source( source, style, "styled", buffer, true, false ); } style = parse_style(info._def, style); } } else if (c == VERBATIM) { i = read_verbatim_text(in, text, i, style, source); if (token(in, buffer) != END) { ; // error } } else if (c == IMPORT) { i = read_import_text(in, text, i, style, source, buffer); } else if (c == MACRO) { i = read_macro_text(in, text, i, style, source, buffer); if (token(in, buffer) != END) { ; } } else if (c == PARAMETER) { if (parameter != nil) { i = read_parameter_text( *parameter, text, i, style, source ); parameter = nil; } } else if (c == PARBOX) { TextItem* parbox = new TextItem(this, text, style, source, buffer); read_encoded_text(in, parbox, 0, style, source, END); i = text->insert(i, 0, style, source, parbox); if (token(in, buffer) != END) { ; } } else if (c == FLOAT) { FloatItem* f = new FloatItem(this, text, style, source); if (expecting_position != nil) { Coord x = document_metric("textwidth") / 2; Coord y = - (document_metric("textheight") / 2); long page = -1; adjust_float(expecting_position->item(), x, y, page); expecting_position = nil; } expecting_position = f; f->read(in); i = text->insert(i, 0, style, source, f); if (token(in, buffer) != END) { ; } } else if (c == TABULAR) { TabularItem* tabular = new TabularItem(this, text, style, source); tabular->read(in); i = text->insert(i, 0, style, source, tabular); if (token(in, buffer) != END) { ; } } else if (c == PSFIG) { PSFigItem* psfig = new PSFigItem(this, text, style, source); psfig->read(in); i = text->insert(i, 0, style, source, psfig); if (token(in, buffer) != END) { ; } } else if (c == COUNTER) { CounterItem* counter = new CounterItem(this, text, style, source); counter->read(in); i = text->insert(i, 0, style, source, counter); if (token(in, buffer) != END) { ; } } else if (c == LABEL) { LabelItem* label = new LabelItem(this, text, style, source); label->read(in); i = text->insert(i, 0, style, source, label); if (token(in, buffer) != END) { ; } } else if (c == REF) { RefItem* ref = new RefItem(this, text, style, source); ref->read(in); i = text->insert(i, 0, style, source, ref); if (token(in, buffer) != END) { ; } } else if (c == PAGENUMBER) { PagenumberItem* p = new PagenumberItem(this, text, style, source); p->read(in); i = text->insert(i, 0, style, source, p); if (token(in, buffer) != END) { ; } } else { i = text->insert(i, c, style, source, nil); } } while (!done); return i; } void Document::write_encoded_text ( ostream& out, TextItem* text, long index, long count, long style, long source ) { long current_style = style; boolean generated = !_source->item(source)._source._editable; char buffer[1000]; long i = index; while (i < index + count) { long new_source = text->item_source(i); if (new_source != source) { long nested = nested_source(source, text->item_source(i)); long new_style = _source->item(nested)._style; if (!generated && new_style != current_style) { out << "{"; column += 1; unparse_style(buffer, new_style, current_style); out << buffer; column += strlen(buffer); } long j = i + 1; while ( j < index + count && nested == nested_source(source, text->item_source(j)) ) { ++j; } TextSource& info = _source->item(nested)._source; if (strcmp(info._source, "document") == 0) { write_encoded_text( out, text, i, j - i, current_style, nested ); } else if (strcmp(info._source, "verbatim") == 0) { write_verbatim_text( out, text, i, j - i, current_style, source ); } else if (strcmp(info._source, "macro") == 0) { write_macro_text( out, text, i, j - i, current_style, source, info._name ); } else if (strcmp(info._source, "parameter") == 0) { write_parameter_text( out, text, i, j - i, current_style, source ); } else if (strcmp(info._source, "import") == 0) { write_import_text( out, text, i, j - i, current_style, source, info._name ); } else if (strcmp(info._source, "styled") == 0) { write_styled_text( out, text, i, j - i, current_style, source, info._name ); } else { break; } if (!generated && new_style != current_style) { out << "}"; column += 1; } i = j; } else { long new_style = text->item_style(i); if (!generated) { if (new_style != current_style) { if (current_style == style) { out << "{"; column += 1; } else if (new_style == style) { column += 1; out << "}"; } if (new_style != style) { unparse_style(buffer, new_style, current_style); column += strlen(buffer); out << buffer; } } } current_style = new_style; Item* item = text->item(i); if (item == nil) { if (!generated) { long fold = unparse_text(buffer, text->item_code(i)); out << buffer; if (fold > 0) { column += strlen(buffer); } else if (fold < 0) { out << "\n"; column = 0; } else { if (column >= FOLDCOLUMN) { out << "\n"; column = 0; } else { out << " "; column += strlen(buffer) + 1; } } } } else { item->write(out); } i = i + 1; } } if (current_style != style && !generated) { out << "}"; column += 1; } } void Document::relabel () { _relabel = true; } void Document::step (const char* counter, const char* context) { long count = _counter->count(); for (long i = 0; i < count; ++i) { CounterInfo& info = _counter->item(i); if (strcmp(info._name, counter) == 0) { info._value += 1; char buffer[100]; buffer[0] = '\0'; if (info._within != nil && strlen(info._within) > 0) { strcat(buffer, label(info._within)); strcat(buffer, "."); } long j = 0; while (counter_format[j]._name != nil) { if (strcmp(counter_format[j]._name, info._format) == 0) { (*counter_format[j]._formatter)( info._value, strchr(buffer, '\0') ); } ++j; } label(info._name, buffer); label(context, buffer); } else if (info._within != nil && strcmp(info._within, counter) == 0) { info._value = 0; label(info._name, ""); } } } void Document::label (const char* name, const char* text) { long label = find_label(name); define_label(label, text, _label->item(label)._save); } const char* Document::label (const char* name) { LabelInfo& info = _label->item(find_label(name)); if (info._text != nil) { return info._text; } else { return "?"; } } void Document::attach (DocumentViewer* viewer) { DocumentViewerInfo info; info._viewer = viewer; _viewer->append(info); long count = _float->count(); for (long i = 0; i < count; ++i) { FloatInfo& info = _float->item(i); viewer->float_inserted(info._item); viewer->float_adjusted(info._item, info._x, info._y, info._page); } viewer->update(); } void Document::detach (DocumentViewer* viewer) { long count = _viewer->count(); for (long i = 0; i < count; ++i) { DocumentViewerInfo& info = _viewer->item(i); if (info._viewer == viewer) { _viewer->remove(i); break; } } } void Document::notify () { while (_body != nil && _relabel) { long count = _counter->count(); for (long i = 0; i < count; ++i) { CounterInfo& info = _counter->item(i); info._value = info._initial; } _relabel = false; _body->label(""); } long count = _viewer->count(); for (long i = 0; i < count; ++i) { DocumentViewerInfo& info = _viewer->item(i); info._viewer->update(); } } long Document::find_style ( long oldstyle, const char* font, const char* color, const char* size, const char* alignment ) { long count = _style->count(); long i; if (oldstyle >= 0) { TextStyle& info = _style->item(oldstyle)._style; if (strlen(font) == 0) font = info._font; if (strlen(color) == 0) color = info._color; if (strlen(size) == 0) size = info._size; if (strlen(alignment) == 0) alignment = info._alignment; for (i = 0; i < count; ++i) { TextStyle& info = _style->item(i)._style; if ( strcmp(font, info._font) == 0 && strcmp(color, info._color) == 0 && strcmp(size, info._size) == 0 && strcmp(alignment, info._alignment) == 0 ) { break; } } } else { i = count; } if (i == count) { StyleInfo info; info._style._font = strcpy(new char[strlen(font) + 1], font); info._style._color = strcpy(new char[strlen(color) + 1], color); info._style._size = strcpy(new char[strlen(size) + 1], size); info._style._alignment = strcpy(new char[strlen(alignment) + 1], alignment); _style->append(info); initialize_style(i); } return i; } void Document::initialize_style (long index) { static FontFamily* times; static FontFamily* helvetica; static FontFamily* courier; StyleInfo& style = _style->item(index); char screenfont[100]; strcpy(screenfont, style._style._font); long len = strlen(screenfont); for (long i = 0; i < len; ++i) { if (isupper(screenfont[i])) { screenfont[i] += 'a' - 'A'; } } char* hyphen = strchr(screenfont, '-'); char* screenstyle; if (hyphen != nil) { *hyphen = '\0'; screenstyle = hyphen+1; } else { screenstyle = ""; } FontFamily* family = find_font_family(screenfont); float pointsize; sscanf(style._style._size, "%g", &pointsize); float scale; char* name; if (family != nil && family->font( int(pointsize), screenstyle, name, scale) ) { if (!World::current()->property_is_on(SCREEN_METRICS) && PSFont::exists(style._style._font) ) { style._font = new PSFont( style._style._font, pointsize, name, scale ); } else { style._font = new Font(name, scale); } } else { style._font = World::current()->font(); } style._font->ref(); style._color = Color::lookup( World::current()->display(), style._style._color ); if (style._color == nil) { style._color = World::current()->foreground(); } style._color->ref(); Coord baseline_skip = pointsize * document_metric("baselineskip"); Coord baseline_stretch = pointsize * document_metric("baselinestretch"); Coord par_skip = pointsize * document_metric("parskip"); Coord par_stretch = pointsize * document_metric("parstretch"); Coord big_skip = pointsize * document_metric("bigskip"); Coord big_stretch = pointsize * document_metric("bigstretch"); Coord med_skip = pointsize * document_metric("medskip"); Coord med_stretch = pointsize * document_metric("medstretch"); Coord small_skip = pointsize * document_metric("smallskip"); Coord small_stretch = pointsize * document_metric("smallstretch"); if (strcmp(style._style._alignment, "left") == 0) { style._begin_line_strut = new VStrut(0); style._end_line_strut = new Strut(style._font, 0, fil, 0); style._begin_par_strut = new VStrut(0); style._end_par_strut = new Strut(style._font, 0, fil, 0); } else if(strcmp(style._style._alignment, "right") == 0) { style._begin_line_strut = new VStrut(0, 0, 0, fil, 0); style._end_line_strut = new Strut(style._font); style._begin_par_strut = new VStrut(0, 0, 0, fil, 0); style._end_par_strut = new Strut(style._font); } else if (strcmp(style._style._alignment, "center") == 0) { style._begin_line_strut = new VStrut(0, 0, 0, fil, 0); style._end_line_strut = new Strut(style._font, 0, fil, 0); style._begin_par_strut = new VStrut(0, 0, 0, fil, 0); style._end_par_strut = new Strut(style._font, 0, fil, 0); } else if (strcmp(style._style._alignment, "justify") == 0) { style._begin_line_strut = new VStrut(0); style._end_line_strut = new Strut(style._font); style._begin_par_strut = new VStrut(0); style._end_par_strut = new Strut(style._font, 0, fil, 0); } else { style._begin_line_strut = new VStrut(0); style._end_line_strut = new Strut(style._font, 0, fil, 0); style._begin_par_strut = new VStrut(0); style._end_par_strut = new Strut(style._font, 0, fil, 0); } style._begin_line_strut->ref(); style._end_line_strut->ref(); style._begin_par_strut->ref(); style._end_par_strut->ref(); style._line_strut = new Strut(style._font); style._line_strut->ref(); style._fil_strut = new Strut(style._font, 0, fil, 0); style._fil_strut->ref(); style._hyphen = new Character('-', style._font, style._color); style._hyphen->ref(); style._interline_glue = new VGlue(baseline_skip, baseline_stretch, 0); style._interline_glue->ref(); style._interpar_glue = new VGlue(par_skip, par_stretch, 0); style._interpar_glue->ref(); style._hfil_glue = new HGlue(0, fil, 0); style._hfil_glue->ref(); style._hfill_glue = new HGlue(0, 1000000*fil, 0); style._hfill_glue->ref(); style._vfil_glue = new VGlue(0, fil, 0); style._vfil_glue->ref(); style._bigskip_glue = new VGlue(big_skip, big_stretch, 0); style._bigskip_glue->ref(); style._medskip_glue = new VGlue(med_skip, med_stretch, 0); style._medskip_glue->ref(); style._smallskip_glue = new VGlue(small_skip, small_stretch, 0); style._smallskip_glue->ref(); style._word_space = new Space(2, 0.5, style._font, style._color); style._word_space->ref(); style._sentence_space = new Space(3, 0.5, style._font, style._color); style._sentence_space->ref(); for (int c = 0; c < 256; ++c) { style._glyph[c] = nil; } } void Document::cleanup_style (long index) { StyleInfo& style = _style->item(index); delete style._style._font; delete style._style._color; delete style._style._alignment; style._font->unref(); style._color->unref(); style._begin_line_strut->unref(); style._end_line_strut->unref(); style._begin_par_strut->unref(); style._end_par_strut->unref(); style._line_strut->unref(); style._fil_strut->unref(); style._hyphen->unref(); style._interline_glue->unref(); style._interpar_glue->unref(); style._hfil_glue->unref(); style._hfill_glue->unref(); style._vfil_glue->unref(); style._bigskip_glue->unref(); style._medskip_glue->unref(); style._smallskip_glue->unref(); style._word_space->unref(); style._sentence_space->unref(); for (int c = 0; c < 256; ++c) { if (style._glyph[c] != nil) { style._glyph[c]->unref(); } } } long Document::find_source ( long enclosing, long style, const char* source, const char* name, boolean editable, boolean unique ) { long count = _source->count(); long i; if (!unique) { for (i = 0; i < count; ++i) { SourceInfo& info = _source->item(i); if ( info._enclosing == enclosing && info._style == style && strcmp(info._source._source, source) == 0 && strcmp(info._source._name, name) == 0 ) { break; } } } else { i = count; } if (i == count) { SourceInfo info; info._enclosing = enclosing; info._style = style; info._source._name = strcpy(new char[strlen(name) + 1], name); info._source._source = strcpy(new char[strlen(source) + 1], source); if (enclosing >= 0) { info._source._depth = _source->item(enclosing)._source._depth + 1; } else { info._source._depth = 0; } info._source._editable = editable; _source->append(info); } return i; } long Document::nested_source (long enclosing, long source) { while (source != 0) { SourceInfo& info = _source->item(source); if (info._enclosing == enclosing) { break; } else { source = info._enclosing; } }; return source; } void Document::cleanup_source (long index) { SourceInfo& info = _source->item(index); delete info._source._name; delete info._source._source; } long Document::find_macro (const char* name) { long count = _macro->count(); for (long i = 0; i < count; ++i) { MacroInfo& info = _macro->item(i); if (strcmp(info._name, name) == 0) { break; } } if (i == count) { MacroInfo info; info._name = strcpy(new char[strlen(name) + 1], name); info._def = strcpy(new char[2], "#"); info._save = false; _macro->append(info); } return i; } void Document::define_macro (long index, const char* def, boolean save) { MacroInfo& info = _macro->item(index); if (info._def != nil) { delete info._def; } info._def = strcpy(new char[strlen(def) + 1], def); info._save = save; } void Document::cleanup_macro (long index) { MacroInfo& info = _macro->item(index); if (info._name != nil) { delete info._name; } if (info._def != nil) { delete info._def; } } long Document::find_counter (const char* name) { long count = _counter->count(); for (long i = 0; i < count; ++i) { CounterInfo& info = _counter->item(i); if (strcmp(info._name, name) == 0) { break; } } if (i == count) { CounterInfo info; info._name = strcpy(new char[strlen(name) + 1], name); info._within = nil; info._format = nil; info._initial = 0; info._value = 0; info._save = false; _counter->append(info); } return i; } void Document::define_counter ( long index, const char* within, const char* format, long initial, boolean save ) { CounterInfo& info = _counter->item(index); if (info._within != nil) { delete info._within; } info._within = strcpy(new char[strlen(within) + 1], within); if (info._format != nil) { delete info._format; } info._format = strcpy(new char[strlen(format) + 1], format); info._initial = initial; info._save = save; } void Document::cleanup_counter (long index) { CounterInfo& info = _counter->item(index); if (info._name != nil) { delete info._name; } if (info._within != nil) { delete info._within; } if (info._format != nil) { delete info._format; } } long Document::find_parameter (const char* name) { long count = _parameter->count(); for (long i = 0; i < count; ++i) { DocumentParameterInfo& info = _parameter->item(i); if (strcmp(info._name, name) == 0) { break; } } if (i == count) { DocumentParameterInfo info; info._name = strcpy(new char[strlen(name) + 1], name); info._value = nil; info._save = false; _parameter->append(info); } return i; } void Document::define_parameter (long index, const char* value, boolean save) { DocumentParameterInfo& info = _parameter->item(index); if (info._value != nil) { delete info._value; } if (value != nil) { info._value = strcpy(new char[strlen(value) + 1], value); } else { info._value = nil; } info._save = save; } void Document::cleanup_parameter (long index) { DocumentParameterInfo& info = _parameter->item(index); if (info._name != nil) { delete info._name; } if (info._value != nil) { delete info._value; } } long Document::find_label (const char* name) { long count = _label->count(); for (long i = 0; i < count; ++i) { LabelInfo& info = _label->item(i); if (strcmp(info._name, name) == 0) { break; } } if (i == count) { LabelInfo info; info._name = strcpy(new char[strlen(name) + 1], name); info._text = nil; info._save = false; _label->append(info); } return i; } void Document::define_label (long index, const char* text, boolean save) { LabelInfo& info = _label->item(index); if (info._text != nil) { delete info._text; } if (text != nil) { info._text = strcpy(new char[strlen(text) + 1], text); } else { info._text = nil; } info._save = save; } void Document::cleanup_label (long index) { LabelInfo& info = _label->item(index); if (info._name != nil) { delete info._name; } if (info._text != nil) { delete info._text; } } long Document::find_float (Item* item) { long count = _float->count(); for (long i = 0; i < count; ++i) { FloatInfo& info = _float->item(i); if (info._item == item) { break; } } if (i == count) { FloatInfo info; info._item = item; info._item->ref(); info._x = 0; info._y = 0; info._page = -1; _float->append(info); } return i; } void Document::cleanup_float (long index) { FloatInfo& info = _float->item(index); info._item->unref(); } void Document::read_parameter (istream& in, char* buffer) { int c; char* p = buffer; do { *p++ = (c = in.get()); } while (c != '}'); *--p = '\0'; in.putback(c); } void Document::read_name (istream& in, char* buffer) { int c; char* p = buffer; do { *p++ = (c = in.get()); } while (isalpha(c) || c == '*'); *--p = '\0'; in.putback(c); } int Document::token (istream& in, char* buffer) { int c = in.get(); if (c == EOF) { return EOF; } else if (c == '%') { char* p = buffer; while ((*p++ = in.get()) != '\n') { } *p = '\0'; return COMMENT; } else if (c == '{') { return BLOCK; } else if (c == '}') { return END; } else if (c == '&') { while ((c = in.get()) == ' ') { } if (c == '\n' && (c = in.get()) == '\n') { in.putback(c); } in.putback(c); return FIELD; } else if (c == '\\') { c = in.get(); if (isalpha(c)) { in.putback(c); read_name(in, buffer); if ((c = in.get()) == '{') { if (strcmp(buffer, "end") == 0) { read_parameter(in, buffer); in.ignore(1); return END; } if (strcmp(buffer, "begin") == 0) { read_parameter(in, buffer); in.ignore(1); } if (strcmp(buffer, "color") == 0) { read_parameter(in, buffer); in.ignore(1); return COLOR; } else if (strcmp(buffer, "font") == 0) { read_parameter(in, buffer); in.ignore(1); return FONT; } else if (strcmp(buffer, "size") == 0) { read_parameter(in, buffer); in.ignore(1); return SIZE; } else if (strcmp(buffer, "align") == 0) { read_parameter(in, buffer); in.ignore(1); return ALIGN; } else if (strcmp(buffer, "import") == 0) { read_parameter(in, buffer); in.ignore(1); return IMPORT; } else if (strcmp(buffer, "parbox") == 0) { read_parameter(in, buffer); in.ignore(2); return PARBOX; } else if (strcmp(buffer, "float") == 0) { return FLOAT; } else if (strcmp(buffer, "verbatim") == 0) { return VERBATIM; } else if (strcmp(buffer, "tabular") == 0) { return TABULAR; } else if (strcmp(buffer, "psfig") == 0) { return PSFIG; } else if (strcmp(buffer, "counter") == 0) { return COUNTER; } else if (strcmp(buffer, "label") == 0) { return LABEL; } else if (strcmp(buffer, "ref") == 0) { return REF; } else if (strcmp(buffer, "pagenumber") == 0) { return PAGENUMBER; } else { return MACRO; } } else { in.putback(c); while ((c = in.get()) == ' ') { } if (c == '\n' && (c = in.get()) == '\n') { in.putback(c); } in.putback(c); return COMMAND; } } else if (isdigit(c)) { int i = c - '0'; if (isdigit(c = in.get())) { i = i * 8 + (c - '0'); } else { in.putback(c); } if (isdigit(c = in.get())) { i = i * 8 + (c - '0'); } else { in.putback(c); } return i; } else if (c == '\\') { while ((c = in.get()) == '\n') { } in.putback(c); return LINE; } else if (c == '-') { return discretionaryhyphen; } else if (c == ',') { return thinspace; } else if (c == '!') { return negthinspace; } else { return c; } } else if (c == '-') { if ((c = in.get()) == '-') { if ((c = in.get()) == '-') { return emdash; } else { in.putback(c); return endash; } } else { in.putback(c); return visiblehyphen; } } else if (c == ' ') { int count = 1; while ((c = in.get()) == ' ') { ++count; } in.putback(c); if (count > 1) { return sentencespace; } else if (c == '\n') { return token(in, buffer); } else { return wordspace; } } else if (c == '\n') { if ((c = in.get()) == '\n') { in.putback(c); while ((c = in.get()) == '\n') { } in.putback(c); while ((c = in.get()) == ' ') { } in.putback(c); return parbreak; } else { in.putback(c); while ((c = in.get()) == ' ') { } in.putback(c); return wordspace; } } else if (c == '#') { return PARAMETER; } else if (c == '~') { return nobreakspace; } else { return c; } }