2 * paradox.c: Paradox support for Gnumeric
5 * Uwe Steinmann <uwe@steinmann.cx>
7 #include <gnumeric-config.h>
8 #include <glib/gi18n-lib.h>
12 #include <workbook-view.h>
16 #include <gnm-plugin.h>
20 #include <sheet-style.h>
22 #include <goffice/goffice.h>
27 GNM_PLUGIN_MODULE_HEADER
;
29 #ifdef PX_MEMORY_DEBUGGING
30 static void gn_errorhandler (pxdoc_t
*p
, int error
, const char *str
, void *data
) { g_warning ("%s", str
); }
32 static void *gn_malloc (pxdoc_t
*p
, size_t len
, const char *caller
) { return ((void *) g_malloc (len
)); }
33 static void *gn_realloc (pxdoc_t
*p
, void *mem
, size_t len
, const char *caller
) { return ((void *) g_realloc ((gpointer
) mem
, len
)); }
34 static void gn_free (pxdoc_t
*p
, void *ptr
) { g_free ((gpointer
) ptr
); ptr
= NULL
; }
37 void paradox_file_open (GOFileOpener
const *fo
, GOIOContext
*io_context
,
38 WorkbookView
*wb_view
, GsfInput
*input
);
40 paradox_file_open (GOFileOpener
const *fo
, GOIOContext
*io_context
,
41 WorkbookView
*wb_view
, GsfInput
*input
)
52 GOErrorInfo
*open_error
= NULL
;
53 guint row
, i
, j
, offset
;
55 #ifdef PX_MEMORY_DEBUGGING
59 #ifdef PX_MEMORY_DEBUGGING
60 pxdoc
= PX_new2 (gn_errorhandler
, PX_mp_malloc
, PX_mp_realloc
, PX_mp_free
);
62 pxdoc
= PX_new2 (gn_errorhandler
, gn_malloc
, gn_realloc
, gn_free
);
64 if (PX_open_gsf (pxdoc
, input
) < 0) {
65 go_io_error_info_set (io_context
, go_error_info_new_str_with_details (
66 _("Error while opening Paradox file."),
72 PX_set_targetencoding (pxdoc
, "UTF-8");
74 wb
= wb_view_get_workbook (wb_view
);
75 name
= workbook_sheet_get_free_name (wb
, pxh
->px_tablename
, FALSE
, TRUE
);
76 sheet
= sheet_new (wb
, name
, 256, 65536);
78 workbook_sheet_attach (wb
, sheet
);
81 for (i
= 0 ; i
< (guint
) pxh
->px_numfields
; i
++) {
83 char ctypes
[26] = {'?',
84 'A', 'D', 'S', 'I', '$', 'N', '?', '?',
85 'L', '?', '?', 'M', 'B', 'F', 'O', 'G',
86 '?', '?', '?', 'T', '@', '+', '#', 'Y',
88 cell
= sheet_cell_fetch (sheet
, i
, 0);
89 if (pxf
->px_ftype
== pxfBCD
)
90 snprintf (str
, 30, "%s,%c,%d", pxf
->px_fname
, ctypes
[(int)pxf
->px_ftype
], pxf
->px_fdc
);
92 snprintf (str
, 30, "%s,%c,%d", pxf
->px_fname
, ctypes
[(int)pxf
->px_ftype
], pxf
->px_flen
);
93 #if PXLIB_MAJOR_VERSION == 0 && (PXLIB_MINOR_VERION < 3 || (PXLIB_MAJOR_VERSION == 3 && PXLIB_MICRO_VERSION == 0))
94 /* Convert the field names to utf-8. This is actually in pxlib
95 * responsibility, but hasn't been implemented yet. For the mean time
96 * we *misuse* PX_get_data_alpha()
98 PX_get_data_alpha (pxdoc
, str
, strlen (str
), &str2
);
99 gnm_cell_set_text (cell
, str2
);
100 pxdoc
->free (pxdoc
, str2
);
102 gnm_cell_set_text (cell
, str
);
108 GnmStyle
*bold
= gnm_style_new ();
109 gnm_style_set_font_bold (bold
, TRUE
);
110 sheet_style_apply_range (sheet
,
111 range_init (&r
, 0, 0, pxh
->px_numfields
-1, 0), bold
);
114 if ((data
= (char *) pxdoc
->malloc (pxdoc
, pxh
->px_recordsize
, _("Could not allocate memory for record."))) == NULL
) {
115 go_io_error_info_set (io_context
, go_error_info_new_str_with_details (
116 _("Error while opening Paradox file."),
121 for (j
= 0; j
< (guint
)pxh
->px_numrecords
; j
++) {
122 pxdatablockinfo_t pxdbinfo
;
124 if (NULL
!= PX_get_record2 (pxdoc
, j
, data
, &isdeleted
, &pxdbinfo
)) {
126 pxf
= pxh
->px_fields
;
127 for (i
= 0; i
< (guint
) pxh
->px_numfields
; i
++) {
128 cell
= sheet_cell_fetch (sheet
, i
, row
);
130 switch (pxf
->px_ftype
) {
133 if (0 < PX_get_data_alpha (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
134 val
= value_new_string_nocopy (value
);
135 /* value_set_fmt (val, field->fmt); */
141 if (0 < PX_get_data_short (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
142 val
= value_new_int (value
);
149 if (0 < PX_get_data_long (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
150 val
= value_new_int (value
);
157 if (0 < PX_get_data_double (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
158 val
= value_new_float (value
);
159 if (pxf
->px_ftype
== pxfCurrency
)
160 value_set_fmt (val
, go_format_default_money ());
166 if (0 < PX_get_data_double (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
167 value
= value
/ 86400000.0;
168 /* 693594 = number of days up to 31.12.1899 */
170 val
= value_new_float (value
);
171 value_set_fmt (val
, go_format_default_date_time ());
177 if (0 < PX_get_data_byte (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
178 val
= value_new_bool (value
? TRUE
: FALSE
);
184 int year
, month
, day
;
186 if (0 < PX_get_data_long (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
187 PX_SdnToGregorian (value
+1721425, &year
, &month
, &day
);
188 date
= g_date_new_dmy (day
, month
, year
);
189 val
= value_new_int (go_date_g_to_serial (date
, NULL
));
190 value_set_fmt (val
, go_format_default_date ());
197 if (0 < PX_get_data_long (pxdoc
, &data
[offset
], pxf
->px_flen
, &value
)) {
198 val
= value_new_float (value
/86400000.0);
199 value_set_fmt (val
, go_format_default_time ());
205 if (0 < PX_get_data_bcd (pxdoc
, &data
[offset
], pxf
->px_fdc
, &value
)) {
206 val
= value_new_string_nocopy (value
);
213 if (0 < PX_get_data_blob (pxdoc
, &data
[offset
], pxf
->px_flen
, &mod_nr
, &size
, &value
)) {
214 val
= value_new_string_nocopy (value
);
219 val
= value_new_string_nocopy (
220 g_strdup_printf (_("Field type %d is not supported."), pxf
->px_ftype
));
223 gnm_cell_set_value (cell
, val
);
224 offset
+= pxf
->px_flen
;
227 if (pxh
->px_filetype
== pxfFileTypPrimIndex
) {
229 cell
= sheet_cell_fetch (sheet
, i
++, row
);
230 if (0 < PX_get_data_short (pxdoc
, &data
[offset
], 2, &value
)) {
231 val
= value_new_int (value
);
232 gnm_cell_set_value (cell
, val
);
235 cell
= sheet_cell_fetch (sheet
, i
++, row
);
236 if (0 < PX_get_data_short (pxdoc
, &data
[offset
], 2, &value
)) {
237 val
= value_new_int (value
);
238 gnm_cell_set_value (cell
, val
);
241 cell
= sheet_cell_fetch (sheet
, i
++, row
);
242 if (0 < PX_get_data_short (pxdoc
, &data
[offset
], 2, &value
)) {
243 val
= value_new_int (value
);
244 gnm_cell_set_value (cell
, val
);
246 cell
= sheet_cell_fetch (sheet
, i
++, row
);
247 val
= value_new_int (pxdbinfo
.number
);
248 gnm_cell_set_value (cell
, val
);
253 pxdoc
->free (pxdoc
, data
);
258 sheet_flag_recompute_spans (sheet
);
261 /*****************************************************************************/
264 paradox_file_probe (GOFileOpener
const *fo
, GsfInput
*input
,
265 GOFileProbeLevel pl
);
267 G_MODULE_EXPORT gboolean
268 paradox_file_probe (GOFileOpener
const *fo
, GsfInput
*input
,
275 if (PX_open_gsf (pxdoc
, input
) < 0) {
279 pxh
= pxdoc
->px_head
;
284 #ifdef PX_MEMORY_DEBUGGING
285 PX_mp_list_unfreed ();
291 /*****************************************************************************/
293 void paradox_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
294 WorkbookView
const *wb_view
, GsfOutput
*output
);
296 paradox_file_save (GOFileSaver
const *fs
, GOIOContext
*io_context
,
297 WorkbookView
const *wb_view
, GsfOutput
*output
)
303 pxdoc_t
*pxdoc
= NULL
;
308 sheet
= wb_view_cur_sheet (wb_view
);
310 go_io_error_string (io_context
, _("Cannot get default sheet."));
314 r
= sheet_get_extent (sheet
, FALSE
, TRUE
);
316 #ifdef PX_MEMORY_DEBUGGING
317 pxdoc
= PX_new2 (gn_errorhandler
, PX_mp_malloc
, PX_mp_realloc
, PX_mp_free
);
319 pxdoc
= PX_new2 (gn_errorhandler
, gn_malloc
, gn_realloc
, gn_free
);
322 /* Read the field specification and build the field array for
323 * PX_create_fp(). The memory is freed by PX_delete() including
324 * the memory for the field name. */
325 if ((pxf
= (pxfield_t
*) pxdoc
->malloc (pxdoc
, (r
.end
.col
+1)*sizeof (pxfield_t
), _("Allocate memory for field definitions."))) == NULL
){
326 go_io_error_string (io_context
, _("Cannot allocate memory for field definitions."));
331 for (col
= r
.start
.col
; col
<= r
.end
.col
; col
++) {
332 GnmCell
*cell
= sheet_cell_get (sheet
, col
, 0);
333 if (gnm_cell_is_empty (cell
)) {
334 go_io_error_string (io_context
, _("First line of sheet must contain database specification."));
338 gchar
*fieldstr
, *tmp
;
339 int len
, needsize
, needprecision
;
342 fieldstr
= gnm_cell_get_rendered_text (cell
);
346 /* Search for the first comma which is the end of the field name. */
347 tmp
= strchr (fieldstr
, ',');
349 g_warning (_("Field specification must be a comma separated value (Name,Type,Size,Prec)."));
354 if (NULL
== (pxf
[i
].px_fname
= pxdoc
->malloc (pxdoc
, len
+1, _("Allocate memory for column name.")))) {
355 g_warning (_("Could not allocate memory for %d. field name."), i
);
359 strncpy (pxf
[i
].px_fname
, fieldstr
, len
);
360 pxf
[i
].px_fname
[len
] = '\0';
362 /* Get the field Type */
364 if (*fieldstr
== '\0') {
365 g_warning (_("%d. field specification ended unexpectedly."), i
);
369 if (*fieldstr
== ',') {
370 g_warning (_("%d. field specification misses type."), i
);
374 switch ((int) *fieldstr
) {
376 pxf
[i
].px_ftype
= pxfShort
;
380 pxf
[i
].px_ftype
= pxfLong
;
385 pxf
[i
].px_ftype
= pxfAlpha
;
389 pxf
[i
].px_ftype
= pxfNumber
;
393 pxf
[i
].px_ftype
= pxfCurrency
;
397 pxf
[i
].px_ftype
= pxfLogical
;
401 pxf
[i
].px_ftype
= pxfDate
;
405 pxf
[i
].px_ftype
= pxfAutoInc
;
409 pxf
[i
].px_ftype
= pxfTimestamp
;
413 pxf
[i
].px_ftype
= pxfTime
;
417 pxf
[i
].px_ftype
= pxfBCD
;
422 pxf
[i
].px_ftype
= pxfMemoBLOb
;
426 pxf
[i
].px_ftype
= pxfBLOb
;
430 pxf
[i
].px_ftype
= pxfFmtMemoBLOb
;
434 pxf
[i
].px_ftype
= pxfBytes
;
438 g_warning (_("%d. field type '%c' is unknown."), i
, *fieldstr
);
439 pxdoc
->free (pxdoc
, pxf
);
444 if (needsize
|| needprecision
) {
446 /* find end of type definition */
447 tmp
= strchr (fieldstr
, ',');
448 if (NULL
== tmp
|| *(tmp
+1) == '\0') {
449 g_warning (_("Field specification misses the column size."));
455 pxf
[i
].px_flen
= strtol (fieldstr
, &endptr
, 10);
457 pxf
[i
].px_fdc
= strtol (fieldstr
, &endptr
, 10);
458 if ((endptr
== NULL
) || (fieldstr
== endptr
)) {
459 g_warning (_("Field specification misses the column size."));
463 if (*endptr
!= '\0') {
464 /* There is also precision which we do not care about. */
466 g_warning (_("The remainder '%s' of the specification for field %d is being disregarded."), fieldstr
, i
+1);
472 /* Create the paradox file */
473 tmpfilename
= tempnam ("/tmp", NULL
);
474 if (0 > PX_create_file (pxdoc
, pxf
, r
.end
.col
+1, tmpfilename
, pxfFileTypNonIndexDB
)) {
475 g_warning (_("Could not create output file."));
480 PX_set_inputencoding (pxdoc
, "UTF-8");
481 PX_set_parameter (pxdoc
, "targetencoding", "CP1252");
482 PX_set_tablename (pxdoc
, sheet
->name_unquoted
);
484 if ((data
= (char *) pxdoc
->malloc (pxdoc
, pxdoc
->px_head
->px_recordsize
, _("Allocate memory for record data."))) == NULL
) {
485 g_warning (_("Could not allocate memory for record data."));
490 /* Process all cells */
491 for (row
= r
.start
.row
+1; row
<= r
.end
.row
; row
++) {
495 memset (data
, 0, pxdoc
->px_head
->px_recordsize
);
496 for (col
= r
.start
.col
, i
= 0; col
<= r
.end
.col
; col
++) {
497 GnmCell
*cell
= sheet_cell_get (sheet
, col
, row
);
498 if (!gnm_cell_is_empty (cell
)) {
499 char *fieldstr
= gnm_cell_get_rendered_text (cell
);
500 switch (pxf
[i
].px_ftype
) {
502 int value
= value_get_as_int (cell
->value
);
503 PX_put_data_short (pxdoc
, &data
[offset
], 2, (short int) value
);
508 int value
= value_get_as_int (cell
->value
);
509 PX_put_data_long (pxdoc
, &data
[offset
], 4, value
);
513 double value
= value_get_as_float (cell
->value
);
514 /* 60 would be 29.2.1900 which didn't exist. */
519 PX_put_data_double (pxdoc
, &data
[offset
], 8, value
);
524 double value
= value_get_as_float (cell
->value
);
525 PX_put_data_double(pxdoc
, &data
[offset
], 8, value
);
529 char *value
= fieldstr
;
530 int nlen
= strlen (value
);
531 if (nlen
> pxf
[i
].px_flen
)
532 /* xgettext : last %d gives the number of characters.*/
533 /* This is input to ngettext. */
536 ("Field %d in line %d has possibly "
537 "been cut off. Data has %d character.",
538 "Field %d in line %d has possibly "
539 "been cut off. Data has %d characters.",
542 PX_put_data_alpha (pxdoc
, &data
[offset
], pxf
[i
].px_flen
, value
);
546 case pxfFmtMemoBLOb
: {
547 char *value
= fieldstr
;
548 if (0 > PX_put_data_blob (pxdoc
, &data
[offset
], pxf
[i
].px_flen
, value
, strlen (value
))) {
549 g_warning (_("Field %d in row %d could not be written."), i
+1, row
+1);
554 long value
= value_get_as_int (cell
->value
);
555 /* 60 would be 29.2.1900 which didn't exist. */
559 PX_put_data_long (pxdoc
, &data
[offset
], 4, value
);
565 dtmp
= value_get_as_float (cell
->value
);
566 dtmp
-= ((int) dtmp
);
567 value
= (int) (dtmp
* 86400000.0);
568 PX_put_data_long (pxdoc
, &data
[offset
], 4, value
);
572 gboolean err
; /* Ignored */
573 gboolean value
= value_get_as_bool (cell
->value
, &err
);
574 PX_put_data_byte (pxdoc
, &data
[offset
], 1, value
? 1 : 0);
578 PX_put_data_bcd (pxdoc
, &data
[offset
], pxf
[i
].px_fdc
, fieldstr
);
582 offset
+= pxf
[i
].px_flen
;
585 if ((i
> 0) && (0 > PX_put_record (pxdoc
, data
))) {
586 g_warning (_("Could not write record number %d."), i
+1);
587 pxdoc
->free (pxdoc
, data
);
593 pxdoc
->free (pxdoc
, data
);
597 #ifdef PX_MEMORY_DEBUGGING
598 PX_mp_list_unfreed ();
604 fp
= fopen (tmpfilename
, "r");
606 data
= g_malloc (8192);
607 while (0 != (size
= fread (data
, 1, 8192, fp
)))
608 gsf_output_write (output
, size
, data
);
612 g_warning ("Cannot open %s\n", tmpfilename
);
614 unlink (tmpfilename
);