1 | /* |
|
|
2 | * gen_html4.c - Part of psiconv, a PSION 5 data formats converter |
1 | /* 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> |
2 | Copyright (c) 1999-2004 Frodo Looijaard <frodol@dds.nl> |
5 | * |
3 | |
6 | * This program is free software; you can redistribute it and/or modify |
4 | 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 |
5 | 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 |
6 | the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
7 | (at your option) any later version. |
10 | * |
8 | |
11 | * This program is distributed in the hope that it will be useful, |
9 | This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
12 | GNU General Public License for more details. |
15 | * |
13 | |
16 | * You should have received a copy of the GNU General Public License |
14 | You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
15 | along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ |
17 | */ |
20 | |
18 | |
21 | #include "config.h" |
19 | #include "config.h" |
22 | #include <stdio.h> |
20 | |
|
|
21 | #include <psiconv/configuration.h> |
|
|
22 | #include <psiconv/data.h> |
|
|
23 | #include "general.h" |
|
|
24 | |
23 | #include <string.h> |
25 | #include <string.h> |
24 | #include <ctype.h> |
|
|
25 | #include <stdlib.h> |
26 | #include <stdlib.h> |
26 | #include "psiconv/data.h" |
|
|
27 | #include "psiconv/list.h" |
|
|
28 | #include "gen.h" |
|
|
29 | #include "psiconv.h" |
|
|
30 | |
27 | |
31 | #ifndef TRUE |
28 | #ifdef DMALLOC |
32 | #define TRUE (0==0) |
29 | #include "dmalloc.h" |
33 | #endif |
30 | #endif |
34 | |
31 | |
35 | /* |
32 | #define TEMPSTR_LEN 100 |
36 | * Various string tables for HTML4 settings |
|
|
37 | */ |
|
|
38 | |
33 | |
39 | /* How to display each character */ |
34 | static void text(const psiconv_config config,psiconv_list list, |
40 | static const char *char_table[0x100] = { |
35 | psiconv_string_t data,const encoding enc); |
41 | /* 0x00 */ "", "", "", "", "", "", "<BR>\n", "<BR>\n", |
36 | static void header(const psiconv_config config, psiconv_list list, |
42 | /* 0x08 */ "\n<HR>\n", "\t", "", "", "", "", "", "", |
37 | const encoding enc); |
43 | /* 0x10 */ " ", "", "", "", "", "", "", "", |
38 | static void footer(const psiconv_config config, psiconv_list list, |
44 | /* 0x18 */ "", "", "", "", "", "", "", "", |
39 | const encoding enc); |
45 | /* 0x20 */ " ", "!", """, "#", "$", "%", "&", "'", |
40 | static void characters(const psiconv_config config, psiconv_list list, |
46 | /* 0x28 */ "(", ")", "*", "+", ",", "-", ".", "/", |
41 | const psiconv_string_t textstr, |
47 | /* 0x30 */ "0", "1", "2", "3", "4", "5", "6", "7", |
42 | const psiconv_character_layout layout,const encoding enc); |
48 | /* 0x38 */ "8", "9", ":", ";", "<", "=", ">", "?", |
43 | static void paragraph(const psiconv_config config, psiconv_list list, |
49 | /* 0x40 */ "@", "A", "B", "C", "D", "E", "F", "G", |
44 | psiconv_paragraph para, const encoding enc); |
50 | /* 0x48 */ "H", "I", "J", "K", "L", "M", "N", "O", |
45 | static void paragraphs(const psiconv_config config, psiconv_list list, |
51 | /* 0x50 */ "P", "Q", "R", "S", "T", "U", "V", "W", |
46 | psiconv_text_and_layout paragraphs, const encoding enc); |
52 | /* 0x58 */ "X", "Y", "Z", "[", "\\", "]", "^", "_", |
47 | static void gen_word(const psiconv_config config, psiconv_list list, |
53 | /* 0x60 */ "`", "a", "b", "c", "d", "e", "f", "g", |
48 | const psiconv_word_f file, const encoding enc); |
54 | /* 0x68 */ "h", "i", "j", "k", "l", "m", "n", "o", |
49 | static void gen_texted(const psiconv_config config, psiconv_list list, |
55 | /* 0x70 */ "p", "q", "r", "s", "t", "u", "v", "w", |
50 | const psiconv_texted_f file, const encoding enc); |
56 | /* 0x78 */ "x", "y", "z", "{", "|", "}", "~", "", |
51 | static int gen_html4(const psiconv_config config, psiconv_list list, |
57 | /* 0x80 */ "", "", "‚", "ƒ", |
52 | const psiconv_file file, const char *dest, |
58 | "„", "…", "†", "‡", |
53 | 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 | |
54 | |
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 | |
55 | |
96 | /* The order of these must match the enum psiconv_justify (data.h) */ |
56 | void text(const psiconv_config config,psiconv_list list, |
97 | static const char *justify_strings[] = { |
57 | psiconv_string_t data,const encoding enc) |
98 | "left", "center", "right", "justify" |
58 | { |
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; |
59 | int i; |
113 | |
60 | for (i = 0; i < psiconv_unicode_strlen(data); i++) { |
114 | for (i = 0; i < strlen(string); i++) |
61 | if ((data[i] == 0x06) || (data[i] == 0x07) || (data[i] == 0x08)) |
115 | if (isalnum(string[i])) |
62 | output_simple_chars(config,list,"<BR>",enc); |
116 | putc(string[i], of); |
63 | else if ((data[i] == 0x0b) || (data[i] == 0x0c)) |
|
|
64 | output_simple_chars(config,list,"-",enc); |
|
|
65 | else if ((data[i] == 0x0f) || (data[i] == 0x09) || (data[i] == 0x0a)) |
|
|
66 | output_simple_chars(config,list," ",enc); |
|
|
67 | else if (data[i] >= 0x20) |
|
|
68 | output_char(config,list,data[i],enc); |
|
|
69 | } |
117 | } |
70 | } |
118 | |
71 | |
119 | static void fput_text(FILE * of, const char *text, int length, int *pwasspace) { |
72 | void header(const psiconv_config config, psiconv_list list, const encoding enc) |
120 | int j; |
73 | { |
121 | int space; |
74 | output_simple_chars(config,list,"<!DOCTYPE html PUBLIC " |
122 | |
75 | "\"-//W3C//DTD HTML 4.01 Transitional//EN\" " |
123 | for (j = 0; j < length; j++) { |
76 | "\"http://www.w3.org/TR/html4/loose.dtd\">\n", |
124 | space = (text[j] == ' '); |
77 | enc); |
125 | if (*pwasspace && space) |
78 | output_simple_chars(config,list,"<HTML>\n",enc); |
126 | fputs(" ", of); |
79 | output_simple_chars(config,list,"<HEAD>\n",enc); |
127 | else |
80 | output_simple_chars(config,list,"<META HTTP-EQUIV=\"Content-Type\" " |
128 | fputs(char_table[(unsigned char) (text[j])], of); |
81 | "CONTENT=\"text/html; charset=",enc); |
129 | *pwasspace = space; |
82 | output_simple_chars(config,list,enc==ENCODING_UTF8?"UTF-8": |
|
|
83 | enc==ENCODING_UCS2?"UTF-16BE": |
|
|
84 | enc==ENCODING_ASCII?"US-ASCII": |
|
|
85 | "",enc); |
|
|
86 | output_simple_chars(config,list,"\">\n",enc); |
|
|
87 | output_simple_chars(config,list,"<TITLE>EPOC32 file " |
|
|
88 | "converted by psiconv</TITLE>\n",enc); |
|
|
89 | output_simple_chars(config,list,"</HEAD>\n",enc); |
|
|
90 | output_simple_chars(config,list,"<BODY>\n",enc); |
|
|
91 | } |
|
|
92 | |
|
|
93 | void footer(const psiconv_config config, psiconv_list list, const encoding enc) |
|
|
94 | { |
|
|
95 | output_simple_chars(config,list,"</BODY>\n",enc); |
|
|
96 | output_simple_chars(config,list,"</HTML>\n",enc); |
|
|
97 | } |
|
|
98 | |
|
|
99 | |
|
|
100 | void characters(const psiconv_config config, psiconv_list list, |
|
|
101 | const psiconv_string_t textstr, |
|
|
102 | const psiconv_character_layout layout,const encoding enc) |
|
|
103 | { |
|
|
104 | char tempstr[TEMPSTR_LEN]; |
|
|
105 | |
|
|
106 | output_simple_chars(config,list,"<FONT face=\"",enc); |
|
|
107 | output_simple_chars(config,list, |
|
|
108 | layout->font->screenfont == psiconv_font_serif?"serif": |
|
|
109 | layout->font->screenfont == psiconv_font_sansserif?"sans-serif": |
|
|
110 | layout->font->screenfont == psiconv_font_nonprop?"monospace": |
|
|
111 | layout->font->screenfont == psiconv_font_misc?"fantasy":"", |
|
|
112 | enc); |
|
|
113 | output_simple_chars(config,list,"\"",enc); |
|
|
114 | |
|
|
115 | if ((layout->font_size < 10) || (layout->font_size >= 13)) { |
|
|
116 | output_simple_chars(config,list," size=",enc); |
|
|
117 | output_simple_chars(config,list, |
|
|
118 | layout->font_size < 8 ?"1": |
|
|
119 | layout->font_size < 10 ?"2": |
|
|
120 | layout->font_size < 13 ?"3": |
|
|
121 | layout->font_size < 17 ?"4": |
|
|
122 | layout->font_size < 24 ?"5": |
|
|
123 | layout->font_size < 36 ?"6":"7",enc); |
|
|
124 | } |
|
|
125 | if ((layout->color->red != 0) || (layout->color->green != 0) || |
|
|
126 | (layout->color->blue != 0)) { |
|
|
127 | snprintf(tempstr,TEMPSTR_LEN,"%02x%02x%02x", |
|
|
128 | layout->color->red,layout->color->green,layout->color->blue); |
|
|
129 | output_simple_chars(config,list," color=#",enc); |
|
|
130 | output_simple_chars(config,list,tempstr,enc); |
|
|
131 | } |
|
|
132 | output_simple_chars(config,list,">",enc); |
|
|
133 | |
|
|
134 | |
|
|
135 | if (layout->italic) |
|
|
136 | output_simple_chars(config,list,"<I>",enc); |
|
|
137 | if (layout->bold) |
|
|
138 | output_simple_chars(config,list,"<B>",enc); |
|
|
139 | if (layout->super_sub != psiconv_normalscript) |
|
|
140 | output_simple_chars(config,list, |
|
|
141 | layout->super_sub == psiconv_superscript?"<SUP>": |
|
|
142 | layout->super_sub == psiconv_subscript?"<SUB>": |
|
|
143 | "",enc); |
|
|
144 | if (layout->strikethrough) |
|
|
145 | output_simple_chars(config,list,"<S>",enc); |
|
|
146 | if (layout->underline) |
|
|
147 | output_simple_chars(config,list,"<U>",enc); |
|
|
148 | |
|
|
149 | text(config,list,textstr,enc); |
|
|
150 | |
|
|
151 | if (layout->underline) |
|
|
152 | output_simple_chars(config,list,"</U>",enc); |
|
|
153 | if (layout->strikethrough) |
|
|
154 | output_simple_chars(config,list,"</S>",enc); |
|
|
155 | if (layout->super_sub != psiconv_normalscript) |
|
|
156 | output_simple_chars(config,list, |
|
|
157 | layout->super_sub == psiconv_superscript?"</SUP>": |
|
|
158 | layout->super_sub == psiconv_subscript?"</SUB>": |
|
|
159 | "",enc); |
|
|
160 | if (layout->bold) |
|
|
161 | output_simple_chars(config,list,"</B>",enc); |
|
|
162 | if (layout->italic) |
|
|
163 | output_simple_chars(config,list,"</I>",enc); |
|
|
164 | output_simple_chars(config,list,"</FONT>",enc); |
|
|
165 | } |
|
|
166 | |
|
|
167 | void paragraph(const psiconv_config config, psiconv_list list, |
|
|
168 | psiconv_paragraph para, const encoding enc) |
|
|
169 | { |
|
|
170 | int i,charnr; |
|
|
171 | psiconv_string_t text; |
|
|
172 | psiconv_in_line_layout layout; |
|
|
173 | |
|
|
174 | |
|
|
175 | output_simple_chars(config,list, |
|
|
176 | para->base_paragraph->bullet->on?"<UL><LI":"<P",enc); |
|
|
177 | |
|
|
178 | if (para->base_paragraph->justify_hor == psiconv_justify_centre) |
|
|
179 | output_simple_chars(config,list," align=center",enc); |
|
|
180 | else if (para->base_paragraph->justify_hor == psiconv_justify_right) |
|
|
181 | output_simple_chars(config,list," align=right",enc); |
|
|
182 | else if (para->base_paragraph->justify_hor == psiconv_justify_full) |
|
|
183 | output_simple_chars(config,list," align=justify",enc); |
|
|
184 | |
|
|
185 | output_simple_chars(config,list,">",enc); |
|
|
186 | |
|
|
187 | if (psiconv_list_length(para->in_lines) == 0) { |
|
|
188 | characters(config,list,para->text,para->base_character,enc); |
|
|
189 | } else { |
|
|
190 | charnr = 0; |
|
|
191 | for (i = 0; i < psiconv_list_length(para->in_lines); i++) { |
|
|
192 | if (!(layout = psiconv_list_get(para->in_lines,i))) { |
|
|
193 | fputs("Internal data structures corruption\n",stderr); |
|
|
194 | exit(1); |
|
|
195 | } |
|
|
196 | if (!(text = malloc(sizeof (*text) * (layout->length + 1)))) { |
|
|
197 | fputs("Out of memory error\n",stderr); |
|
|
198 | exit(1); |
|
|
199 | } |
|
|
200 | memcpy(text,para->text+charnr,layout->length * sizeof(*text)); |
|
|
201 | text[layout->length] = 0; |
|
|
202 | characters(config,list,text,layout->layout,enc); |
|
|
203 | free(text); |
|
|
204 | charnr += layout->length; |
130 | } |
205 | } |
|
|
206 | } |
|
|
207 | output_simple_chars(config, list, |
|
|
208 | para->base_paragraph->bullet->on?"</UL>\n":"\n",enc); |
131 | } |
209 | } |
132 | |
210 | |
133 | static const char *screenfont_name(psiconv_u8 screenfont) |
211 | void paragraphs(const psiconv_config config, psiconv_list list, |
|
|
212 | psiconv_text_and_layout paragraphs, const encoding enc) |
134 | { |
213 | { |
135 | if (screenfont == psiconv_font_sansserif) |
|
|
136 | return "sans-serif"; |
|
|
137 | else if (screenfont == psiconv_font_nonprop) |
|
|
138 | return "monospace"; |
|
|
139 | else if (screenfont == psiconv_font_serif) |
|
|
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; |
214 | int i; |
154 | |
215 | psiconv_paragraph para; |
155 | for (i=0; i < sizeof(sans_font_names) / sizeof(sans_font_names[0]); i++) |
216 | for (i = 0; i < psiconv_list_length(paragraphs); i++) { |
156 | if (!strcmp(font_name, sans_font_names[i])) |
217 | if (!(para = psiconv_list_get(paragraphs,i))) { |
157 | return "sans-serif"; |
218 | fputs("Internal datastructure corruption\n",stderr); |
158 | |
219 | 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 | } |
220 | } |
|
|
221 | paragraph(config,list,para,enc); |
|
|
222 | } |
208 | } |
223 | } |
209 | |
224 | |
210 | /* Paragraph formats */ |
225 | void gen_word(const psiconv_config config, psiconv_list list, |
211 | static int paragraph_layouts_different( |
226 | const psiconv_word_f file, const encoding enc) |
212 | const psiconv_paragraph_layout old, |
|
|
213 | const psiconv_paragraph_layout new) |
|
|
214 | { |
227 | { |
215 | return ((old->space_above != new->space_above) || |
228 | if (!file) |
216 | (old->indent_right != new->indent_right) || |
229 | return; |
217 | (old->space_below != new->space_below) || |
|
|
218 | (old->indent_left != new->indent_left) || |
|
|
219 | (old->indent_first != new->indent_first) || |
|
|
220 | (old->justify_hor != new->justify_hor) || |
|
|
221 | (old->linespacing_exact != new->linespacing_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 | |
230 | |
228 | static void fput_paragraph_layout(FILE * of, |
231 | header(config,list,enc); |
229 | const psiconv_paragraph_layout old, |
232 | paragraphs(config,list,file->paragraphs,enc); |
230 | const psiconv_paragraph_layout new) |
233 | footer(config,list,enc); |
|
|
234 | } |
|
|
235 | |
|
|
236 | |
|
|
237 | void gen_texted(const psiconv_config config, psiconv_list list, |
|
|
238 | const psiconv_texted_f file, const encoding enc) |
231 | { |
239 | { |
232 | if (!old || (old->space_above != new->space_above)) |
240 | header(config,list,enc); |
233 | fprintf(of, "margin-top:%.1fpt;", new->space_above); |
241 | paragraphs(config,list,file->texted_sec->paragraphs,enc); |
234 | if (!old || (old->indent_right != new->indent_right)) |
242 | footer(config,list,enc); |
235 | fprintf(of, "margin-right:%.2fcm;", new->indent_right); |
243 | } |
236 | if (!old || (old->space_below != new->space_below)) |
244 | |
237 | fprintf(of, "margin-bottom:%.1fpt;", new->space_below); |
245 | int gen_html4(const psiconv_config config, psiconv_list list, |
238 | if (!old || |
246 | const psiconv_file file, const char *dest, |
239 | (old->bullet->on != new->bullet->on) || |
247 | const encoding enc) |
240 | (old->bullet->indent != new->bullet->indent) || |
248 | { |
241 | (old->indent_left != new->indent_left) || |
249 | encoding enc1 = enc; |
242 | (old->indent_first != new->indent_first)) { |
250 | |
243 | psiconv_length_t indent = new->indent_first; |
251 | if (enc == ENCODING_PSION) { |
244 | psiconv_length_t margin = new->indent_left; |
252 | fputs("Unsupported encoding\n",stderr); |
245 | /* Bullets with indent set cause strange margin behaviour: */ |
253 | return -1; |
246 | if (new->bullet->on && new->bullet->indent) { |
254 | } else if (enc == ENCODING_ASCII) |
247 | if (indent > 0.0) { |
255 | enc1 = ENCODING_ASCII_HTML; |
248 | margin += indent; |
256 | |
249 | indent = new->indent_left - indent; |
257 | if (file->type == psiconv_word_file) { |
|
|
258 | gen_word(config,list,(psiconv_word_f) file->file,enc1); |
|
|
259 | return 0; |
|
|
260 | } else if (file->type == psiconv_texted_file) { |
|
|
261 | gen_texted(config,list,(psiconv_texted_f) file->file,enc1); |
|
|
262 | return 0; |
|
|
263 | } else |
|
|
264 | return -1; |
|
|
265 | } |
|
|
266 | |
|
|
267 | |
|
|
268 | static struct fileformat_s ffs[] = |
|
|
269 | { |
|
|
270 | { |
|
|
271 | "HTML4", |
|
|
272 | "HTML 4.01 Transitional, without CSS", |
|
|
273 | FORMAT_WORD | FORMAT_TEXTED, |
|
|
274 | gen_html4 |
250 | } |
275 | }, |
251 | } |
276 | { |
252 | fprintf(of, "margin-left:%.2fcm;", margin); |
277 | NULL, |
253 | fprintf(of, "text-indent:%.2fcm;", indent); |
278 | NULL, |
|
|
279 | 0, |
|
|
280 | NULL |
254 | } |
281 | } |
255 | if (!old || (old->justify_hor != new->justify_hor)) |
|
|
256 | fprintf(of, "text-align:%s;", justify_strings[new->justify_hor]); |
|
|
257 | if (!old || (old->linespacing_exact != new->linespacing_exact)) { |
|
|
258 | if (!old || old->linespacing_exact) |
|
|
259 | fputs("line-height:normal;", of); |
|
|
260 | else |
|
|
261 | fprintf(of, "line-height:%.1fpt;", new->linespacing); |
|
|
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->strikethrough != new->strikethrough)); |
|
|
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->strikethrough != new->strikethrough)) { |
|
|
321 | fputs("text-decoration:", of); |
|
|
322 | if (new->strikethrough) |
|
|
323 | fputs("line-through ", of); |
|
|
324 | if (new->underline) |
|
|
325 | fputs("underline", of); |
|
|
326 | else if (!new->strikethrough) |
|
|
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 (wf->page_sec->header->text) { |
|
|
474 | if (psiconv_list_length(wf->page_sec->header->text->paragraphs) > 0) { |
|
|
475 | fputs(" <TITLE>", of); |
|
|
476 | para = psiconv_list_get(wf->page_sec->header->text->paragraphs, 0); |
|
|
477 | i = 0; |
|
|
478 | fput_text(of, para->text, strlen(para->text), &i); |
|
|
479 | fputs("</TITLE>\n", of); |
|
|
480 | } |
|
|
481 | } |
|
|
482 | |
|
|
483 | normal = wf->styles_sec->normal; |
|
|
484 | fputs(" <STYLE TYPE=\"text/css\"><!--\n", of); |
|
|
485 | fprintf(of," BODY { background-color: #%02x%02x%02x }\n", |
|
|
486 | normal->paragraph->back_color->red, |
|
|
487 | normal->paragraph->back_color->green, |
|
|
488 | normal->paragraph->back_color->blue); |
|
|
489 | fput_style(of, NULL, normal, wf); |
|
|
490 | for (i = 0; i < psiconv_list_length(wf->styles_sec->styles); i++) { |
|
|
491 | sty = psiconv_list_get(wf->styles_sec->styles, i); |
|
|
492 | fput_style(of, normal, sty, wf); |
|
|
493 | } |
|
|
494 | fputs(" --></STYLE>\n</HEAD>\n<BODY>\n", of); |
|
|
495 | if (wf->page_sec->header->text) { |
|
|
496 | for (i = 0; i < psiconv_list_length(wf->paragraphs); i++) { |
|
|
497 | para = psiconv_list_get(wf->paragraphs, i); |
|
|
498 | fput_para(of, para, wf); |
|
|
499 | } |
|
|
500 | } |
|
|
501 | fputs("</BODY>\n</HTML>\n", of); |
|
|
502 | |
|
|
503 | return fclose(of); |
|
|
504 | } |
|
|
505 | |
|
|
506 | static struct psiconv_fileformat_s ff = |
|
|
507 | { |
|
|
508 | "HTML4", |
|
|
509 | "HTML 4.0 with cascading style sheets", |
|
|
510 | psiconv_gen_html4 |
|
|
511 | }; |
282 | }; |
512 | |
283 | |
|
|
284 | |
513 | void init_html4(void) |
285 | void init_html4(void) |
514 | { |
286 | { |
|
|
287 | int i; |
|
|
288 | for (i = 0; ffs[i].name; i++) |
515 | psiconv_list_add(fileformat_list,&ff); |
289 | psiconv_list_add(fileformat_list,ffs+i); |
516 | } |
290 | } |
517 | |
|
|