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>
29 #include <gnumeric-paths.h>
30 #include <gnm-plugin.h>
31 #include <command-context.h>
32 #include <command-context-stderr.h>
33 #include <workbook-view.h>
34 #include <gnumeric-conf.h>
35 #include <gui-clipboard.h>
36 #include <tools/analysis-tools.h>
37 #include <dialogs/dialogs.h>
38 #include <goffice/goffice.h>
39 #include <gsf/gsf-utils.h>
41 #ifdef HAVE_SYS_RESOURCE_H
42 #include <sys/resource.h>
45 // Sheets that an exporter should export.
46 #define SHEET_SELECTION_KEY "sheet-selection"
48 // Sheets user has specified as export options
49 #define SSCONVERT_SHEET_SET_KEY "ssconvert-sheets"
51 static gboolean ssconvert_show_version
= FALSE
;
52 static gboolean ssconvert_verbose
= FALSE
;
53 static gboolean ssconvert_list_exporters
= FALSE
;
54 static gboolean ssconvert_list_importers
= FALSE
;
55 static gboolean ssconvert_one_file_per_sheet
= FALSE
;
56 static gboolean ssconvert_recalc
= FALSE
;
57 static gboolean ssconvert_solve
= FALSE
;
58 static char *ssconvert_resize
= NULL
;
59 static char *ssconvert_clipboard
= NULL
;
60 static char *ssconvert_range
= NULL
;
61 static char *ssconvert_import_encoding
= NULL
;
62 static char *ssconvert_import_id
= NULL
;
63 static char *ssconvert_export_id
= NULL
;
64 static char *ssconvert_export_options
= NULL
;
65 static char *ssconvert_merge_target
= NULL
;
66 static char **ssconvert_goal_seek
= NULL
;
67 static char **ssconvert_tool_test
= NULL
;
69 static const GOptionEntry ssconvert_options
[] = {
72 0, G_OPTION_ARG_NONE
, &ssconvert_show_version
,
73 N_("Display program version"),
79 0, G_OPTION_ARG_NONE
, &ssconvert_verbose
,
80 N_("Be somewhat more verbose during conversion"),
84 /* ---------------------------------------- */
87 "import-encoding", 'E',
88 0, G_OPTION_ARG_STRING
, &ssconvert_import_encoding
,
89 N_("Optionally specify an encoding for imported content"),
95 0, G_OPTION_ARG_STRING
, &ssconvert_import_id
,
96 N_("Optionally specify which importer to use"),
102 0, G_OPTION_ARG_NONE
, &ssconvert_list_importers
,
103 N_("List the available importers"),
107 /* ---------------------------------------- */
111 0, G_OPTION_ARG_STRING
, &ssconvert_merge_target
,
112 N_("Merge listed files (all same format) to make this file"),
118 0, G_OPTION_ARG_STRING
, &ssconvert_export_id
,
119 N_("Optionally specify which exporter to use"),
124 "export-options", 'O',
125 0, G_OPTION_ARG_STRING
, &ssconvert_export_options
,
126 N_("Detailed instructions for the chosen exporter"),
132 0, G_OPTION_ARG_NONE
, &ssconvert_list_exporters
,
133 N_("List the available exporters"),
138 "export-file-per-sheet", 'S',
139 0, G_OPTION_ARG_NONE
, &ssconvert_one_file_per_sheet
,
140 N_("Export a file for each sheet if the exporter only supports one sheet at a time"),
146 0, G_OPTION_ARG_NONE
, &ssconvert_recalc
,
147 N_("Recalculate all cells before writing the result"),
153 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING
, &ssconvert_resize
,
154 N_("Resize to given ROWSxCOLS"),
159 /* ---------------------------------------- */
161 // For now these are for INTERNAL GNUMERIC USE ONLY. They are used
162 // by the test suite.
165 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING
, &ssconvert_clipboard
,
166 N_("Output via the clipboard"),
172 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING
, &ssconvert_range
,
173 N_("The range to export"),
179 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING_ARRAY
, &ssconvert_goal_seek
,
180 N_("Goal seek areas"),
186 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_NONE
, &ssconvert_solve
,
187 N_("Run the solver"),
193 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING_ARRAY
, &ssconvert_tool_test
,
194 N_("Tool test specs"),
198 /* ---------------------------------------- */
203 static GnmRangeRef
const *
204 setup_range (GObject
*obj
, const char *key
, Workbook
*wb
, const char *rtxt
)
208 GnmRangeRef rr
, *rrc
;
211 pp
.sheet
= workbook_sheet_by_index (wb
, 0);
215 end
= rangeref_parse (&rr
, rtxt
, &pp
, gnm_conventions_default
);
216 if (!end
|| end
== rtxt
|| *end
!= 0) {
217 g_printerr ("Invalid range specified.\n");
221 rrc
= g_memdup (&rr
, sizeof (rr
));
222 g_object_set_data_full (obj
, key
, rrc
, g_free
);
227 struct cb_handle_export_options
{
233 cb_handle_export_options (const char *key
, const char *value
,
234 GError
**err
, gpointer user_
)
236 struct cb_handle_export_options
*user
= user_
;
237 return gnm_file_saver_common_export_option (user
->fs
, user
->wb
,
242 handle_export_options (GOFileSaver
*fs
, Workbook
*wb
)
248 if (!ssconvert_export_options
)
251 sig
= g_signal_lookup ("set-export-options", G_TYPE_FROM_INSTANCE (fs
));
252 if (g_signal_handler_find (fs
, G_SIGNAL_MATCH_ID
,
253 sig
, 0, NULL
, NULL
, NULL
))
254 fail
= go_file_saver_set_export_options
256 ssconvert_export_options
,
259 struct cb_handle_export_options data
;
262 fail
= go_parse_key_value (ssconvert_export_options
, &err
,
263 cb_handle_export_options
, &data
);
267 g_printerr ("ssconvert: %s\n", err
269 : _("Cannot parse export options."));
276 // Check that the sheet selection, if any, matches the file saver's
279 validate_sheet_selection (GOFileSaver
*fs
, Workbook
*wb
)
281 GOFileSaveScope fsscope
= go_file_saver_get_save_scope (fs
);
282 gboolean fs_sheet_selection
;
284 g_object_get (G_OBJECT (fs
),
285 "sheet-selection", &fs_sheet_selection
, NULL
);
287 if (ssconvert_one_file_per_sheet
) {
290 case GO_FILE_SAVE_WORKBOOK
:
291 ok
= fs_sheet_selection
;
293 case GO_FILE_SAVE_SHEET
:
296 case GO_FILE_SAVE_RANGE
:
302 g_printerr (_("Selected exporter (%s) does not have the ability to split a workbook into sheets.\n"),
303 go_file_saver_get_id (fs
));
307 GPtrArray
*sheets
= g_object_get_data (G_OBJECT (wb
),
308 SSCONVERT_SHEET_SET_KEY
);
310 case GO_FILE_SAVE_WORKBOOK
:
311 case GO_FILE_SAVE_RANGE
:
313 if (sheets
&& !fs_sheet_selection
) {
314 g_printerr (_("Selected exporter (%s) does not have the ability to export a subset of sheets.\n"),
315 go_file_saver_get_id (fs
));
319 case GO_FILE_SAVE_SHEET
:
320 if (sheets
&& sheets
->len
!= 1) {
321 g_printerr (_("Selected exporter (%s) can only export one sheet at a time.\n"),
322 go_file_saver_get_id (fs
));
333 typedef gchar
const *(*get_desc_f
)(const void *);
336 by_his_id (gconstpointer a
, gconstpointer b
, gpointer user
)
338 get_desc_f get_his_id
= user
;
339 return strcmp (get_his_id (a
), get_his_id (b
));
343 list_them (GList
*them
,
344 get_desc_f get_his_id
,
345 get_desc_f get_his_description
)
347 GList
*them_copy
= g_list_copy (them
);
350 gboolean interactive
;
352 them_copy
= g_list_sort_with_data (them_copy
, by_his_id
, get_his_id
);
354 for (ptr
= them_copy
; ptr
; ptr
= ptr
->next
) {
355 GObject
*obj
= ptr
->data
;
358 g_object_get (obj
, "interactive-only", &interactive
, NULL
);
362 id
= get_his_id (obj
);
364 len
= MAX (len
, strlen (id
));
367 g_printerr ("%-*s | %s\n", len
,
368 /* Translate these? */
371 for (ptr
= them_copy
; ptr
; ptr
= ptr
->next
) {
372 GObject
*obj
= ptr
->data
;
375 g_object_get (obj
, "interactive-only", &interactive
, NULL
);
379 id
= get_his_id (obj
);
381 g_printerr ("%-*s | %s\n", len
,
383 (*get_his_description
) (ptr
->data
));
386 g_list_free (them_copy
);
390 * Read the files we're going to merge and return a list of Workbooks.
393 read_files_to_merge (const char *inputs
[], GOFileOpener
*fo
,
394 GOIOContext
*io_context
, GOCmdContext
*cc
)
399 const char *fname
= *inputs
;
400 char *uri
= go_shell_arg_to_uri (fname
);
402 workbook_view_new_from_uri (uri
, fo
, io_context
,
403 ssconvert_import_encoding
);
407 if (go_io_error_occurred (io_context
)) {
408 g_slist_free_full (wbs
, g_object_unref
);
415 wbs
= g_slist_prepend (wbs
, wb_view_get_workbook (wbv
));
418 return g_slist_reverse (wbs
);
422 * Look at a set of workbooks, and pick a sheet size that would
423 * be good for sheets in a workbook merging them all.
426 suggest_size (GSList
*wbs
, int *csuggest
, int *rsuggest
)
432 for (l
= wbs
; l
; l
= l
->next
) {
433 Workbook
*wb
= l
->data
;
435 WORKBOOK_FOREACH_SHEET (wb
, sheet
, {
436 int r
= gnm_sheet_get_max_rows (sheet
);
437 int c
= gnm_sheet_get_max_cols (sheet
);
438 if (r
> rmax
) rmax
= r
;
439 if (c
> cmax
) cmax
= c
;
443 gnm_sheet_suggest_size (&cmax
, &rmax
);
449 cb_collect_names (G_GNUC_UNUSED gconstpointer key
,
453 if (!expr_name_is_active (nexpr
))
455 *plist
= g_slist_prepend (*plist
, expr_name_ref (nexpr
));
458 /* Append the sheets of workbook wb2 to workbook wb. Resize sheets
459 if necessary. Fix workbook links in sheet if necessary.
460 Merge names in workbook scope (conflicts result in an error). */
462 merge_single (Workbook
*wb
, Workbook
*wb2
,
466 /* Move names with workbook scope in wb2 over to wb */
467 GSList
*names
= g_slist_sort (gnm_named_expr_collection_list (wb2
->names
),
468 (GCompareFunc
)expr_name_cmp_by_name
);
471 for (p
= names
; p
; p
= p
->next
) {
472 GnmNamedExpr
*nexpr
= p
->data
;
473 const char *name
= expr_name_name (nexpr
);
474 GnmNamedExpr
*nexpr2
;
476 GnmParsePos newpos
= nexpr
->pos
;
478 if (!expr_name_is_active (nexpr
))
481 if (nexpr
->pos
.wb
!= wb2
|| nexpr
->pos
.sheet
!= NULL
)
484 /* Check for clash with existing name */
486 parse_pos_init (&pp
, wb
, NULL
, 0, 0);
487 nexpr2
= expr_name_lookup (&pp
, name
);
488 if (nexpr2
/* FIXME: && nexpr2-is-not-the-same-as-nexpr */) {
489 g_printerr (_("Name conflict during merge: '%s' appears twice at workbook scope.\n"),
491 g_slist_free (names
);
495 /* Move name scope to workbook wb */
497 expr_name_set_pos (nexpr
, &newpos
);
499 g_slist_free (names
);
501 while (workbook_sheet_count (wb2
) > 0) {
502 /* Remove sheet from incoming workbook */
503 Sheet
*sheet
= workbook_sheet_by_index (wb2
, 0);
504 int loc
= workbook_sheet_count (wb
);
508 GSList
*names
= NULL
;
510 g_object_ref (sheet
);
511 workbook_sheet_delete (sheet
);
512 sheet
->workbook
= wb
;
514 /* Fix names that reference the old workbook */
515 gnm_sheet_foreach_name (sheet
, (GHFunc
)cb_collect_names
, &names
);
517 GnmNamedExpr
*nexpr
= names
->data
;
518 names
= g_slist_delete_link (names
, names
);
521 GnmParsePos newpos
= nexpr
->pos
;
523 expr_name_set_pos (nexpr
, &newpos
);
525 expr_name_unref (nexpr
);
528 undo
= gnm_sheet_resize (sheet
, cmax
, rmax
, cc
, &err
);
530 g_object_unref (undo
);
532 /* Pick a free sheet name */
533 sheet_name
= workbook_sheet_get_free_name
534 (wb
, sheet
->name_unquoted
, FALSE
, TRUE
);
535 g_object_set (sheet
, "name", sheet_name
, NULL
);
538 /* Insert and revive the sheet */
539 workbook_sheet_attach_at_pos (wb
, sheet
, loc
);
540 dependents_revive_sheet (sheet
);
541 g_object_unref (sheet
);
547 /* Merge a collection of workbooks into one. */
549 merge (Workbook
*wb
, char const *inputs
[],
550 GOFileOpener
*fo
, GOIOContext
*io_context
, GOCmdContext
*cc
)
556 wbs
= read_files_to_merge (inputs
, fo
, io_context
, cc
);
557 if (go_io_error_occurred (io_context
)) {
558 go_io_error_display (io_context
);
562 suggest_size (wbs
, &cmax
, &rmax
);
564 for (l
= wbs
; l
; l
= l
->next
) {
565 Workbook
*wb2
= l
->data
;
566 const char *uri
= go_doc_get_uri (GO_DOC (wb2
));
568 g_printerr (_("Adding sheets from %s\n"), uri
);
570 result
= merge_single (wb
, wb2
, cmax
, rmax
, cc
);
575 g_slist_free_full (wbs
, g_object_unref
);
580 resolve_template (const char *template, Sheet
*sheet
, unsigned n
)
582 GString
*s
= g_string_new (NULL
);
587 char *res
= go_shell_arg_to_uri (s
->str
);
588 g_string_free (s
, TRUE
);
597 g_string_append_printf (s
, "%u", n
);
600 g_string_append (s
, sheet
->name_unquoted
);
603 g_string_append_c (s
, '%');
609 g_string_append_c (s
, *template);
616 run_solver (Sheet
*sheet
, WorkbookView
*wbv
)
618 GnmSolverParameters
*params
= sheet
->solver_parameters
;
620 WorkbookControl
*wbc
;
621 GnmSolver
*sol
= NULL
;
623 wbc
= g_object_new (GNM_WBC_TYPE
, NULL
);
624 wb_control_set_view (wbc
, wbv
, NULL
);
626 /* Pick a functional algorithm. */
627 if (!gnm_solver_factory_functional (params
->options
.algorithm
,
630 for (l
= gnm_solver_db_get (); l
; l
= l
->next
) {
631 GnmSolverFactory
*factory
= l
->data
;
632 if (params
->options
.model_type
!= factory
->type
)
634 if (gnm_solver_factory_functional (factory
, NULL
)) {
635 gnm_solver_param_set_algorithm (params
,
642 if (!gnm_solver_param_valid (params
, &err
))
645 sol
= params
->options
.algorithm
646 ? gnm_solver_factory_create (params
->options
.algorithm
, params
)
649 g_set_error (&err
, go_error_invalid (), 0,
650 _("Failed to create solver"));
654 if (!gnm_solver_start (sol
, wbc
, &err
))
657 while (!gnm_solver_finished (sol
)) {
658 g_main_context_iteration (NULL
, TRUE
);
661 switch (sol
->status
) {
662 case GNM_SOLVER_STATUS_DONE
:
664 case GNM_SOLVER_STATUS_CANCELLED
:
665 g_printerr (_("Solver reached time or iteration limit\n"));
668 g_set_error (&err
, go_error_invalid (), 0,
669 _("Solver ran, but failed"));
673 gnm_solver_store_result (sol
);
675 gnm_solver_create_report (sol
, "Solver");
679 g_object_unref (sol
);
681 g_printerr (_("Solver: %s\n"), err
->message
);
686 #define GET_ARG(conv_,name_,def_) (g_hash_table_lookup_extended(args,(name_),NULL,&arg) ? conv_((const char *)arg) : (def_))
687 #define RANGE_ARG(s_) value_new_cellrange_str(sheet,(s_))
688 #define RANGE_LIST_ARG(s_) g_slist_prepend (NULL, value_new_cellrange_str(sheet,(s_)))
689 #define SHEET_ARG(s_) workbook_sheet_by_name(wb,(s_))
692 run_tool_test (const char *tool
, char **argv
, WorkbookView
*wbv
)
695 WorkbookControl
*wbc
;
697 data_analysis_output_t
*dao
;
698 analysis_tool_engine engine
;
705 * Arguments in argv are of the form key:value.
706 * Make a hash for those.
708 args
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
709 (GDestroyNotify
)g_free
,
710 (GDestroyNotify
)g_free
);
711 for (i
= 0; argv
[i
]; i
++) {
712 const char *s
= argv
[i
];
713 const char *colon
= strchr (s
, ':');
715 g_printerr ("Ignoring tool test argument \"%s\"\n", s
);
718 g_hash_table_replace (args
, g_strndup (s
, colon
- s
),
719 g_strdup (colon
+ 1));
722 wb
= wb_view_get_workbook (wbv
);
723 wbc
= g_object_new (GNM_WBC_TYPE
, NULL
);
724 wb_control_set_view (wbc
, wbv
, NULL
);
726 sheet
= GET_ARG (SHEET_ARG
, "sheet", wb_view_cur_sheet (wbv
));
728 if (g_str_equal (tool
, "regression")) {
729 analysis_tools_data_regression_t
*data
=
730 g_new0 (analysis_tools_data_regression_t
, 1);
732 data
->base
.wbc
= wbc
;
733 data
->base
.range_1
= GET_ARG (RANGE_ARG
, "x", value_new_error_REF (NULL
));
734 data
->base
.range_2
= GET_ARG (RANGE_ARG
, "y", value_new_error_REF (NULL
));
735 data
->base
.labels
= GET_ARG (atoi
, "labels", FALSE
);
736 data
->base
.alpha
= GET_ARG (atof
, "alpha", 0.05);
737 data
->group_by
= GET_ARG ((group_by_t
), "grouped-by", GROUPED_BY_COL
);
738 data
->intercept
= GET_ARG (atoi
, "intercept", TRUE
);
739 data
->multiple_regression
= GET_ARG (atoi
, "multiple", TRUE
);
740 data
->multiple_y
= GET_ARG (atoi
, "multiple-y", FALSE
);
741 data
->residual
= GET_ARG (atoi
, "residual", TRUE
);
743 engine
= analysis_tool_regression_engine
;
745 } else if (g_str_equal (tool
, "anova")) {
746 analysis_tools_data_anova_single_t
*data
=
747 g_new0 (analysis_tools_data_anova_single_t
, 1);
749 data
->base
.input
= GET_ARG (RANGE_LIST_ARG
, "data", NULL
);
750 data
->base
.labels
= GET_ARG (atoi
, "labels", FALSE
);
751 data
->base
.group_by
= GET_ARG ((group_by_t
), "grouped-by", GROUPED_BY_COL
);
752 data
->alpha
= GET_ARG (atof
, "alpha", 0.05);
754 engine
= analysis_tool_anova_single_engine
;
757 g_printerr ("no test for tool \"%s\"\n", tool
);
761 dao
= dao_init_new_sheet (NULL
);
762 dao
->put_formulas
= TRUE
;
763 cmd_analysis_tool (wbc
, sheet
, dao
, specs
, engine
, TRUE
);
765 g_hash_table_destroy (args
);
775 do_split_save (GOFileSaver
*fs
, WorkbookView
*wbv
,
776 const char *outarg
, GOCmdContext
*cc
)
778 Workbook
*wb
= wb_view_get_workbook (wbv
);
783 GPtrArray
*sheet_sel
=
784 g_object_get_data (G_OBJECT (wb
), SHEET_SELECTION_KEY
);
785 gboolean fs_sheet_selection
;
787 g_object_get (G_OBJECT (fs
), "sheet-selection", &fs_sheet_selection
, NULL
);
789 template = strchr (outarg
, '%')
791 : g_strconcat (outarg
, ".%n", NULL
);
793 sheets
= g_object_get_data (G_OBJECT (wb
),
794 SSCONVERT_SHEET_SET_KEY
);
796 g_ptr_array_ref (sheets
);
799 sheets
= g_ptr_array_new ();
800 for (i
= 0; i
< workbook_sheet_count (wb
); i
++) {
801 Sheet
*sheet
= workbook_sheet_by_index (wb
, i
);
802 g_ptr_array_add (sheets
, sheet
);
806 for (ui
= 0; ui
< sheets
->len
; ui
++) {
807 Sheet
*sheet
= g_ptr_array_index (sheets
, ui
);
808 char *tmpfile
= resolve_template (template, sheet
, ui
);
809 int oldn
= sheet
->index_in_wb
;
811 g_ptr_array_set_size (sheet_sel
, 0);
812 g_ptr_array_add (sheet_sel
, sheet
);
814 if (!fs_sheet_selection
) {
816 * HACK: (bug 694408).
818 * We don't have a good way of specifying the
819 * sheet. Move it to the front and select
820 * it. That will at least make cvs and txt
821 * exporters reliably find it.
823 workbook_sheet_move (sheet
, -oldn
);
824 wb_view_sheet_focus (wbv
, sheet
);
827 res
= !workbook_view_save_as (wbv
, fs
, tmpfile
, cc
);
829 if (!fs_sheet_selection
)
830 workbook_sheet_move (sheet
, +oldn
);
838 g_ptr_array_unref (sheets
);
844 convert (char const *inarg
, char const *outarg
, char const *mergeargs
[],
848 GOFileSaver
*fs
= NULL
;
849 GOFileOpener
*fo
= NULL
;
850 char *infile
= go_shell_arg_to_uri (inarg
);
851 char *outfile
= outarg
? go_shell_arg_to_uri (outarg
) : NULL
;
853 GOIOContext
*io_context
= NULL
;
855 GOFileSaveScope fsscope
;
856 GPtrArray
*sheet_sel
= NULL
;
857 GnmRangeRef
const *range
= NULL
;
859 if (ssconvert_export_id
!= NULL
) {
860 fs
= go_file_saver_for_id (ssconvert_export_id
);
863 g_printerr (_("Unknown exporter '%s'.\n"
864 "Try --list-exporters to see a list of possibilities.\n"),
865 ssconvert_export_id
);
867 } else if (outfile
== NULL
&&
868 !ssconvert_one_file_per_sheet
&&
869 go_file_saver_get_extension (fs
) != NULL
) {
870 char const *ext
= gsf_extension_pointer (infile
);
872 GString
*res
= g_string_new (NULL
);
873 g_string_append_len (res
, infile
, ext
- infile
);
874 g_string_append (res
, go_file_saver_get_extension(fs
));
875 outfile
= g_string_free (res
, FALSE
);
879 if (outfile
!= NULL
) {
880 fs
= go_file_saver_for_file_name (outfile
);
883 g_printerr (_("Unable to guess exporter to use for '%s'.\n"
884 "Try --list-exporters to see a list of possibilities.\n"),
888 if (ssconvert_verbose
)
889 g_printerr (_("Using exporter %s\n"),
890 go_file_saver_get_id (fs
));
894 if (outfile
== NULL
) {
895 g_printerr (_("An output file name or an explicit export type is required.\n"
896 "Try --list-exporters to see a list of possibilities.\n"));
901 if (ssconvert_import_id
!= NULL
) {
902 fo
= go_file_opener_for_id (ssconvert_import_id
);
905 g_printerr (_("Unknown importer '%s'.\n"
906 "Try --list-importers to see a list of possibilities.\n"),
907 ssconvert_import_id
);
914 fsscope
= go_file_saver_get_save_scope (fs
);
916 io_context
= go_io_context_new (cc
);
917 if (mergeargs
== NULL
) {
918 wbv
= workbook_view_new_from_uri (infile
, fo
,
920 ssconvert_import_encoding
);
922 wbv
= workbook_view_new (NULL
);
925 if (go_io_error_occurred (io_context
)) {
926 go_io_error_display (io_context
);
929 } else if (wbv
== NULL
) {
930 g_printerr (_("Loading %s failed\n"), infile
);
935 wb
= wb_view_get_workbook (wbv
);
937 res
= handle_export_options (fs
, wb
);
941 res
= validate_sheet_selection (fs
, wb
);
945 if (mergeargs
!= NULL
) {
946 if (merge (wb
, mergeargs
, fo
, io_context
, cc
))
950 if (ssconvert_goal_seek
) {
952 Sheet
*sheet
= wb_view_cur_sheet (wbv
);
954 for (i
= 0; ssconvert_goal_seek
[i
]; i
++) {
955 setup_range (G_OBJECT (sheet
),
956 "ssconvert-goal-seek",
958 ssconvert_goal_seek
[i
]);
959 dialog_goal_seek (NULL
, sheet
);
963 if (ssconvert_solve
) {
964 Sheet
*sheet
= wb_view_cur_sheet (wbv
);
965 run_solver (sheet
, wbv
);
968 if (ssconvert_tool_test
&& ssconvert_tool_test
[0]) {
969 run_tool_test (ssconvert_tool_test
[0],
970 ssconvert_tool_test
+ 1,
974 if (ssconvert_resize
) {
976 if (sscanf (ssconvert_resize
, "%dx%d", &rows
, &cols
) == 2) {
979 if (ssconvert_verbose
)
980 g_printerr (_("Resizing to %dx%d\n"),
983 for (n
= workbook_sheet_count (wb
) - 1;
987 Sheet
*sheet
= workbook_sheet_by_index (wb
, n
);
989 gnm_sheet_resize (sheet
, cols
, rows
,
992 g_printerr (_("Resizing of sheet %s failed\n"),
993 sheet
->name_unquoted
);
994 g_object_unref (undo
);
999 if (ssconvert_recalc
)
1000 workbook_recalc_all (wb
);
1003 if (ssconvert_range
)
1004 range
= setup_range (G_OBJECT (wb
),
1009 if (ssconvert_one_file_per_sheet
||
1010 fsscope
== GO_FILE_SAVE_SHEET
||
1012 Sheet
*def_sheet
= NULL
;
1014 if (range
&& range
->a
.sheet
)
1015 def_sheet
= range
->a
.sheet
;
1016 else if (fsscope
== GO_FILE_SAVE_SHEET
|| range
)
1017 def_sheet
= wb_view_cur_sheet (wbv
);
1019 sheet_sel
= g_ptr_array_new ();
1021 g_ptr_array_add (sheet_sel
, def_sheet
);
1022 g_object_set_data (G_OBJECT (wb
),
1023 SHEET_SELECTION_KEY
, sheet_sel
);
1026 if (ssconvert_one_file_per_sheet
) {
1027 res
= do_split_save (fs
, wbv
, outarg
, cc
);
1029 res
= !workbook_view_save_as (wbv
, fs
, outfile
, cc
);
1033 g_object_set_data (G_OBJECT (wb
),
1034 SHEET_SELECTION_KEY
, NULL
);
1035 g_ptr_array_free (sheet_sel
, TRUE
);
1040 g_object_unref (wb
);
1042 g_object_unref (io_context
);
1050 clipboard_export (const char *inarg
, char const *outarg
, GOCmdContext
*cc
)
1052 GOFileOpener
*fo
= NULL
;
1053 GOIOContext
*io_context
= NULL
;
1055 Workbook
*wb
= NULL
;
1056 char *infile
= go_shell_arg_to_uri (inarg
);
1057 char *outfile
= go_shell_arg_to_uri (outarg
);
1059 GnmRangeRef
const *range
;
1061 WorkbookControl
*wbc
= NULL
;
1062 GBytes
*data
= NULL
;
1065 io_context
= go_io_context_new (cc
);
1066 wbv
= workbook_view_new_from_uri (infile
, fo
,
1068 ssconvert_import_encoding
);
1070 if (go_io_error_occurred (io_context
)) {
1071 go_io_error_display (io_context
);
1074 } else if (wbv
== NULL
) {
1075 g_printerr (_("Loading %s failed\n"), infile
);
1080 wb
= wb_view_get_workbook (wbv
);
1082 range
= setup_range (G_OBJECT (wb
),
1086 range_init_rangeref (&r
, range
);
1088 wb_view_sheet_focus (wbv
, range
->a
.sheet
);
1090 gnm_app_clipboard_cut_copy (wbc
, FALSE
,
1091 wb_view_cur_sheet_view (wbv
),
1094 data
= gui_clipboard_test (ssconvert_clipboard
);
1096 g_printerr ("Failed to get clipboard data.\n");
1101 dst
= go_file_create (outfile
, NULL
);
1103 g_printerr ("Failed to write to %s\n", outfile
);
1108 gsf_output_write (dst
, g_bytes_get_size (data
),
1109 g_bytes_get_data (data
, NULL
));
1110 gsf_output_close (dst
);
1111 g_object_unref (dst
);
1115 g_bytes_unref (data
);
1117 g_object_unref (wb
);
1119 g_object_unref (io_context
);
1127 main (int argc
, char const **argv
)
1129 GOErrorInfo
*plugin_errs
;
1132 GOptionContext
*ocontext
;
1133 GError
*error
= NULL
;
1134 gboolean do_usage
= FALSE
;
1136 /* No code before here, we need to init threads */
1137 argv
= gnm_pre_parse_init (argc
, argv
);
1139 gnm_conf_set_persistence (FALSE
);
1141 ocontext
= g_option_context_new (_("INFILE [OUTFILE]"));
1142 g_option_context_add_main_entries (ocontext
, ssconvert_options
, GETTEXT_PACKAGE
);
1143 g_option_context_add_group (ocontext
, gnm_get_option_group ());
1145 * The printing code uses gtk+ stuff, so we need to init gtk+. We
1146 * do that without opening any displays.
1148 g_option_context_add_group (ocontext
, gtk_get_option_group (FALSE
));
1149 g_option_context_parse (ocontext
, &argc
, (char ***)&argv
, &error
);
1150 g_option_context_free (ocontext
);
1153 g_printerr (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
1154 error
->message
, argv
[0]);
1155 g_error_free (error
);
1159 if (ssconvert_show_version
) {
1160 g_print (_("ssconvert version '%s'\ndatadir := '%s'\nlibdir := '%s'\n"),
1161 GNM_VERSION_FULL
, gnm_sys_data_dir (), gnm_sys_lib_dir ());
1165 if (ssconvert_one_file_per_sheet
&& ssconvert_merge_target
) {
1166 g_printerr (_("--export-file-per-sheet and --merge-to are incompatible\n"));
1172 cc
= gnm_cmd_context_stderr_new ();
1173 gnm_plugins_init (GO_CMD_CONTEXT (cc
));
1174 go_plugin_db_activate_plugin_list (
1175 go_plugins_get_available_plugins (), &plugin_errs
);
1177 /* FIXME: What do we want to do here? */
1178 go_error_info_free (plugin_errs
);
1180 go_component_set_default_command_context (cc
);
1182 if (ssconvert_list_exporters
)
1183 list_them (go_get_file_savers (),
1184 (get_desc_f
) &go_file_saver_get_id
,
1185 (get_desc_f
) &go_file_saver_get_description
);
1186 else if (ssconvert_list_importers
)
1187 list_them (go_get_file_openers (),
1188 (get_desc_f
) &go_file_opener_get_id
,
1189 (get_desc_f
) &go_file_opener_get_description
);
1190 else if (ssconvert_clipboard
)
1191 if (argc
== 3 && ssconvert_range
)
1192 res
= clipboard_export (argv
[1], argv
[2], cc
);
1195 else if (ssconvert_merge_target
) {
1197 res
= convert (argv
[1], ssconvert_merge_target
,
1201 } else if (argc
== 2 || argc
== 3) {
1202 res
= convert (argv
[1], argv
[2], NULL
, cc
);
1207 g_printerr (_("Usage: %s [OPTION...] %s\n"),
1209 _("INFILE [OUTFILE]"));
1213 go_component_set_default_command_context (NULL
);
1214 g_object_unref (cc
);
1216 gnm_pre_parse_shutdown ();