lemon-project-template-glpk

comparison deps/glpk/src/glpmpl06.c @ 9:33de93886c88

Import GLPK 4.47
author Alpar Juttner <alpar@cs.elte.hu>
date Sun, 06 Nov 2011 20:59:10 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:279731340c68
1 /* glpmpl06.c */
2
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
5 *
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
9 * E-mail: <mao@gnu.org>.
10 *
11 * GLPK is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 * License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
23 ***********************************************************************/
24
25 #define _GLPSTD_ERRNO
26 #define _GLPSTD_STDIO
27 #include "glpmpl.h"
28 #include "glpsql.h"
29
30 /**********************************************************************/
31
32 #define CSV_FIELD_MAX 50
33 /* maximal number of fields in record */
34
35 #define CSV_FDLEN_MAX 100
36 /* maximal field length */
37
38 struct csv
39 { /* comma-separated values file */
40 int mode;
41 /* 'R' = reading; 'W' = writing */
42 char *fname;
43 /* name of csv file */
44 FILE *fp;
45 /* stream assigned to csv file */
46 jmp_buf jump;
47 /* address for non-local go to in case of error */
48 int count;
49 /* record count */
50 /*--------------------------------------------------------------*/
51 /* used only for input csv file */
52 int c;
53 /* current character or EOF */
54 int what;
55 /* current marker: */
56 #define CSV_EOF 0 /* end-of-file */
57 #define CSV_EOR 1 /* end-of-record */
58 #define CSV_NUM 2 /* floating-point number */
59 #define CSV_STR 3 /* character string */
60 char field[CSV_FDLEN_MAX+1];
61 /* current field just read */
62 int nf;
63 /* number of fields in the csv file */
64 int ref[1+CSV_FIELD_MAX];
65 /* ref[k] = k', if k-th field of the csv file corresponds to
66 k'-th field in the table statement; if ref[k] = 0, k-th field
67 of the csv file is ignored */
68 #if 1 /* 01/VI-2010 */
69 int nskip;
70 /* number of comment records preceding the header record */
71 #endif
72 };
73
74 #undef read_char
75
76 static void read_char(struct csv *csv)
77 { /* read character from csv data file */
78 int c;
79 xassert(csv->c != EOF);
80 if (csv->c == '\n') csv->count++;
81 loop: c = fgetc(csv->fp);
82 if (ferror(csv->fp))
83 { xprintf("%s:%d: read error - %s\n", csv->fname, csv->count,
84 strerror(errno));
85 longjmp(csv->jump, 0);
86 }
87 if (feof(csv->fp))
88 { if (csv->c == '\n')
89 { csv->count--;
90 c = EOF;
91 }
92 else
93 { xprintf("%s:%d: warning: missing final end-of-line\n",
94 csv->fname, csv->count);
95 c = '\n';
96 }
97 }
98 else if (c == '\r')
99 goto loop;
100 else if (c == '\n')
101 ;
102 else if (iscntrl(c))
103 { xprintf("%s:%d: invalid control character 0x%02X\n",
104 csv->fname, csv->count, c);
105 longjmp(csv->jump, 0);
106 }
107 csv->c = c;
108 return;
109 }
110
111 static void read_field(struct csv *csv)
112 { /* read field from csv data file */
113 /* check for end of file */
114 if (csv->c == EOF)
115 { csv->what = CSV_EOF;
116 strcpy(csv->field, "EOF");
117 goto done;
118 }
119 /* check for end of record */
120 if (csv->c == '\n')
121 { csv->what = CSV_EOR;
122 strcpy(csv->field, "EOR");
123 read_char(csv);
124 if (csv->c == ',')
125 err1: { xprintf("%s:%d: empty field not allowed\n", csv->fname,
126 csv->count);
127 longjmp(csv->jump, 0);
128 }
129 if (csv->c == '\n')
130 { xprintf("%s:%d: empty record not allowed\n", csv->fname,
131 csv->count);
132 longjmp(csv->jump, 0);
133 }
134 #if 1 /* 01/VI-2010 */
135 /* skip comment records; may appear only before the very first
136 record containing field names */
137 if (csv->c == '#' && csv->count == 1)
138 { while (csv->c == '#')
139 { while (csv->c != '\n')
140 read_char(csv);
141 read_char(csv);
142 csv->nskip++;
143 }
144 }
145 #endif
146 goto done;
147 }
148 /* skip comma before next field */
149 if (csv->c == ',')
150 read_char(csv);
151 /* read field */
152 if (csv->c == '\'' || csv->c == '"')
153 { /* read a field enclosed in quotes */
154 int quote = csv->c, len = 0;
155 csv->what = CSV_STR;
156 /* skip opening quote */
157 read_char(csv);
158 /* read field characters within quotes */
159 for (;;)
160 { /* check for closing quote and read it */
161 if (csv->c == quote)
162 { read_char(csv);
163 if (csv->c == quote)
164 ;
165 else if (csv->c == ',' || csv->c == '\n')
166 break;
167 else
168 { xprintf("%s:%d: invalid field\n", csv->fname,
169 csv->count);
170 longjmp(csv->jump, 0);
171 }
172 }
173 /* check the current field length */
174 if (len == CSV_FDLEN_MAX)
175 err2: { xprintf("%s:%d: field too long\n", csv->fname,
176 csv->count);
177 longjmp(csv->jump, 0);
178 }
179 /* add the current character to the field */
180 csv->field[len++] = (char)csv->c;
181 /* read the next character */
182 read_char(csv);
183 }
184 /* the field has been read */
185 if (len == 0) goto err1;
186 csv->field[len] = '\0';
187 }
188 else
189 { /* read a field not enclosed in quotes */
190 int len = 0;
191 double temp;
192 csv->what = CSV_NUM;
193 while (!(csv->c == ',' || csv->c == '\n'))
194 { /* quotes within the field are not allowed */
195 if (csv->c == '\'' || csv->c == '"')
196 { xprintf("%s:%d: invalid use of single or double quote wi"
197 "thin field\n", csv->fname, csv->count);
198 longjmp(csv->jump, 0);
199 }
200 /* check the current field length */
201 if (len == CSV_FDLEN_MAX) goto err2;
202 /* add the current character to the field */
203 csv->field[len++] = (char)csv->c;
204 /* read the next character */
205 read_char(csv);
206 }
207 /* the field has been read */
208 if (len == 0) goto err1;
209 csv->field[len] = '\0';
210 /* check the field type */
211 if (str2num(csv->field, &temp)) csv->what = CSV_STR;
212 }
213 done: return;
214 }
215
216 static struct csv *csv_open_file(TABDCA *dca, int mode)
217 { /* open csv data file */
218 struct csv *csv;
219 /* create control structure */
220 csv = xmalloc(sizeof(struct csv));
221 csv->mode = mode;
222 csv->fname = NULL;
223 csv->fp = NULL;
224 if (setjmp(csv->jump)) goto fail;
225 csv->count = 0;
226 csv->c = '\n';
227 csv->what = 0;
228 csv->field[0] = '\0';
229 csv->nf = 0;
230 /* try to open the csv data file */
231 if (mpl_tab_num_args(dca) < 2)
232 { xprintf("csv_driver: file name not specified\n");
233 longjmp(csv->jump, 0);
234 }
235 csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
236 strcpy(csv->fname, mpl_tab_get_arg(dca, 2));
237 if (mode == 'R')
238 { /* open the file for reading */
239 int k;
240 csv->fp = fopen(csv->fname, "r");
241 if (csv->fp == NULL)
242 { xprintf("csv_driver: unable to open %s - %s\n",
243 csv->fname, strerror(errno));
244 longjmp(csv->jump, 0);
245 }
246 #if 1 /* 01/VI-2010 */
247 csv->nskip = 0;
248 #endif
249 /* skip fake new-line */
250 read_field(csv);
251 xassert(csv->what == CSV_EOR);
252 /* read field names */
253 xassert(csv->nf == 0);
254 for (;;)
255 { read_field(csv);
256 if (csv->what == CSV_EOR)
257 break;
258 if (csv->what != CSV_STR)
259 { xprintf("%s:%d: invalid field name\n", csv->fname,
260 csv->count);
261 longjmp(csv->jump, 0);
262 }
263 if (csv->nf == CSV_FIELD_MAX)
264 { xprintf("%s:%d: too many fields\n", csv->fname,
265 csv->count);
266 longjmp(csv->jump, 0);
267 }
268 csv->nf++;
269 /* find corresponding field in the table statement */
270 for (k = mpl_tab_num_flds(dca); k >= 1; k--)
271 { if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0)
272 break;
273 }
274 csv->ref[csv->nf] = k;
275 }
276 /* find dummy RECNO field in the table statement */
277 for (k = mpl_tab_num_flds(dca); k >= 1; k--)
278 if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
279 csv->ref[0] = k;
280 }
281 else if (mode == 'W')
282 { /* open the file for writing */
283 int k, nf;
284 csv->fp = fopen(csv->fname, "w");
285 if (csv->fp == NULL)
286 { xprintf("csv_driver: unable to create %s - %s\n",
287 csv->fname, strerror(errno));
288 longjmp(csv->jump, 0);
289 }
290 /* write field names */
291 nf = mpl_tab_num_flds(dca);
292 for (k = 1; k <= nf; k++)
293 fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k),
294 k < nf ? ',' : '\n');
295 csv->count++;
296 }
297 else
298 xassert(mode != mode);
299 /* the file has been open */
300 return csv;
301 fail: /* the file cannot be open */
302 if (csv->fname != NULL) xfree(csv->fname);
303 if (csv->fp != NULL) fclose(csv->fp);
304 xfree(csv);
305 return NULL;
306 }
307
308 static int csv_read_record(TABDCA *dca, struct csv *csv)
309 { /* read next record from csv data file */
310 int k, ret = 0;
311 xassert(csv->mode == 'R');
312 if (setjmp(csv->jump))
313 { ret = 1;
314 goto done;
315 }
316 /* read dummy RECNO field */
317 if (csv->ref[0] > 0)
318 #if 0 /* 01/VI-2010 */
319 mpl_tab_set_num(dca, csv->ref[0], csv->count-1);
320 #else
321 mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1);
322 #endif
323 /* read fields */
324 for (k = 1; k <= csv->nf; k++)
325 { read_field(csv);
326 if (csv->what == CSV_EOF)
327 { /* end-of-file reached */
328 xassert(k == 1);
329 ret = -1;
330 goto done;
331 }
332 else if (csv->what == CSV_EOR)
333 { /* end-of-record reached */
334 int lack = csv->nf - k + 1;
335 if (lack == 1)
336 xprintf("%s:%d: one field missing\n", csv->fname,
337 csv->count);
338 else
339 xprintf("%s:%d: %d fields missing\n", csv->fname,
340 csv->count, lack);
341 longjmp(csv->jump, 0);
342 }
343 else if (csv->what == CSV_NUM)
344 { /* floating-point number */
345 if (csv->ref[k] > 0)
346 { double num;
347 xassert(str2num(csv->field, &num) == 0);
348 mpl_tab_set_num(dca, csv->ref[k], num);
349 }
350 }
351 else if (csv->what == CSV_STR)
352 { /* character string */
353 if (csv->ref[k] > 0)
354 mpl_tab_set_str(dca, csv->ref[k], csv->field);
355 }
356 else
357 xassert(csv != csv);
358 }
359 /* now there must be NL */
360 read_field(csv);
361 xassert(csv->what != CSV_EOF);
362 if (csv->what != CSV_EOR)
363 { xprintf("%s:%d: too many fields\n", csv->fname, csv->count);
364 longjmp(csv->jump, 0);
365 }
366 done: return ret;
367 }
368
369 static int csv_write_record(TABDCA *dca, struct csv *csv)
370 { /* write next record to csv data file */
371 int k, nf, ret = 0;
372 const char *c;
373 xassert(csv->mode == 'W');
374 nf = mpl_tab_num_flds(dca);
375 for (k = 1; k <= nf; k++)
376 { switch (mpl_tab_get_type(dca, k))
377 { case 'N':
378 fprintf(csv->fp, "%.*g", DBL_DIG,
379 mpl_tab_get_num(dca, k));
380 break;
381 case 'S':
382 fputc('"', csv->fp);
383 for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++)
384 { if (*c == '"')
385 fputc('"', csv->fp), fputc('"', csv->fp);
386 else
387 fputc(*c, csv->fp);
388 }
389 fputc('"', csv->fp);
390 break;
391 default:
392 xassert(dca != dca);
393 }
394 fputc(k < nf ? ',' : '\n', csv->fp);
395 }
396 csv->count++;
397 if (ferror(csv->fp))
398 { xprintf("%s:%d: write error - %s\n", csv->fname, csv->count,
399 strerror(errno));
400 ret = 1;
401 }
402 return ret;
403 }
404
405 static int csv_close_file(TABDCA *dca, struct csv *csv)
406 { /* close csv data file */
407 int ret = 0;
408 xassert(dca == dca);
409 if (csv->mode == 'W')
410 { fflush(csv->fp);
411 if (ferror(csv->fp))
412 { xprintf("%s:%d: write error - %s\n", csv->fname,
413 csv->count, strerror(errno));
414 ret = 1;
415 }
416 }
417 xfree(csv->fname);
418 fclose(csv->fp);
419 xfree(csv);
420 return ret;
421 }
422
423 /**********************************************************************/
424
425 #define DBF_FIELD_MAX 50
426 /* maximal number of fields in record */
427
428 #define DBF_FDLEN_MAX 100
429 /* maximal field length */
430
431 struct dbf
432 { /* xBASE data file */
433 int mode;
434 /* 'R' = reading; 'W' = writing */
435 char *fname;
436 /* name of xBASE file */
437 FILE *fp;
438 /* stream assigned to xBASE file */
439 jmp_buf jump;
440 /* address for non-local go to in case of error */
441 int offset;
442 /* offset of a byte to be read next */
443 int count;
444 /* record count */
445 int nf;
446 /* number of fields */
447 int ref[1+DBF_FIELD_MAX];
448 /* ref[k] = k', if k-th field of the csv file corresponds to
449 k'-th field in the table statement; if ref[k] = 0, k-th field
450 of the csv file is ignored */
451 int type[1+DBF_FIELD_MAX];
452 /* type[k] is type of k-th field */
453 int len[1+DBF_FIELD_MAX];
454 /* len[k] is length of k-th field */
455 int prec[1+DBF_FIELD_MAX];
456 /* prec[k] is precision of k-th field */
457 };
458
459 static int read_byte(struct dbf *dbf)
460 { /* read byte from xBASE data file */
461 int b;
462 b = fgetc(dbf->fp);
463 if (ferror(dbf->fp))
464 { xprintf("%s:0x%X: read error - %s\n", dbf->fname,
465 dbf->offset, strerror(errno));
466 longjmp(dbf->jump, 0);
467 }
468 if (feof(dbf->fp))
469 { xprintf("%s:0x%X: unexpected end of file\n", dbf->fname,
470 dbf->offset);
471 longjmp(dbf->jump, 0);
472 }
473 xassert(0x00 <= b && b <= 0xFF);
474 dbf->offset++;
475 return b;
476 }
477
478 static void read_header(TABDCA *dca, struct dbf *dbf)
479 { /* read xBASE data file header */
480 int b, j, k, recl;
481 char name[10+1];
482 /* (ignored) */
483 for (j = 1; j <= 10; j++)
484 read_byte(dbf);
485 /* length of each record, in bytes */
486 recl = read_byte(dbf);
487 recl += read_byte(dbf) << 8;
488 /* (ignored) */
489 for (j = 1; j <= 20; j++)
490 read_byte(dbf);
491 /* field descriptor array */
492 xassert(dbf->nf == 0);
493 for (;;)
494 { /* check for end of array */
495 b = read_byte(dbf);
496 if (b == 0x0D) break;
497 if (dbf->nf == DBF_FIELD_MAX)
498 { xprintf("%s:0x%X: too many fields\n", dbf->fname,
499 dbf->offset);
500 longjmp(dbf->jump, 0);
501 }
502 dbf->nf++;
503 /* field name */
504 name[0] = (char)b;
505 for (j = 1; j < 10; j++)
506 { b = read_byte(dbf);
507 name[j] = (char)b;
508 }
509 name[10] = '\0';
510 b = read_byte(dbf);
511 if (b != 0x00)
512 { xprintf("%s:0x%X: invalid field name\n", dbf->fname,
513 dbf->offset);
514 longjmp(dbf->jump, 0);
515 }
516 /* find corresponding field in the table statement */
517 for (k = mpl_tab_num_flds(dca); k >= 1; k--)
518 if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break;
519 dbf->ref[dbf->nf] = k;
520 /* field type */
521 b = read_byte(dbf);
522 if (!(b == 'C' || b == 'N'))
523 { xprintf("%s:0x%X: invalid field type\n", dbf->fname,
524 dbf->offset);
525 longjmp(dbf->jump, 0);
526 }
527 dbf->type[dbf->nf] = b;
528 /* (ignored) */
529 for (j = 1; j <= 4; j++)
530 read_byte(dbf);
531 /* field length */
532 b = read_byte(dbf);
533 if (b == 0)
534 { xprintf("%s:0x%X: invalid field length\n", dbf->fname,
535 dbf->offset);
536 longjmp(dbf->jump, 0);
537 }
538 if (b > DBF_FDLEN_MAX)
539 { xprintf("%s:0x%X: field too long\n", dbf->fname,
540 dbf->offset);
541 longjmp(dbf->jump, 0);
542 }
543 dbf->len[dbf->nf] = b;
544 recl -= b;
545 /* (ignored) */
546 for (j = 1; j <= 15; j++)
547 read_byte(dbf);
548 }
549 if (recl != 1)
550 { xprintf("%s:0x%X: invalid file header\n", dbf->fname,
551 dbf->offset);
552 longjmp(dbf->jump, 0);
553 }
554 /* find dummy RECNO field in the table statement */
555 for (k = mpl_tab_num_flds(dca); k >= 1; k--)
556 if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
557 dbf->ref[0] = k;
558 return;
559 }
560
561 static void parse_third_arg(TABDCA *dca, struct dbf *dbf)
562 { /* parse xBASE file format (third argument) */
563 int j, k, temp;
564 const char *arg;
565 dbf->nf = mpl_tab_num_flds(dca);
566 arg = mpl_tab_get_arg(dca, 3), j = 0;
567 for (k = 1; k <= dbf->nf; k++)
568 { /* parse specification of k-th field */
569 if (arg[j] == '\0')
570 { xprintf("xBASE driver: field %s: specification missing\n",
571 mpl_tab_get_name(dca, k));
572 longjmp(dbf->jump, 0);
573 }
574 /* parse field type */
575 if (arg[j] == 'C' || arg[j] == 'N')
576 dbf->type[k] = arg[j], j++;
577 else
578 { xprintf("xBASE driver: field %s: invalid field type\n",
579 mpl_tab_get_name(dca, k));
580 longjmp(dbf->jump, 0);
581 }
582 /* check for left parenthesis */
583 if (arg[j] == '(')
584 j++;
585 else
586 err: { xprintf("xBASE driver: field %s: invalid field format\n",
587 mpl_tab_get_name(dca, k));
588 longjmp(dbf->jump, 0);
589 }
590 /* parse field length */
591 temp = 0;
592 while (isdigit(arg[j]))
593 { if (temp > DBF_FDLEN_MAX) break;
594 temp = 10 * temp + (arg[j] - '0'), j++;
595 }
596 if (!(1 <= temp && temp <= DBF_FDLEN_MAX))
597 { xprintf("xBASE driver: field %s: invalid field length\n",
598 mpl_tab_get_name(dca, k));
599 longjmp(dbf->jump, 0);
600 }
601 dbf->len[k] = temp;
602 /* parse optional field precision */
603 if (dbf->type[k] == 'N' && arg[j] == ',')
604 { j++;
605 temp = 0;
606 while (isdigit(arg[j]))
607 { if (temp > dbf->len[k]) break;
608 temp = 10 * temp + (arg[j] - '0'), j++;
609 }
610 if (temp > dbf->len[k])
611 { xprintf("xBASE driver: field %s: invalid field precision"
612 "\n", mpl_tab_get_name(dca, k));
613 longjmp(dbf->jump, 0);
614 }
615 dbf->prec[k] = temp;
616 }
617 else
618 dbf->prec[k] = 0;
619 /* check for right parenthesis */
620 if (arg[j] == ')')
621 j++;
622 else
623 goto err;
624 }
625 /* ignore other specifications */
626 return;
627 }
628
629 static void write_byte(struct dbf *dbf, int b)
630 { /* write byte to xBASE data file */
631 fputc(b, dbf->fp);
632 dbf->offset++;
633 return;
634 }
635
636 static void write_header(TABDCA *dca, struct dbf *dbf)
637 { /* write xBASE data file header */
638 int j, k, temp;
639 const char *name;
640 /* version number */
641 write_byte(dbf, 0x03 /* file without DBT */);
642 /* date of last update (YYMMDD) */
643 write_byte(dbf, 70 /* 1970 */);
644 write_byte(dbf, 1 /* January */);
645 write_byte(dbf, 1 /* 1st */);
646 /* number of records (unknown so far) */
647 for (j = 1; j <= 4; j++)
648 write_byte(dbf, 0xFF);
649 /* length of the header, in bytes */
650 temp = 32 + dbf->nf * 32 + 1;
651 write_byte(dbf, temp);
652 write_byte(dbf, temp >> 8);
653 /* length of each record, in bytes */
654 temp = 1;
655 for (k = 1; k <= dbf->nf; k++)
656 temp += dbf->len[k];
657 write_byte(dbf, temp);
658 write_byte(dbf, temp >> 8);
659 /* (reserved) */
660 for (j = 1; j <= 20; j++)
661 write_byte(dbf, 0x00);
662 /* field descriptor array */
663 for (k = 1; k <= dbf->nf; k++)
664 { /* field name (terminated by 0x00) */
665 name = mpl_tab_get_name(dca, k);
666 for (j = 0; j < 10 && name[j] != '\0'; j++)
667 write_byte(dbf, name[j]);
668 for (j = j; j < 11; j++)
669 write_byte(dbf, 0x00);
670 /* field type */
671 write_byte(dbf, dbf->type[k]);
672 /* (reserved) */
673 for (j = 1; j <= 4; j++)
674 write_byte(dbf, 0x00);
675 /* field length */
676 write_byte(dbf, dbf->len[k]);
677 /* field precision */
678 write_byte(dbf, dbf->prec[k]);
679 /* (reserved) */
680 for (j = 1; j <= 14; j++)
681 write_byte(dbf, 0x00);
682 }
683 /* end of header */
684 write_byte(dbf, 0x0D);
685 return;
686 }
687
688 static struct dbf *dbf_open_file(TABDCA *dca, int mode)
689 { /* open xBASE data file */
690 struct dbf *dbf;
691 /* create control structure */
692 dbf = xmalloc(sizeof(struct dbf));
693 dbf->mode = mode;
694 dbf->fname = NULL;
695 dbf->fp = NULL;
696 if (setjmp(dbf->jump)) goto fail;
697 dbf->offset = 0;
698 dbf->count = 0;
699 dbf->nf = 0;
700 /* try to open the xBASE data file */
701 if (mpl_tab_num_args(dca) < 2)
702 { xprintf("xBASE driver: file name not specified\n");
703 longjmp(dbf->jump, 0);
704 }
705 dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
706 strcpy(dbf->fname, mpl_tab_get_arg(dca, 2));
707 if (mode == 'R')
708 { /* open the file for reading */
709 dbf->fp = fopen(dbf->fname, "rb");
710 if (dbf->fp == NULL)
711 { xprintf("xBASE driver: unable to open %s - %s\n",
712 dbf->fname, strerror(errno));
713 longjmp(dbf->jump, 0);
714 }
715 read_header(dca, dbf);
716 }
717 else if (mode == 'W')
718 { /* open the file for writing */
719 if (mpl_tab_num_args(dca) < 3)
720 { xprintf("xBASE driver: file format not specified\n");
721 longjmp(dbf->jump, 0);
722 }
723 parse_third_arg(dca, dbf);
724 dbf->fp = fopen(dbf->fname, "wb");
725 if (dbf->fp == NULL)
726 { xprintf("xBASE driver: unable to create %s - %s\n",
727 dbf->fname, strerror(errno));
728 longjmp(dbf->jump, 0);
729 }
730 write_header(dca, dbf);
731 }
732 else
733 xassert(mode != mode);
734 /* the file has been open */
735 return dbf;
736 fail: /* the file cannot be open */
737 if (dbf->fname != NULL) xfree(dbf->fname);
738 if (dbf->fp != NULL) fclose(dbf->fp);
739 xfree(dbf);
740 return NULL;
741 }
742
743 static int dbf_read_record(TABDCA *dca, struct dbf *dbf)
744 { /* read next record from xBASE data file */
745 int b, j, k, ret = 0;
746 char buf[DBF_FDLEN_MAX+1];
747 xassert(dbf->mode == 'R');
748 if (setjmp(dbf->jump))
749 { ret = 1;
750 goto done;
751 }
752 /* check record flag */
753 b = read_byte(dbf);
754 if (b == 0x1A)
755 { /* end of data */
756 ret = -1;
757 goto done;
758 }
759 if (b != 0x20)
760 { xprintf("%s:0x%X: invalid record flag\n", dbf->fname,
761 dbf->offset);
762 longjmp(dbf->jump, 0);
763 }
764 /* read dummy RECNO field */
765 if (dbf->ref[0] > 0)
766 mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1);
767 /* read fields */
768 for (k = 1; k <= dbf->nf; k++)
769 { /* read k-th field */
770 for (j = 0; j < dbf->len[k]; j++)
771 buf[j] = (char)read_byte(dbf);
772 buf[dbf->len[k]] = '\0';
773 /* set field value */
774 if (dbf->type[k] == 'C')
775 { /* character field */
776 if (dbf->ref[k] > 0)
777 mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf));
778 }
779 else if (dbf->type[k] == 'N')
780 { /* numeric field */
781 if (dbf->ref[k] > 0)
782 { double num;
783 strspx(buf);
784 xassert(str2num(buf, &num) == 0);
785 mpl_tab_set_num(dca, dbf->ref[k], num);
786 }
787 }
788 else
789 xassert(dbf != dbf);
790 }
791 /* increase record count */
792 dbf->count++;
793 done: return ret;
794 }
795
796 static int dbf_write_record(TABDCA *dca, struct dbf *dbf)
797 { /* write next record to xBASE data file */
798 int j, k, ret = 0;
799 char buf[255+1];
800 xassert(dbf->mode == 'W');
801 if (setjmp(dbf->jump))
802 { ret = 1;
803 goto done;
804 }
805 /* record flag */
806 write_byte(dbf, 0x20);
807 xassert(dbf->nf == mpl_tab_num_flds(dca));
808 for (k = 1; k <= dbf->nf; k++)
809 { if (dbf->type[k] == 'C')
810 { /* character field */
811 const char *str;
812 if (mpl_tab_get_type(dca, k) == 'N')
813 { sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
814 str = buf;
815 }
816 else if (mpl_tab_get_type(dca, k) == 'S')
817 str = mpl_tab_get_str(dca, k);
818 else
819 xassert(dca != dca);
820 if ((int)strlen(str) > dbf->len[k])
821 { xprintf("xBASE driver: field %s: cannot convert %.15s..."
822 " to field format\n", mpl_tab_get_name(dca, k), str);
823 longjmp(dbf->jump, 0);
824 }
825 for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++)
826 write_byte(dbf, str[j]);
827 for (j = j; j < dbf->len[k]; j++)
828 write_byte(dbf, ' ');
829 }
830 else if (dbf->type[k] == 'N')
831 { /* numeric field */
832 double num = mpl_tab_get_num(dca, k);
833 if (fabs(num) > 1e20)
834 err: { xprintf("xBASE driver: field %s: cannot convert %g to fi"
835 "eld format\n", mpl_tab_get_name(dca, k), num);
836 longjmp(dbf->jump, 0);
837 }
838 sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num);
839 xassert(strlen(buf) < sizeof(buf));
840 if ((int)strlen(buf) != dbf->len[k]) goto err;
841 for (j = 0; j < dbf->len[k]; j++)
842 write_byte(dbf, buf[j]);
843 }
844 else
845 xassert(dbf != dbf);
846 }
847 /* increase record count */
848 dbf->count++;
849 done: return ret;
850 }
851
852 static int dbf_close_file(TABDCA *dca, struct dbf *dbf)
853 { /* close xBASE data file */
854 int ret = 0;
855 xassert(dca == dca);
856 if (dbf->mode == 'W')
857 { if (setjmp(dbf->jump))
858 { ret = 1;
859 goto skip;
860 }
861 /* end-of-file flag */
862 write_byte(dbf, 0x1A);
863 /* number of records */
864 dbf->offset = 4;
865 if (fseek(dbf->fp, dbf->offset, SEEK_SET))
866 { xprintf("%s:0x%X: seek error - %s\n", dbf->fname,
867 dbf->offset, strerror(errno));
868 longjmp(dbf->jump, 0);
869 }
870 write_byte(dbf, dbf->count);
871 write_byte(dbf, dbf->count >> 8);
872 write_byte(dbf, dbf->count >> 16);
873 write_byte(dbf, dbf->count >> 24);
874 fflush(dbf->fp);
875 if (ferror(dbf->fp))
876 { xprintf("%s:0x%X: write error - %s\n", dbf->fname,
877 dbf->offset, strerror(errno));
878 longjmp(dbf->jump, 0);
879 }
880 skip: ;
881 }
882 xfree(dbf->fname);
883 fclose(dbf->fp);
884 xfree(dbf);
885 return ret;
886 }
887
888 /**********************************************************************/
889
890 #define TAB_CSV 1
891 #define TAB_XBASE 2
892 #define TAB_ODBC 3
893 #define TAB_MYSQL 4
894
895 void mpl_tab_drv_open(MPL *mpl, int mode)
896 { TABDCA *dca = mpl->dca;
897 xassert(dca->id == 0);
898 xassert(dca->link == NULL);
899 xassert(dca->na >= 1);
900 if (strcmp(dca->arg[1], "CSV") == 0)
901 { dca->id = TAB_CSV;
902 dca->link = csv_open_file(dca, mode);
903 }
904 else if (strcmp(dca->arg[1], "xBASE") == 0)
905 { dca->id = TAB_XBASE;
906 dca->link = dbf_open_file(dca, mode);
907 }
908 else if (strcmp(dca->arg[1], "ODBC") == 0 ||
909 strcmp(dca->arg[1], "iODBC") == 0)
910 { dca->id = TAB_ODBC;
911 dca->link = db_iodbc_open(dca, mode);
912 }
913 else if (strcmp(dca->arg[1], "MySQL") == 0)
914 { dca->id = TAB_MYSQL;
915 dca->link = db_mysql_open(dca, mode);
916 }
917 else
918 xprintf("Invalid table driver `%s'\n", dca->arg[1]);
919 if (dca->link == NULL)
920 error(mpl, "error on opening table %s",
921 mpl->stmt->u.tab->name);
922 return;
923 }
924
925 int mpl_tab_drv_read(MPL *mpl)
926 { TABDCA *dca = mpl->dca;
927 int ret;
928 switch (dca->id)
929 { case TAB_CSV:
930 ret = csv_read_record(dca, dca->link);
931 break;
932 case TAB_XBASE:
933 ret = dbf_read_record(dca, dca->link);
934 break;
935 case TAB_ODBC:
936 ret = db_iodbc_read(dca, dca->link);
937 break;
938 case TAB_MYSQL:
939 ret = db_mysql_read(dca, dca->link);
940 break;
941 default:
942 xassert(dca != dca);
943 }
944 if (ret > 0)
945 error(mpl, "error on reading data from table %s",
946 mpl->stmt->u.tab->name);
947 return ret;
948 }
949
950 void mpl_tab_drv_write(MPL *mpl)
951 { TABDCA *dca = mpl->dca;
952 int ret;
953 switch (dca->id)
954 { case TAB_CSV:
955 ret = csv_write_record(dca, dca->link);
956 break;
957 case TAB_XBASE:
958 ret = dbf_write_record(dca, dca->link);
959 break;
960 case TAB_ODBC:
961 ret = db_iodbc_write(dca, dca->link);
962 break;
963 case TAB_MYSQL:
964 ret = db_mysql_write(dca, dca->link);
965 break;
966 default:
967 xassert(dca != dca);
968 }
969 if (ret)
970 error(mpl, "error on writing data to table %s",
971 mpl->stmt->u.tab->name);
972 return;
973 }
974
975 void mpl_tab_drv_close(MPL *mpl)
976 { TABDCA *dca = mpl->dca;
977 int ret;
978 switch (dca->id)
979 { case TAB_CSV:
980 ret = csv_close_file(dca, dca->link);
981 break;
982 case TAB_XBASE:
983 ret = dbf_close_file(dca, dca->link);
984 break;
985 case TAB_ODBC:
986 ret = db_iodbc_close(dca, dca->link);
987 break;
988 case TAB_MYSQL:
989 ret = db_mysql_close(dca, dca->link);
990 break;
991 default:
992 xassert(dca != dca);
993 }
994 dca->id = 0;
995 dca->link = NULL;
996 if (ret)
997 error(mpl, "error on closing table %s",
998 mpl->stmt->u.tab->name);
999 return;
1000 }
1001
1002 /* eof */