diff options
Diffstat (limited to 'gnu/dist/groff/src/devices/grohtml/post-html.cpp')
| -rw-r--r-- | gnu/dist/groff/src/devices/grohtml/post-html.cpp | 444 |
1 files changed, 353 insertions, 91 deletions
diff --git a/gnu/dist/groff/src/devices/grohtml/post-html.cpp b/gnu/dist/groff/src/devices/grohtml/post-html.cpp index 6724e12569d..d1bd7c99df3 100644 --- a/gnu/dist/groff/src/devices/grohtml/post-html.cpp +++ b/gnu/dist/groff/src/devices/grohtml/post-html.cpp @@ -1,7 +1,7 @@ -/* $NetBSD: post-html.cpp,v 1.1.1.1 2003/06/30 17:52:16 wiz Exp $ */ +/* $NetBSD: post-html.cpp,v 1.1.1.2 2004/07/30 14:45:05 wiz Exp $ */ // -*- C++ -*- -/* Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. * * Gaius Mulley (gaius@glam.ac.uk) wrote post-html.cpp * but it owes a huge amount of ideas and raw code from @@ -80,6 +80,11 @@ static int simple_anchors = FALSE; /* default to anchors with static int manufacture_headings = FALSE; /* default is to use the Hn html headings, */ /* rather than manufacture our own. */ static color *default_background = NULL; /* has user requested initial bg color? */ +static string job_name; /* if set then the output is split into */ + /* multiple files with `job_name'-%d.html */ +static int multiple_files = FALSE; /* must we the output be divided into */ + /* multiple html files, one for each */ + /* heading? */ /* @@ -130,6 +135,9 @@ static int is_digit (char ch) struct file { FILE *fp; file *next; + int new_output_file; + int require_links; + string output_file_name; file (FILE *f); }; @@ -139,21 +147,28 @@ struct file { */ file::file (FILE *f) - : fp(f), next(0) + : fp(f), next(0), new_output_file(FALSE), + require_links(FALSE), output_file_name("") { } class files { public: - files (); - FILE *get_file (void); - void start_of_list (void); - void move_next (void); - void add_new_file (FILE *f); + files (); + FILE *get_file (void); + void start_of_list (void); + void move_next (void); + void add_new_file (FILE *f); + void set_file_name (string name); + void set_links_required (void); + int are_links_required (void); + int is_new_output_file (void); + string file_name (void); + string next_file_name (void); private: - file *head; - file *tail; - file *ptr; + file *head; + file *tail; + file *ptr; }; /* @@ -171,11 +186,10 @@ files::files () FILE *files::get_file (void) { - if (ptr) { - return( ptr->fp ); - } else { - return( 0 ); - } + if (ptr) + return ptr->fp; + else + return 0; } /* @@ -214,6 +228,76 @@ void files::add_new_file (FILE *f) } /* + * set_file_name - sets the final file name to contain the html + * data to name. + */ + +void files::set_file_name (string name) +{ + if (ptr != NULL) { + ptr->output_file_name = name; + ptr->new_output_file = TRUE; + } +} + +/* + * set_links_required - issue links when processing this component + * of the file. + */ + +void files::set_links_required (void) +{ + if (ptr != NULL) + ptr->require_links = TRUE; +} + +/* + * are_links_required - returns TRUE if this section of the file + * requires that links should be issued. + */ + +int files::are_links_required (void) +{ + if (ptr != NULL) + return ptr->require_links; + return FALSE; +} + +/* + * is_new_output_file - returns TRUE if this component of the file + * is the start of a new output file. + */ + +int files::is_new_output_file (void) +{ + if (ptr != NULL) + return ptr->new_output_file; + return FALSE; +} + +/* + * file_name - returns the name of the file. + */ + +string files::file_name (void) +{ + if (ptr != NULL) + return ptr->output_file_name; + return string(""); +} + +/* + * next_file_name - returns the name of the next file. + */ + +string files::next_file_name (void) +{ + if (ptr != NULL && ptr->next != NULL) + return ptr->next->output_file_name; + return string(""); +} + +/* * the class and methods for styles */ @@ -425,11 +509,11 @@ text_glob::text_glob (style *s, const char *str, int length, int max_vertical, int max_horizontal, bool is_troff_command, bool is_auto_image, bool is_special_command, - bool is_a_line, int line_thickness) + bool is_a_line_flag, int line_thickness) : text_style(*s), text_string(str), text_length(length), minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal), is_tag(is_troff_command), is_img_auto(is_auto_image), is_special(is_special_command), - is_line(is_a_line), thickness(line_thickness), tab(NULL) + is_line(is_a_line_flag), thickness(line_thickness), tab(NULL) { } @@ -485,11 +569,11 @@ void text_glob::text_glob_special (style *s, char *str, int length, void text_glob::text_glob_line (style *s, int min_vertical , int min_horizontal, int max_vertical , int max_horizontal, - int thickness) + int thickness_value) { text_glob *g = new text_glob(s, "", 0, min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, FALSE, TRUE, thickness); + FALSE, FALSE, FALSE, TRUE, thickness_value); *this = *g; delete g; } @@ -1204,15 +1288,18 @@ void page::add_tag (style *s, const string &str, void page::add_line (style *s, int line_number, - int x1, int y1, int x2, int y2, + int x_1, int y_1, int x_2, int y_2, int thickness) { - if (y1 == y2) { + if (y_1 == y_2) { text_glob *g = new text_glob(); g->text_glob_line(s, - min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2), + min(y_1, y_2), min(x_1, x_2), + max(y_1, y_2), max(x_1, x_2), thickness); - glyphs.add(g, line_number, min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2)); + glyphs.add(g, line_number, + min(y_1, y_2), min(x_1, x_2), + max(y_1, y_2), max(x_1, x_2)); } } @@ -1269,10 +1356,10 @@ void page::add_and_encode (style *s, const string &str, if (html_glyph) html_string += html_glyph; else { - int index=s->f->name_to_index((troff_charname + '\0').contents()); + int idx=s->f->name_to_index((troff_charname + '\0').contents()); - if (s->f->contains(index) && (index != 0)) - html_string += s->f->get_code(index); + if (s->f->contains(idx) && (idx != 0)) + html_string += s->f->get_code(idx); } } } else @@ -1382,18 +1469,21 @@ public: header_desc (); ~header_desc (); - int no_of_headings; // how many headings have we found? - char_buffer headings; // all the headings used in the document - list headers; // list of headers built from .NH and .SH - int header_level; // current header level - int written_header; // have we written the header yet? - string header_buffer; // current header text + int no_of_level_one_headings; // how many .SH or .NH 1 have we found? + int no_of_headings; // how many headings have we found? + char_buffer headings; // all the headings used in the document + list headers; // list of headers built from .NH and .SH + list header_filename; // in which file is this header? + int header_level; // current header level + int written_header; // have we written the header yet? + string header_buffer; // current header text void write_headings (FILE *f, int force); }; header_desc::header_desc () - : no_of_headings(0), header_level(2), written_header(0) + : no_of_level_one_headings(0), no_of_headings(0), + header_level(2), written_header(0) { } @@ -1414,9 +1504,15 @@ void header_desc::write_headings (FILE *f, int force) int h=1; headers.start_from_head(); + header_filename.start_from_head(); do { g = headers.get_data(); - fputs("<a href=\"#", f); + fputs("<a href=\"", f); + if (multiple_files && (! header_filename.is_empty())) { + text_glob *fn = header_filename.get_data(); + fputs(fn->text_string, f); + } + fputs("#", f); if (simple_anchors) { string buffer(ANCHOR_TEMPLATE); @@ -1430,6 +1526,8 @@ void header_desc::write_headings (FILE *f, int force) fputs(g->text_string, f); fputs("</a><br>\n", f); headers.move_right(); + if (multiple_files && (! header_filename.is_empty())) + header_filename.move_right(); } while (! headers.is_equal_to_head()); fputs("\n", f); } @@ -1535,6 +1633,8 @@ class html_printer : public printer { void do_auto_image (text_glob *g, const char *filename); void do_links (void); void do_flush (void); + void do_job_name (char *name); + void insert_split_file (void); int is_in_middle (int left, int right); void do_sup_or_sub (text_glob *g); int start_subscript (text_glob *g); @@ -1565,6 +1665,10 @@ class html_printer : public printer { void remove_courier_tabs (void); void update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g); void add_table_end (const char *); + void do_file_components (void); + void write_navigation (const string &top, const string &prev, + const string &next, const string ¤t); + void emit_link (const string &to, const char *name); // ADD HERE public: @@ -1939,6 +2043,22 @@ void html_printer::write_header (void) html.put_string(">").nl(); } + /* and now we save the file name in which this header will occur */ + + style st; // fake style to enable us to use the list data structure + + text_glob *h=new text_glob(); + h->text_glob_html(&st, + header.headings.add_string(file_list.file_name()), + file_list.file_name().length(), + header.no_of_headings, header.header_level, + header.no_of_headings, header.header_level); + + header.header_filename.add(h, + header.no_of_headings, + header.no_of_headings, header.no_of_headings, + header.no_of_headings, header.no_of_headings); + current_paragraph->do_para(&html, "", indentation, pageoffset, linelength); } } @@ -1957,6 +2077,10 @@ void html_printer::determine_header_level (int level) } } header.header_level = level+1; + if (header.header_level == 2) { + header.no_of_level_one_headings++; + insert_split_file(); + } } /* @@ -1987,7 +2111,7 @@ void html_printer::do_heading (char *arg) } } else if (! (g->is_a_line() || g->is_a_tag())) { /* - * we ignore tags commands when constructing a heading + * we ignore tag commands when constructing a heading */ if (l != 0) header.header_buffer += " "; @@ -2210,10 +2334,48 @@ void html_printer::do_links (void) current_paragraph->done_para(); auto_links = FALSE; /* from now on only emit under user request */ file_list.add_new_file(xtmpfile()); + file_list.set_links_required(); html.set_file(file_list.get_file()); } /* + * insert_split_file - + */ + +void html_printer::insert_split_file (void) +{ + if (multiple_files) { + current_paragraph->done_para(); // flush paragraph + html.end_line(); // flush line + html.set_file(file_list.get_file()); // flush current file + file_list.add_new_file(xtmpfile()); + string split_file = job_name; + + split_file += string("-"); + split_file += as_string(header.no_of_level_one_headings); + split_file += string(".html"); + split_file += '\0'; + + file_list.set_file_name(split_file); + html.set_file(file_list.get_file()); + } +} + +/* + * do_job_name - assigns the job_name to name. + */ + +void html_printer::do_job_name (char *name) +{ + if (! multiple_files) { + multiple_files = TRUE; + while (name != NULL && (*name != (char)0) && (*name == ' ')) + name++; + job_name = name; + } +} + +/* * do_break - handles the ".br" request and also * undoes an outstanding ".ti" command. */ @@ -2391,6 +2553,9 @@ void html_printer::troff_tag (text_glob *g) do_pointsize(a); } else if (strcmp(t, ".links") == 0) { do_links(); + } else if (strncmp(t, ".job-name", 9) == 0) { + char *a = (char *)t+9; + do_job_name(a); } else if (strcmp(t, ".no-auto-rule") == 0) { auto_rule = FALSE; } else if (strcmp(t, ".tab-ts") == 0) { @@ -2723,9 +2888,9 @@ void html_printer::lookahead_for_tables (void) int found_col = FALSE; int seen_text = FALSE; int ncol = 0; - int colmin; - int colmax; - html_table *table = new html_table(&html, -1); + int colmin = 0; // pacify compiler + int colmax = 0; // pacify compiler + html_table *tbl = new html_table(&html, -1); const char *tab_defs = NULL; char align = 'L'; int nf = FALSE; @@ -2754,11 +2919,11 @@ void html_printer::lookahead_for_tables (void) if (type_of_col == tab_tag && start_of_table != NULL) { page_contents->glyphs.move_left(); insert_tab_te(); - start_of_table->remember_table(table); - table = new html_table(&html, -1); + start_of_table->remember_table(tbl); + tbl = new html_table(&html, -1); page_contents->insert_tag(string("*** TAB -> COL ***")); if (tab_defs != NULL) - table->tab_stops->init(tab_defs); + tbl->tab_stops->init(tab_defs); start_of_table = NULL; last = NULL; } @@ -2772,28 +2937,28 @@ void html_printer::lookahead_for_tables (void) type_of_col = tab_tag; colmin = g->get_tab_args(&align); align = 'L'; // for now as 'C' and 'R' are broken - ncol = table->find_tab_column(colmin); + ncol = tbl->find_tab_column(colmin); colmin += pageoffset + indentation; - colmax = table->get_tab_pos(ncol+1); + colmax = tbl->get_tab_pos(ncol+1); if (colmax > 0) colmax += pageoffset + indentation; } else if (g->is_tab0()) { if (type_of_col == col_tag && start_of_table != NULL) { page_contents->glyphs.move_left(); insert_tab_te(); - start_of_table->remember_table(table); - table = new html_table(&html, -1); + start_of_table->remember_table(tbl); + tbl = new html_table(&html, -1); page_contents->insert_tag(string("*** COL -> TAB ***")); start_of_table = NULL; last = NULL; } if (tab_defs != NULL) - table->tab_stops->init(tab_defs); + tbl->tab_stops->init(tab_defs); type_of_col = tab0_tag; ncol = 1; colmin = 0; - colmax = table->get_tab_pos(2) + pageoffset + indentation; + colmax = tbl->get_tab_pos(2) + pageoffset + indentation; } else if (! g->is_a_tag()) update_min_max(type_of_col, &colmin, &colmax, g); @@ -2807,34 +2972,34 @@ void html_printer::lookahead_for_tables (void) seen_text = FALSE; } else if (g->is_ce() && (start_of_table != NULL)) { add_table_end("*** CE ***"); - start_of_table->remember_table(table); + start_of_table->remember_table(tbl); start_of_table = NULL; last = NULL; } else if (g->is_ta()) { tab_defs = g->text_string; - if (!table->tab_stops->compatible(tab_defs)) { + if (!tbl->tab_stops->compatible(tab_defs)) { if (start_of_table != NULL) { add_table_end("*** TABS ***"); - start_of_table->remember_table(table); - table = new html_table(&html, -1); + start_of_table->remember_table(tbl); + tbl = new html_table(&html, -1); start_of_table = NULL; type_of_col = none; last = NULL; } - table->tab_stops->init(tab_defs); + tbl->tab_stops->init(tab_defs); } } if (((! g->is_a_tag()) || g->is_tab()) && (start_of_table != NULL)) { // we are in a table and have a glyph - if ((ncol == 0) || (! table->add_column(ncol, colmin, colmax, align))) { + if ((ncol == 0) || (! tbl->add_column(ncol, colmin, colmax, align))) { if (ncol == 0) add_table_end("*** NCOL == 0 ***"); else add_table_end("*** CROSSED COLS ***"); - start_of_table->remember_table(table); - table = new html_table(&html, -1); + start_of_table->remember_table(tbl); + tbl = new html_table(&html, -1); start_of_table = NULL; type_of_col = none; last = NULL; @@ -2878,13 +3043,13 @@ void html_printer::lookahead_for_tables (void) page_contents->glyphs.move_left(); insert_tab_te(); - start_of_table->remember_table(table); - table = NULL; + start_of_table->remember_table(tbl); + tbl = NULL; page_contents->insert_tag(string("*** LAST ***")); } } - if (table != NULL) - delete table; + if (tbl != NULL) + delete tbl; // and reset the registers pageoffset = old_pageoffset; @@ -3338,17 +3503,17 @@ html_printer::html_printer() * add_to_sbuf - adds character code or name to the sbuf. */ -void html_printer::add_to_sbuf (int index, const string &s) +void html_printer::add_to_sbuf (int idx, const string &s) { if (sbuf_style.f == NULL) return; char *html_glyph = NULL; - unsigned int code = sbuf_style.f->get_code(index); + unsigned int code = sbuf_style.f->get_code(idx); if (s.empty()) { - if (sbuf_style.f->contains(index)) - html_glyph = (char *)sbuf_style.f->get_special_device_encoding(index); + if (sbuf_style.f->contains(idx)) + html_glyph = (char *)sbuf_style.f->get_special_device_encoding(idx); else html_glyph = NULL; @@ -3364,7 +3529,7 @@ void html_printer::add_to_sbuf (int index, const string &s) sbuf += html_glyph; } -int html_printer::sbuf_continuation (int index, const char *name, +int html_printer::sbuf_continuation (int idx, const char *name, const environment *env, int w) { /* @@ -3374,7 +3539,7 @@ int html_printer::sbuf_continuation (int index, const char *name, || ((sbuf_prev_hpos < sbuf_end_hpos) && (env->hpos < sbuf_end_hpos) && ((sbuf_end_hpos-env->hpos < env->hpos-sbuf_prev_hpos)))) { - add_to_sbuf(index, name); + add_to_sbuf(idx, name); sbuf_prev_hpos = sbuf_end_hpos; sbuf_end_hpos += w + sbuf_kern; return TRUE; @@ -3386,7 +3551,7 @@ int html_printer::sbuf_continuation (int index, const char *name, */ if (env->hpos-sbuf_end_hpos < space_width) { - add_to_sbuf(index, name); + add_to_sbuf(idx, name); sbuf_prev_hpos = sbuf_end_hpos; sbuf_end_hpos = env->hpos + w; return TRUE; @@ -3403,18 +3568,18 @@ int html_printer::sbuf_continuation (int index, const char *name, char *get_html_translation (font *f, const string &name) { - int index; + int idx; if ((f == 0) || name.empty()) return NULL; else { - index = f->name_to_index((char *)(name + '\0').contents()); - if (index == 0) { + idx = f->name_to_index((char *)(name + '\0').contents()); + if (idx == 0) { error("character `%s' not found", (name + '\0').contents()); return NULL; } else - if (f->contains(index)) - return (char *)f->get_special_device_encoding(index); + if (f->contains(idx)) + return (char *)f->get_special_device_encoding(idx); else return NULL; } @@ -3427,7 +3592,7 @@ char *get_html_translation (font *f, const string &name) * is flushed. */ -int html_printer::overstrike(int index, const char *name, const environment *env, int w) +int html_printer::overstrike(int idx, const char *name, const environment *env, int w) { if ((env->hpos < sbuf_end_hpos) || ((sbuf_kern != 0) && (sbuf_end_hpos - sbuf_kern < env->hpos))) { @@ -3437,7 +3602,7 @@ int html_printer::overstrike(int index, const char *name, const environment *env if (overstrike_detected) { /* already detected, remove previous glyph and use this glyph */ sbuf.set_length(last_sbuf_length); - add_to_sbuf(index, name); + add_to_sbuf(idx, name); sbuf_end_hpos = env->hpos + w; return TRUE; } else { @@ -3446,7 +3611,7 @@ int html_printer::overstrike(int index, const char *name, const environment *env if (! is_bold(sbuf_style.f)) flush_sbuf(); overstrike_detected = TRUE; - add_to_sbuf(index, name); + add_to_sbuf(idx, name); sbuf_end_hpos = env->hpos + w; return TRUE; } @@ -3608,6 +3773,105 @@ void html_printer::do_body (void) } } +/* + * emit_link - generates: <a href="to">name</a> + */ + +void html_printer::emit_link (const string &to, const char *name) +{ + fputs("<a href=\"", stdout); + fputs(to.contents(), stdout); + fputs("\">", stdout); + fputs(name, stdout); + fputs("</a>", stdout); +} + +/* + * write_navigation - writes out the links which navigate between + * file fragments. + */ + +void html_printer::write_navigation (const string &top, const string &prev, + const string &next, const string ¤t) +{ + int need_bar = FALSE; + + if (multiple_files) { + write_rule(); + fputs("[ ", stdout); + if (prev != "" && prev != top) { + emit_link(prev, "prev"); + need_bar = TRUE; + } + if (next != "" && next != top) { + if (need_bar) + fputs(" | ", stdout); + emit_link(next, "next"); + need_bar = TRUE; + } + if (top != "<standard input>" && top != "" && top != current) { + if (need_bar) + fputs(" | ", stdout); + emit_link(top, "top"); + fputs(" ]\n", stdout); + } + write_rule(); + } +} + +/* + * do_file_components - scan the file list copying each temporary file in turn. + * This is used twofold: + * + * firstly to emit section heading links, between file fragments if required + * and secondly to generate jobname file fragments if required. + */ + +void html_printer::do_file_components (void) +{ + int fragment_no = 1; + string top; + string prev; + string next; + string current; + + file_list.start_of_list(); + top = string(job_name); + top += string(".html"); + top += '\0'; + next = file_list.next_file_name(); + next += '\0'; + current = next; + while (file_list.get_file() != 0) { + if (fseek(file_list.get_file(), 0L, 0) < 0) + fatal("fseek on temporary file failed"); + html.copy_file(file_list.get_file()); + fclose(file_list.get_file()); + + file_list.move_next(); + if (file_list.is_new_output_file()) { + if (fragment_no > 1) + write_navigation(top, prev, next, current); + prev = current; + current = next; + next = file_list.next_file_name(); + next += '\0'; + string split_file = file_list.file_name(); + split_file += '\0'; + fflush(stdout); + freopen(split_file.contents(), "w", stdout); + fragment_no++; + write_navigation(top, prev, next, current); + } + if (file_list.are_links_required()) + header.write_headings(stdout, TRUE); + } + if (fragment_no > 1) + write_navigation(top, prev, next, current); + else + write_rule(); +} + html_printer::~html_printer() { #ifdef LONG_FOR_TIME_T @@ -3652,22 +3916,16 @@ html_printer::~html_printer() #endif html.end_line(); html.end_line(); - /* - * now run through the file list copying each temporary file in turn and emitting the links. - */ - file_list.start_of_list(); - while (file_list.get_file() != 0) { - if (fseek(file_list.get_file(), 0L, 0) < 0) - fatal("fseek on temporary file failed"); - html.copy_file(file_list.get_file()); - fclose(file_list.get_file()); - file_list.move_next(); - if (file_list.get_file() != 0) - header.write_headings(stdout, TRUE); + + if (multiple_files) { + fputs("</body>\n", stdout); + fputs("</html>\n", stdout); + do_file_components(); + } else { + do_file_components(); + fputs("</body>\n", stdout); + fputs("</html>\n", stdout); } - write_rule(); - fputs("</body>\n", stdout); - fputs("</html>\n", stdout); } /* @@ -3735,7 +3993,7 @@ int main(int argc, char **argv) { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, "a:g:o:i:I:D:F:vbdhlrnp", long_options, NULL)) + while ((c = getopt_long(argc, argv, "a:g:o:i:I:j:D:F:vbdhlrnp", long_options, NULL)) != EOF) switch(c) { case 'v': @@ -3756,6 +4014,10 @@ int main(int argc, char **argv) case 'F': font::command_line_font_dir(optarg); break; + case 'j': + multiple_files = TRUE; + job_name = optarg; + break; case 'l': auto_links = FALSE; break; |
