diff options
Diffstat (limited to 'texinfo.c')
-rw-r--r-- | texinfo.c | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/texinfo.c b/texinfo.c new file mode 100644 index 0000000..1b464b6 --- /dev/null +++ b/texinfo.c @@ -0,0 +1,465 @@ +/* $Id: texinfo.c,v 1.1 2004-05-03 05:17:48 behdad Exp $ + * functions for texinfo style output. + */ +#include "c2man.h" +#include "manpage.h" +#include "output.h" +#include <ctype.h> + +static char *heading_not_in_contents[] = + {"@chapheading ", "@heading ", "@subheading ", "@subsubheading "}; +static char *heading_in_contents[] = + {"@chapter ", "@section ", "@subsection ", "@subsubsection "}; + +#define n_levels (sizeof(heading_not_in_contents) / sizeof(char *)) + +#define level(n) ((n) >= n_levels ? n_levels - 1 : (n)) + +/* section level for man page entry */ +static int top_level = 1; + +/* always output node for manpage, even if embedded */ +static int embed_node_info = 0; + +/* use title as name of section, rather than "NAME" */ +static int title_name = 0; + +/* the section title, filled in by texinfo_header */ +static const char *title = "INTERNAL ERROR, BOGUS TITLE DUDE!"; + +/* do section titles get capitalized? */ +static int capitalize_sections = 0; + +void texinfo_char(c) +const int c; +{ + int i; + + switch(c) + { + case '\t': + for (i = 0; i < NUM_TAB_SPACES; i++) + putchar(' '); + break; + default: + putchar(c); + break; + } +} + +void texinfo_text(text) +const char *text; +{ + while (*text) + texinfo_char(*text++); +} + +void put_section(text) +const char *text; +{ + + if (capitalize_sections) + { + int first_letter = 1; + + for ( ; *text ; text++) + { + texinfo_char(first_letter ? toupper(*text) : tolower(*text)); + first_letter = isspace(*text); + } + } + else + texinfo_text(text); +} + +void texinfo_comment() { put_string("@c "); } + +void texinfo_header(firstpage, input_files, grouped, name, terse, section) +ManualPage *firstpage; +int input_files; +boolean grouped; +const char *name; +const char *terse; +const char *section; +{ + if (! make_embeddable) + { + put_string("\\input texinfo @c -*-texinfo-*-\n"); + output_warning(); + put_string("@c %**start of header\n"); + put_string("@setfilename "); + texinfo_text(name); + put_string(".info\n@settitle "); + texinfo_text(name); + putchar('\n'); + put_string("@c %**end of header\n"); + + put_string("@node Top, "); + texinfo_text(name); + put_string(", (dir), (dir)\n"); + } + + if (! make_embeddable || embed_node_info) + { + put_string("@node "); + texinfo_text(name); + put_string(", (dir), Top, (dir)\n"); + } + + title = name; +} + +void texinfo_dash() { put_string("---"); } + +void texinfo_section(name) +const char *name; +{ + put_string(heading_not_in_contents[level(top_level)]); + put_section(name); + putchar('\n'); + put_string("@noindent\n"); +} + +void texinfo_section_in_contents(name) +const char *name; +{ + put_string(heading_in_contents[level(top_level)]); + put_section(name); + putchar('\n'); + put_string("@noindent\n"); +} + +void texinfo_sub_section(name) +const char *name; +{ + put_string(heading_not_in_contents[level(top_level+1)]); + put_section(name); + putchar('\n'); + put_string("@noindent\n"); +} + +void texinfo_break_line() { /* put_string("@*\n"); */ } +void texinfo_blank_line() { put_string("@sp 1\n"); } + +void texinfo_code_start() { put_string("@example\n"); } +void texinfo_code_end() { put_string("@end example\n"); } + +void texinfo_code(text) +const char *text; +{ + put_string("@code{"); + texinfo_text(text); + put_string("}"); +} + +void texinfo_tag_list_start() { put_string("@quotation\n@table @code\n"); } +void texinfo_tag_entry_start() { put_string("@item "); } +void texinfo_tag_entry_end() { putchar('\n'); } + +void texinfo_tag_entry_end_extra(text) +const char *text; +{ + putchar('('); + texinfo_text(text); + putchar(')'); + texinfo_tag_entry_end(); +} +void texinfo_tag_list_end() { put_string("@end table\n@end quotation\n"); } + +void texinfo_table_start(longestag) +const char *longestag; +{ put_string("@quotation\n@table @code\n"); } + +void texinfo_table_entry(name, description) +const char *name; +const char *description; +{ + put_string("@item "); + texinfo_text(name); + putchar('\n'); + if (description) + output_comment(description); + else + putchar('\n'); +} + +void texinfo_table_end() { put_string("@end table\n@end quotation\n"); } + +void texinfo_list_start() { } +void texinfo_list_entry(text) +const char *text; +{ + texinfo_code(text); +} +void texinfo_list_separator() { put_string(",\n"); } +void texinfo_list_end() { putchar('\n'); } + +void texinfo_include(filename) +const char *filename; +{ + put_string("@include "); + texinfo_text(filename); + put_string("\n"); +} + +void texinfo_file_end() { put_string("@bye\n"); } + +static first_name = 1; +void texinfo_name(name) +const char *name; +{ + if (name) + { + if (!first_name || !title_name || strcmp(title,name)) + texinfo_text(name); + first_name = 0; + } + else + { + first_name = 1; + if (title_name) + { + /* don't muck around with capitalization of title */ + int capitalize_sections_save = capitalize_sections; + capitalize_sections = 0; + + texinfo_section_in_contents(title); + capitalize_sections = capitalize_sections_save; + } + else + texinfo_section("NAME"); + } +} + +void texinfo_terse_sep() +{ + if (!title_name || group_together) + { + texinfo_char(' '); + texinfo_dash(); + texinfo_char(' '); + } +} + +void texinfo_reference(text) +const char *text; +{ + texinfo_text(text); + texinfo_char('('); + texinfo_text(manual_section); + texinfo_char(')'); +} + +/* ideally, this should be made aware of embedded texinfo commands */ +void texinfo_description(text) +const char *text; +{ + enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE; + boolean new_line = TRUE; + + /* correct punctuation a bit as it goes out */ + for (;*text;text++) + { + int c = *text; + + if (new_line && (c == '-' || c == '*' || is_numbered(text))) + { + output->break_line(); + state = CAPITALISE; + } + else if (c == '.') + state = PERIOD; + else if (isspace(c) && state == PERIOD) + state = CAPITALISE; + else if (isalnum(c)) + { + if (islower(c) && state == CAPITALISE) c = toupper(c); + state = TEXT; + } + + output->character(c); + new_line = c == '\n'; + } + + /* do a full stop if there wasn't one */ + if (state == TEXT) output->character('.'); +} + +/* ideally, this should be made aware of embedded texinfo commands */ +void +texinfo_returns(comment) +const char *comment; +{ + enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE; + char lastchar = '\n'; + boolean tag_list_started = FALSE; + + /* for each line... */ + while (*comment) + { + boolean tagged = FALSE; + + { + const char *c = comment; + + /* search along until the end of a word */ + while (*c && *c != ':' && !isspace(*c)) + c++; + + /* skip all spaces or tabs after the first word */ + while (*c && *c != '\n') + { + if (*c == '\t' || *c == ':') + { + tagged = TRUE; + break; + } + else if (!isspace(*c)) + break; + + c++; + } + } + + /* is it tagged?; explicitly reject dot commands */ + if (tagged) + { + /* output lingering newline if necessary */ + if (lastchar != '\n') + { + if (state == TEXT && !ispunct(lastchar)) output->character('.'); + output->character(lastchar = '\n'); + } + + if (!tag_list_started) + { + output->tag_list_start(); + tag_list_started = TRUE; + } + + /* output the taggy bit */ + output->tag_entry_start(); + while (*comment && *comment != ':' && !isspace(*comment)) + output->character(*comment++); + output->tag_entry_end(); + + /* skip any extra tabs or spaces */ + while (*comment == ':' || (isspace(*comment) && *comment != '\n')) + comment++; + + state = CAPITALISE; + } + + /* terminate the previous line if necessary */ + if (lastchar != '\n') output->character(lastchar = '\n'); + + /* correct punctuation a bit as the line goes out */ + for (;*comment && *comment != '\n'; comment++) + { + char c = *comment; + + if (c == '.') + state = PERIOD; + else if (isspace(c) && state == PERIOD) + state = CAPITALISE; + else if (isalnum(c)) + { + if (islower(c) && state == CAPITALISE && fixup_comments) + c = toupper(c); + state = TEXT; + } + + output->character(lastchar = c); + } + + /* if it ended in punctuation, just output the nl straight away. */ + if (ispunct(lastchar)) + { + if (lastchar == '.') state = CAPITALISE; + output->character(lastchar = '\n'); + } + + if (*comment) comment++; + } + + /* output lingering newline if necessary */ + if (lastchar != '\n') + { + if (state == TEXT && !ispunct(lastchar) && fixup_comments) + output->character('.'); + output->character('\n'); + } + + if (tag_list_started) + output->tag_list_end(); +} + + +int texinfo_parse_option(option) +const char *option; +{ + if (option[0] == 't') + title_name = 1; + else if (option[0] == 'n') + embed_node_info = 1; + else if (option[0] == 's') + { + top_level = atoi(&option[1]); + if (top_level < 0) return 1; + } + else if (option[0] == 'C') + capitalize_sections = 1; + else return 1; + + return 0; +} + +void texinfo_print_options() +{ + fputs("\ttexinfo options:\n", stderr); + fputs("\tt\tuse manpage title as NAME title\n", stderr); + fputs("\tn\toutput node info if embedded output\n", stderr); + fputs("\ts<n>\tset top heading level to <n>\n", stderr); + fputs("\tC\tcaptialize section titles\n", stderr); +} + + +struct Output texinfo_output = +{ + texinfo_comment, + texinfo_header, + texinfo_dash, + texinfo_section, + texinfo_sub_section, + texinfo_break_line, + texinfo_blank_line, + texinfo_code_start, + texinfo_code_end, + texinfo_code, + texinfo_tag_list_start, + texinfo_tag_list_end, + texinfo_tag_entry_start, + texinfo_tag_entry_start, /* entry_start_extra */ + texinfo_tag_entry_end, + texinfo_tag_entry_end_extra, + texinfo_table_start, + texinfo_table_entry, + texinfo_table_end, + dummy, /* texinfo_indent */ + texinfo_list_start, + texinfo_list_entry, + texinfo_list_separator, + texinfo_list_end, + texinfo_include, + texinfo_file_end, + texinfo_text, + texinfo_char, + texinfo_parse_option, + texinfo_print_options, + texinfo_name, + texinfo_terse_sep, + texinfo_reference, + texinfo_text, + texinfo_description, + texinfo_returns +}; |