1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * sylk-write.c : export sylk
5 * Copyright (C) 2007 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) version 3.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 #include <gnumeric-config.h>
25 #include "workbook-priv.h"
26 #include "workbook-view.h"
28 #include "sheet-style.h"
34 #include "parse-util.h"
35 #include "style-border.h"
38 #include <goffice/goffice.h>
40 #include <gsf/gsf-output.h>
41 #include <gsf/gsf-utils.h>
42 #include <gsf/gsf-impl-utils.h>
43 #include <glib/gi18n-lib.h>
47 font_equal (gconstpointer a_
, gconstpointer b_
)
49 GnmStyle
const *a
= a_
;
50 GnmStyle
const *b
= b_
;
52 return g_str_equal (gnm_style_get_font_name (a
), gnm_style_get_font_name (b
)) &&
53 gnm_style_get_font_size (a
) == gnm_style_get_font_size (b
);
57 font_hash (gconstpointer s_
)
59 GnmStyle
const *s
= s_
;
61 return g_str_hash (gnm_style_get_font_name (s
)) ^
62 (guint
)(gnm_style_get_font_size (s
));
69 GnmConventions
*convs
;
77 GHashTable
*format_hash
;
80 GHashTable
*font_hash
;
84 sylk_write (SylkWriter
*state
, char const *str
)
89 /* export the valid chunks */
90 for (p
= str
; *p
; p
= next
) {
91 next
= g_utf8_next_char (p
);
92 c
= g_utf8_get_char (p
);
95 gsf_output_write (state
->output
, p
- str
, str
);
96 gsf_output_write (state
->output
, 2, ";;");
98 } else if ((next
- p
) > 1) {
99 gsf_output_write (state
->output
, p
- str
, str
);
100 gsf_output_write (state
->output
, 1, "?");
103 #warning "handle the magic ascii escaping"
105 gsf_output_write (state
->output
, p
- str
, str
);
109 sylk_output_string (GnmConventionsOut
*out
, GOString
const *string
)
111 g_string_append_c (out
->accum
, '\"');
112 g_string_append (out
->accum
, string
->str
);
113 g_string_append_c (out
->accum
, '\"');
117 cb_sylk_write_cell (GnmCellIter
const *iter
, SylkWriter
*state
)
120 GnmExprTop
const *texpr
;
122 if (iter
->pp
.eval
.row
!= state
->cur_row
)
123 gsf_output_printf (state
->output
, "C;Y%d;X%d",
124 (state
->cur_row
= iter
->pp
.eval
.row
) + 1,
125 iter
->pp
.eval
.col
+ 1);
127 gsf_output_printf (state
->output
, "C;X%d",
128 iter
->pp
.eval
.col
+ 1);
130 v
= iter
->cell
->value
;
132 if (VALUE_IS_STRING (v
)) {
133 gsf_output_write (state
->output
, 3, ";K\"");
134 sylk_write (state
, v
->v_str
.val
->str
);
135 gsf_output_write (state
->output
, 1, "\"");
136 } else if (VALUE_IS_NUMBER (v
) || VALUE_IS_ERROR (v
)) {
137 GString
*res
= g_string_sized_new (10);
138 value_get_as_gstring (v
, res
, state
->convs
);
139 gsf_output_write (state
->output
, 2, ";K");
140 gsf_output_write (state
->output
, res
->len
, res
->str
);
141 g_string_free (res
, TRUE
);
142 } /* ignore the rest */
145 texpr
= iter
->cell
->base
.texpr
;
147 if (gnm_expr_top_is_array_corner (texpr
)) {
149 gnm_expr_top_get_array_size (texpr
, &cols
, &rows
);
151 gsf_output_printf (state
->output
, ";R%d;C%d;M",
152 iter
->pp
.eval
.row
+ rows
,
153 iter
->pp
.eval
.col
+ cols
);
154 } else if (gnm_expr_top_is_array_elem (texpr
, NULL
, NULL
)) {
155 gsf_output_write (state
->output
, 2, ";I");
158 gsf_output_write (state
->output
, 2, ";E");
161 GnmConventionsOut out
;
162 out
.accum
= g_string_new (NULL
);
164 out
.convs
= state
->convs
;
165 gnm_expr_top_as_gstring (texpr
, &out
);
166 sylk_write (state
, out
.accum
->str
);
167 g_string_free (out
.accum
, TRUE
);
170 gsf_output_write (state
->output
, 2, "\r\n");
175 sylk_get_border (GnmStyle
const *style
, GnmStyleElement border
)
177 GnmBorder
*b
= gnm_style_get_border (style
, border
);
178 return b
&& b
->line_type
> GNM_STYLE_BORDER_NONE
;
182 sylk_write_style (SylkWriter
*state
, GnmStyle
const *style
)
188 gsf_output_printf (state
->output
, "F");
190 halign
= gnm_style_get_align_h (style
);
192 case GNM_HALIGN_LEFT
: gsf_output_printf (state
->output
, ";FD0L"); break;
193 case GNM_HALIGN_RIGHT
: gsf_output_printf (state
->output
, ";FD0R"); break;
194 case GNM_HALIGN_CENTER
: gsf_output_printf (state
->output
, ";FD0C"); break;
195 case GNM_HALIGN_FILL
: gsf_output_printf (state
->output
, ";FD0X"); break;
200 fmt
= gnm_style_get_format (style
);
201 n
= GPOINTER_TO_UINT (g_hash_table_lookup (state
->format_hash
, (gpointer
)fmt
));
202 gsf_output_printf (state
->output
, ";P%d", n
);
204 n
= GPOINTER_TO_UINT (g_hash_table_lookup (state
->font_hash
, style
));
205 gsf_output_printf (state
->output
, ";SM%d", n
+ 1);
207 if (gnm_style_get_font_bold (style
))
208 gsf_output_printf (state
->output
, ";SD");
209 if (gnm_style_get_font_italic (style
))
210 gsf_output_printf (state
->output
, ";SI");
211 if (gnm_style_get_pattern (style
) == 5)
212 gsf_output_printf (state
->output
, ";SS");
213 if (sylk_get_border (style
, MSTYLE_BORDER_TOP
))
214 gsf_output_printf (state
->output
, ";ST");
215 if (sylk_get_border (style
, MSTYLE_BORDER_BOTTOM
))
216 gsf_output_printf (state
->output
, ";SB");
217 if (sylk_get_border (style
, MSTYLE_BORDER_LEFT
))
218 gsf_output_printf (state
->output
, ";SL");
219 if (sylk_get_border (style
, MSTYLE_BORDER_RIGHT
))
220 gsf_output_printf (state
->output
, ";SR");
222 // Line not terminated
226 sylk_write_pos (SylkWriter
*state
, int col
, int row
)
228 if (row
!= state
->cur_row
) {
229 state
->cur_row
= row
;
230 gsf_output_printf (state
->output
, ";Y%d", row
+ 1);
232 gsf_output_printf (state
->output
, ";X%d\r\n", col
+ 1);
236 cb_sylk_write_cell_style (GnmCellIter
const *iter
, SylkWriter
*state
)
238 GnmStyle
const *style
= sheet_style_get (state
->sheet
, iter
->pp
.eval
.col
, iter
->pp
.eval
.row
);
240 sylk_write_style (state
, style
);
241 sylk_write_pos (state
, iter
->pp
.eval
.col
, iter
->pp
.eval
.row
);
248 cb_sylk_collect_styles (GnmStyle
const *st
, SylkWriter
*state
)
252 fmt
= gnm_style_get_format (st
);
253 if (!g_hash_table_lookup_extended (state
->format_hash
, fmt
, NULL
, NULL
)) {
254 unsigned n
= state
->formats
->len
;
255 g_hash_table_insert (state
->format_hash
, (gpointer
)fmt
, GUINT_TO_POINTER (n
));
256 g_ptr_array_add (state
->formats
, (gpointer
)fmt
);
259 if (!g_hash_table_lookup_extended (state
->font_hash
, st
, NULL
, NULL
)) {
260 unsigned n
= state
->fonts
->len
;
261 g_hash_table_insert (state
->font_hash
, (gpointer
)st
, GUINT_TO_POINTER (n
));
262 g_ptr_array_add (state
->fonts
, (gpointer
)st
);
268 cb_sylk_collect_cell_styles (G_GNUC_UNUSED gpointer unused
,
269 GnmCell
*cell
, SylkWriter
*state
)
274 sylk_write_sheet (SylkWriter
*state
)
276 Sheet
*sheet
= state
->sheet
;
279 GnmRange whole_sheet
;
281 ColRowInfo
const *cr_def
;
284 /* collect style and font info */
285 range_init_full_sheet (&whole_sheet
, sheet
);
286 extent
= sheet_get_extent (sheet
, FALSE
, TRUE
);
287 col_defs
= sheet_style_most_common (sheet
, TRUE
);
288 sheet_style_get_nondefault_extent (sheet
, &extent
, &whole_sheet
, col_defs
);
290 sheet_style_foreach (sheet
,
291 (GFunc
)cb_sylk_collect_styles
, state
);
292 sheet_cell_foreach (sheet
,
293 (GHFunc
)cb_sylk_collect_cell_styles
, state
);
295 for (ui
= 0; ui
< state
->formats
->len
; ui
++) {
296 GOFormat
const *fmt
= g_ptr_array_index (state
->formats
, ui
);
297 gsf_output_printf (state
->output
, "P;P%s\r\n",
298 go_format_as_XL (fmt
));
300 for (ui
= 0; ui
< state
->fonts
->len
; ui
++) {
301 GnmStyle
const *s
= g_ptr_array_index (state
->fonts
, ui
);
302 gsf_output_printf (state
->output
, "P;E%s;M%d\r\n",
303 gnm_style_get_font_name (s
),
304 (int)(gnm_style_get_font_size (s
) * 20 + 0.5));
308 for (col
= extent
.start
.col
; col
<= extent
.end
.col
; col
++) {
309 sylk_write_style (state
, col_defs
[col
]);
310 gsf_output_printf (state
->output
, ";C%d\r\n", col
+ 1);
315 sheet_foreach_cell_in_range (sheet
, 0, &extent
,
316 (CellIterFunc
) cb_sylk_write_cell_style
, state
);
319 cr_def
= sheet_colrow_get_default (sheet
, TRUE
);
320 for (col
= extent
.start
.col
; col
<= extent
.end
.col
; col
++) {
321 ColRowInfo
*cr
= sheet_col_get (sheet
, col
);
322 if (!cr
|| cr
->size_pts
== cr_def
->size_pts
)
324 gsf_output_printf (state
->output
, "F;W%d %d %d\r\n",
325 col
+ 1, col
+ 1, (int)(cr
->size_pts
/ 7.45 + 0.5));
329 cr_def
= sheet_colrow_get_default (sheet
, FALSE
);
330 for (row
= extent
.start
.row
; row
<= extent
.end
.row
; row
++) {
331 ColRowInfo
*cr
= sheet_row_get (sheet
, row
);
332 if (!cr
|| cr
->size_pts
== cr_def
->size_pts
)
334 gsf_output_printf (state
->output
, "F;M%d;R%d\r\n",
335 (int)(cr
->size_pts
* 20 + 0.5),
339 /* Global Formatting */
340 /* F;P0;DG0G10;SM0;Z;M280;N3 10 */
343 gsf_output_printf (state
->output
, "B;Y%d;X%d;D0 0 %d %d\r\n",
344 extent
.end
.row
+ 1, extent
.end
.col
+ 1,
345 extent
.end
.row
, extent
.end
.col
);
348 gsf_output_printf (state
->output
, "O;%c%d %f",
349 (state
->wb
->iteration
.enabled
? 'A' : 'G'),
350 state
->wb
->iteration
.max_number
,
351 state
->wb
->iteration
.tolerance
);
352 if (!sheet
->convs
->r1c1_addresses
)
353 gsf_output_puts (state
->output
, ";L");
354 if (!state
->wb
->recalc_auto
)
355 gsf_output_puts (state
->output
, ";M");
356 gsf_output_printf (state
->output
, ";V%d",
357 workbook_date_conv (state
->wb
)->use_1904
? 4 : 0);
358 if (sheet
->hide_zero
)
359 gsf_output_puts (state
->output
, ";Z");
360 gsf_output_write (state
->output
, 2, "\r\n");
364 sheet_foreach_cell_in_range (sheet
, CELL_ITER_IGNORE_BLANK
, &extent
,
365 (CellIterFunc
) cb_sylk_write_cell
, state
);
370 static GnmConventions
*
371 sylk_conventions_new (void)
373 GnmConventions
*res
= gnm_conventions_new ();
375 res
->range_sep_colon
= TRUE
;
376 res
->r1c1_addresses
= TRUE
;
377 res
->input
.range_ref
= rangeref_parse
;
378 res
->output
.translated
= FALSE
;
379 res
->output
.string
= sylk_output_string
;
385 sylk_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
386 gconstpointer wb_view
, GsfOutput
*output
);
388 sylk_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
389 gconstpointer wb_view
, GsfOutput
*output
)
394 state
.wb
= wb_view_get_workbook (wb_view
);
395 state
.sheet
= wb_view_cur_sheet (wb_view
);
396 state
.output
= output
;
397 state
.convs
= sylk_conventions_new ();
399 state
.formats
= g_ptr_array_new ();
400 state
.format_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
402 state
.fonts
= g_ptr_array_new ();
403 state
.font_hash
= g_hash_table_new (font_hash
, font_equal
);
405 locale
= gnm_push_C_locale ();
406 gsf_output_puts (output
, "ID;PGnumeric;N;E\r\n");
408 sylk_write_sheet (&state
);
410 gsf_output_puts (output
, "E\r\n");
411 gnm_pop_C_locale (locale
);
412 gnm_conventions_unref (state
.convs
);
414 g_hash_table_destroy (state
.font_hash
);
415 g_ptr_array_free (state
.fonts
, TRUE
);
417 g_hash_table_destroy (state
.format_hash
);
418 g_ptr_array_free (state
.formats
, TRUE
);