/* text.c -- Text output Copyright (c) 1993-1999 Eberhard Mattes This file is part of emxdoc. emxdoc is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. emxdoc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with emxdoc; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "emxdoc.h" #include "text.h" #include "lb.h" static int text_width = 70; static int format_width; static int format_margin; static struct lb *lb; static struct lbh *lbh = NULL; static void text_indent (int margin) { uchar *s; int i; i = margin - output_x; if (i > 0) { s = alloca (i); memset (s, ' ', i); write_nstring (s, i); } } static void text_para (void) { if (para_flag) { para_flag = FALSE; write_nl (); } } static int isblank (const uchar *p) { while (*p != 0) if (*p++ != ' ') return FALSE; return TRUE; } void text_output (const uchar *p, int may_break) { if (opt_b == 0) { if (may_break && output_x + strlen (p) > format_width) write_nl (); text_indent (format_margin); write_string (p); } else { int rc; if (may_break && isblank (p)) rc = lb_glue (lb, strlen (p), NULL); else rc = lb_word (lb, strlen (p), p, NULL); if (rc != 0) fatal ("lb_glue or lb_word failed, rc=%d", rc); } } static int text_elements (int margin, int width, int newline) { const struct element *ep, *ep2; int i, spaces, line, rc; enum style style_stack[STYLE_STACK_SIZE]; int style_sp; enum style style = STYLE_NORMAL; style_sp = 0; style_stack[style_sp] = style; line = output_line_no; spaces = 0; format_width = width; format_margin = margin; if (opt_b != 0) { rc = lb_init (&lb, margin, width); if (rc != 0) fatal ("lb_init failed, rc=%d", rc); if (output_x > margin) lb_first_lmargin (lb, output_x); } for (ep = elements; ep->el != EL_END; ++ep) switch (ep->el) { case EL_WORD: case EL_PUNCT: if (spaces != 0) { format_spaces (spaces, STYLE_NORMAL, TRUE); spaces = 0; } if (ep->wp->special != NULL && ep->wp->special->text != NULL) format_output (ep->wp->special->text, FALSE); else if (style_sp == 0 || style_stack[style_sp] == STYLE_NORMAL) format_string (ep->wp->str, (ep->wp->style != STYLE_NORMAL ? ep->wp->style : style), FALSE); else format_string (ep->wp->str, style_stack[style_sp], FALSE); break; case EL_SPACE: if (opt_b == 0) { spaces += ep->n; i = 0; ep2 = ep + 1; while (ep2->el != EL_END && ep2->el != EL_SPACE) { if (ep2->el == EL_WORD || ep2->el == EL_PUNCT) i += strlen (ep2->wp->str); ++ep2; } if (output_x + spaces + i > format_width) { write_nl (); spaces = 0; } } else format_spaces (ep->n, STYLE_NORMAL, TRUE); break; case EL_BREAK: if (opt_b == 0) { if (output_x != 0 || ep->n) { write_nl (); spaces = 0; } } else lb_penalty (lb, -10000); break; case EL_STYLE: if (style_sp + 1 >= STYLE_STACK_SIZE) fatal ("%s:%d: Style stack overflow", input_fname, line_no); style_stack[++style_sp] = ep->n; break; case EL_ENDSTYLE: if (style_sp == 0) fatal ("%s:%d: Style stack underflow", input_fname, line_no); --style_sp; break; default: abort (); } if (opt_b != 0) { struct lb_node lbn; if (lbh != NULL) lb_use_hyphenation (lb, lbh); rc = lb_format (lb); if (rc != 0) fatal ("lb_format failed, rc=%d", rc); for (;;) { rc = lb_next (lb, &lbn); if (rc != 0) fatal ("lb_next failed, rc=%d", rc); if (lbn.type == LBN_END) break; switch (lbn.type) { case LBN_WORD: case LBN_PRE: case LBN_POST: text_indent (margin); write_string (lbn.word); break; case LBN_GLUE: text_indent (margin); write_fmt ("%*s", lbn.value, ""); break; case LBN_NEWLINE: write_nl (); break; default: abort (); } } lb_exit (&lb); } if (newline && output_x > margin) write_nl (); return output_line_no - line; } void text_heading1 (void) { env_stack[0].tmargin = 0; write_nl (); write_nl (); } void text_heading2 (uchar *s) { if (tg_level == 0) { if (para_flag) write_nl (); write_nl (); } write_line (s); memset (s, tg_underline, strlen (s)); write_line (s); } void text_see_also_start (void) { if (para_flag) write_nl (); } void text_see_also_end (const uchar *s) { write_string (" See also: "); make_elements (s); text_elements (output_x, text_width, TRUE); } void text_description_item (const uchar *s) { write_nl (); text_para (); make_elements (s); text_elements (env_stack[env_sp-1].tmargin, text_width, FALSE); if (output_x + 2 <= env_stack[env_sp].tmargin) write_string (" "); else write_nl (); } void text_enumerate_item (void) { write_nl (); text_para (); text_indent (env_stack[env_sp-1].tmargin); write_fmt ("%d.", ++env_stack[env_sp].counter); } void text_itemize_item (void) { write_nl (); text_para (); text_indent (env_stack[env_sp-1].tmargin); write_string ("- "); } void text_list_item (const uchar *s) { write_nl (); text_para (); make_elements (s); text_elements (env_stack[env_sp-1].tmargin, text_width, TRUE); write_nl (); } void text_copy (void) { if (para_flag) write_nl (); text_elements (env_stack[env_sp].tmargin, text_width, TRUE); } void text_verbatim_start (enum tag tag_end, int *ptmargin) { switch (tag_end) { case TAG_ENDHEADERS: break; case TAG_ENDSAMPLECODE: write_nl (); write_line (" Example:"); write_nl (); break; case TAG_ENDEXAMPLE: *ptmargin += 4; write_nl (); break; default: write_nl (); break; } } static void add_compat (uchar *dst, uchar *compat) { int i, len; len = strlen (dst); i = 78 - len - strlen (compat) - 2; if (i > 0) { memset (dst + len, ' ', i); len += i; } dst[len++] = '['; strcpy (dst+len, compat); strcat (dst+len, "]"); compat[0] = 0; } void text_verbatim_line (enum tag tag_end, int tmargin, uchar *compat) { uchar buf[512]; memset (buf, ' ', tmargin); strcpy (buf + tmargin, input); if (tag_end == TAG_ENDHEADERS && compat[0] != 0) add_compat (buf, compat); write_line (buf); } void text_function (void) { env_stack[0].tmargin = 0; write_nl (); write_line("---------------------------------------" "---------------------------------------"); } void text_prototype_start (uchar *compat) { uchar buf[512]; if (compat[0] != 0) { buf[0] = 0; add_compat (buf, compat); write_string (buf); } write_nl (); } void text_prototype_end (void) { text_elements (0, 78, TRUE); env_stack[0].tmargin = 4; } void text_toc_line (const uchar *s, const struct toc *tp) { write_string (s); write_line (tp->title); } void text_table_start (int do_indent, int *ptmargin) { if (do_indent) *ptmargin += 4; write_nl (); } void text_table_line (const uchar *s, int tmargin) { make_elements (s); if (text_elements (tmargin, 78, TRUE) > 1) fatal ("%s:%d: Table entry too long", input_fname, line_no); } void text_sample_file (const uchar *s) { if (para_flag) write_nl (); write_string (" Example: See "); write_line (s); } void text_libref_section (const uchar *s) { if (para_flag) write_nl (); write_fmt (" %s:", s); write_nl (); para_flag = TRUE; } void text_hyphenation (const char *name) { FILE *f; char line[128], *p; int line_no, rc; if (opt_b == 0) return; rc = lbh_init (&lbh); if (rc != 0) fatal ("lb_init failed, rc=%d", rc); f = fopen (name, "rt"); if (f == NULL) { perror (name); exit (1); } line_no = 0; while (fgets (line, sizeof (line), f) != NULL) { ++line_no; p = strchr (line, '\n'); if (p == NULL) fatal ("%s:%d: Line too long", name, line_no); *p = 0; rc = lbh_word (lbh, line); if (rc != 0) fatal ("lbh_word failed, rc=%d", rc); } if (ferror (f)) { perror (name); exit (1); } fclose (f); }