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