2 * utils.c: Various utility routines that do not depend on the GUI of Gnumeric
5 * Miguel de Icaza (miguel@gnu.org)
6 * Jukka-Pekka Iivonen (iivonen@iki.fi)
7 * Zbigniew Chyla (cyba@gnome.pl)
9 #include <gnumeric-config.h>
10 #include <glib/gi18n-lib.h>
13 #include <gnumeric-paths.h>
18 #include <workbook-view.h>
21 #include <goffice/goffice.h>
26 #include <sys/types.h>
31 #include <gsf/gsf-impl-utils.h>
32 #include <gsf/gsf-doc-meta-data.h>
33 #include <gsf/gsf-timestamp.h>
35 #define SHEET_SELECTION_KEY "sheet-selection"
36 #define SSCONVERT_SHEET_SET_KEY "ssconvert-sheets"
38 static char *gnumeric_lib_dir
;
39 static char *gnumeric_data_dir
;
40 static char *gnumeric_locale_dir
;
41 static char *gnumeric_usr_dir
;
42 static char *gnumeric_usr_dir_unversioned
;
43 static char *gnumeric_extern_plugin_dir
;
44 static GSList
*gutils_xml_in_docs
;
47 running_in_tree (void)
49 const char *argv0
= g_get_prgname ();
54 /* Look for ".libs" as final path element. */
56 const char *dotlibs
= strstr (argv0
, ".libs/");
58 (dotlibs
== argv0
|| G_IS_DIR_SEPARATOR (dotlibs
[-1])) &&
59 strchr (dotlibs
+ 6, G_DIR_SEPARATOR
) == NULL
) {
60 size_t l
= dotlibs
- argv0
;
61 char *res
= g_strndup (argv0
, l
);
63 while (l
> 0 && G_IS_DIR_SEPARATOR (res
[l
- 1]))
65 while (l
> 0 && !G_IS_DIR_SEPARATOR (res
[l
- 1]))
67 while (l
> 0 && G_IS_DIR_SEPARATOR (res
[l
- 1]))
75 const char *builddir
= g_getenv ("GNM_TEST_TOP_BUILDDIR");
77 return g_strdup (builddir
);
83 static gboolean gutils_inited
= FALSE
;
91 // This function will end up being called twice in normal operation:
92 // once from gnm_pre_parse_init and once from gnm_init. Introspection
93 // will not get the first.
98 gchar
*dir
= g_win32_get_package_installation_directory_of_module (NULL
);
99 gnumeric_lib_dir
= g_build_filename (dir
, "lib",
100 "gnumeric", GNM_VERSION_FULL
,
102 gnumeric_data_dir
= g_build_filename (dir
, "share",
103 "gnumeric", GNM_VERSION_FULL
,
105 gnumeric_locale_dir
= g_build_filename (dir
, "share", "locale", NULL
);
106 gnumeric_extern_plugin_dir
= g_build_filename
107 (dir
, "lib", "gnumeric", GNM_API_VERSION
, "plugins",
111 top_builddir
= running_in_tree ();
114 go_filename_simplify (top_builddir
, GO_DOTDOT_SYNTACTIC
,
116 if (gnm_debug_flag ("in-tree"))
117 g_printerr ("Running in-tree [%s]\n", top_builddir
);
118 g_free (top_builddir
);
121 if (!gnumeric_lib_dir
)
122 gnumeric_lib_dir
= g_strdup (GNUMERIC_LIBDIR
);
123 gnumeric_data_dir
= g_strdup (GNUMERIC_DATADIR
);
124 gnumeric_locale_dir
= g_strdup (GNUMERIC_LOCALEDIR
);
125 gnumeric_extern_plugin_dir
= g_strdup (GNUMERIC_EXTERNPLUGINDIR
);
127 home_dir
= g_get_home_dir ();
128 gnumeric_usr_dir_unversioned
= home_dir
129 ? g_build_filename (home_dir
, ".gnumeric", NULL
)
131 gnumeric_usr_dir
= gnumeric_usr_dir_unversioned
132 ? g_build_filename (gnumeric_usr_dir_unversioned
, GNM_VERSION_FULL
, NULL
)
135 gutils_inited
= TRUE
;
139 gutils_shutdown (void)
143 g_free (gnumeric_lib_dir
);
144 gnumeric_lib_dir
= NULL
;
145 g_free (gnumeric_data_dir
);
146 gnumeric_data_dir
= NULL
;
147 g_free (gnumeric_locale_dir
);
148 gnumeric_locale_dir
= NULL
;
149 g_free (gnumeric_usr_dir
);
150 gnumeric_usr_dir
= NULL
;
151 g_free (gnumeric_usr_dir_unversioned
);
152 gnumeric_usr_dir_unversioned
= NULL
;
153 g_free (gnumeric_extern_plugin_dir
);
154 gnumeric_extern_plugin_dir
= NULL
;
156 for (l
= gutils_xml_in_docs
; l
; l
= l
->next
) {
157 GsfXMLInDoc
**pdoc
= l
->data
;
158 gsf_xml_in_doc_free (*pdoc
);
161 g_slist_free (gutils_xml_in_docs
);
162 gutils_xml_in_docs
= NULL
;
166 gnm_sys_lib_dir (void)
168 return gnumeric_lib_dir
;
172 gnm_sys_data_dir (void)
174 return gnumeric_data_dir
;
178 gnm_sys_extern_plugin_dir (void)
180 return gnumeric_extern_plugin_dir
;
184 gnm_locale_dir (void)
186 return gnumeric_locale_dir
;
190 gnm_usr_dir (gboolean versioned
)
192 return versioned
? gnumeric_usr_dir
: gnumeric_usr_dir_unversioned
;
197 all_ascii (const char *s
)
199 while ((guchar
)*s
< 0x7f) {
209 * Like strto[ld], but...
210 * 1. handles non-ascii characters
211 * 2. disallows 0x000.0p+00 and 0.0d+00
212 * 3. ensures sane errno on exit
215 gnm_utf8_strto (const char *s
, char **end
)
221 GString
const *decimal
= go_locale_get_decimal ();
222 gboolean seen_decimal
= FALSE
;
223 gboolean seen_digit
= FALSE
;
229 res
= gnm_strto (s
, end
);
230 goto handle_denormal
;
233 ascii
= g_string_sized_new (100);
239 while (g_unichar_isspace (g_utf8_get_char (p
))) {
240 p
= g_utf8_next_char (p
);
244 sign
= go_unichar_issign (g_utf8_get_char (p
));
246 g_string_append_c (ascii
, "-/+"[sign
+ 1]);
247 p
= g_utf8_next_char (p
);
251 if (strncmp (p
, decimal
->str
, decimal
->len
) == 0) {
255 go_string_append_gstring (ascii
, decimal
);
257 } else if (g_unichar_isdigit (g_utf8_get_char (p
))) {
258 g_string_append_c (ascii
, '0' + g_unichar_digit_value (g_utf8_get_char (p
)));
259 p
= g_utf8_next_char (p
);
266 /* No conversion, bail to gnm_strto for nan etc. */
267 g_string_free (ascii
, TRUE
);
268 return gnm_strto (s
, end
);
271 if (*p
== 'e' || *p
== 'E') {
274 g_string_append_c (ascii
, 'e');
275 p
= g_utf8_next_char (p
);
277 sign
= go_unichar_issign (g_utf8_get_char (p
));
279 g_string_append_c (ascii
, "-/+"[sign
+ 1]);
280 p
= g_utf8_next_char (p
);
282 while (g_unichar_isdigit (g_utf8_get_char (p
))) {
283 g_string_append_c (ascii
, '0' + g_unichar_digit_value (g_utf8_get_char (p
)));
284 p
= g_utf8_next_char (p
);
288 res
= gnm_strto (ascii
->str
, end
);
290 *end
= g_utf8_offset_to_pointer
291 (s
, spaces
+ g_utf8_pointer_to_offset (ascii
->str
, *end
));
292 g_string_free (ascii
, TRUE
);
298 if (res
!= 0 && gnm_abs (res
) < GNM_MIN
)
307 * Like strtol, but...
308 * 1. handles non-ascii characters
309 * 2. assumes base==10
310 * 3. ensures sane errno on exit
313 gnm_utf8_strtol (const char *s
, char **end
)
318 unsigned long res
= 0, lim
, limd
;
324 while (g_unichar_isspace (g_utf8_get_char (p
)))
325 p
= g_utf8_next_char (p
);
327 sign
= go_unichar_issign (g_utf8_get_char (p
));
329 p
= g_utf8_next_char (p
);
331 lim
= (-(unsigned long)LONG_MIN
) / 10u;
332 limd
= (-(unsigned long)LONG_MIN
) % 10u;
334 lim
= (unsigned long)LONG_MAX
/ 10u;
335 limd
= (unsigned long)LONG_MAX
% 10u;
338 if (!g_unichar_isdigit (g_utf8_get_char (p
))) {
344 while (g_unichar_isdigit (g_utf8_get_char (p
))) {
345 guint8 dig
= g_unichar_digit_value (g_utf8_get_char (p
));
346 p
= g_utf8_next_char (p
);
348 if (res
> lim
|| (res
== lim
&& dig
> limd
)) {
350 while (g_unichar_isdigit (g_utf8_get_char (p
)))
351 p
= g_utf8_next_char (p
);
354 return sign
< 0 ? LONG_MIN
: LONG_MAX
;
357 res
= res
* 10u + dig
;
361 return sign
< 0 ? (long)-res
: (long)res
;
366 gnm_regcomp_XL (GORegexp
*preg
, char const *pattern
, int cflags
,
367 gboolean anchor_start
, gboolean anchor_end
)
369 GString
*res
= g_string_new (NULL
);
373 g_string_append_c (res
, '^');
378 g_string_append (res
, ".*");
383 g_string_append_c (res
, '.');
388 if (pattern
[1] == '*' ||
394 pattern
= go_regexp_quote1 (res
, pattern
);
399 g_string_append_c (res
, '$');
401 retval
= go_regcomp (preg
, res
->str
, cflags
);
402 g_string_free (res
, TRUE
);
407 * gnm_excel_search_impl:
408 * @needle: the pattern to search for, see gnm_regcomp_XL.
409 * @haystack: the string to search in.
410 * @skip: zero-based search start point in characters.
412 * Returns: -1 for a non-match, or zero-based location in
415 * The is the implementation of Excel's SEARCH function.
416 * However, note that @skip and return value are zero-based.
419 gnm_excel_search_impl (const char *needle
, const char *haystack
,
426 for (i
= skip
, hay2
= haystack
; i
> 0; i
--) {
429 hay2
= g_utf8_next_char (hay2
);
432 if (gnm_regcomp_XL (&r
, needle
, GO_REG_ICASE
, FALSE
, FALSE
) == GO_REG_OK
) {
435 switch (go_regexec (&r
, hay2
, 1, &rm
, 0)) {
441 g_utf8_pointer_to_offset (hay2
, hay2
+ rm
.rm_so
);
443 g_warning ("Unexpected go_regexec result");
447 g_warning ("Unexpected regcomp result");
456 color_to_string (PangoColor color
)
458 static char result
[100];
459 sprintf (result
, "%04x:%04x:%04x", color
.red
, color
.green
, color
.blue
);
464 enum_name (GType typ
, int i
)
466 static char result
[100];
467 GEnumClass
*ec
= g_type_class_ref (typ
);
470 GEnumValue
*ev
= g_enum_get_value (ec
, i
);
471 g_type_class_unref (ec
);
473 if (ev
&& ev
->value_nick
)
474 return ev
->value_nick
;
475 if (ev
&& ev
->value_name
)
476 return ev
->value_name
;
479 sprintf (result
, "%d", i
);
484 cb_gnm_pango_attr_dump (PangoAttribute
*attr
, gpointer user_data
)
486 g_print (" start=%u; end=%u\n", attr
->start_index
, attr
->end_index
);
487 switch (attr
->klass
->type
) {
488 case PANGO_ATTR_FAMILY
:
489 g_print (" family=\"%s\"\n", ((PangoAttrString
*)attr
)->value
);
491 case PANGO_ATTR_LANGUAGE
:
492 g_print (" language=\"%s\"\n", pango_language_to_string (((PangoAttrLanguage
*)attr
)->value
));
494 case PANGO_ATTR_STYLE
:
495 g_print (" style=%s\n",
496 enum_name (PANGO_TYPE_STYLE
, ((PangoAttrInt
*)attr
)->value
));
498 case PANGO_ATTR_WEIGHT
:
499 g_print (" weight=%s\n",
500 enum_name (PANGO_TYPE_WEIGHT
, ((PangoAttrInt
*)attr
)->value
));
502 case PANGO_ATTR_VARIANT
:
503 g_print (" variant=%s\n",
504 enum_name (PANGO_TYPE_VARIANT
, ((PangoAttrInt
*)attr
)->value
));
506 case PANGO_ATTR_STRETCH
:
507 g_print (" stretch=%s\n",
508 enum_name (PANGO_TYPE_STRETCH
, ((PangoAttrInt
*)attr
)->value
));
510 case PANGO_ATTR_UNDERLINE
:
511 g_print (" underline=%s\n",
512 enum_name (PANGO_TYPE_UNDERLINE
, ((PangoAttrInt
*)attr
)->value
));
514 case PANGO_ATTR_STRIKETHROUGH
:
515 g_print (" strikethrough=%d\n", ((PangoAttrInt
*)attr
)->value
);
517 case PANGO_ATTR_RISE
:
518 g_print (" rise=%d\n", ((PangoAttrInt
*)attr
)->value
);
520 case PANGO_ATTR_FALLBACK
:
521 g_print (" fallback=%d\n", ((PangoAttrInt
*)attr
)->value
);
523 case PANGO_ATTR_LETTER_SPACING
:
524 g_print (" letter_spacing=%d\n", ((PangoAttrInt
*)attr
)->value
);
526 case PANGO_ATTR_SIZE
:
527 g_print (" size=%d%s\n",
528 ((PangoAttrSize
*)attr
)->size
,
529 ((PangoAttrSize
*)attr
)->absolute
? " abs" : "");
531 case PANGO_ATTR_SCALE
:
532 g_print (" scale=%g\n", ((PangoAttrFloat
*)attr
)->value
);
534 case PANGO_ATTR_FOREGROUND
:
535 g_print (" foreground=%s\n", color_to_string (((PangoAttrColor
*)attr
)->color
));
537 case PANGO_ATTR_BACKGROUND
:
538 g_print (" background=%s\n", color_to_string (((PangoAttrColor
*)attr
)->color
));
540 case PANGO_ATTR_UNDERLINE_COLOR
:
541 g_print (" underline_color=%s\n", color_to_string (((PangoAttrColor
*)attr
)->color
));
543 case PANGO_ATTR_STRIKETHROUGH_COLOR
:
544 g_print (" strikethrough_color=%s\n", color_to_string (((PangoAttrColor
*)attr
)->color
));
546 case PANGO_ATTR_FONT_DESC
: {
547 char *desc
= pango_font_description_to_string (((PangoAttrFontDesc
*)attr
)->desc
);
548 g_print (" font=\"%s\"\n", desc
);
553 g_print (" type=%s\n", enum_name (PANGO_TYPE_ATTR_TYPE
, attr
->klass
->type
));
560 gnm_pango_attr_dump (PangoAttrList
*list
)
562 g_print ("PangoAttrList at %p\n", list
);
563 pango_attr_list_filter (list
, cb_gnm_pango_attr_dump
, NULL
);
569 cb_gnm_pango_attr_list_equal (PangoAttribute
*a
, gpointer _sl
)
572 *sl
= g_slist_prepend (*sl
, a
);
577 * This is a bit of a hack. It might claim a difference even when things
578 * actually are equal. But not the other way around.
581 gnm_pango_attr_list_equal (PangoAttrList
const *l1
, PangoAttrList
const *l2
)
585 else if (l1
== NULL
|| l2
== NULL
)
589 GSList
*sl1
= NULL
, *sl2
= NULL
;
590 (void)pango_attr_list_filter ((PangoAttrList
*)l1
,
591 cb_gnm_pango_attr_list_equal
,
593 (void)pango_attr_list_filter ((PangoAttrList
*)l2
,
594 cb_gnm_pango_attr_list_equal
,
598 const PangoAttribute
*a1
= sl1
->data
;
599 const PangoAttribute
*a2
= sl2
->data
;
600 if (a1
->start_index
!= a2
->start_index
||
601 a1
->end_index
!= a2
->end_index
||
602 !pango_attribute_equal (a1
, a2
))
604 sl1
= g_slist_delete_link (sl1
, sl1
);
605 sl2
= g_slist_delete_link (sl2
, sl2
);
615 /* ------------------------------------------------------------------------- */
619 char *monetary_locale
;
622 * gnm_push_C_locale: (skip)
624 * Returns the current locale, and sets the locale and the value-format
625 * engine's locale to 'C'. The caller must call gnm_pop_C_locale to free the
626 * result and restore the previous locale.
629 gnm_push_C_locale (void)
631 GnmLocale
*old
= g_new0 (GnmLocale
, 1);
633 old
->num_locale
= g_strdup (go_setlocale (LC_NUMERIC
, NULL
));
634 go_setlocale (LC_NUMERIC
, "C");
635 old
->monetary_locale
= g_strdup (go_setlocale (LC_MONETARY
, NULL
));
636 go_setlocale (LC_MONETARY
, "C");
637 go_locale_untranslated_booleans ();
643 * gnm_pop_C_locale: (skip)
644 * @locale: #GnmLocale
646 * Frees the result of gnm_push_C_locale and restores the original locale.
649 gnm_pop_C_locale (GnmLocale
*locale
)
651 /* go_setlocale restores bools to locale translation */
652 go_setlocale (LC_MONETARY
, locale
->monetary_locale
);
653 g_free (locale
->monetary_locale
);
654 go_setlocale (LC_NUMERIC
, locale
->num_locale
);
655 g_free (locale
->num_locale
);
659 /* ------------------------------------------------------------------------- */
662 gnm_debug_flag (const char *flag
)
665 key
.key
= (char *)flag
;
668 return g_parse_debug_string (g_getenv ("GNM_DEBUG"), &key
, 1) != 0;
671 /* ------------------------------------------------------------------------- */
674 gnm_string_add_number (GString
*buf
, gnm_float d
)
676 size_t old_len
= buf
->len
;
681 gnm_float l10
= gnm_log10 (FLT_RADIX
);
682 digits
= (int)gnm_ceil (GNM_MANT_DIG
* l10
) +
683 (l10
== (int)l10
? 0 : 1);
686 g_string_append_printf (buf
, "%.*" GNM_FORMAT_g
, digits
- 1, d
);
687 d2
= gnm_strto (buf
->str
+ old_len
, NULL
);
690 g_string_truncate (buf
, old_len
);
691 g_string_append_printf (buf
, "%.*" GNM_FORMAT_g
, digits
, d
);
695 /* ------------------------------------------------------------------------- */
698 gnm_insert_meta_date (GODoc
*doc
, char const *name
)
700 GValue
*value
= g_new0 (GValue
, 1);
702 GsfTimestamp
*ts
= gsf_timestamp_new ();
704 g_get_current_time (&tm
);
707 gsf_timestamp_set_time (ts
, tm
.tv_sec
);
708 g_value_init (value
, GSF_TIMESTAMP_TYPE
);
709 gsf_timestamp_to_value (ts
, value
);
710 gsf_timestamp_free (ts
);
712 gsf_doc_meta_data_insert (go_doc_get_meta_data (doc
),
717 /* ------------------------------------------------------------------------- */
720 * gnm_object_get_bool:
722 * @name: property name
724 * Returns: the value of @o's boolean property @name.
727 gnm_object_get_bool (gpointer o
, const char *name
)
730 g_object_get (o
, name
, &b
, NULL
);
735 * gnm_object_has_readable_prop:
737 * @property: property name
738 * @typ: property's type or %G_TYPE_NONE. (Exact type, not is-a.)
739 * @pres: (out) (optional): location to store property value.
741 * Returns: %TRUE if @obj has a readable property named @property
745 gnm_object_has_readable_prop (gconstpointer obj
, const char *property
,
746 GType typ
, gpointer pres
)
754 klass
= G_OBJECT_GET_CLASS (G_OBJECT (obj
));
755 spec
= g_object_class_find_property (klass
, property
);
757 !(G_PARAM_READABLE
& spec
->flags
) ||
758 (typ
!= G_TYPE_NONE
&& spec
->value_type
!= typ
))
762 g_object_get (G_OBJECT (obj
), property
, pres
, NULL
);
766 /* ------------------------------------------------------------------------- */
769 gnm_float_equal (gnm_float
const *a
, const gnm_float
*b
)
775 gnm_float_hash (gnm_float
const *d
)
778 gnm_float mant
= gnm_frexp (gnm_abs (*d
), &expt
);
779 guint h
= ((guint
)(0x80000000u
* mant
)) ^ expt
;
785 /* ------------------------------------------------------------------------- */
788 GnmHashTableOrder order
;
793 cb_compare (gconstpointer a_
, gconstpointer b_
, gpointer user_data
)
795 struct cb_compare
*user
= user_data
;
796 gpointer
*a
= (gpointer
)a_
;
797 gpointer
*b
= (gpointer
)b_
;
799 return user
->order (a
[0], a
[1], b
[0], b
[1], user
->user
);
804 * gnm_hash_table_foreach_ordered:
806 * @callback: (scope call): #GHFunc
807 * @order: (scope call): Ordering function
808 * @user: user data for callback and order
810 * Like g_hash_table_foreach, but with an ordering imposed.
813 gnm_hash_table_foreach_ordered (GHashTable
*h
,
815 GnmHashTableOrder order
,
821 GHashTableIter hiter
;
824 /* Gather all key-value pairs */
825 data
= g_ptr_array_new ();
826 g_hash_table_iter_init (&hiter
, h
);
827 while (g_hash_table_iter_next (&hiter
, &key
, &value
)) {
828 g_ptr_array_add (data
, key
);
829 g_ptr_array_add (data
, value
);
832 /* Sort according to given ordering */
835 g_qsort_with_data (data
->pdata
,
836 data
->len
/ 2, 2 * sizeof (gpointer
),
840 /* Call user callback with all pairs */
841 for (ui
= 0; ui
< data
->len
; ui
+= 2)
842 callback (g_ptr_array_index (data
, ui
),
843 g_ptr_array_index (data
, ui
+ 1),
847 g_ptr_array_free (data
, TRUE
);
850 /* ------------------------------------------------------------------------- */
853 gnm_xml_in_doc_dispose_on_exit (GsfXMLInDoc
**pdoc
)
855 gutils_xml_in_docs
= g_slist_prepend (gutils_xml_in_docs
, pdoc
);
858 /* ------------------------------------------------------------------------- */
861 * gnm_file_saver_get_sheet:
863 * @wbv: #WorkbookView
865 * For a single-sheet saver, this function determines what sheet to save.
867 * Returns: (transfer none): the sheet to export
870 gnm_file_saver_get_sheet (GOFileSaver
const *fs
, WorkbookView
const *wbv
)
875 g_return_val_if_fail (GO_IS_FILE_SAVER (fs
), NULL
);
876 g_return_val_if_fail (go_file_saver_get_save_scope (fs
) ==
877 GO_FILE_SAVE_SHEET
, NULL
);
878 g_return_val_if_fail (GNM_IS_WORKBOOK_VIEW (wbv
), NULL
);
880 wb
= wb_view_get_workbook (wbv
);
882 sel
= g_object_get_data (G_OBJECT (wb
), SHEET_SELECTION_KEY
);
885 return g_ptr_array_index (sel
, 0);
886 g_critical ("Someone messed up sheet selection");
889 return wb_view_cur_sheet (wbv
);
893 * gnm_file_saver_get_sheets:
895 * @wbv: #WorkbookView
896 * @default_all: If %TRUE, all sheets will be selected by default; if %FALSE,
897 * this function will return %NULL if no sheets were explicitly selected.
899 * This function determines what sheets to save.
901 * Returns: (transfer container) (element-type Sheet): the sheets to export
903 * Note: the return value should be unreffed, not freed.
906 gnm_file_saver_get_sheets (GOFileSaver
const *fs
,
907 WorkbookView
const *wbv
,
908 gboolean default_all
)
911 GPtrArray
*sel
, *sheets
;
912 GOFileSaveScope save_scope
;
914 g_return_val_if_fail (GO_IS_FILE_SAVER (fs
), NULL
);
915 g_return_val_if_fail (GNM_IS_WORKBOOK_VIEW (wbv
), NULL
);
917 save_scope
= go_file_saver_get_save_scope (fs
);
918 wb
= wb_view_get_workbook (wbv
);
919 sel
= g_object_get_data (G_OBJECT (wb
), SHEET_SELECTION_KEY
);
920 sheets
= g_object_get_data (G_OBJECT (wb
), SSCONVERT_SHEET_SET_KEY
);
922 g_ptr_array_ref (sel
);
924 sel
= g_ptr_array_ref (sheets
);
925 else if (save_scope
!= GO_FILE_SAVE_WORKBOOK
) {
926 sel
= g_ptr_array_new ();
927 g_ptr_array_add (sel
, wb_view_cur_sheet (wbv
));
928 } else if (default_all
) {
930 sel
= g_ptr_array_new ();
931 for (i
= 0; i
< workbook_sheet_count (wb
); i
++) {
932 Sheet
*sheet
= workbook_sheet_by_index (wb
, i
);
933 g_ptr_array_add (sel
, sheet
);
941 gnm_file_saver_common_export_option (GOFileSaver
const *fs
,
943 const char *key
, const char *value
,
949 g_return_val_if_fail (GO_IS_FILE_SAVER (fs
), FALSE
);
950 g_return_val_if_fail (GNM_IS_WORKBOOK (wb
), FALSE
);
951 g_return_val_if_fail (key
!= NULL
, FALSE
);
952 g_return_val_if_fail (value
!= NULL
, FALSE
);
954 if (strcmp (key
, "sheet") == 0) {
956 Sheet
*sheet
= workbook_sheet_by_name (wb
, value
);
960 *err
= g_error_new (go_error_invalid (), 0,
961 _("Unknown sheet \"%s\""),
966 sheets
= g_object_get_data (G_OBJECT (wb
), SSCONVERT_SHEET_SET_KEY
);
968 sheets
= g_ptr_array_new ();
969 g_object_set_data_full (G_OBJECT (wb
),
970 SSCONVERT_SHEET_SET_KEY
,
972 (GDestroyNotify
)g_ptr_array_unref
);
974 g_ptr_array_add (sheets
, sheet
);
980 *err
= g_error_new (go_error_invalid (), 0,
981 _("Invalid export option \"%s\" for format %s"),
983 go_file_saver_get_id (fs
));