1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * ssconvert.c: A wrapper application to convert spreadsheet formats
6 * Jon Kåre Hellan <hellan@acm.org>
7 * Morten Welinder <terra@gnome.org>
8 * Jody Goldberg <jody@gnome.org>
10 * Copyright (C) 2002-2003 Jody Goldberg
11 * Copyright (C) 2006-2009 Morten Welinder (terra@gnome.org)
13 #include <gnumeric-config.h>
14 #include <glib/gi18n.h>
17 #include "parse-util.h"
18 #include "application.h"
20 #include "workbook-priv.h"
21 #include "workbook-control.h"
23 #include "dependent.h"
24 #include "expr-name.h"
25 #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 "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 static gboolean ssconvert_show_version
= FALSE
;
44 static gboolean ssconvert_verbose
= FALSE
;
45 static gboolean ssconvert_list_exporters
= FALSE
;
46 static gboolean ssconvert_list_importers
= FALSE
;
47 static gboolean ssconvert_one_file_per_sheet
= FALSE
;
48 static gboolean ssconvert_recalc
= FALSE
;
49 static gboolean ssconvert_solve
= FALSE
;
50 static char *ssconvert_resize
= NULL
;
51 static char *ssconvert_range
= NULL
;
52 static char *ssconvert_import_encoding
= NULL
;
53 static char *ssconvert_import_id
= NULL
;
54 static char *ssconvert_export_id
= NULL
;
55 static char *ssconvert_export_options
= NULL
;
56 static char *ssconvert_merge_target
= NULL
;
57 static char **ssconvert_goal_seek
= NULL
;
58 static char **ssconvert_tool_test
= NULL
;
60 static const GOptionEntry ssconvert_options
[] = {
63 0, G_OPTION_ARG_NONE
, &ssconvert_show_version
,
64 N_("Display program version"),
70 0, G_OPTION_ARG_NONE
, &ssconvert_verbose
,
71 N_("Be somewhat more verbose during conversion"),
75 /* ---------------------------------------- */
78 "import-encoding", 'E',
79 0, G_OPTION_ARG_STRING
, &ssconvert_import_encoding
,
80 N_("Optionally specify an encoding for imported content"),
86 0, G_OPTION_ARG_STRING
, &ssconvert_import_id
,
87 N_("Optionally specify which importer to use"),
93 0, G_OPTION_ARG_NONE
, &ssconvert_list_importers
,
94 N_("List the available importers"),
98 /* ---------------------------------------- */
102 0, G_OPTION_ARG_STRING
, &ssconvert_merge_target
,
103 N_("Merge listed files (all same format) to make this file"),
109 0, G_OPTION_ARG_STRING
, &ssconvert_export_id
,
110 N_("Optionally specify which exporter to use"),
115 "export-options", 'O',
116 0, G_OPTION_ARG_STRING
, &ssconvert_export_options
,
117 N_("Detailed instructions for the chosen exporter"),
123 0, G_OPTION_ARG_NONE
, &ssconvert_list_exporters
,
124 N_("List the available exporters"),
129 "export-file-per-sheet", 'S',
130 0, G_OPTION_ARG_NONE
, &ssconvert_one_file_per_sheet
,
131 N_("Export a file for each sheet if the exporter only supports one sheet at a time"),
137 0, G_OPTION_ARG_NONE
, &ssconvert_recalc
,
138 N_("Recalculate all cells before writing the result"),
144 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING
, &ssconvert_resize
,
145 N_("Resize to given ROWSxCOLS"),
150 /* ---------------------------------------- */
152 /* For now these are for INTERNAL GNUMERIC USE ONLY. */
155 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING
, &ssconvert_range
,
156 N_("The range to export"),
162 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING_ARRAY
, &ssconvert_goal_seek
,
163 N_("Goal seek areas"),
169 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_NONE
, &ssconvert_solve
,
170 N_("Run the solver"),
176 G_OPTION_FLAG_HIDDEN
, G_OPTION_ARG_STRING_ARRAY
, &ssconvert_tool_test
,
177 N_("Tool test specs"),
181 /* ---------------------------------------- */
187 setup_range (GObject
*obj
, const char *key
, Workbook
*wb
, const char *rtxt
)
194 pp
.sheet
= workbook_sheet_by_index (wb
, 0);
198 end
= rangeref_parse (&rr
, rtxt
, &pp
, gnm_conventions_default
);
199 if (!end
|| end
== rtxt
|| *end
!= 0) {
200 g_printerr ("Invalid range specified.\n");
204 g_object_set_data_full (obj
, key
,
205 g_memdup (&rr
, sizeof (rr
)),
210 handle_export_options (GOFileSaver
*fs
, GODoc
*doc
)
212 guint sig
= g_signal_lookup ("set-export-options",
213 G_TYPE_FROM_INSTANCE (fs
));
215 if (!ssconvert_export_options
)
218 if (g_signal_handler_find (fs
, G_SIGNAL_MATCH_ID
,
219 sig
, 0, NULL
, NULL
, NULL
)) {
222 go_file_saver_set_export_options
224 ssconvert_export_options
,
228 g_printerr ("ssconvert: %s\n", err
230 : _("Cannot parse export options."));
236 g_printerr (_("The file saver does not take options\n"));
242 typedef gchar
const *(*get_desc_f
)(void *);
245 list_them (GList
*them
,
246 get_desc_f get_his_id
,
247 get_desc_f get_his_description
)
251 gboolean interactive
;
253 for (ptr
= them
; ptr
; ptr
= ptr
->next
) {
254 GObject
*obj
= ptr
->data
;
257 g_object_get (obj
, "interactive-only", &interactive
, NULL
);
261 id
= get_his_id (obj
);
263 len
= MAX (len
, strlen (id
));
266 g_printerr ("%-*s | %s\n", len
,
267 /* Translate these? */
270 for (ptr
= them
; ptr
; ptr
= ptr
->next
) {
271 GObject
*obj
= ptr
->data
;
274 g_object_get (obj
, "interactive-only", &interactive
, NULL
);
278 id
= get_his_id (obj
);
280 g_printerr ("%-*s | %s\n", len
,
282 (*get_his_description
) (ptr
->data
));
287 * Read the files we're going to merge and return a list of Workbooks.
290 read_files_to_merge (const char *inputs
[], GOFileOpener
*fo
,
291 GOIOContext
*io_context
, GOCmdContext
*cc
)
296 const char *fname
= *inputs
;
297 char *uri
= go_shell_arg_to_uri (fname
);
299 workbook_view_new_from_uri (uri
, fo
, io_context
,
300 ssconvert_import_encoding
);
304 if (go_io_error_occurred (io_context
)) {
305 g_slist_free_full (wbs
, g_object_unref
);
312 wbs
= g_slist_prepend (wbs
, wb_view_get_workbook (wbv
));
315 return g_slist_reverse (wbs
);
319 * Look at a set of workbooks, and pick a sheet size that would
320 * be good for sheets in a workbook merging them all.
323 suggest_size (GSList
*wbs
, int *csuggest
, int *rsuggest
)
329 for (l
= wbs
; l
; l
= l
->next
) {
330 Workbook
*wb
= l
->data
;
332 WORKBOOK_FOREACH_SHEET (wb
, sheet
, {
333 int r
= gnm_sheet_get_max_rows (sheet
);
334 int c
= gnm_sheet_get_max_cols (sheet
);
335 if (r
> rmax
) rmax
= r
;
336 if (c
> cmax
) cmax
= c
;
340 gnm_sheet_suggest_size (&cmax
, &rmax
);
346 cb_fixup_name_wb (G_GNUC_UNUSED gconstpointer key
,
350 GnmParsePos newpos
= nexpr
->pos
;
352 if (!expr_name_is_active (nexpr
))
357 expr_name_set_pos (nexpr
, &newpos
);
362 /* Append the sheets of workbook wb2 to workbook wb. Resize sheets
363 if necessary. Fix workbook links in sheet if necessary.
364 Merge names in workbook scope (conflicts result in an error). */
366 merge_single (Workbook
*wb
, Workbook
*wb2
,
370 /* Move names with workbook scope in wb2 over to wb */
371 GSList
*names
= g_slist_sort (gnm_named_expr_collection_list (wb2
->names
),
372 (GCompareFunc
)expr_name_cmp_by_name
);
375 for (p
= names
; p
; p
= p
->next
) {
376 GnmNamedExpr
*nexpr
= p
->data
;
377 const char *name
= expr_name_name (nexpr
);
378 GnmNamedExpr
*nexpr2
;
380 GnmParsePos newpos
= nexpr
->pos
;
382 if (!expr_name_is_active (nexpr
))
385 if (nexpr
->pos
.wb
!= wb2
|| nexpr
->pos
.sheet
!= NULL
)
388 /* Check for clash with existing name */
390 parse_pos_init (&pp
, wb
, NULL
, 0, 0);
391 nexpr2
= expr_name_lookup (&pp
, name
);
392 if (nexpr2
/* FIXME: && nexpr2-is-not-the-same-as-nexpr */) {
393 g_printerr (_("Name conflict during merge: '%s' appears twice at workbook scope.\n"),
395 g_slist_free (names
);
399 /* Move name scope to workbook wb */
401 expr_name_set_pos (nexpr
, &newpos
);
403 g_slist_free (names
);
405 while (workbook_sheet_count (wb2
) > 0) {
406 /* Remove sheet from incoming workbook */
407 Sheet
*sheet
= workbook_sheet_by_index (wb2
, 0);
408 int loc
= workbook_sheet_count (wb
);
413 g_object_ref (sheet
);
414 workbook_sheet_delete (sheet
);
415 sheet
->workbook
= wb
;
417 /* Fix names that reference the old workbook */
418 gnm_sheet_foreach_name (sheet
, (GHFunc
)cb_fixup_name_wb
, wb
);
420 undo
= gnm_sheet_resize (sheet
, cmax
, rmax
, cc
, &err
);
422 g_object_unref (undo
);
424 /* Pick a free sheet name */
425 sheet_name
= workbook_sheet_get_free_name
426 (wb
, sheet
->name_unquoted
, FALSE
, TRUE
);
427 g_object_set (sheet
, "name", sheet_name
, NULL
);
430 /* Insert and revive the sheet */
431 workbook_sheet_attach_at_pos (wb
, sheet
, loc
);
432 dependents_revive_sheet (sheet
);
433 g_object_unref (sheet
);
439 /* Merge a collection of workbooks into one. */
441 merge (Workbook
*wb
, char const *inputs
[],
442 GOFileOpener
*fo
, GOIOContext
*io_context
, GOCmdContext
*cc
)
448 wbs
= read_files_to_merge (inputs
, fo
, io_context
, cc
);
449 if (go_io_error_occurred (io_context
)) {
450 go_io_error_display (io_context
);
454 suggest_size (wbs
, &cmax
, &rmax
);
456 for (l
= wbs
; l
; l
= l
->next
) {
457 Workbook
*wb2
= l
->data
;
458 const char *uri
= go_doc_get_uri (GO_DOC (wb2
));
460 g_printerr ("Adding sheets from %s\n", uri
);
462 result
= merge_single (wb
, wb2
, cmax
, rmax
, cc
);
467 g_slist_free_full (wbs
, g_object_unref
);
472 resolve_template (const char *template, Sheet
*sheet
)
474 GString
*s
= g_string_new (NULL
);
479 char *res
= go_shell_arg_to_uri (s
->str
);
480 g_string_free (s
, TRUE
);
489 g_string_append_printf (s
, "%d", sheet
->index_in_wb
);
492 g_string_append (s
, sheet
->name_unquoted
);
495 g_string_append_c (s
, '%');
501 g_string_append_c (s
, *template);
508 run_solver (Sheet
*sheet
, WorkbookView
*wbv
)
510 GnmSolverParameters
*params
= sheet
->solver_parameters
;
512 WorkbookControl
*wbc
;
513 GnmSolver
*sol
= NULL
;
515 wbc
= g_object_new (GNM_WBC_TYPE
, NULL
);
516 wb_control_set_view (wbc
, wbv
, NULL
);
518 /* Pick a functional algorithm. */
519 if (!gnm_solver_factory_functional (params
->options
.algorithm
,
522 for (l
= gnm_solver_db_get (); l
; l
= l
->next
) {
523 GnmSolverFactory
*factory
= l
->data
;
524 if (params
->options
.model_type
!= factory
->type
)
526 if (gnm_solver_factory_functional (factory
, NULL
)) {
527 gnm_solver_param_set_algorithm (params
,
534 if (!gnm_solver_param_valid (params
, &err
))
537 sol
= params
->options
.algorithm
538 ? gnm_solver_factory_create (params
->options
.algorithm
, params
)
541 g_set_error (&err
, go_error_invalid (), 0,
542 _("Failed to create solver"));
546 if (!gnm_solver_start (sol
, wbc
, &err
))
549 while (!gnm_solver_finished (sol
)) {
550 g_main_context_iteration (NULL
, TRUE
);
553 switch (sol
->status
) {
554 case GNM_SOLVER_STATUS_DONE
:
556 case GNM_SOLVER_STATUS_CANCELLED
:
557 g_printerr ("Solver reached time or iteration limit\n");
560 g_set_error (&err
, go_error_invalid (), 0,
561 _("Solver ran, but failed"));
565 gnm_solver_store_result (sol
);
567 gnm_solver_create_report (sol
, "Solver");
571 g_object_unref (sol
);
573 g_printerr (_("Solver: %s\n"), err
->message
);
578 #define GET_ARG(conv_,name_,def_) (g_hash_table_lookup_extended(args,(name_),NULL,&arg) ? conv_((const char *)arg) : (def_))
579 #define RANGE_ARG(s_) value_new_cellrange_str(sheet,(s_))
580 #define RANGE_LIST_ARG(s_) g_slist_prepend (NULL, value_new_cellrange_str(sheet,(s_)))
581 #define SHEET_ARG(s_) workbook_sheet_by_name(wb,(s_))
584 run_tool_test (const char *tool
, char **argv
, WorkbookView
*wbv
)
587 WorkbookControl
*wbc
;
589 data_analysis_output_t
*dao
;
590 analysis_tool_engine engine
;
597 * Arguments in argv are of the form key:value.
598 * Make a hash for those.
600 args
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
601 (GDestroyNotify
)g_free
,
602 (GDestroyNotify
)g_free
);
603 for (i
= 0; argv
[i
]; i
++) {
604 const char *s
= argv
[i
];
605 const char *colon
= strchr (s
, ':');
607 g_printerr ("Ignoring tool test argument \"%s\"\n", s
);
610 g_hash_table_replace (args
, g_strndup (s
, colon
- s
),
611 g_strdup (colon
+ 1));
614 wb
= wb_view_get_workbook (wbv
);
615 wbc
= g_object_new (GNM_WBC_TYPE
, NULL
);
616 wb_control_set_view (wbc
, wbv
, NULL
);
618 sheet
= GET_ARG (SHEET_ARG
, "sheet", wb_view_cur_sheet (wbv
));
620 if (g_str_equal (tool
, "regression")) {
621 analysis_tools_data_regression_t
*data
=
622 g_new0 (analysis_tools_data_regression_t
, 1);
624 data
->base
.wbc
= wbc
;
625 data
->base
.range_1
= GET_ARG (RANGE_ARG
, "x", value_new_error_REF (NULL
));
626 data
->base
.range_2
= GET_ARG (RANGE_ARG
, "y", value_new_error_REF (NULL
));
627 data
->base
.labels
= GET_ARG (atoi
, "labels", FALSE
);
628 data
->base
.alpha
= GET_ARG (atof
, "alpha", 0.05);
629 data
->group_by
= GET_ARG ((group_by_t
), "grouped-by", GROUPED_BY_COL
);
630 data
->intercept
= GET_ARG (atoi
, "intercept", TRUE
);
631 data
->multiple_regression
= GET_ARG (atoi
, "multiple", TRUE
);
632 data
->multiple_y
= GET_ARG (atoi
, "multiple-y", FALSE
);
633 data
->residual
= GET_ARG (atoi
, "residual", TRUE
);
635 engine
= analysis_tool_regression_engine
;
637 } else if (g_str_equal (tool
, "anova")) {
638 analysis_tools_data_anova_single_t
*data
=
639 g_new0 (analysis_tools_data_anova_single_t
, 1);
641 data
->base
.input
= GET_ARG (RANGE_LIST_ARG
, "data", NULL
);
642 data
->base
.labels
= GET_ARG (atoi
, "labels", FALSE
);
643 data
->base
.group_by
= GET_ARG ((group_by_t
), "grouped-by", GROUPED_BY_COL
);
644 data
->alpha
= GET_ARG (atof
, "alpha", 0.05);
646 engine
= analysis_tool_anova_single_engine
;
649 g_printerr ("no test for tool \"%s\"\n", tool
);
653 dao
= dao_init_new_sheet (NULL
);
654 dao
->put_formulas
= TRUE
;
655 cmd_analysis_tool (wbc
, sheet
, dao
, specs
, engine
, TRUE
);
657 g_hash_table_destroy (args
);
666 convert (char const *inarg
, char const *outarg
, char const *mergeargs
[],
670 GOFileSaver
*fs
= NULL
;
671 GOFileOpener
*fo
= NULL
;
672 char *infile
= go_shell_arg_to_uri (inarg
);
673 char *outfile
= outarg
? go_shell_arg_to_uri (outarg
) : NULL
;
675 GOIOContext
*io_context
= NULL
;
678 if (ssconvert_export_id
!= NULL
) {
679 fs
= go_file_saver_for_id (ssconvert_export_id
);
682 g_printerr (_("Unknown exporter '%s'.\n"
683 "Try --list-exporters to see a list of possibilities.\n"),
684 ssconvert_export_id
);
686 } else if (outfile
== NULL
&&
687 !ssconvert_one_file_per_sheet
&&
688 go_file_saver_get_extension (fs
) != NULL
) {
689 char const *ext
= gsf_extension_pointer (infile
);
691 GString
*res
= g_string_new (NULL
);
692 g_string_append_len (res
, infile
, ext
- infile
);
693 g_string_append (res
, go_file_saver_get_extension(fs
));
694 outfile
= g_string_free (res
, FALSE
);
698 if (outfile
!= NULL
) {
699 fs
= go_file_saver_for_file_name (outfile
);
702 g_printerr (_("Unable to guess exporter to use for '%s'.\n"
703 "Try --list-exporters to see a list of possibilities.\n"),
707 if (ssconvert_verbose
)
708 g_printerr ("Using exporter %s\n",
709 go_file_saver_get_id (fs
));
713 if (outfile
== NULL
) {
714 g_printerr (_("An output file name or an explicit export type is required.\n"
715 "Try --list-exporters to see a list of possibilities.\n"));
720 if (ssconvert_import_id
!= NULL
) {
721 fo
= go_file_opener_for_id (ssconvert_import_id
);
724 g_printerr (_("Unknown importer '%s'.\n"
725 "Try --list-importers to see a list of possibilities.\n"),
726 ssconvert_import_id
);
734 io_context
= go_io_context_new (cc
);
735 if (mergeargs
== NULL
) {
736 wbv
= workbook_view_new_from_uri (infile
, fo
,
738 ssconvert_import_encoding
);
740 wbv
= workbook_view_new (NULL
);
743 if (go_io_error_occurred (io_context
)) {
744 go_io_error_display (io_context
);
747 } else if (wbv
== NULL
) {
748 g_printerr (_("Loading %s failed\n"), infile
);
753 wb
= wb_view_get_workbook (wbv
);
755 res
= handle_export_options (fs
, GO_DOC (wb
));
759 if (mergeargs
!= NULL
) {
760 if (merge (wb
, mergeargs
, fo
, io_context
, cc
))
764 if (ssconvert_goal_seek
) {
766 Sheet
*sheet
= wb_view_cur_sheet (wbv
);
768 for (i
= 0; ssconvert_goal_seek
[i
]; i
++) {
769 setup_range (G_OBJECT (sheet
),
770 "ssconvert-goal-seek",
772 ssconvert_goal_seek
[i
]);
773 dialog_goal_seek (NULL
, sheet
);
777 if (ssconvert_solve
) {
778 Sheet
*sheet
= wb_view_cur_sheet (wbv
);
779 run_solver (sheet
, wbv
);
782 if (ssconvert_tool_test
&& ssconvert_tool_test
[0]) {
783 run_tool_test (ssconvert_tool_test
[0],
784 ssconvert_tool_test
+ 1,
788 if (ssconvert_resize
) {
790 if (sscanf (ssconvert_resize
, "%dx%d", &rows
, &cols
) == 2) {
793 if (ssconvert_verbose
)
794 g_printerr ("Resizing to %dx%d\n", rows
, cols
);
796 for (n
= workbook_sheet_count (wb
) - 1;
800 Sheet
*sheet
= workbook_sheet_by_index (wb
, n
);
802 gnm_sheet_resize (sheet
, cols
, rows
,
805 g_printerr ("Resizing of sheet %s failed\n",
806 sheet
->name_unquoted
);
807 g_object_unref (undo
);
812 if (ssconvert_recalc
)
813 workbook_recalc_all (wb
);
817 setup_range (G_OBJECT (wb
),
821 else if (ssconvert_one_file_per_sheet
||
822 (workbook_sheet_count (wb
) > 1 &&
823 go_file_saver_get_save_scope (fs
) != GO_FILE_SAVE_WORKBOOK
)) {
824 if (ssconvert_one_file_per_sheet
) {
825 GSList
*ptr
, *sheets
;
830 template = strchr (outarg
, '%')
832 : g_strconcat (outarg
, ".%n", NULL
);
834 sheets
= workbook_sheets (wb
);
835 for (ptr
= sheets
; ptr
; ptr
= ptr
->next
) {
836 Sheet
*sheet
= ptr
->data
;
837 char *tmpfile
= resolve_template (template, sheet
);
838 int oldn
= sheet
->index_in_wb
;
841 * HACK: (bug 694408).
843 * We don't have a good way of specifying the
844 * sheet. Move it to the front and select
845 * it. That will at least make cvs and txt
846 * exporters reliable find it.
848 workbook_sheet_move (sheet
, -oldn
);
849 wb_view_sheet_focus (wbv
, sheet
);
851 res
= !workbook_view_save_as (wbv
, fs
, tmpfile
, cc
);
852 workbook_sheet_move (sheet
, +oldn
);
859 g_slist_free (sheets
);
862 g_printerr (_("Selected exporter (%s) does not support saving multiple sheets in one file.\n"
863 "Only the current sheet will be saved. To get around this limitation, use -S.\n"),
864 go_file_saver_get_id (fs
));
866 res
= !workbook_view_save_as (wbv
, fs
, outfile
, cc
);
872 g_object_unref (io_context
);
880 main (int argc
, char const **argv
)
882 GOErrorInfo
*plugin_errs
;
885 GOptionContext
*ocontext
;
886 GError
*error
= NULL
;
888 /* No code before here, we need to init threads */
889 argv
= gnm_pre_parse_init (argc
, argv
);
891 ocontext
= g_option_context_new (_("INFILE [OUTFILE]"));
892 g_option_context_add_main_entries (ocontext
, ssconvert_options
, GETTEXT_PACKAGE
);
893 g_option_context_add_group (ocontext
, gnm_get_option_group ());
895 * The printing code uses gtk+ stuff, so we need to init gtk+. We
896 * do that without opening any displays.
898 g_option_context_add_group (ocontext
, gtk_get_option_group (FALSE
));
899 g_option_context_parse (ocontext
, &argc
, (char ***)&argv
, &error
);
900 g_option_context_free (ocontext
);
903 g_printerr (_("%s\nRun '%s --help' to see a full list of available command line options.\n"),
904 error
->message
, argv
[0]);
905 g_error_free (error
);
909 if (ssconvert_show_version
) {
910 g_print (_("ssconvert version '%s'\ndatadir := '%s'\nlibdir := '%s'\n"),
911 GNM_VERSION_FULL
, gnm_sys_data_dir (), gnm_sys_lib_dir ());
917 cc
= gnm_cmd_context_stderr_new ();
918 gnm_plugins_init (GO_CMD_CONTEXT (cc
));
919 go_plugin_db_activate_plugin_list (
920 go_plugins_get_available_plugins (), &plugin_errs
);
922 /* FIXME: What do we want to do here? */
923 go_error_info_free (plugin_errs
);
925 go_component_set_default_command_context (cc
);
927 if (ssconvert_list_exporters
)
928 list_them (go_get_file_savers (),
929 (get_desc_f
) &go_file_saver_get_id
,
930 (get_desc_f
) &go_file_saver_get_description
);
931 else if (ssconvert_list_importers
)
932 list_them (go_get_file_openers (),
933 (get_desc_f
) &go_file_opener_get_id
,
934 (get_desc_f
) &go_file_opener_get_description
);
935 else if (ssconvert_merge_target
!=NULL
&& argc
>=3) {
936 res
= convert (argv
[1], ssconvert_merge_target
, argv
+1, cc
);
937 } else if (argc
== 2 || argc
== 3) {
938 res
= convert (argv
[1], argv
[2], NULL
, cc
);
940 g_printerr (_("Usage: %s [OPTION...] %s\n"),
942 _("INFILE [OUTFILE]"));
946 go_component_set_default_command_context (NULL
);
949 gnm_pre_parse_shutdown ();