1 | /* |
1 | /* |
2 | * gen_html4.c - Part of psiconv, a PSION 5 data formats converter |
2 | gen_html.c - Part of psiconv, a PSION 5 file formats converter |
3 | * Copyright (c) 1999 Andrew Johnson <anjohnson@iee.org> |
|
|
4 | * Portions Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> |
3 | Copyright (c) 1999-2004 Frodo Looijaard <frodol@dds.nl> |
5 | * |
4 | |
6 | * This program is free software; you can redistribute it and/or modify |
5 | This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
6 | it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
7 | the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
8 | (at your option) any later version. |
10 | * |
9 | |
11 | * This program is distributed in the hope that it will be useful, |
10 | This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
13 | GNU General Public License for more details. |
15 | * |
14 | |
16 | * You should have received a copy of the GNU General Public License |
15 | You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
16 | along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ |
18 | */ |
20 | |
19 | |
21 | #include "config.h" |
20 | #include "config.h" |
22 | #include <stdio.h> |
21 | |
|
|
22 | #include <psiconv/configuration.h> |
|
|
23 | #include <psiconv/data.h> |
|
|
24 | #include "general.h" |
|
|
25 | |
23 | #include <string.h> |
26 | #include <string.h> |
24 | #include <ctype.h> |
|
|
25 | #include <stdlib.h> |
27 | #include <stdlib.h> |
26 | #include "psiconv/data.h" |
|
|
27 | #include "psiconv/list.h" |
|
|
28 | #include "gen.h" |
|
|
29 | #include "psiconv.h" |
|
|
30 | |
28 | |
31 | #ifndef TRUE |
29 | #ifdef DMALLOC |
32 | #define TRUE (0==0) |
30 | #include "dmalloc.h" |
33 | #endif |
31 | #endif |
34 | |
32 | |
35 | /* |
33 | #define TEMPSTR_LEN 100 |
36 | * Various string tables for HTML4 settings |
|
|
37 | */ |
|
|
38 | |
34 | |
39 | /* How to display each character */ |
35 | static void text(const psiconv_config config,psiconv_list list, |
40 | static const char *char_table[0x100] = { |
36 | psiconv_string_t data,const encoding enc); |
41 | /* 0x00 */ "", "", "", "", "", "", "<BR>\n", "<BR>\n", |
37 | static void header(const psiconv_config config, psiconv_list list, |
42 | /* 0x08 */ "\n<HR>\n", "\t", "", "", "", "", "", "", |
38 | const encoding enc); |
43 | /* 0x10 */ " ", "", "", "", "", "", "", "", |
39 | static void footer(const psiconv_config config, psiconv_list list, |
44 | /* 0x18 */ "", "", "", "", "", "", "", "", |
40 | const encoding enc); |
45 | /* 0x20 */ " ", "!", """, "#", "$", "%", "&", "'", |
41 | static void characters(const psiconv_config config, psiconv_list list, |
46 | /* 0x28 */ "(", ")", "*", "+", ",", "-", ".", "/", |
42 | const psiconv_string_t textstr, |
47 | /* 0x30 */ "0", "1", "2", "3", "4", "5", "6", "7", |
43 | const psiconv_character_layout layout,const encoding enc); |
48 | /* 0x38 */ "8", "9", ":", ";", "<", "=", ">", "?", |
44 | static void paragraph(const psiconv_config config, psiconv_list list, |
49 | /* 0x40 */ "@", "A", "B", "C", "D", "E", "F", "G", |
45 | psiconv_paragraph para, const encoding enc); |
50 | /* 0x48 */ "H", "I", "J", "K", "L", "M", "N", "O", |
46 | static void paragraphs(const psiconv_config config, psiconv_list list, |
51 | /* 0x50 */ "P", "Q", "R", "S", "T", "U", "V", "W", |
47 | psiconv_text_and_layout paragraphs, const encoding enc); |
52 | /* 0x58 */ "X", "Y", "Z", "[", "\\", "]", "^", "_", |
48 | static void gen_word(const psiconv_config config, psiconv_list list, |
53 | /* 0x60 */ "`", "a", "b", "c", "d", "e", "f", "g", |
49 | const psiconv_word_f file, const encoding enc); |
54 | /* 0x68 */ "h", "i", "j", "k", "l", "m", "n", "o", |
50 | static void gen_texted(const psiconv_config config, psiconv_list list, |
55 | /* 0x70 */ "p", "q", "r", "s", "t", "u", "v", "w", |
51 | const psiconv_texted_f file, const encoding enc); |
56 | /* 0x78 */ "x", "y", "z", "{", "|", "}", "~", "", |
52 | static int gen_html4(const psiconv_config config, psiconv_list list, |
57 | /* 0x80 */ "", "", "‚", "ƒ", |
53 | const psiconv_file file, const char *dest, |
58 | "„", "…", "†", "‡", |
54 | const encoding enc); |
59 | /* 0x88 */ "ˆ", "‰", "Š", "<", |
|
|
60 | "Œ", "", "", "", |
|
|
61 | /* 0x90 */ "", "‘", "’", "“", |
|
|
62 | "”","•", "–", "—", |
|
|
63 | /* 0x98 */ "˜", "™", "š", ">", |
|
|
64 | "œ", "", "", "Ÿ", |
|
|
65 | /* 0xa0 */ " ", "¡", "¢", "£", |
|
|
66 | "¤", "¥", "¦", "§", |
|
|
67 | /* 0xa8 */ "¨", "©", "ª", "«", |
|
|
68 | "¬", "­", "®", "¯", |
|
|
69 | /* 0xb0 */ "°", "±", "²", "³", |
|
|
70 | "´", "µ", "¶", "·", |
|
|
71 | /* 0xb8 */ "¸", "¹", "º", "»", |
|
|
72 | "¼", "½", "¾", "¿", |
|
|
73 | /* 0xc0 */ "À", "Á", "Â", "Ã", |
|
|
74 | "Ä", "Å", "Æ", "Ç", |
|
|
75 | /* 0xc8 */ "È", "É", "Ê", "Ë", |
|
|
76 | "Ì", "Í", "Î", "Ï", |
|
|
77 | /* 0xd0 */ "Ð", "Ñ", "Ò", "Ó", |
|
|
78 | "Ô", "Õ", "Ö", "×", |
|
|
79 | /* 0xd8 */ "Ø", "Ù", "Ú", "Û", |
|
|
80 | "Ü", "Ý", "Þ", "ß", |
|
|
81 | /* 0xe0 */ "à", "á", "â", "ã", |
|
|
82 | "ä", "å", "æ", "ç", |
|
|
83 | /* 0xe8 */ "è", "é", "ê", "ë", |
|
|
84 | "ì", "í", "î", "ï", |
|
|
85 | /* 0xf0 */ "ð", "ñ", "ò", "ó", |
|
|
86 | "ô", "õ", "ö", "÷", |
|
|
87 | /* 0xf8 */ "ø", "ù", "ú", "û", |
|
|
88 | "ü", "ý", "þ", "ÿ" |
|
|
89 | }; |
|
|
90 | |
55 | |
91 | /* The order of these must match the enum psiconv_border_kind (data.h) */ |
|
|
92 | static const char *border_strings[] = { |
|
|
93 | "none", "solid", "double", "dotted", "dashed", "dashed", "dotted" |
|
|
94 | }; |
|
|
95 | |
56 | |
96 | /* The order of these must match the enum psiconv_justify (data.h) */ |
57 | void text(const psiconv_config config,psiconv_list list, |
97 | static const char *justify_strings[] = { |
58 | psiconv_string_t data,const encoding enc) |
98 | "left", "center", "right", "justify" |
59 | { |
99 | }; |
|
|
100 | |
|
|
101 | /* The order of these must match the enum psiconv_super_sub (data.h) */ |
|
|
102 | static const char *vertical_strings[] = { |
|
|
103 | "baseline", "super", "sub" |
|
|
104 | }; |
|
|
105 | |
|
|
106 | |
|
|
107 | /* |
|
|
108 | * Support routines for particular formatting structures |
|
|
109 | */ |
|
|
110 | |
|
|
111 | static void fput_name(FILE * of, const char *string) { |
|
|
112 | int i; |
60 | int i; |
113 | |
61 | for (i = 0; i < psiconv_unicode_strlen(data); i++) { |
114 | for (i = 0; i < strlen(string); i++) |
62 | if ((data[i] == 0x06) || (data[i] == 0x07) || (data[i] == 0x08)) |
115 | if (isalnum(string[i])) |
63 | output_simple_chars(config,list,"<BR>",enc); |
116 | putc(string[i], of); |
64 | else if ((data[i] == 0x0b) || (data[i] == 0x0c)) |
|
|
65 | output_simple_chars(config,list,"-",enc); |
|
|
66 | else if ((data[i] == 0x0f) || (data[i] == 0x09) || (data[i] == 0x0a)) |
|
|
67 | output_simple_chars(config,list," ",enc); |
|
|
68 | else if (data[i] >= 0x20) |
|
|
69 | output_char(config,list,data[i],enc); |
|
|
70 | } |
117 | } |
71 | } |
118 | |
72 | |
119 | static void fput_text(FILE * of, const char *text, int length, int *pwasspace) { |
73 | void header(const psiconv_config config, psiconv_list list, const encoding enc) |
120 | int j; |
74 | { |
121 | int space; |
75 | output_simple_chars(config,list,"<!DOCTYPE html PUBLIC " |
122 | |
76 | "\"-//W3C//DTD HTML 4.01 Transitional//EN\" " |
123 | for (j = 0; j < length; j++) { |
77 | "\"http://www.w3.org/TR/html4/loose.dtd\">\n", |
124 | space = (text[j] == ' '); |
78 | enc); |
125 | if (*pwasspace && space) |
79 | output_simple_chars(config,list,"<HTML>\n",enc); |
126 | fputs(" ", of); |
80 | output_simple_chars(config,list,"<HEAD>\n",enc); |
127 | else |
81 | output_simple_chars(config,list,"<META HTTP-EQUIV=\"Content-Type\" " |
128 | fputs(char_table[(unsigned char) (text[j])], of); |
82 | "CONTENT=\"text/html; charset=",enc); |
129 | *pwasspace = space; |
83 | output_simple_chars(config,list,enc==ENCODING_UTF8?"UTF-8": |
|
|
84 | enc==ENCODING_UCS2?"UTF-16BE": |
|
|
85 | enc==ENCODING_ASCII?"US-ASCII": |
|
|
86 | "",enc); |
|
|
87 | output_simple_chars(config,list,"\">\n",enc); |
|
|
88 | output_simple_chars(config,list,"<TITLE>EPOC32 file " |
|
|
89 | "converted by psiconv</TITLE>\n",enc); |
|
|
90 | output_simple_chars(config,list,"</HEAD>\n",enc); |
|
|
91 | output_simple_chars(config,list,"<BODY>\n",enc); |
|
|
92 | } |
|
|
93 | |
|
|
94 | void footer(const psiconv_config config, psiconv_list list, const encoding enc) |
|
|
95 | { |
|
|
96 | output_simple_chars(config,list,"</BODY>\n",enc); |
|
|
97 | output_simple_chars(config,list,"</HTML>\n",enc); |
|
|
98 | } |
|
|
99 | |
|
|
100 | int character_layout_equal(const psiconv_character_layout l1, |
|
|
101 | const psiconv_character_layout l2) |
|
|
102 | { |
|
|
103 | int font_size1,font_size2; |
|
|
104 | |
|
|
105 | font_size1 = l1->font_size < 8 ?1: |
|
|
106 | l1->font_size < 10 ?2: |
|
|
107 | l1->font_size < 13 ?3: |
|
|
108 | l1->font_size < 17 ?4: |
|
|
109 | l1->font_size < 24 ?5: |
|
|
110 | l1->font_size < 36 ?6:7; |
|
|
111 | font_size2 = l2->font_size < 8 ?1: |
|
|
112 | l2->font_size < 10 ?2: |
|
|
113 | l2->font_size < 13 ?3: |
|
|
114 | l2->font_size < 17 ?4: |
|
|
115 | l2->font_size < 24 ?5: |
|
|
116 | l2->font_size < 36 ?6:7; |
|
|
117 | |
|
|
118 | return (l1 && l2 && |
|
|
119 | (l1->color->red == l2->color->red) && |
|
|
120 | (l1->color->green == l2->color->green) && |
|
|
121 | (l1->color->blue == l2->color->blue) && |
|
|
122 | (font_size1 == font_size2) && |
|
|
123 | (l1->italic == l2->italic) && |
|
|
124 | (l1->bold == l2->bold) && |
|
|
125 | (l1->super_sub == l2->super_sub) && |
|
|
126 | (l1->underline == l2->underline) && |
|
|
127 | (l1->strikethrough == l2->strikethrough) && |
|
|
128 | (l1->font->screenfont == l2->font->screenfont)); |
|
|
129 | } |
|
|
130 | |
|
|
131 | void characters(const psiconv_config config, psiconv_list list, |
|
|
132 | const psiconv_string_t textstr, |
|
|
133 | const psiconv_character_layout layout,const encoding enc) |
|
|
134 | { |
|
|
135 | char tempstr[TEMPSTR_LEN]; |
|
|
136 | |
|
|
137 | output_simple_chars(config,list,"<FONT face=\"",enc); |
|
|
138 | output_simple_chars(config,list, |
|
|
139 | layout->font->screenfont == psiconv_font_serif?"serif": |
|
|
140 | layout->font->screenfont == psiconv_font_sansserif?"sans-serif": |
|
|
141 | layout->font->screenfont == psiconv_font_nonprop?"monospace": |
|
|
142 | layout->font->screenfont == psiconv_font_misc?"fantasy":"", |
|
|
143 | enc); |
|
|
144 | output_simple_chars(config,list,"\"",enc); |
|
|
145 | |
|
|
146 | if ((layout->font_size < 10) || (layout->font_size >= 13)) { |
|
|
147 | output_simple_chars(config,list," size=",enc); |
|
|
148 | output_simple_chars(config,list, |
|
|
149 | layout->font_size < 8 ?"1": |
|
|
150 | layout->font_size < 10 ?"2": |
|
|
151 | layout->font_size < 13 ?"3": |
|
|
152 | layout->font_size < 17 ?"4": |
|
|
153 | layout->font_size < 24 ?"5": |
|
|
154 | layout->font_size < 36 ?"6":"7",enc); |
|
|
155 | } |
|
|
156 | if ((layout->color->red != 0) || (layout->color->green != 0) || |
|
|
157 | (layout->color->blue != 0)) { |
|
|
158 | snprintf(tempstr,TEMPSTR_LEN,"%02x%02x%02x", |
|
|
159 | layout->color->red,layout->color->green,layout->color->blue); |
|
|
160 | output_simple_chars(config,list," color=#",enc); |
|
|
161 | output_simple_chars(config,list,tempstr,enc); |
|
|
162 | } |
|
|
163 | output_simple_chars(config,list,">",enc); |
|
|
164 | |
|
|
165 | |
|
|
166 | if (layout->italic) |
|
|
167 | output_simple_chars(config,list,"<I>",enc); |
|
|
168 | if (layout->bold) |
|
|
169 | output_simple_chars(config,list,"<B>",enc); |
|
|
170 | if (layout->super_sub != psiconv_normalscript) |
|
|
171 | output_simple_chars(config,list, |
|
|
172 | layout->super_sub == psiconv_superscript?"<SUP>": |
|
|
173 | layout->super_sub == psiconv_subscript?"<SUB>": |
|
|
174 | "",enc); |
|
|
175 | if (layout->strikethrough) |
|
|
176 | output_simple_chars(config,list,"<S>",enc); |
|
|
177 | if (layout->underline) |
|
|
178 | output_simple_chars(config,list,"<U>",enc); |
|
|
179 | |
|
|
180 | text(config,list,textstr,enc); |
|
|
181 | |
|
|
182 | if (layout->underline) |
|
|
183 | output_simple_chars(config,list,"</U>",enc); |
|
|
184 | if (layout->strikethrough) |
|
|
185 | output_simple_chars(config,list,"</S>",enc); |
|
|
186 | if (layout->super_sub != psiconv_normalscript) |
|
|
187 | output_simple_chars(config,list, |
|
|
188 | layout->super_sub == psiconv_superscript?"</SUP>": |
|
|
189 | layout->super_sub == psiconv_subscript?"</SUB>": |
|
|
190 | "",enc); |
|
|
191 | if (layout->bold) |
|
|
192 | output_simple_chars(config,list,"</B>",enc); |
|
|
193 | if (layout->italic) |
|
|
194 | output_simple_chars(config,list,"</I>",enc); |
|
|
195 | output_simple_chars(config,list,"</FONT>",enc); |
|
|
196 | } |
|
|
197 | |
|
|
198 | void paragraph(const psiconv_config config, psiconv_list list, |
|
|
199 | psiconv_paragraph para, const encoding enc) |
|
|
200 | { |
|
|
201 | int i,charnr,start,len; |
|
|
202 | psiconv_string_t text; |
|
|
203 | psiconv_in_line_layout layout,next_layout; |
|
|
204 | |
|
|
205 | |
|
|
206 | output_simple_chars(config,list, |
|
|
207 | para->base_paragraph->bullet->on?"<UL><LI":"<P",enc); |
|
|
208 | |
|
|
209 | if (para->base_paragraph->justify_hor == psiconv_justify_centre) |
|
|
210 | output_simple_chars(config,list," align=center",enc); |
|
|
211 | else if (para->base_paragraph->justify_hor == psiconv_justify_right) |
|
|
212 | output_simple_chars(config,list," align=right",enc); |
|
|
213 | else if (para->base_paragraph->justify_hor == psiconv_justify_full) |
|
|
214 | output_simple_chars(config,list," align=justify",enc); |
|
|
215 | |
|
|
216 | output_simple_chars(config,list,">",enc); |
|
|
217 | |
|
|
218 | if (psiconv_list_length(para->in_lines) == 0) { |
|
|
219 | if (psiconv_unicode_strlen(para->text)) |
|
|
220 | characters(config,list,para->text,para->base_character,enc); |
|
|
221 | } else { |
|
|
222 | charnr = 0; |
|
|
223 | start = -1; |
|
|
224 | for (i = 0; i < psiconv_list_length(para->in_lines); i++) { |
|
|
225 | if (start < 0) |
|
|
226 | start = charnr; |
|
|
227 | if (!(layout = psiconv_list_get(para->in_lines,i))) { |
|
|
228 | fputs("Internal data structures corruption\n",stderr); |
|
|
229 | exit(1); |
|
|
230 | } |
|
|
231 | if (i+1 < psiconv_list_length(para->in_lines)) { |
|
|
232 | if (!(next_layout = psiconv_list_get(para->in_lines,i+1))) { |
|
|
233 | fputs("Internal data structures corruption\n",stderr); |
|
|
234 | exit(1); |
|
|
235 | } |
|
|
236 | } else { |
|
|
237 | next_layout = NULL; |
|
|
238 | } |
|
|
239 | if (next_layout && |
|
|
240 | character_layout_equal(layout->layout,next_layout->layout)) { |
|
|
241 | charnr += layout->length; |
|
|
242 | continue; |
|
|
243 | } |
|
|
244 | len = charnr - start + layout->length; |
|
|
245 | if (len) { |
|
|
246 | if (!(text = malloc(sizeof (*text) * (len + 1)))) { |
|
|
247 | fputs("Out of memory error\n",stderr); |
|
|
248 | exit(1); |
|
|
249 | } |
|
|
250 | memcpy(text,para->text+charnr,len * sizeof(*text)); |
|
|
251 | text[len] = 0; |
|
|
252 | characters(config,list,text,layout->layout,enc); |
|
|
253 | free(text); |
|
|
254 | } |
|
|
255 | charnr += layout->length; |
|
|
256 | start = -1; |
130 | } |
257 | } |
|
|
258 | } |
|
|
259 | output_simple_chars(config, list, |
|
|
260 | para->base_paragraph->bullet->on?"</UL>\n":"\n",enc); |
131 | } |
261 | } |
132 | |
262 | |
133 | static const char *screenfont_name(psiconv_u8 screenfont) |
263 | void paragraphs(const psiconv_config config, psiconv_list list, |
|
|
264 | psiconv_text_and_layout paragraphs, const encoding enc) |
134 | { |
265 | { |
135 | if (screenfont == 1) |
|
|
136 | return "sans-serif"; |
|
|
137 | else if (screenfont == 2) |
|
|
138 | return "monospace"; |
|
|
139 | else if (screenfont == 3) |
|
|
140 | return "serif"; |
|
|
141 | else |
|
|
142 | return "serif"; |
|
|
143 | } |
|
|
144 | |
|
|
145 | static const char *generic_font_family(const char *font_name) { |
|
|
146 | static const char *sans_font_names[] = { |
|
|
147 | "Arial", "Univers", "Sans Serif" |
|
|
148 | }; |
|
|
149 | static const char *mono_font_names[] = { |
|
|
150 | "Courier New", "Courier", "Mono", "Lineprinter", "Elite", "Swiss", |
|
|
151 | "Courier (compressed)", "Courier (expanded)", "Letter Gothic" |
|
|
152 | }; |
|
|
153 | int i; |
266 | int i; |
154 | |
267 | psiconv_paragraph para; |
155 | for (i=0; i < sizeof(sans_font_names) / sizeof(sans_font_names[0]); i++) |
268 | for (i = 0; i < psiconv_list_length(paragraphs); i++) { |
156 | if (!strcmp(font_name, sans_font_names[i])) |
269 | if (!(para = psiconv_list_get(paragraphs,i))) { |
157 | return "sans-serif"; |
270 | fputs("Internal datastructure corruption\n",stderr); |
158 | |
271 | exit(1); |
159 | for (i=0; i < sizeof(mono_font_names) / sizeof(mono_font_names[0]); i++) |
|
|
160 | if (!strcmp(font_name, mono_font_names[i])) |
|
|
161 | return "monospace"; |
|
|
162 | |
|
|
163 | return "serif"; |
|
|
164 | } |
|
|
165 | |
|
|
166 | static int colors_different( |
|
|
167 | const psiconv_color old, |
|
|
168 | const psiconv_color new) |
|
|
169 | { |
|
|
170 | return ((old->red != new->red) || |
|
|
171 | (old->green != new->green) || |
|
|
172 | (old->blue != new->blue)); |
|
|
173 | } |
|
|
174 | |
|
|
175 | |
|
|
176 | /* Borders */ |
|
|
177 | static int borders_different( |
|
|
178 | const psiconv_border old, |
|
|
179 | const psiconv_border new) |
|
|
180 | { |
|
|
181 | return (!old || |
|
|
182 | (old->kind != new->kind) || |
|
|
183 | colors_different(old->color, new->color) || |
|
|
184 | (old->thickness != new->thickness)); |
|
|
185 | } |
|
|
186 | |
|
|
187 | static void fput_border(FILE * of, |
|
|
188 | const char *which, |
|
|
189 | const psiconv_border old, |
|
|
190 | const psiconv_border new) |
|
|
191 | { |
|
|
192 | /* If the border changed at all we'll set all parameters, as they're |
|
|
193 | * fairly closely linked and it's much easier to do it this way */ |
|
|
194 | if (borders_different(old, new)) { |
|
|
195 | fprintf(of, "border-%s-style:%s;", |
|
|
196 | which, border_strings[new->kind]); |
|
|
197 | if ((new->kind != psiconv_border_none) && |
|
|
198 | (new->color->red || new->color->green || new->color->blue)) |
|
|
199 | fprintf(of, "border-%s-color:#%02x%02x%02x;", which, |
|
|
200 | new->color->red, new->color->green, new->color->blue); |
|
|
201 | if ((new->kind == psiconv_border_solid) || |
|
|
202 | (new->kind == psiconv_border_double)) |
|
|
203 | fprintf(of, "border-%s-width:%.0fpx;", |
|
|
204 | which, (new->thickness / 10.0) - 1); |
|
|
205 | else if (new->kind != psiconv_border_none) |
|
|
206 | fprintf(of, "border-%s-width:1px;", which); |
|
|
207 | } |
272 | } |
|
|
273 | paragraph(config,list,para,enc); |
|
|
274 | } |
208 | } |
275 | } |
209 | |
276 | |
210 | /* Paragraph formats */ |
277 | void gen_word(const psiconv_config config, psiconv_list list, |
211 | static int paragraph_layouts_different( |
278 | const psiconv_word_f file, const encoding enc) |
212 | const psiconv_paragraph_layout old, |
|
|
213 | const psiconv_paragraph_layout new) |
|
|
214 | { |
279 | { |
215 | return ((old->top_space != new->top_space) || |
280 | if (!file) |
216 | (old->indent_right != new->indent_right) || |
281 | return; |
217 | (old->bottom_space != new->bottom_space) || |
|
|
218 | (old->indent_left != new->indent_left) || |
|
|
219 | (old->indent_first != new->indent_first) || |
|
|
220 | (old->justify_hor != new->justify_hor) || |
|
|
221 | (old->interline_exact != new->interline_exact) || |
|
|
222 | borders_different(old->left_border, new->left_border) || |
|
|
223 | borders_different(old->right_border, new->right_border) || |
|
|
224 | borders_different(old->top_border, new->top_border) || |
|
|
225 | borders_different(old->bottom_border, new->bottom_border)); |
|
|
226 | } |
|
|
227 | |
282 | |
228 | static void fput_paragraph_layout(FILE * of, |
283 | header(config,list,enc); |
229 | const psiconv_paragraph_layout old, |
284 | paragraphs(config,list,file->paragraphs,enc); |
230 | const psiconv_paragraph_layout new) |
285 | footer(config,list,enc); |
|
|
286 | } |
|
|
287 | |
|
|
288 | |
|
|
289 | void gen_texted(const psiconv_config config, psiconv_list list, |
|
|
290 | const psiconv_texted_f file, const encoding enc) |
231 | { |
291 | { |
232 | if (!old || (old->top_space != new->top_space)) |
292 | header(config,list,enc); |
233 | fprintf(of, "margin-top:%.1fpt;", new->top_space); |
293 | paragraphs(config,list,file->texted_sec->paragraphs,enc); |
234 | if (!old || (old->indent_right != new->indent_right)) |
294 | footer(config,list,enc); |
235 | fprintf(of, "margin-right:%.2fcm;", new->indent_right); |
295 | } |
236 | if (!old || (old->bottom_space != new->bottom_space)) |
296 | |
237 | fprintf(of, "margin-bottom:%.1fpt;", new->bottom_space); |
297 | int gen_html4(const psiconv_config config, psiconv_list list, |
238 | if (!old || |
298 | const psiconv_file file, const char *dest, |
239 | (old->bullet->on != new->bullet->on) || |
299 | const encoding enc) |
240 | (old->bullet->indent != new->bullet->indent) || |
300 | { |
241 | (old->indent_left != new->indent_left) || |
301 | encoding enc1 = enc; |
242 | (old->indent_first != new->indent_first)) { |
302 | |
243 | psiconv_length_t indent = new->indent_first; |
303 | if (enc == ENCODING_PSION) { |
244 | psiconv_length_t margin = new->indent_left; |
304 | fputs("Unsupported encoding\n",stderr); |
245 | /* Bullets with indent set cause strange margin behaviour: */ |
305 | return -1; |
246 | if (new->bullet->on && new->bullet->indent) { |
306 | } else if (enc == ENCODING_ASCII) |
247 | if (indent > 0.0) { |
307 | enc1 = ENCODING_ASCII_HTML; |
248 | margin += indent; |
308 | |
249 | indent = new->indent_left - indent; |
309 | if (file->type == psiconv_word_file) { |
|
|
310 | gen_word(config,list,(psiconv_word_f) file->file,enc1); |
|
|
311 | return 0; |
|
|
312 | } else if (file->type == psiconv_texted_file) { |
|
|
313 | gen_texted(config,list,(psiconv_texted_f) file->file,enc1); |
|
|
314 | return 0; |
|
|
315 | } else |
|
|
316 | return -1; |
|
|
317 | } |
|
|
318 | |
|
|
319 | |
|
|
320 | static struct fileformat_s ffs[] = |
|
|
321 | { |
|
|
322 | { |
|
|
323 | "HTML4", |
|
|
324 | "HTML 4.01 Transitional, without CSS", |
|
|
325 | FORMAT_WORD | FORMAT_TEXTED, |
|
|
326 | gen_html4 |
250 | } |
327 | }, |
251 | } |
328 | { |
252 | fprintf(of, "margin-left:%.2fcm;", margin); |
329 | NULL, |
253 | fprintf(of, "text-indent:%.2fcm;", indent); |
330 | NULL, |
|
|
331 | 0, |
|
|
332 | NULL |
254 | } |
333 | } |
255 | if (!old || (old->justify_hor != new->justify_hor)) |
|
|
256 | fprintf(of, "text-align:%s;", justify_strings[new->justify_hor]); |
|
|
257 | if (!old || (old->interline_exact != new->interline_exact)) { |
|
|
258 | if (!old || old->interline_exact) |
|
|
259 | fputs("line-height:normal;", of); |
|
|
260 | else |
|
|
261 | fprintf(of, "line-height:%.1fpt;", new->interline); |
|
|
262 | } |
|
|
263 | fput_border(of, "left", old ? old->left_border : NULL, |
|
|
264 | new->left_border); |
|
|
265 | fput_border(of, "right", old ? old->right_border : NULL, |
|
|
266 | new->right_border); |
|
|
267 | fput_border(of, "top", old ? old->top_border : NULL, |
|
|
268 | new->top_border); |
|
|
269 | fput_border(of, "bottom", old ? old->bottom_border : NULL, |
|
|
270 | new->bottom_border); |
|
|
271 | } |
|
|
272 | |
|
|
273 | /* Character formats */ |
|
|
274 | static int character_layouts_different( |
|
|
275 | const psiconv_character_layout old, |
|
|
276 | const psiconv_character_layout new) |
|
|
277 | { |
|
|
278 | return ((old->font->screenfont != new->font->screenfont) || |
|
|
279 | (strcmp(old->font->name,new->font->name)) || |
|
|
280 | (old->font_size != new->font_size) || |
|
|
281 | (old->color->red != new->color->red) || |
|
|
282 | (old->color->green != new->color->green) || |
|
|
283 | (old->color->blue != new->color->blue) || |
|
|
284 | (old->back_color->red != new->back_color->red) || |
|
|
285 | (old->back_color->green != new->back_color->green) || |
|
|
286 | (old->back_color->blue != new->back_color->blue) || |
|
|
287 | (old->italic != new->italic) || |
|
|
288 | (old->bold != new->bold) || |
|
|
289 | (old->super_sub != new->super_sub) || |
|
|
290 | (old->underline != new->underline) || |
|
|
291 | (old->strike_out != new->strike_out)); |
|
|
292 | } |
|
|
293 | |
|
|
294 | static void fput_character_layout(FILE * of, |
|
|
295 | const psiconv_character_layout old, |
|
|
296 | const psiconv_character_layout new, |
|
|
297 | psiconv_word_f wf) |
|
|
298 | { |
|
|
299 | if (!old || (old->font->screenfont != new->font->screenfont) || |
|
|
300 | strcmp(old->font->name,new->font->name)) { |
|
|
301 | fprintf(of, "font-family:%s,%s,%s;", new->font->name, |
|
|
302 | generic_font_family(new->font->name), |
|
|
303 | screenfont_name(new->font->screenfont)); |
|
|
304 | } |
|
|
305 | if (!old || (old->font_size != new->font_size)) |
|
|
306 | fprintf(of, "font-size:%.1f%%;", 100.0 * new->font_size / 10.0); |
|
|
307 | if (!old || (old->bold != new->bold)) |
|
|
308 | fprintf(of, "font-weight:%s;", new->bold ? "bold" : "normal"); |
|
|
309 | if (!old || (old->italic != new->italic)) |
|
|
310 | fprintf(of, "font-style:%s;", new->italic ? "italic" : "normal"); |
|
|
311 | if (!old || (colors_different(old->color, new->color))) |
|
|
312 | fprintf(of, "color:#%02x%02x%02x;", |
|
|
313 | new->color->red, new->color->green, new->color->blue); |
|
|
314 | if (!old || (colors_different(old->back_color, new->back_color))) |
|
|
315 | fprintf(of, "background-color:#%02x%02x%02x;", |
|
|
316 | new->back_color->red, new->back_color->green, new->back_color->blue); |
|
|
317 | if (!old || (old->super_sub != new->super_sub)) |
|
|
318 | fprintf(of, "vertical-align:%s;", vertical_strings[new->super_sub]); |
|
|
319 | if (!old || (old->underline != new->underline) || |
|
|
320 | (old->strike_out != new->strike_out)) { |
|
|
321 | fputs("text-decoration:", of); |
|
|
322 | if (new->strike_out) |
|
|
323 | fputs("line-through ", of); |
|
|
324 | if (new->underline) |
|
|
325 | fputs("underline", of); |
|
|
326 | else if (!new->strike_out) |
|
|
327 | fputs("none", of); |
|
|
328 | fputs(";", of); |
|
|
329 | } |
|
|
330 | } |
|
|
331 | |
|
|
332 | |
|
|
333 | /* Formatted paragraphs */ |
|
|
334 | static void fput_para(FILE * of, |
|
|
335 | const psiconv_paragraph para, |
|
|
336 | psiconv_word_f wf) |
|
|
337 | { |
|
|
338 | psiconv_paragraph_layout base_para = para->base_paragraph; |
|
|
339 | psiconv_character_layout base_char = para->base_character; |
|
|
340 | psiconv_character_layout cur_char; |
|
|
341 | psiconv_character_layout *layout_stack; |
|
|
342 | psiconv_in_line_layout inl; |
|
|
343 | psiconv_word_style sty; |
|
|
344 | int spans = 0; |
|
|
345 | int wasspace = 0; |
|
|
346 | int i, j, loc; |
|
|
347 | |
|
|
348 | layout_stack = calloc(psiconv_list_length(para->in_lines), |
|
|
349 | sizeof(*layout_stack)); |
|
|
350 | fputs("<P", of); |
|
|
351 | sty = psiconv_get_style(wf->styles_sec, para->base_style); |
|
|
352 | cur_char = sty->character; |
|
|
353 | |
|
|
354 | if (sty->name) { |
|
|
355 | fputs(" CLASS=\"", of); |
|
|
356 | fput_name(of, sty->name); |
|
|
357 | putc('"', of); |
|
|
358 | } |
|
|
359 | |
|
|
360 | if (paragraph_layouts_different(sty->paragraph, base_para) || |
|
|
361 | character_layouts_different(cur_char, base_char)) { |
|
|
362 | fputs(" STYLE=\"", of); |
|
|
363 | fput_paragraph_layout(of, sty->paragraph, base_para); |
|
|
364 | fput_character_layout(of, cur_char, base_char, wf); |
|
|
365 | cur_char = base_char; |
|
|
366 | putc('"', of); |
|
|
367 | } |
|
|
368 | putc('>', of); |
|
|
369 | |
|
|
370 | if (base_para->bullet->on) { |
|
|
371 | fputs("<SPAN STYLE=\"", of); |
|
|
372 | if (base_para->bullet->font != base_char->font) { |
|
|
373 | fprintf(of, "font-family:%s,%s,%s;", |
|
|
374 | base_para->bullet->font->name, |
|
|
375 | generic_font_family(base_para->bullet->font->name), |
|
|
376 | screenfont_name(base_para->bullet->font->screenfont)); |
|
|
377 | } |
|
|
378 | if (base_para->bullet->font_size != base_char->font_size) |
|
|
379 | fprintf(of, "font-size:%.1f%%;", |
|
|
380 | 100.0 * base_para->bullet->font_size / 10.0); |
|
|
381 | if ((base_para->bullet->color->red != base_char->color->red) || |
|
|
382 | (base_para->bullet->color->green != base_char->color->green) || |
|
|
383 | (base_para->bullet->color->blue != base_char->color->blue)) |
|
|
384 | fprintf(of, "color:#%02x%02x%02x;", |
|
|
385 | base_para->bullet->color->red, |
|
|
386 | base_para->bullet->color->green, |
|
|
387 | base_para->bullet->color->blue); |
|
|
388 | fprintf(of, "\">%s </SPAN>", |
|
|
389 | char_table[base_para->bullet->character]); |
|
|
390 | wasspace = TRUE; |
|
|
391 | } |
|
|
392 | |
|
|
393 | loc = 0; |
|
|
394 | for (i = 0; i < psiconv_list_length(para->in_lines); i++) { |
|
|
395 | inl = psiconv_list_get(para->in_lines, i); |
|
|
396 | if (character_layouts_different(cur_char, inl->layout)) { |
|
|
397 | for (j = 0; j < spans; j++) |
|
|
398 | if (!character_layouts_different(inl->layout, layout_stack[j])) |
|
|
399 | break; |
|
|
400 | if (j < spans) { |
|
|
401 | while (spans > j) { |
|
|
402 | fputs("</SPAN>",of); |
|
|
403 | spans--; |
|
|
404 | } |
|
|
405 | } else { |
|
|
406 | fputs("<SPAN STYLE=\"", of); |
|
|
407 | fput_character_layout(of, cur_char, inl->layout, wf); |
|
|
408 | fputs("\">",of); |
|
|
409 | layout_stack[spans++] = cur_char; |
|
|
410 | } |
|
|
411 | cur_char = inl->layout; |
|
|
412 | } |
|
|
413 | fput_text(of, ¶->text[loc], inl->length, &wasspace); |
|
|
414 | loc += inl->length; |
|
|
415 | } |
|
|
416 | |
|
|
417 | while (spans > 0) { |
|
|
418 | fputs("</SPAN>",of); |
|
|
419 | spans--; |
|
|
420 | } |
|
|
421 | |
|
|
422 | if (loc < strlen(para->text)) { |
|
|
423 | fput_text(of, ¶->text[loc], strlen(para->text) - loc, &wasspace); |
|
|
424 | } |
|
|
425 | |
|
|
426 | if (strlen(para->text) == 0) |
|
|
427 | fputs(" ", of); |
|
|
428 | |
|
|
429 | fputs("</P>\n", of); |
|
|
430 | free(layout_stack); |
|
|
431 | } |
|
|
432 | |
|
|
433 | static void fput_style(FILE * of, |
|
|
434 | const psiconv_word_style normal, |
|
|
435 | const psiconv_word_style sty, |
|
|
436 | psiconv_word_f wf) |
|
|
437 | { |
|
|
438 | if (sty->name == NULL) |
|
|
439 | fputs(" P {", of); |
|
|
440 | else { |
|
|
441 | fputs(" P.", of); |
|
|
442 | fput_name(of, sty->name); |
|
|
443 | fputs(" {", of); |
|
|
444 | } |
|
|
445 | fput_paragraph_layout(of, normal ? normal->paragraph : NULL, sty->paragraph); |
|
|
446 | fput_character_layout(of, normal ? normal->character : NULL, sty->character, wf); |
|
|
447 | fputs("}\n", of); |
|
|
448 | } |
|
|
449 | |
|
|
450 | static int psiconv_gen_html4(const char *filename, const psiconv_file file, |
|
|
451 | const char *dest) |
|
|
452 | { |
|
|
453 | FILE * of; |
|
|
454 | int i; |
|
|
455 | psiconv_paragraph para; |
|
|
456 | psiconv_word_style normal, sty; |
|
|
457 | psiconv_word_f wf; |
|
|
458 | |
|
|
459 | if (file->type == psiconv_word_file) |
|
|
460 | wf = file->file; |
|
|
461 | else { |
|
|
462 | /* Fall back on the normal HTML generator */ |
|
|
463 | return psiconv_gen_html(filename,file,dest); |
|
|
464 | } |
|
|
465 | |
|
|
466 | if (! (of = fopen(filename,"w"))) |
|
|
467 | return -1; |
|
|
468 | |
|
|
469 | fputs("<!doctype html public \"-//W3C//DTD HTML 4.0 STRICT//EN\">", of); |
|
|
470 | fputs("\n<HTML>\n<HEAD>\n <META NAME=\"GENERATOR\"", of); |
|
|
471 | fputs(" CONTENT=\"psiconv-" VERSION "\">\n", of); |
|
|
472 | |
|
|
473 | if (psiconv_list_length(wf->page_sec->header->text->paragraphs) > 0) { |
|
|
474 | fputs(" <TITLE>", of); |
|
|
475 | para = psiconv_list_get(wf->page_sec->header->text->paragraphs, 0); |
|
|
476 | i = 0; |
|
|
477 | fput_text(of, para->text, strlen(para->text), &i); |
|
|
478 | fputs("</TITLE>\n", of); |
|
|
479 | } |
|
|
480 | |
|
|
481 | normal = wf->styles_sec->normal; |
|
|
482 | fputs(" <STYLE TYPE=\"text/css\"><!--\n", of); |
|
|
483 | fprintf(of," BODY { background-color: #%02x%02x%02x }\n", |
|
|
484 | normal->paragraph->back_color->red, |
|
|
485 | normal->paragraph->back_color->green, |
|
|
486 | normal->paragraph->back_color->blue); |
|
|
487 | fput_style(of, NULL, normal, wf); |
|
|
488 | for (i = 0; i < psiconv_list_length(wf->styles_sec->styles); i++) { |
|
|
489 | sty = psiconv_list_get(wf->styles_sec->styles, i); |
|
|
490 | fput_style(of, normal, sty, wf); |
|
|
491 | } |
|
|
492 | fputs(" --></STYLE>\n</HEAD>\n<BODY>\n", of); |
|
|
493 | for (i = 0; i < psiconv_list_length(wf->paragraphs); i++) { |
|
|
494 | para = psiconv_list_get(wf->paragraphs, i); |
|
|
495 | fput_para(of, para, wf); |
|
|
496 | } |
|
|
497 | fputs("</BODY>\n</HTML>\n", of); |
|
|
498 | |
|
|
499 | return fclose(of); |
|
|
500 | } |
|
|
501 | |
|
|
502 | static struct psiconv_fileformat_s ff = |
|
|
503 | { |
|
|
504 | "HTML4", |
|
|
505 | "HTML 4.0 with cascading style sheets", |
|
|
506 | psiconv_gen_html4 |
|
|
507 | }; |
334 | }; |
508 | |
335 | |
|
|
336 | |
509 | void init_html4(void) |
337 | void init_html4(void) |
510 | { |
338 | { |
|
|
339 | int i; |
|
|
340 | for (i = 0; ffs[i].name; i++) |
511 | psiconv_list_add(fileformat_list,&ff); |
341 | psiconv_list_add(fileformat_list,ffs+i); |
512 | } |
342 | } |
513 | |
|
|