/* $Id: text-fmt.cc,v 1.13 1997/04/13 04:15:33 dps Exp $ */ /* Everything is declared as static to avoid namespace polution but */ /* is reachable externally via the exported table (and this it the */ /* only way they get called). */ #ifdef __GNUC__ #define alloca __builtin_alloca #else #if HAVE_ALLOCA_H #include #else /* Do not have alloca.h */ #ifdef _AIX #pragma alloca #else /* not _AIX */ extern "C" char *alloca(int); #endif /* _AIX */ #endif /* HAVE_ALLOCA_H */ #endif /* __GNUC__ */ #include #include #include "interface.h" #include "lib.h" #include "text-table.h" /* Local data */ struct text_data { text_table *tabl; int col; int row; int margin; int l_indent; }; /* Most of these values are thanks to catdoc by * Victor B. Wagner et al */ static const cmap char_map[]= { { 0x1E, "-" }, // Unbreakable join { 0x1F, "" }, // Soft hypen { 0x7f, "" }, // Delete 127s { 0x85, "..." }, // Dots { 0x91, "`" }, // 91 = left quote { 0x92, "'" }, // 92 = right quote { 0x93, "\"" }, // 93 = opening double quote { 0x94, "\"" }, // 94 = closing double quote { 0x95, "o" }, // 95 = Bullet { 0x96, "-" }, // em-dash { 0x97, "-" }, // en-dash { 0x99, "(tm)" }, // Trademark { 0xA0, " " }, // Unbreakable space { 0xA3, "<=" }, // Less than or = came out as A3 { 0xA9, "(c)" }, // Copyright { 0xAB, "<<" }, // Openning << quotes { 0xAE, "(R)" }, // Reserved sign { 0xB3, ">=" }, // Greater than or = came out as B3 { 0xBB, ">>" }, // Closing >> quotes }; /* Allocate local data */ static void *allocate_txt(void) { struct text_data *tdata; tdata=new(struct text_data); tdata->tabl=NULL; tdata->margin=0; tdata->l_indent=0; return tdata; } static void txt_code(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { d=d; switch(*(t->data.d)) { case CH_PAGE: if (fmt->flags.new_pages) fputc('\014', out); break; default: break; } } /* Free local data */ static void free_txt(void *d) { struct text_data *tdata; tdata=(struct text_data *) d; if (tdata->tabl!=NULL) delete(tdata->tabl); } /* list start increases margin */ static void inc_margin(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct text_data *tdata; t=t; fmt=fmt; out=out; tdata=(struct text_data *) d; tdata->margin+=4; } /* list start decreases margin */ static void dec_margin(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct text_data *tdata; t=t; fmt=fmt; out=out; tdata=(struct text_data *) d; tdata->margin-=4; } /* items are easy */ static void txt_item(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { tblock *ts; const char *s; int i, m; struct text_data *dp; fmt=fmt; // No need for fmt dp=(struct text_data *) d; ts=map_string(t->data.d, char_map); s=*ts; fputc('\n', out); m=dp->margin-strlen(s)-1; for (i=0; il_indent=dp->margin; delete(ts); } /* Paragraphs are easy */ static void fold_para(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { tblock *b, *ts; const char *s; char *nl; struct text_data *dp; int i; dp=(struct text_data *) d; if (dp->margin==0 || (nl=(char *) alloca(dp->margin+2))==NULL) nl="\n"; else { *nl='\n'; for (i=1; i<=dp->margin; i++) *(nl+i)=' '; *(nl+dp->margin+1)='\0'; } ts=map_string(t->data.d, char_map); b=word_wrap((*ts), nl, nl, fmt->maxline-(dp->margin), 0); delete(ts); s=*b; for (i=dp->l_indent; imargin; i++) fputc(' ', out); fputs(s, out); fputs("\n\n", out); dp->l_indent=0; delete(b); } /* Start a table === allocate table and initialise */ static void alloc_tbl(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct text_data *tdata; out=out; fmt=fmt; tdata=(struct text_data *) d; tdata->col=0; tdata->row=0; tdata->tabl=new(text_table)(t->data.table.cols, t->data.table.rows); } /* End of a table==print the table */ static void format_tbl(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct text_data *tdata; t=t; tdata=(struct text_data *) d; tdata->tabl->print_table(fmt->maxline, out); // Print table delete(tdata->tabl); tdata->tabl=NULL; } /* start row==set column to 0 */ static void start_row(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct text_data *tdata; out=out; fmt=fmt; t=t; tdata=(struct text_data *) d; tdata->col=0; } /* end row==add one to row */ static void inc_row(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct text_data *tdata; out=out; fmt=fmt; t=t; tdata=(struct text_data *) d; tdata->row++; } /* Start field === set field */ static void set_field(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct tblock *ts; struct text_data *tdata; out=out; fmt=fmt; ts=map_string(t->data.d, char_map); tdata=(struct text_data *) d; tdata->tabl->set(tdata->col, tdata->row, (*ts)); delete(ts); } /* end field==add one to col */ static void inc_col(const tok_seq::tok *t, const docfmt *fmt, FILE *out, void *d) { struct text_data *tdata; out=out; fmt=fmt; t=t; tdata=(struct text_data *) d; tdata->col++; } /* pointers to the functions that do the work */ docfmt txtfmt= { { 0 }, // No page breaks 76, // Width "\n", // Use \n as line ends allocate_txt, // Allocate space free_txt, // Free text { { null_proc, null_proc }, // End and start of document---do nothing { fold_para, null_proc }, // Paragraph { alloc_tbl, format_tbl }, // Start/end table { set_field, inc_col }, // Start/end field { start_row, inc_row }, // Start/end row { null_proc, null_proc }, // Throw away embed messages { inc_margin, dec_margin }, // list start and end { txt_item, null_proc}, // Items { txt_code, null_proc}, // Code { null_proc, null_proc } // Do not understanding anything else } };