1 /* $Id: text-fmt.cc,v 1.13 1997/04/13 04:15:33 dps Exp $ */
2 
3 /* Everything is declared as static to avoid namespace polution but */
4 /* is reachable externally via the exported table (and this it the  */
5 /* only way they get called).					    */
6 #ifdef __GNUC__
7 #define alloca __builtin_alloca
8 #else
9 #if HAVE_ALLOCA_H
10 #include <alloca.h>
11 #else /* Do not have alloca.h */
12  #ifdef _AIX
13 #pragma alloca
14 #else /* not _AIX */
15 extern "C" char *alloca(int);
16 #endif /* _AIX */
17 #endif /* HAVE_ALLOCA_H */
18 #endif /* __GNUC__ */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "interface.h"
23 #include "lib.h"
24 #include "text-table.h"
25 
26 /* Local data */
27 struct text_data
28 {
29     text_table *tabl;
30     int col;
31     int row;
32     int margin;
33     int l_indent;
34 };
35 
36 /* Most of these values are thanks to catdoc by
37  * Victor B. Wagner <vitus@agropc.msk.su> et al */
38 static const cmap char_map[]=
39 {
40     { 0x1E, "-" },      // Unbreakable join
41     { 0x1F, "" },	// Soft hypen
42     { 0x7f, "" },	// Delete 127s
43     { 0x85, "..." },    // Dots
44     { 0x91, "`" },      // 91 = left quote
45     { 0x92, "'" },      // 92 = right quote
46     { 0x93, "\"" },     // 93 = opening double quote
47     { 0x94, "\"" },     // 94 = closing double quote
48     { 0x95, "o" },	// 95 = Bullet
49     { 0x96, "-" },      // em-dash
50     { 0x97, "-" },      // en-dash
51     { 0x99, "(tm)" },   // Trademark
52     { 0xA0, " " },      // Unbreakable space
53     { 0xA3, "<=" },	// Less than or = came out as A3
54     { 0xA9, "(c)" },    // Copyright
55     { 0xAB, "<<" },     // Openning << quotes
56     { 0xAE, "(R)" },    // Reserved sign
57     { 0xB3, ">=" },	// Greater than or = came out as B3
58     { 0xBB, ">>" },	// Closing >> quotes
59 };
60 
61 /* Allocate local data */
allocate_txt(void)62 static void *allocate_txt(void)
63 {
64     struct text_data *tdata;
65 
66     tdata=new(struct text_data);
67     tdata->tabl=NULL;
68     tdata->margin=0;
69     tdata->l_indent=0;
70     return tdata;
71 }
72 
txt_code(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)73 static void txt_code(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
74 		     void *d)
75 {
76     d=d;
77     switch(*(t->data.d))
78     {
79     case CH_PAGE:
80 	if (fmt->flags.new_pages)
81 	    fputc('\014', out);
82 	break;
83 
84     default:
85 	break;
86     }
87 }
88 
89 /* Free local data */
free_txt(void * d)90 static void free_txt(void *d)
91 {
92     struct text_data *tdata;
93 
94     tdata=(struct text_data *) d;
95     if (tdata->tabl!=NULL)
96 	delete(tdata->tabl);
97 }
98 
99 
100 /* list start increases margin */
inc_margin(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)101 static void inc_margin(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
102 		      void *d)
103 {
104     struct text_data *tdata;
105     t=t;
106     fmt=fmt;
107     out=out;
108 
109     tdata=(struct text_data *) d;
110     tdata->margin+=4;
111 }
112 
113 
114 /* list start decreases margin */
dec_margin(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)115 static void dec_margin(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
116 		      void *d)
117 {
118     struct text_data *tdata;
119     t=t;
120     fmt=fmt;
121     out=out;
122 
123     tdata=(struct text_data *) d;
124     tdata->margin-=4;
125 }
126 
127 
128 /* items are easy */
txt_item(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)129 static void txt_item(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
130 		      void *d)
131 {
132     tblock *ts;
133     const char *s;
134     int i, m;
135     struct text_data *dp;
136 
137     fmt=fmt;			// No need for fmt
138     dp=(struct text_data *) d;
139     ts=map_string(t->data.d, char_map);
140     s=*ts;
141     fputc('\n', out);
142     m=dp->margin-strlen(s)-1;
143     for (i=0; i<m; i++)
144 	fputc(' ', out);
145     fputs(s, out);
146     fputc(' ', out);
147     dp->l_indent=dp->margin;
148     delete(ts);
149 }
150 
151 
152 /* Paragraphs are easy */
fold_para(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)153 static void fold_para(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
154 		      void *d)
155 {
156     tblock *b, *ts;
157     const char *s;
158     char *nl;
159     struct text_data *dp;
160     int i;
161 
162     dp=(struct text_data *) d;
163     if (dp->margin==0 || (nl=(char *) alloca(dp->margin+2))==NULL)
164 	nl="\n";
165     else
166     {
167 	*nl='\n';
168 	for (i=1; i<=dp->margin; i++)
169 	    *(nl+i)=' ';
170 	*(nl+dp->margin+1)='\0';
171     }
172     ts=map_string(t->data.d, char_map);
173     b=word_wrap((*ts), nl, nl, fmt->maxline-(dp->margin), 0);
174     delete(ts);
175     s=*b;
176     for (i=dp->l_indent; i<dp->margin; i++)
177 	fputc(' ', out);
178     fputs(s, out);
179     fputs("\n\n", out);
180     dp->l_indent=0;
181     delete(b);
182 }
183 
184 /* Start a table === allocate table and initialise */
alloc_tbl(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)185 static void alloc_tbl(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
186 		      void *d)
187 {
188     struct text_data *tdata;
189 
190     out=out;
191     fmt=fmt;
192     tdata=(struct text_data *) d;
193     tdata->col=0;
194     tdata->row=0;
195     tdata->tabl=new(text_table)(t->data.table.cols, t->data.table.rows);
196 }
197 
198 
199 /* End of a table==print the table */
format_tbl(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)200 static void format_tbl(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
201 		       void *d)
202 {
203     struct text_data *tdata;
204 
205     t=t;
206     tdata=(struct text_data *) d;
207     tdata->tabl->print_table(fmt->maxline, out); // Print table
208     delete(tdata->tabl);
209     tdata->tabl=NULL;
210 }
211 
212 /* start row==set column to 0 */
start_row(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)213 static void start_row(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
214 		      void *d)
215 {
216     struct text_data *tdata;
217 
218     out=out;
219     fmt=fmt;
220     t=t;
221     tdata=(struct text_data *) d;
222     tdata->col=0;
223 }
224 
225 /* end row==add one to row */
inc_row(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)226 static void inc_row(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
227 		    void *d)
228 {
229     struct text_data *tdata;
230 
231     out=out;
232     fmt=fmt;
233     t=t;
234     tdata=(struct text_data *) d;
235     tdata->row++;
236 }
237 
238 
239 /* Start field === set field */
set_field(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)240 static void set_field(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
241 		      void *d)
242 {
243     struct tblock *ts;
244     struct text_data *tdata;
245 
246     out=out;
247     fmt=fmt;
248     ts=map_string(t->data.d, char_map);
249     tdata=(struct text_data *) d;
250     tdata->tabl->set(tdata->col, tdata->row, (*ts));
251     delete(ts);
252 }
253 
254 /* end field==add one to col */
inc_col(const tok_seq::tok * t,const docfmt * fmt,FILE * out,void * d)255 static void inc_col(const tok_seq::tok *t, const docfmt *fmt, FILE *out,
256 		    void *d)
257 {
258     struct text_data *tdata;
259 
260     out=out;
261     fmt=fmt;
262     t=t;
263     tdata=(struct text_data *) d;
264     tdata->col++;
265 }
266 
267 /* pointers to the functions that do the work */
268 docfmt txtfmt=
269 {
270     { 0 },			    // No page breaks
271     76,				    // Width
272     "\n",			    // Use \n as line ends
273     allocate_txt,		    // Allocate space
274     free_txt,			    // Free text
275     {
276 	{ null_proc, null_proc },   // End and start of document---do nothing
277 	{ fold_para, null_proc },   // Paragraph
278 	{ alloc_tbl, format_tbl },  // Start/end table
279 	{ set_field, inc_col },	    // Start/end field
280 	{ start_row, inc_row },	    // Start/end row
281 	{ null_proc, null_proc },   // Throw away embed messages
282 	{ inc_margin, dec_margin }, // list start and end
283 	{ txt_item, null_proc},	    // Items
284 	{ txt_code, null_proc},	    // Code
285 	{ null_proc, null_proc }    // Do not understanding anything else
286     }
287 };
288