COIN-OR::LEMON - Graph Library

source: glpk-cmake/src/glpmpl06.c @ 1:c445c931472f

Last change on this file since 1:c445c931472f was 1:c445c931472f, checked in by Alpar Juttner <alpar@…>, 10 years ago

Import glpk-4.45

  • Generated files and doc/notes are removed
File size: 30.6 KB
Line 
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 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
38struct 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
76static 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++;
81loop: 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
111static 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 == ',')
125err1:    {  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)
175err2:       {  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      }
213done: return;
214}
215
216static 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;
301fail: /* 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
308static 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      }
366done: return ret;
367}
368
369static 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
405static 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
431struct 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
459static 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
478static 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
561static 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
586err:     {  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
629static 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
636static 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
688static 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;
736fail: /* 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
743static 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++;
793done: return ret;
794}
795
796static 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)
834err:        {  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++;
849done: return ret;
850}
851
852static 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         }
880skip:    ;
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
895void 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
925int 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
950void 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
975void 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 */
Note: See TracBrowser for help on using the repository browser.