2 * ssconvert.c: A wrapper application to convert spreadsheet formats
5 * Jon Kåre Hellan <hellan@acm.org>
6 * Morten Welinder <terra@gnome.org>
7 * Jody Goldberg <jody@gnome.org>
9 * Copyright (C) 2002-2003 Jody Goldberg
10 * Copyright (C) 2006-2018 Morten Welinder (terra@gnome.org)
12 #include <gnumeric-config.h>
13 #include <glib/gi18n.h>
16 #include <parse-util.h>
17 #include <application.h>
19 #include <workbook-priv.h>
20 #include <workbook-control.h>
22 #include <dependent.h>
23 #include <expr-name.h>
24 #include <libgnumeric.h>
28 #include <gnumeric-paths.h>
29 #include <gnm-plugin.h>
30 #include <command-context.h>
31 #include <command-context-stderr.h>
32 #include <workbook-view.h>
33 #include <gnumeric-conf.h>
34 #include <tools/analysis-tools.h>
35 #include <dialogs/dialogs.h>
36 #include <goffice/goffice.h>
37 #include <gsf/gsf-utils.h>
39 #ifdef HAVE_SYS_RESOURCE_H
40 #include <sys/resource.h>
43 // Sheets that an exporter should export.
44 #define SHEET_SELECTION_KEY "sheet-selection"
46 // Sheets user has specified as export options
47 #define SSCONVERT_SHEET_SET_KEY "ssconvert-sheets"
49 static gboolean ssconvert_show_version
= FALSE
;
50 static gboolean ssconvert_verbose
= FALSE
;
51 static gboolean ssconvert_list_exporters
= FALSE
;
52 static gboolean ssconvert_list_importers
= FALSE
;
53 static gboolean ssconvert_one_file_per_sheet
= FALSE
;
54 static gboolean ssconvert_recalc
= FALSE
;
55 static gboolean ssconvert_solve
= FALSE
;
56 static char *ssconvert_resize
= NULL
;
57 static char *ssconvert_range
= NULL
;
58 static char *ssconvert_import_encoding
= NULL
;
59 static char *ssconvert_import_id
= NULL
;
60 static char *ssconvert_export_id
= NULL
;
61 static char *ssconvert_export_options
= NULL
;
62 static char *ssconvert_merge_target
= NULL
;
63 static char **ssconvert_goal_seek
= NULL
;
64 static char **ssconvert_tool_test
= NULL
;
66 static const GOptionEntry ssconvert_options
[] = {
69 0, G_OPTION_ARG_NONE
, &ssconvert_show_version
,
70 N_("Display program version"),
76 0, G_OPTION_ARG_NONE
, &ssconvert_verbose
,
77 N_("Be somewhat more verbose during conversion"),
81 /* ---------------------------------------- */
84 "import-encoding", 'E',
85 0, G_OPTION_ARG_STRING
, &ssconvert_import_encoding
,
86 N_("Optionally specify an encoding for imported content"),
92 0, G_OPTION_ARG_STRING
, &ssconvert_import_id
,
93 N_("Optionally specify which importer to use"),
99 0, G_OPTION_ARG_NONE
, &ssconvert_list_importers
,
100 N_("List the available importers"),
104 /* ---------------------------------------- */
108 0, G_OPTION_ARG_STRING
, &ssconvert_merge_target
,
109 N_("Merge listed files (all same format) to make this file"),
115 0, G_OPTION_ARG_STRING
, &ssconvert_export_id
,
116 N_("Optionally specify which exporter to use"),
121 "export-options", 'O',
122 0, G_OPTION_ARG_STRING
, &ssconvert_export_options
,
123 N_("Detailed instructions for the chosen exporter"),
129 0, G_OPTION_ARG_NONE
, &ssconvert_list_exporters
,
130 N_("List the available exporters"),
135 "export-file-per-sheet", 'S',
136 0, G_OPTION_ARG_NONE
, &ssconvert_one_file_per_sheet
,
137 N_("Export a file for each sheet if the exporter only supports one sheet at a time"),
143 0, G_OPTION_ARG_NONE
, &ssconvert_recalc
,
144 N_("Recalculate all cells before writing the result"),
150 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING
, &ssconvert_resize
,
151 N_("Resize to given ROWSxCOLS"),
156 /* ---------------------------------------- */
158 /* For now these are for INTERNAL GNUMERIC USE ONLY. */
161 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING
, &ssconvert_range
,
162 N_("The range to export"),
168 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING_ARRAY
, &ssconvert_goal_seek
,
169 N_("Goal seek areas"),
175 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_NONE
, &ssconvert_solve
,
176 N_("Run the solver"),
182 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING_ARRAY
, &ssconvert_tool_test
,
183 N_("Tool test specs"),
187 /* ---------------------------------------- */
192 static GnmRangeRef
const *
193 setup_range (GObject
*obj
, const char *key
, Workbook
*wb
, const char *rtxt
)
197 GnmRangeRef rr
, *rrc
;
200 pp
.sheet
= workbook_sheet_by_index (wb
, 0);
204 end
= rangeref_parse (&rr
, rtxt
, &pp
, gnm_conventions_default
);
205 if (!end
|| end
== rtxt
|| *end
!= 0) {
206 g_printerr ("Invalid range specified.\n");
210 rrc
= g_memdup (&rr
, sizeof (rr
));
211 g_object_set_data_full (obj
, key
, rrc
, g_free
);
216 struct cb_handle_export_options
{
222 cb_handle_export_options (const char *key
, const char *value
,
223 GError
**err
, gpointer user_
)
225 struct cb_handle_export_options
*user
= user_
;
226 return gnm_file_saver_common_export_option (user
->fs
, user
->wb
,
231 handle_export_options (GOFileSaver
*fs
, Workbook
*wb
)
237 if (!ssconvert_export_options
)
240 sig
= g_signal_lookup ("set-export-options", G_TYPE_FROM_INSTANCE (fs
));
241 if (g_signal_handler_find (fs
, G_SIGNAL_MATCH_ID
,
242 sig
, 0, NULL
, NULL
, NULL
))
243 fail
= go_file_saver_set_export_options
245 ssconvert_export_options
,
248 struct cb_handle_export_options data
;
251 fail
= go_parse_key_value (ssconvert_export_options
, &err
,
252 cb_handle_export_options
, &data
);
256 g_printerr ("ssconvert: %s\n", err
258 : _("Cannot parse export options."));
265 // Check that the sheet selection, if any, matches the file saver's
268 validate_sheet_selection (GOFileSaver
*fs
, Workbook
*wb
)
270 GOFileSaveScope fsscope
= go_file_saver_get_save_scope (fs
);
271 gboolean fs_sheet_selection
;
273 g_object_get (G_OBJECT (fs
),
274 "sheet-selection", &fs_sheet_selection
, NULL
);
276 if (ssconvert_one_file_per_sheet
) {
279 case GO_FILE_SAVE_WORKBOOK
:
280 ok
= fs_sheet_selection
;
282 case GO_FILE_SAVE_SHEET
:
285 case GO_FILE_SAVE_RANGE
:
291 g_printerr (_("Selected exporter (%s) does not have the ability to split a workbook into sheets.\n"),
292 go_file_saver_get_id (fs
));
296 GPtrArray
*sheets
= g_object_get_data (G_OBJECT (wb
),
297 SSCONVERT_SHEET_SET_KEY
);
299 case GO_FILE_SAVE_WORKBOOK
:
300 case GO_FILE_SAVE_RANGE
:
302 if (sheets
&& !fs_sheet_selection
) {
303 g_printerr (_("Selected exporter (%s) does not have the ability to export a subset of sheets.\n"),
304 go_file_saver_get_id (fs
));
308 case GO_FILE_SAVE_SHEET
:
309 if (sheets
&& sheets
->len
!= 1) {
310 g_printerr (_("Selected exporter (%s) can only export one sheet at a time.\n"),
311 go_file_saver_get_id (fs
));
322 typedef gchar
const *(*get_desc_f
)(const void *);
325 by_his_id (gconstpointer a
, gconstpointer b
, gpointer user
)
327 get_desc_f get_his_id
= user
;
328 return strcmp (get_his_id (a
), get_his_id (b
));
332 list_them (GList
*them
,
333 get_desc_f get_his_id
,
334 get_desc_f get_his_description
)
336 GList
*them_copy
= g_list_copy (them
);
339 gboolean interactive
;
341 them_copy
= g_list_sort_with_data (them_copy
, by_his_id
, get_his_id
);
343 for (ptr
= them_copy
; ptr
; ptr
= ptr
->next
) {
344 GObject
*obj
= ptr
->data
;
347 g_object_get (obj
, "interactive-only", &interactive
, NULL
);
351 id
= get_his_id (obj
);
353 len
= MAX (len
, strlen (id
));
356 g_printerr ("%-*s | %s\n", len
,
357 /* Translate these? */
360 for (ptr
= them_copy
; ptr
; ptr
= ptr
->next
) {
361 GObject
*obj
= ptr
->data
;
364 g_object_get (obj
, "interactive-only", &interactive
, NULL
);
368 id
= get_his_id (obj
);
370 g_printerr ("%-*s | %s\n", len
,
372 (*get_his_description
) (ptr
->data
));
375 g_list_free (them_copy
);
379 * Read the files we're going to merge and return a list of Workbooks.
382 read_files_to_merge (const char *inputs
[], GOFileOpener
*fo
,
383 GOIOContext
*io_context
, GOCmdContext
*cc
)
388 const char *fname
= *inputs
;
389 char *uri
= go_shell_arg_to_uri (fname
);
391 workbook_view_new_from_uri (uri
, fo
, io_context
,
392 ssconvert_import_encoding
);
396 if (go_io_error_occurred (io_context
)) {
397 g_slist_free_full (wbs
, g_object_unref
);
404 wbs
= g_slist_prepend (wbs
, wb_view_get_workbook (wbv
));
407 return g_slist_reverse (wbs
);
411 * Look at a set of workbooks, and pick a sheet size that would
412 * be good for sheets in a workbook merging them all.
415 suggest_size (GSList
*wbs
, int *csuggest
, int *rsuggest
)
421 for (l
= wbs
; l
; l
= l
->next
) {
422 Workbook
*wb
= l
->data
;
424 WORKBOOK_FOREACH_SHEET (wb
, sheet
, {
425 int r
= gnm_sheet_get_max_rows (sheet
);
426 int c
= gnm_sheet_get_max_cols (sheet
);
427 if (r
> rmax
) rmax
= r
;
428 if (c
> cmax
) cmax
= c
;
432 gnm_sheet_suggest_size (&cmax
, &rmax
);
438 cb_collect_names (G_GNUC_UNUSED gconstpointer key
,
442 if (!expr_name_is_active (nexpr
))
444 *plist
= g_slist_prepend (*plist
, expr_name_ref (nexpr
));
447 /* Append the sheets of workbook wb2 to workbook wb. Resize sheets
448 if necessary. Fix workbook links in sheet if necessary.
449 Merge names in workbook scope (conflicts result in an error). */
451 merge_single (Workbook
*wb
, Workbook
*wb2
,
455 /* Move names with workbook scope in wb2 over to wb */
456 GSList
*names
= g_slist_sort (gnm_named_expr_collection_list (wb2
->names
),
457 (GCompareFunc
)expr_name_cmp_by_name
);
460 for (p
= names
; p
; p
= p
->next
) {
461 GnmNamedExpr
*nexpr
= p
->data
;
462 const char *name
= expr_name_name (nexpr
);
463 GnmNamedExpr
*nexpr2
;
465 GnmParsePos newpos
= nexpr
->pos
;
467 if (!expr_name_is_active (nexpr
))
470 if (nexpr
->pos
.wb
!= wb2
|| nexpr
->pos
.sheet
!= NULL
)
473 /* Check for clash with existing name */
475 parse_pos_init (&pp
, wb
, NULL
, 0, 0);
476 nexpr2
= expr_name_lookup (&pp
, name
);
477 if (nexpr2
/* FIXME: && nexpr2-is-not-the-same-as-nexpr */) {
478 g_printerr (_("Name conflict during merge: '%s' appears twice at workbook scope.\n"),
480 g_slist_free (names
);
484 /* Move name scope to workbook wb */
486 expr_name_set_pos (nexpr
, &newpos
);
488 g_slist_free (names
);
490 while (workbook_sheet_count (wb2
) > 0) {
491 /* Remove sheet from incoming workbook */
492 Sheet
*sheet
= workbook_sheet_by_index (wb2
, 0);
493 int loc
= workbook_sheet_count (wb
);
497 GSList
*names
= NULL
;
499 g_object_ref (sheet
);
500 workbook_sheet_delete (sheet
);
501 sheet
->workbook
= wb
;
503 /* Fix names that reference the old workbook */
504 gnm_sheet_foreach_name (sheet
, (GHFunc
)cb_collect_names
, &names
);
506 GnmNamedExpr
*nexpr
= names
->data
;
507 names
= g_slist_delete_link (names
, names
);
510 GnmParsePos newpos
= nexpr
->pos
;
512 expr_name_set_pos (nexpr
, &newpos
);
514 expr_name_unref (nexpr
);
517 undo
= gnm_sheet_resize (sheet
, cmax
, rmax
, cc
, &err
);
519 g_object_unref (undo
);
521 /* Pick a free sheet name */
522 sheet_name
= workbook_sheet_get_free_name
523 (wb
, sheet
->name_unquoted
, FALSE
, TRUE
);
524 g_object_set (sheet
, "name", sheet_name
, NULL
);
527 /* Insert and revive the sheet */
528 workbook_sheet_attach_at_pos (wb
, sheet
, loc
);
529 dependents_revive_sheet (sheet
);
530 g_object_unref (sheet
);
536 /* Merge a collection of workbooks into one. */
538 merge (Workbook
*wb
, char const *inputs
[],
539 GOFileOpener
*fo
, GOIOContext
*io_context
, GOCmdContext
*cc
)
545 wbs
= read_files_to_merge (inputs
, fo
, io_context
, cc
);
546 if (go_io_error_occurred (io_context
)) {
547 go_io_error_display (io_context
);
551 suggest_size (wbs
, &cmax
, &rmax
);
553 for (l
= wbs
; l
; l
= l
->next
) {
554 Workbook
*wb2
= l
->data
;
555 const char *uri
= go_doc_get_uri (GO_DOC (wb2
));
557 g_printerr (_("Adding sheets from %s\n"), uri
);
559 result
= merge_single (wb
, wb2
, cmax
, rmax
, cc
);
564 g_slist_free_full (wbs
, g_object_unref
);
569 resolve_template (const char *template, Sheet
*sheet
, unsigned n
)
571 GString
*s
= g_string_new (NULL
);
576 char *res
= go_shell_arg_to_uri (s
->str
);
577 g_string_free (s
, TRUE
);
586 g_string_append_printf (s
, "%u", n
);
589 g_string_append (s
, sheet
->name_unquoted
);
592 g_string_append_c (s
, '%');
598 g_string_append_c (s
, *template);
605 run_solver (Sheet
*sheet
, WorkbookView
*wbv
)
607 GnmSolverParameters
*params
= sheet
->solver_parameters
;
609 WorkbookControl
*wbc
;
610 GnmSolver
*sol
= NULL
;
612 wbc
= g_object_new (GNM_WBC_TYPE
, NULL
);
613 wb_control_set_view (wbc
, wbv
, NULL
);
615 /* Pick a functional algorithm. */
616 if (!gnm_solver_factory_functional (params
->options
.algorithm
,
619 for (l
= gnm_solver_db_get (); l
; l
= l
->next
) {
620 GnmSolverFactory
*factory
= l
->data
;
621 if (params
->options
.model_type
!= factory
->type
)
623 if (gnm_solver_factory_functional (factory
, NULL
)) {
624 gnm_solver_param_set_algorithm (params
,
631 if (!gnm_solver_param_valid (params
, &err
))
634 sol
= params
->options
.algorithm
635 ? gnm_solver_factory_create (params
->options
.algorithm
, params
)
638 g_set_error (&err
, go_error_invalid (), 0,
639 _("Failed to create solver"));
643 if (!gnm_solver_start (sol
, wbc
, &err
))
646 while (!gnm_solver_finished (sol
)) {
647 g_main_context_iteration (NULL
, TRUE
);
650 switch (sol
->status
) {
651 case GNM_SOLVER_STATUS_DONE
:
653 case GNM_SOLVER_STATUS_CANCELLED
:
654 g_printerr (_("Solver reached time or iteration limit\n"));
657 g_set_error (&err
, go_error_invalid (), 0,
658 _("Solver ran, but failed"));
662 gnm_solver_store_result (sol
);
664 gnm_solver_create_report (sol
, "Solver");
668 g_object_unref (sol
);
670 g_printerr (_("Solver: %s\n"), err
->message
);
675 #define GET_ARG(conv_,name_,def_) (g_hash_table_lookup_extended(args,(name_),NULL,&arg) ? conv_((const char *)arg) : (def_))
676 #define RANGE_ARG(s_) value_new_cellrange_str(sheet,(s_))
677 #define RANGE_LIST_ARG(s_) g_slist_prepend (NULL, value_new_cellrange_str(sheet,(s_)))
678 #define SHEET_ARG(s_) workbook_sheet_by_name(wb,(s_))
681 run_tool_test (const char *tool
, char **argv
, WorkbookView
*wbv
)
684 WorkbookControl
*wbc
;
686 data_analysis_output_t
*dao
;
687 analysis_tool_engine engine
;
694 * Arguments in argv are of the form key:value.
695 * Make a hash for those.
697 args
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
698 (GDestroyNotify
)g_free
,
699 (GDestroyNotify
)g_free
);
700 for (i
= 0; argv
[i
]; i
++) {
701 const char *s
= argv
[i
];
702 const char *colon
= strchr (s
, ':');
704 g_printerr ("Ignoring tool test argument \"%s\"\n", s
);
707 g_hash_table_replace (args
, g_strndup (s
, colon
- s
),
708 g_strdup (colon
+ 1));
711 wb
= wb_view_get_workbook (wbv
);
712 wbc
= g_object_new (GNM_WBC_TYPE
, NULL
);
713 wb_control_set_view (wbc
, wbv
, NULL
);
715 sheet
= GET_ARG (SHEET_ARG
, "sheet", wb_view_cur_sheet (wbv
));
717 if (g_str_equal (tool
, "regression")) {
718 analysis_tools_data_regression_t
*data
=
719 g_new0 (analysis_tools_data_regression_t
, 1);
721 data
->base
.wbc
= wbc
;
722 data
->base
.range_1
= GET_ARG (RANGE_ARG
, "x", value_new_error_REF (NULL
));
723 data
->base
.range_2
= GET_ARG (RANGE_ARG
, "y", value_new_error_REF (NULL
));
724 data
->base
.labels
= GET_ARG (atoi
, "labels", FALSE
);
725 data
->base
.alpha
= GET_ARG (atof
, "alpha", 0.05);
726 data
->group_by
= GET_ARG ((group_by_t
), "grouped-by", GROUPED_BY_COL
);
727 data
->intercept
= GET_ARG (atoi
, "intercept", TRUE
);
728 data
->multiple_regression
= GET_ARG (atoi
, "multiple", TRUE
);
729 data
->multiple_y
= GET_ARG (atoi
, "multiple-y", FALSE
);
730 data
->residual
= GET_ARG (atoi
, "residual", TRUE
);
732 engine
= analysis_tool_regression_engine
;
734 } else if (g_str_equal (tool
, "anova")) {
735 analysis_tools_data_anova_single_t
*data
=
736 g_new0 (analysis_tools_data_anova_single_t
, 1);
738 data
->base
.input
= GET_ARG (RANGE_LIST_ARG
, "data", NULL
);
739 data
->base
.labels
= GET_ARG (atoi
, "labels", FALSE
);
740 data
->base
.group_by
= GET_ARG ((group_by_t
), "grouped-by", GROUPED_BY_COL
);
741 data
->alpha
= GET_ARG (atof
, "alpha", 0.05);
743 engine
= analysis_tool_anova_single_engine
;
746 g_printerr ("no test for tool \"%s\"\n", tool
);
750 dao
= dao_init_new_sheet (NULL
);
751 dao
->put_formulas
= TRUE
;
752 cmd_analysis_tool (wbc
, sheet
, dao
, specs
, engine
, TRUE
);
754 g_hash_table_destroy (args
);
764 do_split_save (GOFileSaver
*fs
, WorkbookView
*wbv
,
765 const char *outarg
, GOCmdContext
*cc
)
767 Workbook
*wb
= wb_view_get_workbook (wbv
);
772 GPtrArray
*sheet_sel
=
773 g_object_get_data (G_OBJECT (wb
), SHEET_SELECTION_KEY
);
774 gboolean fs_sheet_selection
;
776 g_object_get (G_OBJECT (fs
), "sheet-selection", &fs_sheet_selection
, NULL
);
778 template = strchr (outarg
, '%')
780 : g_strconcat (outarg
, ".%n", NULL
);
782 sheets
= g_object_get_data (G_OBJECT (wb
),
783 SSCONVERT_SHEET_SET_KEY
);
785 g_ptr_array_ref (sheets
);
788 sheets
= g_ptr_array_new ();
789 for (i
= 0; i
< workbook_sheet_count (wb
); i
++) {
790 Sheet
*sheet
= workbook_sheet_by_index (wb
, i
);
791 g_ptr_array_add (sheets
, sheet
);
795 for (ui
= 0; ui
< sheets
->len
; ui
++) {
796 Sheet
*sheet
= g_ptr_array_index (sheets
, ui
);
797 char *tmpfile
= resolve_template (template, sheet
, ui
);
798 int oldn
= sheet
->index_in_wb
;
800 g_ptr_array_set_size (sheet_sel
, 0);
801 g_ptr_array_add (sheet_sel
, sheet
);
803 if (!fs_sheet_selection
) {
805 * HACK: (bug 694408).
807 * We don't have a good way of specifying the
808 * sheet. Move it to the front and select
809 * it. That will at least make cvs and txt
810 * exporters reliably find it.
812 workbook_sheet_move (sheet
, -oldn
);
813 wb_view_sheet_focus (wbv
, sheet
);
816 res
= !workbook_view_save_as (wbv
, fs
, tmpfile
, cc
);
818 if (!fs_sheet_selection
)
819 workbook_sheet_move (sheet
, +oldn
);
827 g_ptr_array_unref (sheets
);
833 convert (char const *inarg
, char const *outarg
, char const *mergeargs
[],
837 GOFileSaver
*fs
= NULL
;
838 GOFileOpener
*fo
= NULL
;
839 char *infile
= go_shell_arg_to_uri (inarg
);
840 char *outfile
= outarg
? go_shell_arg_to_uri (outarg
) : NULL
;
842 GOIOContext
*io_context
= NULL
;
844 GOFileSaveScope fsscope
;
845 GPtrArray
*sheet_sel
= NULL
;
846 GnmRangeRef
const *range
= NULL
;
848 if (ssconvert_export_id
!= NULL
) {
849 fs
= go_file_saver_for_id (ssconvert_export_id
);
852 g_printerr (_("Unknown exporter '%s'.\n"
853 "Try --list-exporters to see a list of possibilities.\n"),
854 ssconvert_export_id
);
856 } else if (outfile
== NULL
&&
857 !ssconvert_one_file_per_sheet
&&
858 go_file_saver_get_extension (fs
) != NULL
) {
859 char const *ext
= gsf_extension_pointer (infile
);
861 GString
*res
= g_string_new (NULL
);
862 g_string_append_len (res
, infile
, ext
- infile
);
863 g_string_append (res
, go_file_saver_get_extension(fs
));
864 outfile
= g_string_free (res
, FALSE
);
868 if (outfile
!= NULL
) {
869 fs
= go_file_saver_for_file_name (outfile
);
872 g_printerr (_("Unable to guess exporter to use for '%s'.\n"
873 "Try --list-exporters to see a list of possibilities.\n"),
877 if (ssconvert_verbose
)
878 g_printerr (_("Using exporter %s\n"),
879 go_file_saver_get_id (fs
));
883 if (outfile
== NULL
) {
884 g_printerr (_("An output file name or an explicit export type is required.\n"
885 "Try --list-exporters to see a list of possibilities.\n"));
890 if (ssconvert_import_id
!= NULL
) {
891 fo
= go_file_opener_for_id (ssconvert_import_id
);
894 g_printerr (_("Unknown importer '%s'.\n"
895 "Try --list-importers to see a list of possibilities.\n"),
896 ssconvert_import_id
);
903 fsscope
= go_file_saver_get_save_scope (fs
);
905 io_context
= go_io_context_new (cc
);
906 if (mergeargs
== NULL
) {
907 wbv
= workbook_view_new_from_uri (infile
, fo
,
909 ssconvert_import_encoding
);
911 wbv
= workbook_view_new (NULL
);
914 if (go_io_error_occurred (io_context
)) {
915 go_io_error_display (io_context
);
918 } else if (wbv
== NULL
) {
919 g_printerr (_("Loading %s failed\n"), infile
);
924 wb
= wb_view_get_workbook (wbv
);
926 res
= handle_export_options (fs
, wb
);
930 res
= validate_sheet_selection (fs
, wb
);
934 if (mergeargs
!= NULL
) {
935 if (merge (wb
, mergeargs
, fo
, io_context
, cc
))
939 if (ssconvert_goal_seek
) {
941 Sheet
*sheet
= wb_view_cur_sheet (wbv
);
943 for (i
= 0; ssconvert_goal_seek
[i
]; i
++) {
944 setup_range (G_OBJECT (sheet
),
945 "ssconvert-goal-seek",
947 ssconvert_goal_seek
[i
]);
948 dialog_goal_seek (NULL
, sheet
);
952 if (ssconvert_solve
) {
953 Sheet
*sheet
= wb_view_cur_sheet (wbv
);
954 run_solver (sheet
, wbv
);
957 if (ssconvert_tool_test
&& ssconvert_tool_test
[0]) {
958 run_tool_test (ssconvert_tool_test
[0],
959 ssconvert_tool_test
+ 1,
963 if (ssconvert_resize
) {
965 if (sscanf (ssconvert_resize
, "%dx%d", &rows
, &cols
) == 2) {
968 if (ssconvert_verbose
)
969 g_printerr (_("Resizing to %dx%d\n"),
972 for (n
= workbook_sheet_count (wb
) - 1;
976 Sheet
*sheet
= workbook_sheet_by_index (wb
, n
);
978 gnm_sheet_resize (sheet
, cols
, rows
,
981 g_printerr (_("Resizing of sheet %s failed\n"),
982 sheet
->name_unquoted
);
983 g_object_unref (undo
);
988 if (ssconvert_recalc
)
989 workbook_recalc_all (wb
);
993 range
= setup_range (G_OBJECT (wb
),
998 if (ssconvert_one_file_per_sheet
||
999 fsscope
== GO_FILE_SAVE_SHEET
||
1001 Sheet
*def_sheet
= NULL
;
1003 if (range
&& range
->a
.sheet
)
1004 def_sheet
= range
->a
.sheet
;
1005 else if (fsscope
== GO_FILE_SAVE_SHEET
|| range
)
1006 def_sheet
= wb_view_cur_sheet (wbv
);
1008 sheet_sel
= g_ptr_array_new ();
1010 g_ptr_array_add (sheet_sel
, def_sheet
);
1011 g_object_set_data (G_OBJECT (wb
),
1012 SHEET_SELECTION_KEY
, sheet_sel
);
1015 if (ssconvert_one_file_per_sheet
) {
1016 res
= do_split_save (fs
, wbv
, outarg
, cc
);
1018 res
= !workbook_view_save_as (wbv
, fs
, outfile
, cc
);
1022 g_object_set_data (G_OBJECT (wb
),
1023 SHEET_SELECTION_KEY
, NULL
);
1024 g_ptr_array_free (sheet_sel
, TRUE
);
1029 g_object_unref (wb
);
1031 g_object_unref (io_context
);
1039 main (int argc
, char const **argv
)
1041 GOErrorInfo
*plugin_errs
;
1044 GOptionContext
*ocontext
;
1045 GError
*error
= NULL
;
1047 /* No code before here, we need to init threads */
1048 argv
= gnm_pre_parse_init (argc
, argv
);
1050 gnm_conf_set_persistence (FALSE
);
1052 ocontext
= g_option_context_new (_("INFILE [OUTFILE]"));
1053 g_option_context_add_main_entries (ocontext
, ssconvert_options
, GETTEXT_PACKAGE
);
1054 g_option_context_add_group (ocontext
, gnm_get_option_group ());
1056 * The printing code uses gtk+ stuff, so we need to init gtk+. We
1057 * do that without opening any displays.
1059 g_option_context_add_group (ocontext
, gtk_get_option_group (FALSE
));
1060 g_option_context_parse (ocontext
, &argc
, (char ***)&argv
, &error
);
1061 g_option_context_free (ocontext
);
1064 g_printerr (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
1065 error
->message
, argv
[0]);
1066 g_error_free (error
);
1070 if (ssconvert_show_version
) {
1071 g_print (_("ssconvert version '%s'\ndatadir := '%s'\nlibdir := '%s'\n"),
1072 GNM_VERSION_FULL
, gnm_sys_data_dir (), gnm_sys_lib_dir ());
1076 if (ssconvert_one_file_per_sheet
&& ssconvert_merge_target
) {
1077 g_printerr (_("--export-file-per-sheet and --merge-to are incompatible\n"));
1083 cc
= gnm_cmd_context_stderr_new ();
1084 gnm_plugins_init (GO_CMD_CONTEXT (cc
));
1085 go_plugin_db_activate_plugin_list (
1086 go_plugins_get_available_plugins (), &plugin_errs
);
1088 /* FIXME: What do we want to do here? */
1089 go_error_info_free (plugin_errs
);
1091 go_component_set_default_command_context (cc
);
1093 if (ssconvert_list_exporters
)
1094 list_them (go_get_file_savers (),
1095 (get_desc_f
) &go_file_saver_get_id
,
1096 (get_desc_f
) &go_file_saver_get_description
);
1097 else if (ssconvert_list_importers
)
1098 list_them (go_get_file_openers (),
1099 (get_desc_f
) &go_file_opener_get_id
,
1100 (get_desc_f
) &go_file_opener_get_description
);
1101 else if (ssconvert_merge_target
!=NULL
&& argc
>=3) {
1102 res
= convert (argv
[1], ssconvert_merge_target
, argv
+1, cc
);
1103 } else if (argc
== 2 || argc
== 3) {
1104 res
= convert (argv
[1], argv
[2], NULL
, cc
);
1106 g_printerr (_("Usage: %s [OPTION...] %s\n"),
1108 _("INFILE [OUTFILE]"));
1112 go_component_set_default_command_context (NULL
);
1113 g_object_unref (cc
);
1115 gnm_pre_parse_shutdown ();