2 * dif.c: read/write sheets using a DIF encoding.
5 * Kevin Handy <kth@srv.net>
6 * Zbigniew Chyla <cyba@gnome.pl>
8 * Based on ff-csv code.
10 #include <gnumeric-config.h>
11 #include <glib/gi18n-lib.h>
13 #include <libgnumeric.h>
20 #include <goffice/goffice.h>
21 #include <workbook-view.h>
23 #include <gnm-plugin.h>
25 #include <gsf/gsf-input-textline.h>
26 #include <gsf/gsf-output.h>
27 #include <gsf/gsf-utils.h>
31 GNM_PLUGIN_MODULE_HEADER
;
33 #define N_INPUT_LINES_BETWEEN_UPDATES 50
35 void dif_file_open (GOFileOpener
const *fo
, GOIOContext
*io_context
,
36 WorkbookView
*wbv
, GsfInput
*input
);
37 void dif_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
38 WorkbookView
const *wbv
, GsfOutput
*out
);
41 GOIOContext
*io_context
;
43 GsfInputTextline
*input
;
54 static DifInputContext
*
55 dif_input_context_new (GOIOContext
*io_context
, Workbook
*wb
, GsfInput
*input
)
57 DifInputContext
*ctxt
= NULL
;
59 ctxt
= g_new (DifInputContext
, 1);
60 ctxt
->io_context
= io_context
;
62 ctxt
->input
= (GsfInputTextline
*) gsf_input_textline_new (input
);
66 ctxt
->sheet
= workbook_sheet_add (wb
, -1, GNM_DEFAULT_COLS
, GNM_DEFAULT_ROWS
);
67 ctxt
->converter
= g_iconv_open ("UTF-8", "ISO-8859-1");
69 go_io_progress_message (io_context
, _("Reading file..."));
75 dif_input_context_destroy (DifInputContext
*ctxt
)
77 go_io_progress_unset (ctxt
->io_context
);
78 g_object_unref (ctxt
->input
); ctxt
->input
= NULL
;
79 gsf_iconv_close (ctxt
->converter
);
85 dif_get_line (DifInputContext
*ctxt
)
89 if (NULL
== (raw
= gsf_input_textline_ascii_gets (ctxt
->input
)))
93 ctxt
->line
= g_convert_with_iconv (raw
, -1, ctxt
->converter
,
94 NULL
, &ctxt
->line_len
, NULL
);
97 return ctxt
->line
!= NULL
;
101 * Raturns FALSE on EOF.
104 dif_parse_header (DifInputContext
*ctxt
)
107 gchar
*topic
= NULL
, *num_line
= NULL
, *str_line
= NULL
;
111 if (!dif_get_line (ctxt
)) {
115 topic
= g_strdup (ctxt
->line
);
117 if (!dif_get_line (ctxt
)) {
121 num_line
= g_strdup (ctxt
->line
);
123 if (!dif_get_line (ctxt
)) {
127 str_line
= g_strdup (ctxt
->line
);
128 str_line_len
= strlen (str_line
);
130 if (strcmp (topic
, "TABLE") == 0) {
133 if (str_line_len
> 2 && str_line
[0] == '"' && str_line
[str_line_len
- 1] == '"') {
134 str_line
[str_line_len
- 1] = '\0';
139 if (name
[0] != '\0') {
140 /* FIXME - rename the sheet */
142 } else if (strcmp (topic
, "DATA") == 0) {
147 * Other "standard" header entry items are:
148 * SIZE, LABEL, UNITS, TUPLES, VECTORS, COMMENT, MINORSTART,
149 * TRUELENGTH, PERIODICITY, DISPLAYUNITS
162 * Raturns FALSE on EOF.
165 dif_parse_data (DifInputContext
*ctxt
)
167 gboolean too_many_rows
= FALSE
, too_many_columns
= FALSE
;
168 gint row
= -1, col
= 0;
174 if (!dif_get_line (ctxt
))
177 val_type
= atoi (ctxt
->line
);
179 gchar
const *comma
= strchr (ctxt
->line
, ',');
181 go_io_warning (ctxt
->io_context
,
182 _("Syntax error at line %d. Ignoring."),
184 else if (col
> gnm_sheet_get_max_cols (ctxt
->sheet
)) {
185 too_many_columns
= TRUE
;
188 gnm_float num
= gnm_strto (comma
+1, NULL
);
191 if (!dif_get_line (ctxt
))
194 if (0 == strcmp (ctxt
->line
, "V")) { /* V value */
195 v
= value_new_float (num
);
196 } else if (0 == strcmp (ctxt
->line
, "NA")) { /* NA not available res must be O */
197 v
= value_new_error_NA (NULL
);
198 } else if (0 == strcmp (ctxt
->line
, "TRUE")) { /* TRUE bool T res must be 1 */
199 v
= value_new_bool (TRUE
);
200 } else if (0 == strcmp (ctxt
->line
, "FALSE")) { /* FALSE bool F res must be O */
201 v
= value_new_bool (TRUE
);
202 } else if (0 == strcmp (ctxt
->line
, "ERROR")) { /* ERROR err res must be O */
203 go_io_warning (ctxt
->io_context
,
204 _("Unknown value type '%s' at line %d. Ignoring."),
205 ctxt
->line
, ctxt
->line_no
);
209 cell
= sheet_cell_fetch (ctxt
->sheet
, col
, row
);
210 gnm_cell_set_value (cell
, v
);
214 } else if (val_type
== 1) {
215 if (!dif_get_line (ctxt
))
217 if (col
> gnm_sheet_get_max_cols (ctxt
->sheet
)) {
218 too_many_columns
= TRUE
;
221 cell
= sheet_cell_fetch (ctxt
->sheet
, col
, row
);
222 if (ctxt
->line_len
>= 2 &&
223 ctxt
->line
[0] == '"' && ctxt
->line
[ctxt
->line_len
- 1] == '"') {
224 ctxt
->line
[ctxt
->line_len
- 1] = '\0';
225 gnm_cell_set_text (cell
, ctxt
->line
+ 1);
227 gnm_cell_set_text (cell
, ctxt
->line
);
229 } else if (val_type
== -1) {
230 if (!dif_get_line (ctxt
))
232 if (strcmp (ctxt
->line
, "BOT") == 0) {
235 if (row
> gnm_sheet_get_max_rows (ctxt
->sheet
)) {
236 too_many_rows
= TRUE
;
239 } else if (strcmp (ctxt
->line
, "EOD") == 0) {
242 msg
= g_strdup_printf (
243 _("Unknown data value \"%s\" at line %d. Ignoring."),
244 ctxt
->line
, ctxt
->line_no
);
245 g_warning ("%s", msg
);
249 msg
= g_strdup_printf (
250 _("Unknown value type %d at line %d. Ignoring."),
251 val_type
, ctxt
->line_no
);
252 g_warning ("%s", msg
);
254 (void) dif_get_line (ctxt
);
259 g_warning (_("DIF file has more than the maximum number of rows %d. "
260 "Ignoring remaining rows."), gnm_sheet_get_max_rows (ctxt
->sheet
));
262 if (too_many_columns
) {
263 g_warning (_("DIF file has more than the maximum number of columns %d. "
264 "Ignoring remaining columns."), gnm_sheet_get_max_cols (ctxt
->sheet
));
271 dif_parse_sheet (DifInputContext
*ctxt
)
273 GnmLocale
*locale
= gnm_push_C_locale ();
275 if (!dif_parse_header (ctxt
)) {
276 go_io_error_info_set (ctxt
->io_context
, go_error_info_new_printf (
277 _("Unexpected end of file at line %d while reading header."),
279 } else if (!dif_parse_data(ctxt
)) {
280 go_io_error_info_set (ctxt
->io_context
, go_error_info_new_printf (
281 _("Unexpected end of file at line %d while reading data."),
285 gnm_pop_C_locale (locale
);
289 dif_file_open (GOFileOpener
const *fo
, GOIOContext
*io_context
,
290 WorkbookView
*wbv
, GsfInput
*input
)
292 Workbook
*wb
= wb_view_get_workbook (wbv
);
293 DifInputContext
*ctxt
= dif_input_context_new (io_context
, wb
, input
);
295 workbook_set_saveinfo (wb
, GO_FILE_FL_MANUAL_REMEMBER
,
296 go_file_saver_for_id ("Gnumeric_dif:dif"));
298 dif_parse_sheet (ctxt
);
299 if (go_io_error_occurred (io_context
))
300 go_io_error_push (io_context
,
301 go_error_info_new_str (_("Error while reading DIF file.")));
302 dif_input_context_destroy (ctxt
);
303 } else if (!go_io_error_occurred (io_context
))
304 go_io_error_unknown (io_context
);
308 * Write _current_ sheet of the workbook to a DIF format file
311 dif_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
312 WorkbookView
const *wbv
, GsfOutput
*out
)
320 sheet
= wb_view_cur_sheet (wbv
);
322 go_io_error_string (io_context
, _("Cannot get default sheet."));
326 r
= sheet_get_extent (sheet
, FALSE
, TRUE
);
328 /* Write out the standard headers */
329 gsf_output_puts (out
, "TABLE\n" "0,1\n" "\"GNUMERIC\"\n");
330 gsf_output_printf (out
, "VECTORS\n" "0,%d\n" "\"\"\n", r
.end
.col
+1);
331 gsf_output_printf (out
, "TUPLES\n" "0,%d\n" "\"\"\n", r
.end
.row
+1);
332 gsf_output_puts (out
, "DATA\n" "0,0\n" "\"\"\n");
334 locale
= gnm_push_C_locale ();
336 /* Process all cells */
337 for (row
= r
.start
.row
; ok
&& row
<= r
.end
.row
; row
++) {
338 gsf_output_puts (out
, "-1,0\n" "BOT\n");
339 for (col
= r
.start
.col
; col
<= r
.end
.col
; col
++) {
340 GnmCell
*cell
= sheet_cell_get (sheet
, col
, row
);
341 if (gnm_cell_is_empty (cell
)) {
342 gsf_output_puts(out
, "1,0\n" "\"\"\n");
343 } else if (VALUE_IS_BOOLEAN (cell
->value
)) {
344 if (value_get_as_checked_bool (cell
->value
))
345 gsf_output_puts(out
, "0,1\n" "TRUE\n");
347 gsf_output_puts(out
, "0,0\n" "FALSE\n");
348 } else if (VALUE_IS_ERROR (cell
->value
)) {
349 if (value_error_classify (cell
->value
) == GNM_ERROR_NA
)
350 gsf_output_puts(out
, "0,0\n" "NA\n");
352 gsf_output_puts(out
, "0,0\n" "ERROR\n");
353 } else if (VALUE_IS_FLOAT (cell
->value
))
354 gsf_output_printf (out
, "0,%" GNM_FORMAT_g
"\n" "V\n",
355 value_get_as_float (cell
->value
));
357 gchar
*str
= gnm_cell_get_rendered_text (cell
);
358 ok
= gsf_output_printf (out
,
366 gsf_output_puts (out
, "-1,0\n" "EOD\n");
368 gnm_pop_C_locale (locale
);
371 go_io_error_string (io_context
, _("Error while saving DIF file."));