1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * gsf-output-csv.c: a GsfOutput to write .csv style files.
5 * Copyright (C) 2005-2006 Morten Welinder (terra@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2.1 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gsf-config.h>
23 #include <gsf/gsf-output-csv.h>
24 #include <gsf/gsf-output-impl.h>
25 #include <gsf/gsf-impl-utils.h>
26 #include <gsf/gsf-utils.h>
30 static GObjectClass *parent_class;
37 PROP_QUOTING_TRIGGERS,
38 PROP_QUOTING_ON_WHITESPACE,
44 * We really need to add a data member to the structure, but that would be
45 * an ABI change. For now, fake it.
47 #define HACK_QUOTING_ON_WHITESPACE "hack-quoting-on-whitespace"
50 gsf_output_csv_finalize (GObject *obj)
52 GsfOutputCsv *csv = (GsfOutputCsv *)obj;
54 if (csv->sink != NULL)
55 g_object_unref (G_OBJECT (csv->sink));
57 g_free (csv->quoting_triggers);
59 g_free (csv->separator);
60 g_string_free (csv->buf, TRUE);
62 parent_class->finalize (obj);
66 gsf_output_csv_write (GsfOutput *output,
67 size_t num_bytes, guint8 const *data)
69 GsfOutputCsv *csv = GSF_OUTPUT_CSV (output);
70 return gsf_output_write (csv->sink, num_bytes, data);
74 gsf_output_csv_seek (GsfOutput *output,
78 GsfOutputCsv *csv = GSF_OUTPUT_CSV (output);
79 return gsf_output_seek (csv->sink, offset, whence);
83 gsf_output_csv_close (G_GNUC_UNUSED GsfOutput *output)
89 gsf_output_csv_write_field (GsfOutputCsv *csv, char const *field, size_t len)
95 g_return_val_if_fail (GSF_IS_OUTPUT_CSV (csv), FALSE);
96 g_return_val_if_fail (field != NULL, FALSE);
98 if (len == (size_t)-1)
102 if (csv->fields_on_line && csv->separator_len)
103 g_string_append_len (csv->buf,
106 csv->fields_on_line = TRUE;
108 switch (csv->quoting_mode) {
110 case GSF_OUTPUT_CSV_QUOTING_MODE_NEVER:
113 case GSF_OUTPUT_CSV_QUOTING_MODE_ALWAYS:
116 case GSF_OUTPUT_CSV_QUOTING_MODE_AUTO: {
117 char const *p = field;
120 gunichar c = g_utf8_get_char (p);
121 if (g_utf8_strchr (csv->quoting_triggers, -1, c)) {
125 p = g_utf8_next_char (p);
128 if (!quote && *field &&
129 (g_unichar_isspace (g_utf8_get_char (field)) ||
130 g_unichar_isspace (g_utf8_get_char (g_utf8_prev_char (p)))) &&
131 g_object_get_data (G_OBJECT (csv),
132 HACK_QUOTING_ON_WHITESPACE) != NULL)
138 if (quote && csv->quote_len > 0) {
139 g_string_append_len (csv->buf,
143 while (field < end) {
144 gunichar c = g_utf8_get_char (field);
145 if (g_utf8_strchr (csv->quote, -1, c))
146 g_string_append_len (csv->buf,
149 g_string_append_unichar (csv->buf, c);
150 field = g_utf8_next_char (field);
153 g_string_append_len (csv->buf,
157 g_string_append_len (csv->buf, field, len);
159 ok = gsf_output_write (csv->sink, csv->buf->len, csv->buf->str);
161 g_string_truncate (csv->buf, 0);
166 /* ------------------------------------------------------------------------- */
169 gsf_output_csv_write_eol (GsfOutputCsv *csv)
171 g_return_val_if_fail (GSF_IS_OUTPUT_CSV (csv), FALSE);
173 csv->fields_on_line = FALSE;
174 return gsf_output_write (csv->sink, csv->eol_len, csv->eol);
177 /* ------------------------------------------------------------------------- */
180 gsf_output_csv_quoting_mode_get_type (void)
182 static GType gsf_output_csv_quoting_mode_type = 0;
184 if (gsf_output_csv_quoting_mode_type == 0) {
185 static GEnumValue const values[] = {
186 { GSF_OUTPUT_CSV_QUOTING_MODE_NEVER, (char *)"GSF_OUTPUT_CSV_QUOTING_MODE_NEVER", (char *)"never" },
187 { GSF_OUTPUT_CSV_QUOTING_MODE_AUTO, (char *)"GSF_OUTPUT_CSV_QUOTING_MODE_AUTO", (char *)"auto" },
188 { GSF_OUTPUT_CSV_QUOTING_MODE_ALWAYS, (char *)"GSF_OUTPUT_CSV_QUOTING_MODE_ALWAYS", (char *)"always" },
191 gsf_output_csv_quoting_mode_type = g_enum_register_static (
192 g_intern_static_string ("GsfOutputCsvQuotingMode"), values);
195 return gsf_output_csv_quoting_mode_type;
198 /* ------------------------------------------------------------------------- */
201 gsf_output_csv_init (GObject *obj)
203 GsfOutputCsv *csv = (GsfOutputCsv *)obj;
204 csv->quoting_triggers = g_strdup ("");
205 csv->eol = g_strdup ("\n");
206 csv->eol_len = strlen (csv->eol);
207 csv->buf = g_string_new (NULL);
208 g_object_set_data (obj,
209 HACK_QUOTING_ON_WHITESPACE,
210 GINT_TO_POINTER (1));
214 gsf_output_csv_get_property (GObject *object,
219 GsfOutputCsv *csv = (GsfOutputCsv *)object;
221 switch (property_id) {
223 g_value_set_object (value, csv->sink);
226 g_value_set_string (value, csv->quote);
228 case PROP_QUOTING_MODE:
229 g_value_set_enum (value, csv->quoting_mode);
231 case PROP_QUOTING_TRIGGERS:
232 g_value_set_string (value, csv->quoting_triggers);
234 case PROP_QUOTING_ON_WHITESPACE: {
235 gboolean qow = g_object_get_data
236 (object, HACK_QUOTING_ON_WHITESPACE) != NULL;
237 g_value_set_boolean (value, qow);
241 g_value_set_string (value, csv->eol);
244 g_value_set_string (value, csv->separator);
247 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
253 gsf_output_csv_set_sink (GsfOutputCsv *csv, GsfOutput *sink)
258 g_object_unref (csv->sink);
263 gsf_output_csv_set_property (GObject *object,
268 GsfOutputCsv *csv = (GsfOutputCsv *)object;
271 switch (property_id) {
273 gsf_output_csv_set_sink (csv, g_value_get_object (value));
276 scopy = g_strdup (g_value_get_string (value));
279 csv->quote_len = scopy ? strlen (scopy) : 0;
281 case PROP_QUOTING_MODE:
282 csv->quoting_mode = g_value_get_enum (value);
284 case PROP_QUOTING_TRIGGERS:
285 scopy = g_strdup (g_value_get_string (value));
286 g_free (csv->quoting_triggers);
287 csv->quoting_triggers = scopy ? scopy : g_strdup ("");
288 if (*csv->quoting_triggers)
289 csv->quoting_mode = GSF_OUTPUT_CSV_QUOTING_MODE_AUTO;
291 case PROP_QUOTING_ON_WHITESPACE: {
292 gboolean qow = g_value_get_boolean (value);
293 g_object_set_data (object,
294 HACK_QUOTING_ON_WHITESPACE,
295 GINT_TO_POINTER (qow));
299 scopy = g_strdup (g_value_get_string (value));
301 csv->eol = scopy ? scopy : g_strdup ("");
302 csv->eol_len = strlen (csv->eol);
305 scopy = g_strdup (g_value_get_string (value));
306 g_free (csv->separator);
307 csv->separator = scopy;
308 csv->separator_len = scopy ? strlen (scopy) : 0;
311 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
317 gsf_output_csv_class_init (GObjectClass *gobject_class)
319 GsfOutputClass *output_class = GSF_OUTPUT_CLASS (gobject_class);
321 gobject_class->finalize = gsf_output_csv_finalize;
322 gobject_class->set_property = gsf_output_csv_set_property;
323 gobject_class->get_property = gsf_output_csv_get_property;
324 output_class->Write = gsf_output_csv_write;
325 output_class->Seek = gsf_output_csv_seek;
326 output_class->Close = gsf_output_csv_close;
328 g_object_class_install_property
331 g_param_spec_object ("sink", "Sink",
332 "Where the compressed data is written.",
336 g_object_class_install_property
339 g_param_spec_string ("quote", "Quote",
340 "The string used for quoting fields.",
345 g_object_class_install_property
348 g_param_spec_enum ("quoting-mode",
350 "When to quote fields.",
351 GSF_OUTPUT_CSV_QUOTING_MODE_TYPE,
352 GSF_OUTPUT_CSV_QUOTING_MODE_NEVER,
356 g_object_class_install_property
358 PROP_QUOTING_TRIGGERS,
359 g_param_spec_string ("quoting-triggers", "Quoting Triggers",
360 "Characters that cause field quoting.",
364 g_object_class_install_property
366 PROP_QUOTING_ON_WHITESPACE,
367 g_param_spec_boolean ("quoting-on-whitespace",
368 "Quoting On Whitespace",
369 "Does initial or terminal whitespace force quoting?",
373 g_object_class_install_property
376 g_param_spec_string ("separator", "Separator",
377 "The field separator.",
382 g_object_class_install_property
385 g_param_spec_string ("eol", "eol",
386 "The end-of-line marker.",
392 parent_class = g_type_class_peek_parent (gobject_class);
395 GSF_CLASS (GsfOutputCsv, gsf_output_csv,
396 gsf_output_csv_class_init, gsf_output_csv_init,