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