Update Spanish translation
[gnumeric.git] / plugins / paradox / paradox.c
blob6f64518c00e89a6d51f909ab2e071bead0182264
1 /**
2 * paradox.c: Paradox support for Gnumeric
4 * Author:
5 * Uwe Steinmann <uwe@steinmann.cx>
6 **/
7 #include <gnumeric-config.h>
8 #include <glib/gi18n-lib.h>
9 #include <gnumeric.h>
10 #include "px.h"
12 #include <workbook-view.h>
13 #include <workbook.h>
14 #include <cell.h>
15 #include <value.h>
16 #include <gnm-plugin.h>
17 #include <sheet.h>
18 #include <ranges.h>
19 #include <mstyle.h>
20 #include <sheet-style.h>
22 #include <goffice/goffice.h>
24 #include <string.h>
25 #include <unistd.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); }
31 #else
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; }
35 #endif
37 void paradox_file_open (GOFileOpener const *fo, GOIOContext *io_context,
38 WorkbookView *wb_view, GsfInput *input);
39 G_MODULE_EXPORT void
40 paradox_file_open (GOFileOpener const *fo, GOIOContext *io_context,
41 WorkbookView *wb_view, GsfInput *input)
43 Workbook *wb;
44 pxdoc_t *pxdoc;
45 pxhead_t *pxh;
46 pxfield_t *pxf;
47 char *data;
48 char *name;
49 Sheet *sheet;
50 GnmCell *cell;
51 GnmValue *val = NULL;
52 GOErrorInfo *open_error = NULL;
53 guint row, i, j, offset;
55 #ifdef PX_MEMORY_DEBUGGING
56 PX_mp_init ();
57 #endif
59 #ifdef PX_MEMORY_DEBUGGING
60 pxdoc = PX_new2 (gn_errorhandler, PX_mp_malloc, PX_mp_realloc, PX_mp_free);
61 #else
62 pxdoc = PX_new2 (gn_errorhandler, gn_malloc, gn_realloc, gn_free);
63 #endif
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."),
67 open_error));
68 return;
70 pxh = pxdoc->px_head;
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);
77 g_free (name);
78 workbook_sheet_attach (wb, sheet);
80 pxf = pxh->px_fields;
81 for (i = 0 ; i < (guint) pxh->px_numfields; i++) {
82 char str[30], *str2;
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);
91 else
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);
101 #else
102 gnm_cell_set_text (cell, str);
103 #endif
104 pxf++;
107 GnmRange r;
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."),
117 open_error));
118 return;
120 row = 1;
121 for (j = 0; j < (guint)pxh->px_numrecords; j++) {
122 pxdatablockinfo_t pxdbinfo;
123 int isdeleted = 0;
124 if (NULL != PX_get_record2 (pxdoc, j, data, &isdeleted, &pxdbinfo)) {
125 offset = 0;
126 pxf = pxh->px_fields;
127 for (i = 0; i < (guint) pxh->px_numfields ; i++) {
128 cell = sheet_cell_fetch (sheet, i, row);
129 val = NULL;
130 switch (pxf->px_ftype) {
131 case pxfAlpha: {
132 char *value;
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); */
137 break;
139 case pxfShort: {
140 short int value;
141 if (0 < PX_get_data_short (pxdoc, &data[offset], pxf->px_flen, &value)) {
142 val = value_new_int (value);
144 break;
146 case pxfAutoInc:
147 case pxfLong: {
148 long value;
149 if (0 < PX_get_data_long (pxdoc, &data[offset], pxf->px_flen, &value)) {
150 val = value_new_int (value);
152 break;
154 case pxfCurrency:
155 case pxfNumber: {
156 double 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 ());
162 break;
164 case pxfTimestamp: {
165 double value;
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 */
169 value -= 693594;
170 val = value_new_float (value);
171 value_set_fmt (val, go_format_default_date_time ());
173 break;
175 case pxfLogical: {
176 char value;
177 if (0 < PX_get_data_byte (pxdoc, &data[offset], pxf->px_flen, &value)) {
178 val = value_new_bool (value ? TRUE : FALSE);
180 break;
182 case pxfDate: {
183 long value;
184 int year, month, day;
185 GDate *date;
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 ());
191 g_date_free (date);
193 break;
195 case pxfTime: {
196 long value;
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 ());
201 break;
203 case pxfBCD: {
204 char *value;
205 if (0 < PX_get_data_bcd (pxdoc, &data[offset], pxf->px_fdc, &value)) {
206 val = value_new_string_nocopy (value);
208 break;
210 case pxfMemoBLOb: {
211 char *value;
212 int size, mod_nr;
213 if (0 < PX_get_data_blob (pxdoc, &data[offset], pxf->px_flen, &mod_nr, &size, &value)) {
214 val = value_new_string_nocopy (value);
216 break;
218 default:
219 val = value_new_string_nocopy (
220 g_strdup_printf (_("Field type %d is not supported."), pxf->px_ftype));
222 if (val)
223 gnm_cell_set_value (cell, val);
224 offset += pxf->px_flen;
225 pxf++;
227 if (pxh->px_filetype == pxfFileTypPrimIndex) {
228 short int value;
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);
234 offset += 2;
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);
240 offset += 2;
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);
251 row++;
253 pxdoc->free (pxdoc, data);
255 PX_close (pxdoc);
256 PX_delete (pxdoc);
258 sheet_flag_recompute_spans (sheet);
261 /*****************************************************************************/
263 gboolean
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,
269 GOFileProbeLevel pl)
271 pxdoc_t *pxdoc;
272 pxhead_t *pxh;
274 pxdoc = PX_new ();
275 if (PX_open_gsf (pxdoc, input) < 0) {
276 return FALSE;
279 pxh = pxdoc->px_head;
281 PX_close (pxdoc);
282 PX_delete (pxdoc);
284 #ifdef PX_MEMORY_DEBUGGING
285 PX_mp_list_unfreed ();
286 #endif
288 return TRUE;
291 /*****************************************************************************/
293 void paradox_file_save (GOFileSaver const *fs, GOIOContext *io_context,
294 WorkbookView const *wb_view, GsfOutput *output);
295 G_MODULE_EXPORT void
296 paradox_file_save (GOFileSaver const *fs, GOIOContext *io_context,
297 WorkbookView const *wb_view, GsfOutput *output)
299 Sheet *sheet;
300 GnmRange r;
301 gint row, col, i;
303 pxdoc_t *pxdoc = NULL;
304 pxfield_t *pxf;
305 char *data;
306 char *tmpfilename;
308 sheet = wb_view_cur_sheet (wb_view);
309 if (sheet == NULL) {
310 go_io_error_string (io_context, _("Cannot get default sheet."));
311 return;
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);
318 #else
319 pxdoc = PX_new2 (gn_errorhandler, gn_malloc, gn_realloc, gn_free);
320 #endif
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."));
327 PX_delete (pxdoc);
328 return;
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."));
335 PX_delete (pxdoc);
336 return;
337 } else {
338 gchar *fieldstr, *tmp;
339 int len, needsize, needprecision;
341 i = col;
342 fieldstr = gnm_cell_get_rendered_text (cell);
343 needsize = 0;
344 needprecision = 0;
346 /* Search for the first comma which is the end of the field name. */
347 tmp = strchr (fieldstr, ',');
348 if (NULL == tmp) {
349 g_warning (_("Field specification must be a comma separated value (Name,Type,Size,Prec)."));
350 PX_delete (pxdoc);
351 return;
353 len = tmp-fieldstr;
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);
356 PX_delete (pxdoc);
357 return;
359 strncpy (pxf[i].px_fname, fieldstr, len);
360 pxf[i].px_fname[len] = '\0';
362 /* Get the field Type */
363 fieldstr = tmp+1;
364 if (*fieldstr == '\0') {
365 g_warning (_("%d. field specification ended unexpectedly."), i);
366 PX_delete (pxdoc);
367 return;
369 if (*fieldstr == ',') {
370 g_warning (_("%d. field specification misses type."), i);
371 PX_delete (pxdoc);
372 return;
374 switch ((int) *fieldstr) {
375 case 'S':
376 pxf[i].px_ftype = pxfShort;
377 pxf[i].px_flen = 2;
378 break;
379 case 'I':
380 pxf[i].px_ftype = pxfLong;
381 pxf[i].px_flen = 4;
382 break;
383 case 'A':
384 case 'C':
385 pxf[i].px_ftype = pxfAlpha;
386 needsize = 1;
387 break;
388 case 'N':
389 pxf[i].px_ftype = pxfNumber;
390 pxf[i].px_flen = 8;
391 break;
392 case '$':
393 pxf[i].px_ftype = pxfCurrency;
394 pxf[i].px_flen = 8;
395 break;
396 case 'L':
397 pxf[i].px_ftype = pxfLogical;
398 pxf[i].px_flen = 1;
399 break;
400 case 'D':
401 pxf[i].px_ftype = pxfDate;
402 pxf[i].px_flen = 4;
403 break;
404 case '+':
405 pxf[i].px_ftype = pxfAutoInc;
406 pxf[i].px_flen = 4;
407 break;
408 case '@':
409 pxf[i].px_ftype = pxfTimestamp;
410 pxf[i].px_flen = 8;
411 break;
412 case 'T':
413 pxf[i].px_ftype = pxfTime;
414 pxf[i].px_flen = 4;
415 break;
416 case '#':
417 pxf[i].px_ftype = pxfBCD;
418 pxf[i].px_flen = 17;
419 needprecision = 1;
420 break;
421 case 'M':
422 pxf[i].px_ftype = pxfMemoBLOb;
423 needsize = 1;
424 break;
425 case 'B':
426 pxf[i].px_ftype = pxfBLOb;
427 needsize = 1;
428 break;
429 case 'F':
430 pxf[i].px_ftype = pxfFmtMemoBLOb;
431 needsize = 1;
432 break;
433 case 'Y':
434 pxf[i].px_ftype = pxfBytes;
435 needsize = 1;
436 break;
437 default:
438 g_warning (_("%d. field type '%c' is unknown."), i, *fieldstr);
439 pxdoc->free (pxdoc, pxf);
440 PX_delete (pxdoc);
441 return;
444 if (needsize || needprecision) {
445 char *endptr;
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."));
450 PX_delete (pxdoc);
451 return;
453 fieldstr = tmp+1;
454 if (needsize)
455 pxf[i].px_flen = strtol (fieldstr, &endptr, 10);
456 else
457 pxf[i].px_fdc = strtol (fieldstr, &endptr, 10);
458 if ((endptr == NULL) || (fieldstr == endptr)) {
459 g_warning (_("Field specification misses the column size."));
460 PX_delete (pxdoc);
461 return;
463 if (*endptr != '\0') {
464 /* There is also precision which we do not care about. */
465 fieldstr = endptr+1;
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."));
476 PX_delete (pxdoc);
477 return;
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."));
486 PX_close (pxdoc);
487 PX_delete (pxdoc);
488 return;
490 /* Process all cells */
491 for (row = r.start.row+1; row <= r.end.row; row++) {
492 int i;
493 int offset;
494 offset = 0;
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) {
501 case pxfShort: {
502 int value = value_get_as_int (cell->value);
503 PX_put_data_short (pxdoc, &data[offset], 2, (short int) value);
504 break;
506 case pxfLong:
507 case pxfAutoInc: {
508 int value = value_get_as_int (cell->value);
509 PX_put_data_long (pxdoc, &data[offset], 4, value);
510 break;
512 case pxfTimestamp: {
513 double value = value_get_as_float (cell->value);
514 /* 60 would be 29.2.1900 which didn't exist. */
515 if (value < 60)
516 value += 1.0;
517 value += 693594;
518 value *= 86400000.0;
519 PX_put_data_double (pxdoc, &data[offset], 8, value);
520 break;
522 case pxfCurrency:
523 case pxfNumber: {
524 double value = value_get_as_float (cell->value);
525 PX_put_data_double(pxdoc, &data[offset], 8, value);
526 break;
528 case pxfAlpha: {
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. */
534 g_warning
535 (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.",
540 nlen),
541 i+1, row+1, nlen);
542 PX_put_data_alpha (pxdoc, &data[offset], pxf[i].px_flen, value);
543 break;
545 case pxfMemoBLOb:
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);
551 break;
553 case pxfDate: {
554 long value = value_get_as_int (cell->value);
555 /* 60 would be 29.2.1900 which didn't exist. */
556 if (value < 60)
557 value++;
558 value += 693594;
559 PX_put_data_long (pxdoc, &data[offset], 4, value);
560 break;
562 case pxfTime: {
563 double dtmp;
564 int 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);
569 break;
571 case pxfLogical: {
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);
575 break;
577 case pxfBCD:
578 PX_put_data_bcd (pxdoc, &data[offset], pxf[i].px_fdc, fieldstr);
579 break;
582 offset += pxf[i].px_flen;
583 i++;
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);
588 PX_close (pxdoc);
589 PX_delete (pxdoc);
590 return;
593 pxdoc->free (pxdoc, data);
594 PX_close (pxdoc);
595 PX_delete (pxdoc);
597 #ifdef PX_MEMORY_DEBUGGING
598 PX_mp_list_unfreed ();
599 #endif
602 FILE *fp;
603 size_t size;
604 fp = fopen (tmpfilename, "r");
605 if (fp) {
606 data = g_malloc (8192);
607 while (0 != (size = fread (data, 1, 8192, fp)))
608 gsf_output_write (output, size, data);
609 fclose (fp);
610 g_free (data);
611 } else
612 g_warning ("Cannot open %s\n", tmpfilename);
614 unlink (tmpfilename);