📄 format.c
字号:
}static charget_link_cell_attributes(const string &href){ if (href.at(0) == '#') { static const char internal_link_attributes = Formatting::getAttributes("A.attributes.internal_link", Cell::UNDERLINE); return internal_link_attributes; } else { static const char external_link_attributes = Formatting::getAttributes("A.attributes.external_link", Cell::UNDERLINE); return external_link_attributes; }}// Attributes: NAME HREF REL REV TITLE (ignored)Line *Anchor::line_format() const{ auto_ptr<Line> res(::line_format(texts.get())); if (!res.get()) return 0; string href(get_attribute(attributes.get(), "HREF", "")); if (!href.empty()) res->add_attribute(get_link_cell_attributes(href)); return res.release();}Area *Anchor::format(Area::size_type w, int halign) const{ auto_ptr<Area> res(::format(texts.get(), w, halign)); if (!res.get()) return 0; string href(get_attribute(attributes.get(), "HREF", "")); if (!href.empty()) res->add_attribute(get_link_cell_attributes(href)); return res.release();}// Attributes: CLEAR (ignored)Line *LineBreak::line_format() const{ return new Line("\n");}Area *TableHeadingCell::format(Area::size_type w, int halign) const{ Area *a = TableCell::format(w, halign); if (a) a->add_attribute(Cell::BOLD); return a;}Area *Caption::format(Area::size_type w, int halign) const{ auto_ptr<Line> l(::line_format(texts.get())); return l.get() ? make_up(*l, w, halign) : 0;}// Attributes: (none)Line *NoBreak::line_format() const{ Line *l(::line_format(content.get())); if (!l) return 0; for (Line::size_type i = 0; i < l->length(); ++i) { Cell &c((*l)[i]); if (c.character == ' ') c.character = LATIN1_nbsp; } return l;}/* ------------------------------------------------------------------------- *//* * Make up "line" into an Area. Attempt to return an Area no wider than "w". */static Area *make_up(const Line &line, Area::size_type w, int halign){//{// cout << "make_up(\"";// for (Line::size_type i = 0; i < line.length(); i++) {// if (isprint(line[i].character)) cout << line[i].character;// else cout << "[" << (int) line[i].character << "]";// }// cout << "\")" << endl;//} if (line.empty()) return 0; auto_ptr<Area> res(new Area); Line::size_type from = 0; while (from < line.length()) { /* * A sole newline character has a special meaning: Append a blank line. */ if (line[from].character == '\n') { res->resize(res->width(), res->height() + 1); from++; continue; } Line::size_type to = from + 1; Line::size_type lbp = (Line::size_type) -1; // "Last break position". /* * Determine the line break position. */ while (to < line.length()) { if (line[to].character == '\n') { break; } char c1 = line[to].character, c2 = line[to - 1].character; if (c1 == ' ' || c1 == '('/*)*/ || c1 == '['/*]*/ || c1 == '{'/*}*/ || ( ( c2 == '-' || c2 == '/' || c2 == ':' ) && c1 != ',' && c1 != '.' && c1 != ';' && c1 != ':' )) { lbp = to++; while (to < line.length() && line[to].character == ' ') to++; } else { to++; } if (to - from > w && lbp != (Area::size_type) -1) { to = lbp; break; } } /* * Copy the "from...to" range from the "line" to the bottom of the "res" * Area. */ Area::size_type x = 0; Area::size_type len = to - from; if (halign == Area::LEFT || len >= w) { ; } else if (halign == Area::CENTER) { x += (w - len) / 2; } else if (halign == Area::RIGHT) { x += w - len; } res->insert(line.cells() + from, len, x, res->height()); /* * Determine the beginnning of the next line. */ if (to == line.length()) break; from = to; if (line[from].character == '\n') { ++from; } else if (line[from].character == ' ') { do { ++from; } while (from < line.length() && line[from].character == ' '); } } return res.release();}/* ------------------------------------------------------------------------- *//* * Attempt to line-format all "elements". If one of the elements can only be * area-formatted, return null. In that case, "::format()" (below) will * probably work. */static Line *line_format(const list<auto_ptr<Element> > *elements){ auto_ptr<Line> res; if (elements) { list<auto_ptr<Element> >::const_iterator i; for (i = elements->begin(); i != elements->end(); ++i) { auto_ptr<Line> l((*i)->line_format()); if (!l.get()) { auto_ptr<Area> a((*i)->format(100, Area::LEFT)); if (a.get()) return 0; continue; } if (res.get()) { *res += *l; } else { res = l; } } } return res.release();}/* ------------------------------------------------------------------------- *//* * Basically, a list of "Text"s is a stream of words that has to be formatted * into an area. But... as an extension to HTML 3.2 we want to allow "Block"s * be embedded in "Text", e.g. * * <FONT COLOR=red><P>Bla</P><P>Bloh</P></FONT> * * Attempt to line-format the "Text". This will fail if there is a "Block" * inside the "Text". * * The "Text" could not be line-formatted, so... append a line-break and * the area-formatted "Text". */static Area *format( const list<auto_ptr<Element> > *elements, Area::size_type w, int halign){ if (!elements) return 0; auto_ptr<Area> res; auto_ptr<Line> line; list<auto_ptr<Element> >::const_iterator i; for (i = elements->begin(); i != elements->end(); ++i) { if (!(*i).get()) continue; auto_ptr<Line> l((*i)->line_format()); if (l.get()) { if (line.get()) { *line += *l; } else { line = l; } continue; } auto_ptr<Area> a((*i)->format(w, halign)); if (a.get()) { if (line.get()) { auto_ptr<Area> a2(make_up(*line, w, halign)); if (a2.get()) { if (res.get()) { *res += *a2; } else { res = a2; } } line.reset(); } if (res.get()) { *res += *a; } else { res = a; } } } if (line.get()) { auto_ptr<Area> a2(make_up(*line, w, halign)); if (a2.get()) { if (res.get()) { *res += *a2; } else { res = a2; }\ } } return res.release();}/* * A copy of the above function, but the formatted text is printed to "os" * rather than into an Area. */static voidformat( const list<auto_ptr<Element> > *elements, Area::size_type indent_left, Area::size_type w, int halign, ostream &os){ if (!elements) return; auto_ptr<Line> line; list<auto_ptr<Element> >::const_iterator i; for (i = elements->begin(); i != elements->end(); ++i) { if (!(*i).get()) continue; auto_ptr<Line> l((*i)->line_format()); if (l.get()) { if (line.get()) { *line += *l; } else { line = l; } continue; } auto_ptr<Area> a((*i)->format(w, halign)); if (a.get()) { if (line.get()) { auto_ptr<Area> a2(make_up(*line, w, halign)); if (a2.get()) { *a2 >>= indent_left; os << *a2 << flush; } line.reset(); } *a >>= indent_left; os << *a << flush; } } if (line.get()) { auto_ptr<Area> a2(make_up(*line, w, halign)); if (a2.get()) { *a2 >>= indent_left; os << *a2 << flush; } }}/* ------------------------------------------------------------------------- */static Properties formatting_properties;/* ----------------------- *//*static*/ voidFormatting::setProperty(const char *key, const char *value){ formatting_properties.setProperty(key, value);}/* ----------------------- *//*static*/ voidFormatting::loadProperties(istream &is){ formatting_properties.load(is);}/* ----------------------- *//*static*/ const char *Formatting::getString(const char *key, const char *dflt){ return formatting_properties.getProperty(key, dflt);}/* ----------------------- *//* * Property not set => 0 * Property contains only white-space => 0 * Property conains one non-white-space character => { "x" } *//*static*/ vector<string> *Formatting::getStringVector(const char *key, const char *dflt){ const char *p = formatting_properties.getProperty(key, dflt); if (!p) return 0; vector<string> *res = 0; for (;;) { while (isspace(*p)) ++p; if (!*p) break; const char *q = p + 1; while (*q && !isspace(*q)) ++q; if (!res) res = new vector<string>; res->push_back(string(p, q - p)); p = q; } return res;}/* ----------------------- *//*static*/ intFormatting::getInt(const char *key, int dflt){ const char *p = formatting_properties.getProperty(key, 0); return p ? atoi(p) : dflt;}/* ----------------------- *//*static*/ vector<int> *Formatting::getIntVector(const char *key, const char *dflt){ const char *p = formatting_properties.getProperty(key, dflt); if (!p) return 0; vector<int> *res = 0; for (;;) { while (isspace(*p)) ++p; if (!*p) break; if (!res) res = new vector<int>; res->push_back(atoi(p)); ++p; while (*p && !isspace(*p)) ++p; } return res;}/* ----------------------- *//*static*/ charFormatting::getAttributes(const char *key, char dflt){ auto_ptr<vector<string> > v(getStringVector(key, 0)); if (!v.get() || v->empty()) return dflt; char res = Cell::NONE; for (vector<string>::const_iterator i = v->begin(); i != v->end(); ++i) { if (!cmp_nocase(*i, "NONE")) res = Cell::NONE; else if (!cmp_nocase(*i, "BOLD")) res |= Cell::BOLD; else if (!cmp_nocase(*i, "UNDERLINE")) res |= Cell::UNDERLINE; else if (!cmp_nocase(*i, "STRIKETHROUGH")) res |= Cell::STRIKETHROUGH; else ; } return res;}/* ------------------------------------------------------------------------- */BlockFormat::BlockFormat( const char *item_name, Area::size_type default_vspace_before /* = 0 */ , Area::size_type default_vspace_after /* = 0 */ , Area::size_type default_indent_left /* = 0 */ , Area::size_type default_indent_right /* = 0 */){ char lb[80]; sprintf(lb, "%s.vspace.before", item_name); vspace_before = Formatting::getInt(lb, default_vspace_before); sprintf(lb, "%s.vspace.after", item_name); vspace_after = Formatting::getInt(lb, default_vspace_after); sprintf(lb, "%s.indent.left", item_name); indent_left = Formatting::getInt(lb, default_indent_left); sprintf(lb, "%s.indent.right", item_name); indent_right = Formatting::getInt(lb, default_indent_right);}Area::size_typeBlockFormat::effective_width(Area::size_type w) const{ /* * No problem if "w" is wide enough... */ if (indent_left + 10 + indent_right <= w) { return w - indent_left - indent_right; } /* * Does reducing the right indent help? */ if (indent_left + 10 <= w) return 10; /* * Do it with right indent == 0. */ if (indent_left + 1 <= w) return w - indent_left; /* * Even that doesn't help, return "1". */ return 1;}/* ------------------------------------------------------------------------- */ListFormat::ListFormat( const char *item_name, Area::size_type default_vspace_before /* = 0 */ , Area::size_type default_vspace_between /* = 0 */ , Area::size_type default_vspace_after /* = 0 */ , const char *default_indents /* = "6" */ , const char *default_default_types /* = "DISC CIRCLE SQUARE" */){ char lb[80]; sprintf(lb, "%s.vspace.before", item_name); vspace_before = Formatting::getInt(lb, default_vspace_before ); sprintf(lb, "%s.vspace.between", item_name); vspace_between = Formatting::getInt(lb, default_vspace_between); sprintf(lb, "%s.vspace.after", item_name); vspace_after = Formatting::getInt(lb, default_vspace_after ); sprintf(lb, "%s.indents", item_name); indents.reset(Formatting::getIntVector(lb, default_indents)); sprintf(lb, "%s.default_types", item_name); default_types.reset(Formatting::getStringVector(lb, default_default_types));}Area::size_typeListFormat::get_indent(int nesting) const{ return ( (!indents.get() || indents.get()->empty()) ? 6 : nesting < indents->size() ? (*indents)[nesting] : indents->back() );}intListFormat::get_type( const list<TagAttribute> *attributes, int nesting, int default_default_type) const{ const char *default_type = ( !default_types.get() || default_types->empty() ? 0 : nesting < default_types->size() ? (*default_types)[nesting].c_str() : default_types->back().c_str() ); return get_attribute( attributes, "TYPE", default_type, // dflt1 default_default_type, // dflt2, if dflt1 fails "NO_BULLET", NO_BULLET, "DISC", DISC, "SQUARE", SQUARE, "CIRCLE", CIRCLE, "CUSTOM1", CUSTOM1, "CUSTOM2", CUSTOM2, "CUSTOM3", CUSTOM3, "1", ARABIC_NUMBERS, "a", LOWER_ALPHA, "A", UPPER_ALPHA, "i", LOWER_ROMAN, "I", UPPER_ROMAN, 0 );}/* ------------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -