2 * sylk-write.c : export sylk
4 * Copyright (C) 2007 Jody Goldberg (jody@gnome.org)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) version 3.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gnumeric-config.h>
24 #include <workbook-priv.h>
25 #include <workbook-view.h>
27 #include <sheet-style.h>
33 #include <parse-util.h>
34 #include <style-border.h>
37 #include <goffice/goffice.h>
39 #include <gsf/gsf-output.h>
40 #include <gsf/gsf-utils.h>
41 #include <gsf/gsf-impl-utils.h>
42 #include <glib/gi18n-lib.h>
46 font_equal (gconstpointer a_
, gconstpointer b_
)
48 GnmStyle
const *a
= a_
;
49 GnmStyle
const *b
= b_
;
51 return g_str_equal (gnm_style_get_font_name (a
), gnm_style_get_font_name (b
)) &&
52 gnm_style_get_font_size (a
) == gnm_style_get_font_size (b
);
56 font_hash (gconstpointer s_
)
58 GnmStyle
const *s
= s_
;
60 return g_str_hash (gnm_style_get_font_name (s
)) ^
61 (guint
)(gnm_style_get_font_size (s
));
68 GnmConventions
*convs
;
76 GHashTable
*format_hash
;
79 GHashTable
*font_hash
;
83 sylk_write (SylkWriter
*state
, char const *str
)
88 /* export the valid chunks */
89 for (p
= str
; *p
; p
= next
) {
90 next
= g_utf8_next_char (p
);
91 c
= g_utf8_get_char (p
);
94 gsf_output_write (state
->output
, p
- str
, str
);
95 gsf_output_write (state
->output
, 2, ";;");
97 } else if ((next
- p
) > 1) {
98 gsf_output_write (state
->output
, p
- str
, str
);
99 gsf_output_write (state
->output
, 1, "?");
102 #warning "handle the magic ascii escaping"
104 gsf_output_write (state
->output
, p
- str
, str
);
108 sylk_output_string (GnmConventionsOut
*out
, GOString
const *string
)
110 g_string_append_c (out
->accum
, '\"');
111 g_string_append (out
->accum
, string
->str
);
112 g_string_append_c (out
->accum
, '\"');
116 cb_sylk_write_cell (GnmCellIter
const *iter
, SylkWriter
*state
)
119 GnmExprTop
const *texpr
;
121 if (iter
->pp
.eval
.row
!= state
->cur_row
)
122 gsf_output_printf (state
->output
, "C;Y%d;X%d",
123 (state
->cur_row
= iter
->pp
.eval
.row
) + 1,
124 iter
->pp
.eval
.col
+ 1);
126 gsf_output_printf (state
->output
, "C;X%d",
127 iter
->pp
.eval
.col
+ 1);
129 v
= iter
->cell
->value
;
131 if (VALUE_IS_STRING (v
)) {
132 gsf_output_write (state
->output
, 3, ";K\"");
133 sylk_write (state
, v
->v_str
.val
->str
);
134 gsf_output_write (state
->output
, 1, "\"");
135 } else if (VALUE_IS_NUMBER (v
) || VALUE_IS_ERROR (v
)) {
136 GString
*res
= g_string_sized_new (10);
137 value_get_as_gstring (v
, res
, state
->convs
);
138 gsf_output_write (state
->output
, 2, ";K");
139 gsf_output_write (state
->output
, res
->len
, res
->str
);
140 g_string_free (res
, TRUE
);
141 } /* ignore the rest */
144 texpr
= iter
->cell
->base
.texpr
;
146 if (gnm_expr_top_is_array_corner (texpr
)) {
148 gnm_expr_top_get_array_size (texpr
, &cols
, &rows
);
150 gsf_output_printf (state
->output
, ";R%d;C%d;M",
151 iter
->pp
.eval
.row
+ rows
,
152 iter
->pp
.eval
.col
+ cols
);
153 } else if (gnm_expr_top_is_array_elem (texpr
, NULL
, NULL
)) {
154 gsf_output_write (state
->output
, 2, ";I");
157 gsf_output_write (state
->output
, 2, ";E");
160 GnmConventionsOut out
;
161 out
.accum
= g_string_new (NULL
);
163 out
.convs
= state
->convs
;
164 gnm_expr_top_as_gstring (texpr
, &out
);
165 sylk_write (state
, out
.accum
->str
);
166 g_string_free (out
.accum
, TRUE
);
169 gsf_output_write (state
->output
, 2, "\r\n");
174 sylk_get_border (GnmStyle
const *style
, GnmStyleElement border
)
176 GnmBorder
*b
= gnm_style_get_border (style
, border
);
177 return b
&& b
->line_type
> GNM_STYLE_BORDER_NONE
;
181 sylk_write_style (SylkWriter
*state
, GnmStyle
const *style
)
187 gsf_output_printf (state
->output
, "F");
189 halign
= gnm_style_get_align_h (style
);
191 case GNM_HALIGN_LEFT
: gsf_output_printf (state
->output
, ";FD0L"); break;
192 case GNM_HALIGN_RIGHT
: gsf_output_printf (state
->output
, ";FD0R"); break;
193 case GNM_HALIGN_CENTER
: gsf_output_printf (state
->output
, ";FD0C"); break;
194 case GNM_HALIGN_FILL
: gsf_output_printf (state
->output
, ";FD0X"); break;
199 fmt
= gnm_style_get_format (style
);
200 n
= GPOINTER_TO_UINT (g_hash_table_lookup (state
->format_hash
, (gpointer
)fmt
));
201 gsf_output_printf (state
->output
, ";P%d", n
);
203 n
= GPOINTER_TO_UINT (g_hash_table_lookup (state
->font_hash
, style
));
204 gsf_output_printf (state
->output
, ";SM%d", n
+ 1);
206 if (gnm_style_get_font_bold (style
))
207 gsf_output_printf (state
->output
, ";SD");
208 if (gnm_style_get_font_italic (style
))
209 gsf_output_printf (state
->output
, ";SI");
210 if (gnm_style_get_pattern (style
) == 5)
211 gsf_output_printf (state
->output
, ";SS");
212 if (sylk_get_border (style
, MSTYLE_BORDER_TOP
))
213 gsf_output_printf (state
->output
, ";ST");
214 if (sylk_get_border (style
, MSTYLE_BORDER_BOTTOM
))
215 gsf_output_printf (state
->output
, ";SB");
216 if (sylk_get_border (style
, MSTYLE_BORDER_LEFT
))
217 gsf_output_printf (state
->output
, ";SL");
218 if (sylk_get_border (style
, MSTYLE_BORDER_RIGHT
))
219 gsf_output_printf (state
->output
, ";SR");
221 // Line not terminated
225 sylk_write_pos (SylkWriter
*state
, int col
, int row
)
227 if (row
!= state
->cur_row
) {
228 state
->cur_row
= row
;
229 gsf_output_printf (state
->output
, ";Y%d", row
+ 1);
231 gsf_output_printf (state
->output
, ";X%d\r\n", col
+ 1);
235 cb_sylk_write_cell_style (GnmCellIter
const *iter
, SylkWriter
*state
)
237 GnmStyle
const *style
= sheet_style_get (state
->sheet
, iter
->pp
.eval
.col
, iter
->pp
.eval
.row
);
239 sylk_write_style (state
, style
);
240 sylk_write_pos (state
, iter
->pp
.eval
.col
, iter
->pp
.eval
.row
);
247 cb_sylk_collect_styles (GnmStyle
const *st
, SylkWriter
*state
)
251 fmt
= gnm_style_get_format (st
);
252 if (!g_hash_table_lookup_extended (state
->format_hash
, fmt
, NULL
, NULL
)) {
253 unsigned n
= state
->formats
->len
;
254 g_hash_table_insert (state
->format_hash
, (gpointer
)fmt
, GUINT_TO_POINTER (n
));
255 g_ptr_array_add (state
->formats
, (gpointer
)fmt
);
258 if (!g_hash_table_lookup_extended (state
->font_hash
, st
, NULL
, NULL
)) {
259 unsigned n
= state
->fonts
->len
;
260 g_hash_table_insert (state
->font_hash
, (gpointer
)st
, GUINT_TO_POINTER (n
));
261 g_ptr_array_add (state
->fonts
, (gpointer
)st
);
267 cb_sylk_collect_cell_styles (G_GNUC_UNUSED gpointer unused
,
268 GnmCell
*cell
, SylkWriter
*state
)
273 sylk_write_sheet (SylkWriter
*state
)
275 Sheet
*sheet
= state
->sheet
;
278 GnmRange whole_sheet
;
280 ColRowInfo
const *cr_def
;
283 /* collect style and font info */
284 range_init_full_sheet (&whole_sheet
, sheet
);
285 extent
= sheet_get_extent (sheet
, FALSE
, TRUE
);
286 col_defs
= sheet_style_most_common (sheet
, TRUE
);
287 sheet_style_get_nondefault_extent (sheet
, &extent
, &whole_sheet
, col_defs
);
289 sheet_style_foreach (sheet
,
290 (GFunc
)cb_sylk_collect_styles
, state
);
291 sheet_cell_foreach (sheet
,
292 (GHFunc
)cb_sylk_collect_cell_styles
, state
);
294 for (ui
= 0; ui
< state
->formats
->len
; ui
++) {
295 GOFormat
const *fmt
= g_ptr_array_index (state
->formats
, ui
);
296 gsf_output_printf (state
->output
, "P;P%s\r\n",
297 go_format_as_XL (fmt
));
299 for (ui
= 0; ui
< state
->fonts
->len
; ui
++) {
300 GnmStyle
const *s
= g_ptr_array_index (state
->fonts
, ui
);
301 gsf_output_printf (state
->output
, "P;E%s;M%d\r\n",
302 gnm_style_get_font_name (s
),
303 (int)(gnm_style_get_font_size (s
) * 20 + 0.5));
307 for (col
= extent
.start
.col
; col
<= extent
.end
.col
; col
++) {
308 sylk_write_style (state
, col_defs
[col
]);
309 gsf_output_printf (state
->output
, ";C%d\r\n", col
+ 1);
314 sheet_foreach_cell_in_range (sheet
, 0, &extent
,
315 (CellIterFunc
) cb_sylk_write_cell_style
, state
);
318 cr_def
= sheet_colrow_get_default (sheet
, TRUE
);
319 for (col
= extent
.start
.col
; col
<= extent
.end
.col
; col
++) {
320 ColRowInfo
*cr
= sheet_col_get (sheet
, col
);
321 if (!cr
|| cr
->size_pts
== cr_def
->size_pts
)
323 gsf_output_printf (state
->output
, "F;W%d %d %d\r\n",
324 col
+ 1, col
+ 1, (int)(cr
->size_pts
/ 7.45 + 0.5));
328 cr_def
= sheet_colrow_get_default (sheet
, FALSE
);
329 for (row
= extent
.start
.row
; row
<= extent
.end
.row
; row
++) {
330 ColRowInfo
*cr
= sheet_row_get (sheet
, row
);
331 if (!cr
|| cr
->size_pts
== cr_def
->size_pts
)
333 gsf_output_printf (state
->output
, "F;M%d;R%d\r\n",
334 (int)(cr
->size_pts
* 20 + 0.5),
338 /* Global Formatting */
339 /* F;P0;DG0G10;SM0;Z;M280;N3 10 */
342 gsf_output_printf (state
->output
, "B;Y%d;X%d;D0 0 %d %d\r\n",
343 extent
.end
.row
+ 1, extent
.end
.col
+ 1,
344 extent
.end
.row
, extent
.end
.col
);
347 gsf_output_printf (state
->output
, "O;%c%d %f",
348 (state
->wb
->iteration
.enabled
? 'A' : 'G'),
349 state
->wb
->iteration
.max_number
,
350 state
->wb
->iteration
.tolerance
);
351 if (!sheet
->convs
->r1c1_addresses
)
352 gsf_output_puts (state
->output
, ";L");
353 if (!state
->wb
->recalc_auto
)
354 gsf_output_puts (state
->output
, ";M");
355 gsf_output_printf (state
->output
, ";V%d",
356 workbook_date_conv (state
->wb
)->use_1904
? 4 : 0);
357 if (sheet
->hide_zero
)
358 gsf_output_puts (state
->output
, ";Z");
359 gsf_output_write (state
->output
, 2, "\r\n");
363 sheet_foreach_cell_in_range (sheet
, CELL_ITER_IGNORE_BLANK
, &extent
,
364 (CellIterFunc
) cb_sylk_write_cell
, state
);
369 static GnmConventions
*
370 sylk_conventions_new (void)
372 GnmConventions
*res
= gnm_conventions_new ();
374 res
->range_sep_colon
= TRUE
;
375 res
->r1c1_addresses
= TRUE
;
376 res
->input
.range_ref
= rangeref_parse
;
377 res
->output
.translated
= FALSE
;
378 res
->output
.string
= sylk_output_string
;
384 sylk_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
385 gconstpointer wb_view
, GsfOutput
*output
);
387 sylk_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
388 gconstpointer wb_view
, GsfOutput
*output
)
393 state
.wb
= wb_view_get_workbook (wb_view
);
394 state
.sheet
= wb_view_cur_sheet (wb_view
);
395 state
.output
= output
;
396 state
.convs
= sylk_conventions_new ();
398 state
.formats
= g_ptr_array_new ();
399 state
.format_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
401 state
.fonts
= g_ptr_array_new ();
402 state
.font_hash
= g_hash_table_new (font_hash
, font_equal
);
404 locale
= gnm_push_C_locale ();
405 gsf_output_puts (output
, "ID;PGnumeric;N;E\r\n");
407 sylk_write_sheet (&state
);
409 gsf_output_puts (output
, "E\r\n");
410 gnm_pop_C_locale (locale
);
411 gnm_conventions_unref (state
.convs
);
413 g_hash_table_destroy (state
.font_hash
);
414 g_ptr_array_free (state
.fonts
, TRUE
);
416 g_hash_table_destroy (state
.format_hash
);
417 g_ptr_array_free (state
.formats
, TRUE
);