lemon-project-template-glpk
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/deps/glpk/src/glpmpl06.c Sun Nov 06 20:59:10 2011 +0100 1.3 @@ -0,0 +1,1002 @@ 1.4 +/* glpmpl06.c */ 1.5 + 1.6 +/*********************************************************************** 1.7 +* This code is part of GLPK (GNU Linear Programming Kit). 1.8 +* 1.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 1.10 +* 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics, 1.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved. 1.12 +* E-mail: <mao@gnu.org>. 1.13 +* 1.14 +* GLPK is free software: you can redistribute it and/or modify it 1.15 +* under the terms of the GNU General Public License as published by 1.16 +* the Free Software Foundation, either version 3 of the License, or 1.17 +* (at your option) any later version. 1.18 +* 1.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT 1.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 1.22 +* License for more details. 1.23 +* 1.24 +* You should have received a copy of the GNU General Public License 1.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. 1.26 +***********************************************************************/ 1.27 + 1.28 +#define _GLPSTD_ERRNO 1.29 +#define _GLPSTD_STDIO 1.30 +#include "glpmpl.h" 1.31 +#include "glpsql.h" 1.32 + 1.33 +/**********************************************************************/ 1.34 + 1.35 +#define CSV_FIELD_MAX 50 1.36 +/* maximal number of fields in record */ 1.37 + 1.38 +#define CSV_FDLEN_MAX 100 1.39 +/* maximal field length */ 1.40 + 1.41 +struct csv 1.42 +{ /* comma-separated values file */ 1.43 + int mode; 1.44 + /* 'R' = reading; 'W' = writing */ 1.45 + char *fname; 1.46 + /* name of csv file */ 1.47 + FILE *fp; 1.48 + /* stream assigned to csv file */ 1.49 + jmp_buf jump; 1.50 + /* address for non-local go to in case of error */ 1.51 + int count; 1.52 + /* record count */ 1.53 + /*--------------------------------------------------------------*/ 1.54 + /* used only for input csv file */ 1.55 + int c; 1.56 + /* current character or EOF */ 1.57 + int what; 1.58 + /* current marker: */ 1.59 +#define CSV_EOF 0 /* end-of-file */ 1.60 +#define CSV_EOR 1 /* end-of-record */ 1.61 +#define CSV_NUM 2 /* floating-point number */ 1.62 +#define CSV_STR 3 /* character string */ 1.63 + char field[CSV_FDLEN_MAX+1]; 1.64 + /* current field just read */ 1.65 + int nf; 1.66 + /* number of fields in the csv file */ 1.67 + int ref[1+CSV_FIELD_MAX]; 1.68 + /* ref[k] = k', if k-th field of the csv file corresponds to 1.69 + k'-th field in the table statement; if ref[k] = 0, k-th field 1.70 + of the csv file is ignored */ 1.71 +#if 1 /* 01/VI-2010 */ 1.72 + int nskip; 1.73 + /* number of comment records preceding the header record */ 1.74 +#endif 1.75 +}; 1.76 + 1.77 +#undef read_char 1.78 + 1.79 +static void read_char(struct csv *csv) 1.80 +{ /* read character from csv data file */ 1.81 + int c; 1.82 + xassert(csv->c != EOF); 1.83 + if (csv->c == '\n') csv->count++; 1.84 +loop: c = fgetc(csv->fp); 1.85 + if (ferror(csv->fp)) 1.86 + { xprintf("%s:%d: read error - %s\n", csv->fname, csv->count, 1.87 + strerror(errno)); 1.88 + longjmp(csv->jump, 0); 1.89 + } 1.90 + if (feof(csv->fp)) 1.91 + { if (csv->c == '\n') 1.92 + { csv->count--; 1.93 + c = EOF; 1.94 + } 1.95 + else 1.96 + { xprintf("%s:%d: warning: missing final end-of-line\n", 1.97 + csv->fname, csv->count); 1.98 + c = '\n'; 1.99 + } 1.100 + } 1.101 + else if (c == '\r') 1.102 + goto loop; 1.103 + else if (c == '\n') 1.104 + ; 1.105 + else if (iscntrl(c)) 1.106 + { xprintf("%s:%d: invalid control character 0x%02X\n", 1.107 + csv->fname, csv->count, c); 1.108 + longjmp(csv->jump, 0); 1.109 + } 1.110 + csv->c = c; 1.111 + return; 1.112 +} 1.113 + 1.114 +static void read_field(struct csv *csv) 1.115 +{ /* read field from csv data file */ 1.116 + /* check for end of file */ 1.117 + if (csv->c == EOF) 1.118 + { csv->what = CSV_EOF; 1.119 + strcpy(csv->field, "EOF"); 1.120 + goto done; 1.121 + } 1.122 + /* check for end of record */ 1.123 + if (csv->c == '\n') 1.124 + { csv->what = CSV_EOR; 1.125 + strcpy(csv->field, "EOR"); 1.126 + read_char(csv); 1.127 + if (csv->c == ',') 1.128 +err1: { xprintf("%s:%d: empty field not allowed\n", csv->fname, 1.129 + csv->count); 1.130 + longjmp(csv->jump, 0); 1.131 + } 1.132 + if (csv->c == '\n') 1.133 + { xprintf("%s:%d: empty record not allowed\n", csv->fname, 1.134 + csv->count); 1.135 + longjmp(csv->jump, 0); 1.136 + } 1.137 +#if 1 /* 01/VI-2010 */ 1.138 + /* skip comment records; may appear only before the very first 1.139 + record containing field names */ 1.140 + if (csv->c == '#' && csv->count == 1) 1.141 + { while (csv->c == '#') 1.142 + { while (csv->c != '\n') 1.143 + read_char(csv); 1.144 + read_char(csv); 1.145 + csv->nskip++; 1.146 + } 1.147 + } 1.148 +#endif 1.149 + goto done; 1.150 + } 1.151 + /* skip comma before next field */ 1.152 + if (csv->c == ',') 1.153 + read_char(csv); 1.154 + /* read field */ 1.155 + if (csv->c == '\'' || csv->c == '"') 1.156 + { /* read a field enclosed in quotes */ 1.157 + int quote = csv->c, len = 0; 1.158 + csv->what = CSV_STR; 1.159 + /* skip opening quote */ 1.160 + read_char(csv); 1.161 + /* read field characters within quotes */ 1.162 + for (;;) 1.163 + { /* check for closing quote and read it */ 1.164 + if (csv->c == quote) 1.165 + { read_char(csv); 1.166 + if (csv->c == quote) 1.167 + ; 1.168 + else if (csv->c == ',' || csv->c == '\n') 1.169 + break; 1.170 + else 1.171 + { xprintf("%s:%d: invalid field\n", csv->fname, 1.172 + csv->count); 1.173 + longjmp(csv->jump, 0); 1.174 + } 1.175 + } 1.176 + /* check the current field length */ 1.177 + if (len == CSV_FDLEN_MAX) 1.178 +err2: { xprintf("%s:%d: field too long\n", csv->fname, 1.179 + csv->count); 1.180 + longjmp(csv->jump, 0); 1.181 + } 1.182 + /* add the current character to the field */ 1.183 + csv->field[len++] = (char)csv->c; 1.184 + /* read the next character */ 1.185 + read_char(csv); 1.186 + } 1.187 + /* the field has been read */ 1.188 + if (len == 0) goto err1; 1.189 + csv->field[len] = '\0'; 1.190 + } 1.191 + else 1.192 + { /* read a field not enclosed in quotes */ 1.193 + int len = 0; 1.194 + double temp; 1.195 + csv->what = CSV_NUM; 1.196 + while (!(csv->c == ',' || csv->c == '\n')) 1.197 + { /* quotes within the field are not allowed */ 1.198 + if (csv->c == '\'' || csv->c == '"') 1.199 + { xprintf("%s:%d: invalid use of single or double quote wi" 1.200 + "thin field\n", csv->fname, csv->count); 1.201 + longjmp(csv->jump, 0); 1.202 + } 1.203 + /* check the current field length */ 1.204 + if (len == CSV_FDLEN_MAX) goto err2; 1.205 + /* add the current character to the field */ 1.206 + csv->field[len++] = (char)csv->c; 1.207 + /* read the next character */ 1.208 + read_char(csv); 1.209 + } 1.210 + /* the field has been read */ 1.211 + if (len == 0) goto err1; 1.212 + csv->field[len] = '\0'; 1.213 + /* check the field type */ 1.214 + if (str2num(csv->field, &temp)) csv->what = CSV_STR; 1.215 + } 1.216 +done: return; 1.217 +} 1.218 + 1.219 +static struct csv *csv_open_file(TABDCA *dca, int mode) 1.220 +{ /* open csv data file */ 1.221 + struct csv *csv; 1.222 + /* create control structure */ 1.223 + csv = xmalloc(sizeof(struct csv)); 1.224 + csv->mode = mode; 1.225 + csv->fname = NULL; 1.226 + csv->fp = NULL; 1.227 + if (setjmp(csv->jump)) goto fail; 1.228 + csv->count = 0; 1.229 + csv->c = '\n'; 1.230 + csv->what = 0; 1.231 + csv->field[0] = '\0'; 1.232 + csv->nf = 0; 1.233 + /* try to open the csv data file */ 1.234 + if (mpl_tab_num_args(dca) < 2) 1.235 + { xprintf("csv_driver: file name not specified\n"); 1.236 + longjmp(csv->jump, 0); 1.237 + } 1.238 + csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1); 1.239 + strcpy(csv->fname, mpl_tab_get_arg(dca, 2)); 1.240 + if (mode == 'R') 1.241 + { /* open the file for reading */ 1.242 + int k; 1.243 + csv->fp = fopen(csv->fname, "r"); 1.244 + if (csv->fp == NULL) 1.245 + { xprintf("csv_driver: unable to open %s - %s\n", 1.246 + csv->fname, strerror(errno)); 1.247 + longjmp(csv->jump, 0); 1.248 + } 1.249 +#if 1 /* 01/VI-2010 */ 1.250 + csv->nskip = 0; 1.251 +#endif 1.252 + /* skip fake new-line */ 1.253 + read_field(csv); 1.254 + xassert(csv->what == CSV_EOR); 1.255 + /* read field names */ 1.256 + xassert(csv->nf == 0); 1.257 + for (;;) 1.258 + { read_field(csv); 1.259 + if (csv->what == CSV_EOR) 1.260 + break; 1.261 + if (csv->what != CSV_STR) 1.262 + { xprintf("%s:%d: invalid field name\n", csv->fname, 1.263 + csv->count); 1.264 + longjmp(csv->jump, 0); 1.265 + } 1.266 + if (csv->nf == CSV_FIELD_MAX) 1.267 + { xprintf("%s:%d: too many fields\n", csv->fname, 1.268 + csv->count); 1.269 + longjmp(csv->jump, 0); 1.270 + } 1.271 + csv->nf++; 1.272 + /* find corresponding field in the table statement */ 1.273 + for (k = mpl_tab_num_flds(dca); k >= 1; k--) 1.274 + { if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0) 1.275 + break; 1.276 + } 1.277 + csv->ref[csv->nf] = k; 1.278 + } 1.279 + /* find dummy RECNO field in the table statement */ 1.280 + for (k = mpl_tab_num_flds(dca); k >= 1; k--) 1.281 + if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break; 1.282 + csv->ref[0] = k; 1.283 + } 1.284 + else if (mode == 'W') 1.285 + { /* open the file for writing */ 1.286 + int k, nf; 1.287 + csv->fp = fopen(csv->fname, "w"); 1.288 + if (csv->fp == NULL) 1.289 + { xprintf("csv_driver: unable to create %s - %s\n", 1.290 + csv->fname, strerror(errno)); 1.291 + longjmp(csv->jump, 0); 1.292 + } 1.293 + /* write field names */ 1.294 + nf = mpl_tab_num_flds(dca); 1.295 + for (k = 1; k <= nf; k++) 1.296 + fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k), 1.297 + k < nf ? ',' : '\n'); 1.298 + csv->count++; 1.299 + } 1.300 + else 1.301 + xassert(mode != mode); 1.302 + /* the file has been open */ 1.303 + return csv; 1.304 +fail: /* the file cannot be open */ 1.305 + if (csv->fname != NULL) xfree(csv->fname); 1.306 + if (csv->fp != NULL) fclose(csv->fp); 1.307 + xfree(csv); 1.308 + return NULL; 1.309 +} 1.310 + 1.311 +static int csv_read_record(TABDCA *dca, struct csv *csv) 1.312 +{ /* read next record from csv data file */ 1.313 + int k, ret = 0; 1.314 + xassert(csv->mode == 'R'); 1.315 + if (setjmp(csv->jump)) 1.316 + { ret = 1; 1.317 + goto done; 1.318 + } 1.319 + /* read dummy RECNO field */ 1.320 + if (csv->ref[0] > 0) 1.321 +#if 0 /* 01/VI-2010 */ 1.322 + mpl_tab_set_num(dca, csv->ref[0], csv->count-1); 1.323 +#else 1.324 + mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1); 1.325 +#endif 1.326 + /* read fields */ 1.327 + for (k = 1; k <= csv->nf; k++) 1.328 + { read_field(csv); 1.329 + if (csv->what == CSV_EOF) 1.330 + { /* end-of-file reached */ 1.331 + xassert(k == 1); 1.332 + ret = -1; 1.333 + goto done; 1.334 + } 1.335 + else if (csv->what == CSV_EOR) 1.336 + { /* end-of-record reached */ 1.337 + int lack = csv->nf - k + 1; 1.338 + if (lack == 1) 1.339 + xprintf("%s:%d: one field missing\n", csv->fname, 1.340 + csv->count); 1.341 + else 1.342 + xprintf("%s:%d: %d fields missing\n", csv->fname, 1.343 + csv->count, lack); 1.344 + longjmp(csv->jump, 0); 1.345 + } 1.346 + else if (csv->what == CSV_NUM) 1.347 + { /* floating-point number */ 1.348 + if (csv->ref[k] > 0) 1.349 + { double num; 1.350 + xassert(str2num(csv->field, &num) == 0); 1.351 + mpl_tab_set_num(dca, csv->ref[k], num); 1.352 + } 1.353 + } 1.354 + else if (csv->what == CSV_STR) 1.355 + { /* character string */ 1.356 + if (csv->ref[k] > 0) 1.357 + mpl_tab_set_str(dca, csv->ref[k], csv->field); 1.358 + } 1.359 + else 1.360 + xassert(csv != csv); 1.361 + } 1.362 + /* now there must be NL */ 1.363 + read_field(csv); 1.364 + xassert(csv->what != CSV_EOF); 1.365 + if (csv->what != CSV_EOR) 1.366 + { xprintf("%s:%d: too many fields\n", csv->fname, csv->count); 1.367 + longjmp(csv->jump, 0); 1.368 + } 1.369 +done: return ret; 1.370 +} 1.371 + 1.372 +static int csv_write_record(TABDCA *dca, struct csv *csv) 1.373 +{ /* write next record to csv data file */ 1.374 + int k, nf, ret = 0; 1.375 + const char *c; 1.376 + xassert(csv->mode == 'W'); 1.377 + nf = mpl_tab_num_flds(dca); 1.378 + for (k = 1; k <= nf; k++) 1.379 + { switch (mpl_tab_get_type(dca, k)) 1.380 + { case 'N': 1.381 + fprintf(csv->fp, "%.*g", DBL_DIG, 1.382 + mpl_tab_get_num(dca, k)); 1.383 + break; 1.384 + case 'S': 1.385 + fputc('"', csv->fp); 1.386 + for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++) 1.387 + { if (*c == '"') 1.388 + fputc('"', csv->fp), fputc('"', csv->fp); 1.389 + else 1.390 + fputc(*c, csv->fp); 1.391 + } 1.392 + fputc('"', csv->fp); 1.393 + break; 1.394 + default: 1.395 + xassert(dca != dca); 1.396 + } 1.397 + fputc(k < nf ? ',' : '\n', csv->fp); 1.398 + } 1.399 + csv->count++; 1.400 + if (ferror(csv->fp)) 1.401 + { xprintf("%s:%d: write error - %s\n", csv->fname, csv->count, 1.402 + strerror(errno)); 1.403 + ret = 1; 1.404 + } 1.405 + return ret; 1.406 +} 1.407 + 1.408 +static int csv_close_file(TABDCA *dca, struct csv *csv) 1.409 +{ /* close csv data file */ 1.410 + int ret = 0; 1.411 + xassert(dca == dca); 1.412 + if (csv->mode == 'W') 1.413 + { fflush(csv->fp); 1.414 + if (ferror(csv->fp)) 1.415 + { xprintf("%s:%d: write error - %s\n", csv->fname, 1.416 + csv->count, strerror(errno)); 1.417 + ret = 1; 1.418 + } 1.419 + } 1.420 + xfree(csv->fname); 1.421 + fclose(csv->fp); 1.422 + xfree(csv); 1.423 + return ret; 1.424 +} 1.425 + 1.426 +/**********************************************************************/ 1.427 + 1.428 +#define DBF_FIELD_MAX 50 1.429 +/* maximal number of fields in record */ 1.430 + 1.431 +#define DBF_FDLEN_MAX 100 1.432 +/* maximal field length */ 1.433 + 1.434 +struct dbf 1.435 +{ /* xBASE data file */ 1.436 + int mode; 1.437 + /* 'R' = reading; 'W' = writing */ 1.438 + char *fname; 1.439 + /* name of xBASE file */ 1.440 + FILE *fp; 1.441 + /* stream assigned to xBASE file */ 1.442 + jmp_buf jump; 1.443 + /* address for non-local go to in case of error */ 1.444 + int offset; 1.445 + /* offset of a byte to be read next */ 1.446 + int count; 1.447 + /* record count */ 1.448 + int nf; 1.449 + /* number of fields */ 1.450 + int ref[1+DBF_FIELD_MAX]; 1.451 + /* ref[k] = k', if k-th field of the csv file corresponds to 1.452 + k'-th field in the table statement; if ref[k] = 0, k-th field 1.453 + of the csv file is ignored */ 1.454 + int type[1+DBF_FIELD_MAX]; 1.455 + /* type[k] is type of k-th field */ 1.456 + int len[1+DBF_FIELD_MAX]; 1.457 + /* len[k] is length of k-th field */ 1.458 + int prec[1+DBF_FIELD_MAX]; 1.459 + /* prec[k] is precision of k-th field */ 1.460 +}; 1.461 + 1.462 +static int read_byte(struct dbf *dbf) 1.463 +{ /* read byte from xBASE data file */ 1.464 + int b; 1.465 + b = fgetc(dbf->fp); 1.466 + if (ferror(dbf->fp)) 1.467 + { xprintf("%s:0x%X: read error - %s\n", dbf->fname, 1.468 + dbf->offset, strerror(errno)); 1.469 + longjmp(dbf->jump, 0); 1.470 + } 1.471 + if (feof(dbf->fp)) 1.472 + { xprintf("%s:0x%X: unexpected end of file\n", dbf->fname, 1.473 + dbf->offset); 1.474 + longjmp(dbf->jump, 0); 1.475 + } 1.476 + xassert(0x00 <= b && b <= 0xFF); 1.477 + dbf->offset++; 1.478 + return b; 1.479 +} 1.480 + 1.481 +static void read_header(TABDCA *dca, struct dbf *dbf) 1.482 +{ /* read xBASE data file header */ 1.483 + int b, j, k, recl; 1.484 + char name[10+1]; 1.485 + /* (ignored) */ 1.486 + for (j = 1; j <= 10; j++) 1.487 + read_byte(dbf); 1.488 + /* length of each record, in bytes */ 1.489 + recl = read_byte(dbf); 1.490 + recl += read_byte(dbf) << 8; 1.491 + /* (ignored) */ 1.492 + for (j = 1; j <= 20; j++) 1.493 + read_byte(dbf); 1.494 + /* field descriptor array */ 1.495 + xassert(dbf->nf == 0); 1.496 + for (;;) 1.497 + { /* check for end of array */ 1.498 + b = read_byte(dbf); 1.499 + if (b == 0x0D) break; 1.500 + if (dbf->nf == DBF_FIELD_MAX) 1.501 + { xprintf("%s:0x%X: too many fields\n", dbf->fname, 1.502 + dbf->offset); 1.503 + longjmp(dbf->jump, 0); 1.504 + } 1.505 + dbf->nf++; 1.506 + /* field name */ 1.507 + name[0] = (char)b; 1.508 + for (j = 1; j < 10; j++) 1.509 + { b = read_byte(dbf); 1.510 + name[j] = (char)b; 1.511 + } 1.512 + name[10] = '\0'; 1.513 + b = read_byte(dbf); 1.514 + if (b != 0x00) 1.515 + { xprintf("%s:0x%X: invalid field name\n", dbf->fname, 1.516 + dbf->offset); 1.517 + longjmp(dbf->jump, 0); 1.518 + } 1.519 + /* find corresponding field in the table statement */ 1.520 + for (k = mpl_tab_num_flds(dca); k >= 1; k--) 1.521 + if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break; 1.522 + dbf->ref[dbf->nf] = k; 1.523 + /* field type */ 1.524 + b = read_byte(dbf); 1.525 + if (!(b == 'C' || b == 'N')) 1.526 + { xprintf("%s:0x%X: invalid field type\n", dbf->fname, 1.527 + dbf->offset); 1.528 + longjmp(dbf->jump, 0); 1.529 + } 1.530 + dbf->type[dbf->nf] = b; 1.531 + /* (ignored) */ 1.532 + for (j = 1; j <= 4; j++) 1.533 + read_byte(dbf); 1.534 + /* field length */ 1.535 + b = read_byte(dbf); 1.536 + if (b == 0) 1.537 + { xprintf("%s:0x%X: invalid field length\n", dbf->fname, 1.538 + dbf->offset); 1.539 + longjmp(dbf->jump, 0); 1.540 + } 1.541 + if (b > DBF_FDLEN_MAX) 1.542 + { xprintf("%s:0x%X: field too long\n", dbf->fname, 1.543 + dbf->offset); 1.544 + longjmp(dbf->jump, 0); 1.545 + } 1.546 + dbf->len[dbf->nf] = b; 1.547 + recl -= b; 1.548 + /* (ignored) */ 1.549 + for (j = 1; j <= 15; j++) 1.550 + read_byte(dbf); 1.551 + } 1.552 + if (recl != 1) 1.553 + { xprintf("%s:0x%X: invalid file header\n", dbf->fname, 1.554 + dbf->offset); 1.555 + longjmp(dbf->jump, 0); 1.556 + } 1.557 + /* find dummy RECNO field in the table statement */ 1.558 + for (k = mpl_tab_num_flds(dca); k >= 1; k--) 1.559 + if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break; 1.560 + dbf->ref[0] = k; 1.561 + return; 1.562 +} 1.563 + 1.564 +static void parse_third_arg(TABDCA *dca, struct dbf *dbf) 1.565 +{ /* parse xBASE file format (third argument) */ 1.566 + int j, k, temp; 1.567 + const char *arg; 1.568 + dbf->nf = mpl_tab_num_flds(dca); 1.569 + arg = mpl_tab_get_arg(dca, 3), j = 0; 1.570 + for (k = 1; k <= dbf->nf; k++) 1.571 + { /* parse specification of k-th field */ 1.572 + if (arg[j] == '\0') 1.573 + { xprintf("xBASE driver: field %s: specification missing\n", 1.574 + mpl_tab_get_name(dca, k)); 1.575 + longjmp(dbf->jump, 0); 1.576 + } 1.577 + /* parse field type */ 1.578 + if (arg[j] == 'C' || arg[j] == 'N') 1.579 + dbf->type[k] = arg[j], j++; 1.580 + else 1.581 + { xprintf("xBASE driver: field %s: invalid field type\n", 1.582 + mpl_tab_get_name(dca, k)); 1.583 + longjmp(dbf->jump, 0); 1.584 + } 1.585 + /* check for left parenthesis */ 1.586 + if (arg[j] == '(') 1.587 + j++; 1.588 + else 1.589 +err: { xprintf("xBASE driver: field %s: invalid field format\n", 1.590 + mpl_tab_get_name(dca, k)); 1.591 + longjmp(dbf->jump, 0); 1.592 + } 1.593 + /* parse field length */ 1.594 + temp = 0; 1.595 + while (isdigit(arg[j])) 1.596 + { if (temp > DBF_FDLEN_MAX) break; 1.597 + temp = 10 * temp + (arg[j] - '0'), j++; 1.598 + } 1.599 + if (!(1 <= temp && temp <= DBF_FDLEN_MAX)) 1.600 + { xprintf("xBASE driver: field %s: invalid field length\n", 1.601 + mpl_tab_get_name(dca, k)); 1.602 + longjmp(dbf->jump, 0); 1.603 + } 1.604 + dbf->len[k] = temp; 1.605 + /* parse optional field precision */ 1.606 + if (dbf->type[k] == 'N' && arg[j] == ',') 1.607 + { j++; 1.608 + temp = 0; 1.609 + while (isdigit(arg[j])) 1.610 + { if (temp > dbf->len[k]) break; 1.611 + temp = 10 * temp + (arg[j] - '0'), j++; 1.612 + } 1.613 + if (temp > dbf->len[k]) 1.614 + { xprintf("xBASE driver: field %s: invalid field precision" 1.615 + "\n", mpl_tab_get_name(dca, k)); 1.616 + longjmp(dbf->jump, 0); 1.617 + } 1.618 + dbf->prec[k] = temp; 1.619 + } 1.620 + else 1.621 + dbf->prec[k] = 0; 1.622 + /* check for right parenthesis */ 1.623 + if (arg[j] == ')') 1.624 + j++; 1.625 + else 1.626 + goto err; 1.627 + } 1.628 + /* ignore other specifications */ 1.629 + return; 1.630 +} 1.631 + 1.632 +static void write_byte(struct dbf *dbf, int b) 1.633 +{ /* write byte to xBASE data file */ 1.634 + fputc(b, dbf->fp); 1.635 + dbf->offset++; 1.636 + return; 1.637 +} 1.638 + 1.639 +static void write_header(TABDCA *dca, struct dbf *dbf) 1.640 +{ /* write xBASE data file header */ 1.641 + int j, k, temp; 1.642 + const char *name; 1.643 + /* version number */ 1.644 + write_byte(dbf, 0x03 /* file without DBT */); 1.645 + /* date of last update (YYMMDD) */ 1.646 + write_byte(dbf, 70 /* 1970 */); 1.647 + write_byte(dbf, 1 /* January */); 1.648 + write_byte(dbf, 1 /* 1st */); 1.649 + /* number of records (unknown so far) */ 1.650 + for (j = 1; j <= 4; j++) 1.651 + write_byte(dbf, 0xFF); 1.652 + /* length of the header, in bytes */ 1.653 + temp = 32 + dbf->nf * 32 + 1; 1.654 + write_byte(dbf, temp); 1.655 + write_byte(dbf, temp >> 8); 1.656 + /* length of each record, in bytes */ 1.657 + temp = 1; 1.658 + for (k = 1; k <= dbf->nf; k++) 1.659 + temp += dbf->len[k]; 1.660 + write_byte(dbf, temp); 1.661 + write_byte(dbf, temp >> 8); 1.662 + /* (reserved) */ 1.663 + for (j = 1; j <= 20; j++) 1.664 + write_byte(dbf, 0x00); 1.665 + /* field descriptor array */ 1.666 + for (k = 1; k <= dbf->nf; k++) 1.667 + { /* field name (terminated by 0x00) */ 1.668 + name = mpl_tab_get_name(dca, k); 1.669 + for (j = 0; j < 10 && name[j] != '\0'; j++) 1.670 + write_byte(dbf, name[j]); 1.671 + for (j = j; j < 11; j++) 1.672 + write_byte(dbf, 0x00); 1.673 + /* field type */ 1.674 + write_byte(dbf, dbf->type[k]); 1.675 + /* (reserved) */ 1.676 + for (j = 1; j <= 4; j++) 1.677 + write_byte(dbf, 0x00); 1.678 + /* field length */ 1.679 + write_byte(dbf, dbf->len[k]); 1.680 + /* field precision */ 1.681 + write_byte(dbf, dbf->prec[k]); 1.682 + /* (reserved) */ 1.683 + for (j = 1; j <= 14; j++) 1.684 + write_byte(dbf, 0x00); 1.685 + } 1.686 + /* end of header */ 1.687 + write_byte(dbf, 0x0D); 1.688 + return; 1.689 +} 1.690 + 1.691 +static struct dbf *dbf_open_file(TABDCA *dca, int mode) 1.692 +{ /* open xBASE data file */ 1.693 + struct dbf *dbf; 1.694 + /* create control structure */ 1.695 + dbf = xmalloc(sizeof(struct dbf)); 1.696 + dbf->mode = mode; 1.697 + dbf->fname = NULL; 1.698 + dbf->fp = NULL; 1.699 + if (setjmp(dbf->jump)) goto fail; 1.700 + dbf->offset = 0; 1.701 + dbf->count = 0; 1.702 + dbf->nf = 0; 1.703 + /* try to open the xBASE data file */ 1.704 + if (mpl_tab_num_args(dca) < 2) 1.705 + { xprintf("xBASE driver: file name not specified\n"); 1.706 + longjmp(dbf->jump, 0); 1.707 + } 1.708 + dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1); 1.709 + strcpy(dbf->fname, mpl_tab_get_arg(dca, 2)); 1.710 + if (mode == 'R') 1.711 + { /* open the file for reading */ 1.712 + dbf->fp = fopen(dbf->fname, "rb"); 1.713 + if (dbf->fp == NULL) 1.714 + { xprintf("xBASE driver: unable to open %s - %s\n", 1.715 + dbf->fname, strerror(errno)); 1.716 + longjmp(dbf->jump, 0); 1.717 + } 1.718 + read_header(dca, dbf); 1.719 + } 1.720 + else if (mode == 'W') 1.721 + { /* open the file for writing */ 1.722 + if (mpl_tab_num_args(dca) < 3) 1.723 + { xprintf("xBASE driver: file format not specified\n"); 1.724 + longjmp(dbf->jump, 0); 1.725 + } 1.726 + parse_third_arg(dca, dbf); 1.727 + dbf->fp = fopen(dbf->fname, "wb"); 1.728 + if (dbf->fp == NULL) 1.729 + { xprintf("xBASE driver: unable to create %s - %s\n", 1.730 + dbf->fname, strerror(errno)); 1.731 + longjmp(dbf->jump, 0); 1.732 + } 1.733 + write_header(dca, dbf); 1.734 + } 1.735 + else 1.736 + xassert(mode != mode); 1.737 + /* the file has been open */ 1.738 + return dbf; 1.739 +fail: /* the file cannot be open */ 1.740 + if (dbf->fname != NULL) xfree(dbf->fname); 1.741 + if (dbf->fp != NULL) fclose(dbf->fp); 1.742 + xfree(dbf); 1.743 + return NULL; 1.744 +} 1.745 + 1.746 +static int dbf_read_record(TABDCA *dca, struct dbf *dbf) 1.747 +{ /* read next record from xBASE data file */ 1.748 + int b, j, k, ret = 0; 1.749 + char buf[DBF_FDLEN_MAX+1]; 1.750 + xassert(dbf->mode == 'R'); 1.751 + if (setjmp(dbf->jump)) 1.752 + { ret = 1; 1.753 + goto done; 1.754 + } 1.755 + /* check record flag */ 1.756 + b = read_byte(dbf); 1.757 + if (b == 0x1A) 1.758 + { /* end of data */ 1.759 + ret = -1; 1.760 + goto done; 1.761 + } 1.762 + if (b != 0x20) 1.763 + { xprintf("%s:0x%X: invalid record flag\n", dbf->fname, 1.764 + dbf->offset); 1.765 + longjmp(dbf->jump, 0); 1.766 + } 1.767 + /* read dummy RECNO field */ 1.768 + if (dbf->ref[0] > 0) 1.769 + mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1); 1.770 + /* read fields */ 1.771 + for (k = 1; k <= dbf->nf; k++) 1.772 + { /* read k-th field */ 1.773 + for (j = 0; j < dbf->len[k]; j++) 1.774 + buf[j] = (char)read_byte(dbf); 1.775 + buf[dbf->len[k]] = '\0'; 1.776 + /* set field value */ 1.777 + if (dbf->type[k] == 'C') 1.778 + { /* character field */ 1.779 + if (dbf->ref[k] > 0) 1.780 + mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf)); 1.781 + } 1.782 + else if (dbf->type[k] == 'N') 1.783 + { /* numeric field */ 1.784 + if (dbf->ref[k] > 0) 1.785 + { double num; 1.786 + strspx(buf); 1.787 + xassert(str2num(buf, &num) == 0); 1.788 + mpl_tab_set_num(dca, dbf->ref[k], num); 1.789 + } 1.790 + } 1.791 + else 1.792 + xassert(dbf != dbf); 1.793 + } 1.794 + /* increase record count */ 1.795 + dbf->count++; 1.796 +done: return ret; 1.797 +} 1.798 + 1.799 +static int dbf_write_record(TABDCA *dca, struct dbf *dbf) 1.800 +{ /* write next record to xBASE data file */ 1.801 + int j, k, ret = 0; 1.802 + char buf[255+1]; 1.803 + xassert(dbf->mode == 'W'); 1.804 + if (setjmp(dbf->jump)) 1.805 + { ret = 1; 1.806 + goto done; 1.807 + } 1.808 + /* record flag */ 1.809 + write_byte(dbf, 0x20); 1.810 + xassert(dbf->nf == mpl_tab_num_flds(dca)); 1.811 + for (k = 1; k <= dbf->nf; k++) 1.812 + { if (dbf->type[k] == 'C') 1.813 + { /* character field */ 1.814 + const char *str; 1.815 + if (mpl_tab_get_type(dca, k) == 'N') 1.816 + { sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k)); 1.817 + str = buf; 1.818 + } 1.819 + else if (mpl_tab_get_type(dca, k) == 'S') 1.820 + str = mpl_tab_get_str(dca, k); 1.821 + else 1.822 + xassert(dca != dca); 1.823 + if ((int)strlen(str) > dbf->len[k]) 1.824 + { xprintf("xBASE driver: field %s: cannot convert %.15s..." 1.825 + " to field format\n", mpl_tab_get_name(dca, k), str); 1.826 + longjmp(dbf->jump, 0); 1.827 + } 1.828 + for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++) 1.829 + write_byte(dbf, str[j]); 1.830 + for (j = j; j < dbf->len[k]; j++) 1.831 + write_byte(dbf, ' '); 1.832 + } 1.833 + else if (dbf->type[k] == 'N') 1.834 + { /* numeric field */ 1.835 + double num = mpl_tab_get_num(dca, k); 1.836 + if (fabs(num) > 1e20) 1.837 +err: { xprintf("xBASE driver: field %s: cannot convert %g to fi" 1.838 + "eld format\n", mpl_tab_get_name(dca, k), num); 1.839 + longjmp(dbf->jump, 0); 1.840 + } 1.841 + sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num); 1.842 + xassert(strlen(buf) < sizeof(buf)); 1.843 + if ((int)strlen(buf) != dbf->len[k]) goto err; 1.844 + for (j = 0; j < dbf->len[k]; j++) 1.845 + write_byte(dbf, buf[j]); 1.846 + } 1.847 + else 1.848 + xassert(dbf != dbf); 1.849 + } 1.850 + /* increase record count */ 1.851 + dbf->count++; 1.852 +done: return ret; 1.853 +} 1.854 + 1.855 +static int dbf_close_file(TABDCA *dca, struct dbf *dbf) 1.856 +{ /* close xBASE data file */ 1.857 + int ret = 0; 1.858 + xassert(dca == dca); 1.859 + if (dbf->mode == 'W') 1.860 + { if (setjmp(dbf->jump)) 1.861 + { ret = 1; 1.862 + goto skip; 1.863 + } 1.864 + /* end-of-file flag */ 1.865 + write_byte(dbf, 0x1A); 1.866 + /* number of records */ 1.867 + dbf->offset = 4; 1.868 + if (fseek(dbf->fp, dbf->offset, SEEK_SET)) 1.869 + { xprintf("%s:0x%X: seek error - %s\n", dbf->fname, 1.870 + dbf->offset, strerror(errno)); 1.871 + longjmp(dbf->jump, 0); 1.872 + } 1.873 + write_byte(dbf, dbf->count); 1.874 + write_byte(dbf, dbf->count >> 8); 1.875 + write_byte(dbf, dbf->count >> 16); 1.876 + write_byte(dbf, dbf->count >> 24); 1.877 + fflush(dbf->fp); 1.878 + if (ferror(dbf->fp)) 1.879 + { xprintf("%s:0x%X: write error - %s\n", dbf->fname, 1.880 + dbf->offset, strerror(errno)); 1.881 + longjmp(dbf->jump, 0); 1.882 + } 1.883 +skip: ; 1.884 + } 1.885 + xfree(dbf->fname); 1.886 + fclose(dbf->fp); 1.887 + xfree(dbf); 1.888 + return ret; 1.889 +} 1.890 + 1.891 +/**********************************************************************/ 1.892 + 1.893 +#define TAB_CSV 1 1.894 +#define TAB_XBASE 2 1.895 +#define TAB_ODBC 3 1.896 +#define TAB_MYSQL 4 1.897 + 1.898 +void mpl_tab_drv_open(MPL *mpl, int mode) 1.899 +{ TABDCA *dca = mpl->dca; 1.900 + xassert(dca->id == 0); 1.901 + xassert(dca->link == NULL); 1.902 + xassert(dca->na >= 1); 1.903 + if (strcmp(dca->arg[1], "CSV") == 0) 1.904 + { dca->id = TAB_CSV; 1.905 + dca->link = csv_open_file(dca, mode); 1.906 + } 1.907 + else if (strcmp(dca->arg[1], "xBASE") == 0) 1.908 + { dca->id = TAB_XBASE; 1.909 + dca->link = dbf_open_file(dca, mode); 1.910 + } 1.911 + else if (strcmp(dca->arg[1], "ODBC") == 0 || 1.912 + strcmp(dca->arg[1], "iODBC") == 0) 1.913 + { dca->id = TAB_ODBC; 1.914 + dca->link = db_iodbc_open(dca, mode); 1.915 + } 1.916 + else if (strcmp(dca->arg[1], "MySQL") == 0) 1.917 + { dca->id = TAB_MYSQL; 1.918 + dca->link = db_mysql_open(dca, mode); 1.919 + } 1.920 + else 1.921 + xprintf("Invalid table driver `%s'\n", dca->arg[1]); 1.922 + if (dca->link == NULL) 1.923 + error(mpl, "error on opening table %s", 1.924 + mpl->stmt->u.tab->name); 1.925 + return; 1.926 +} 1.927 + 1.928 +int mpl_tab_drv_read(MPL *mpl) 1.929 +{ TABDCA *dca = mpl->dca; 1.930 + int ret; 1.931 + switch (dca->id) 1.932 + { case TAB_CSV: 1.933 + ret = csv_read_record(dca, dca->link); 1.934 + break; 1.935 + case TAB_XBASE: 1.936 + ret = dbf_read_record(dca, dca->link); 1.937 + break; 1.938 + case TAB_ODBC: 1.939 + ret = db_iodbc_read(dca, dca->link); 1.940 + break; 1.941 + case TAB_MYSQL: 1.942 + ret = db_mysql_read(dca, dca->link); 1.943 + break; 1.944 + default: 1.945 + xassert(dca != dca); 1.946 + } 1.947 + if (ret > 0) 1.948 + error(mpl, "error on reading data from table %s", 1.949 + mpl->stmt->u.tab->name); 1.950 + return ret; 1.951 +} 1.952 + 1.953 +void mpl_tab_drv_write(MPL *mpl) 1.954 +{ TABDCA *dca = mpl->dca; 1.955 + int ret; 1.956 + switch (dca->id) 1.957 + { case TAB_CSV: 1.958 + ret = csv_write_record(dca, dca->link); 1.959 + break; 1.960 + case TAB_XBASE: 1.961 + ret = dbf_write_record(dca, dca->link); 1.962 + break; 1.963 + case TAB_ODBC: 1.964 + ret = db_iodbc_write(dca, dca->link); 1.965 + break; 1.966 + case TAB_MYSQL: 1.967 + ret = db_mysql_write(dca, dca->link); 1.968 + break; 1.969 + default: 1.970 + xassert(dca != dca); 1.971 + } 1.972 + if (ret) 1.973 + error(mpl, "error on writing data to table %s", 1.974 + mpl->stmt->u.tab->name); 1.975 + return; 1.976 +} 1.977 + 1.978 +void mpl_tab_drv_close(MPL *mpl) 1.979 +{ TABDCA *dca = mpl->dca; 1.980 + int ret; 1.981 + switch (dca->id) 1.982 + { case TAB_CSV: 1.983 + ret = csv_close_file(dca, dca->link); 1.984 + break; 1.985 + case TAB_XBASE: 1.986 + ret = dbf_close_file(dca, dca->link); 1.987 + break; 1.988 + case TAB_ODBC: 1.989 + ret = db_iodbc_close(dca, dca->link); 1.990 + break; 1.991 + case TAB_MYSQL: 1.992 + ret = db_mysql_close(dca, dca->link); 1.993 + break; 1.994 + default: 1.995 + xassert(dca != dca); 1.996 + } 1.997 + dca->id = 0; 1.998 + dca->link = NULL; 1.999 + if (ret) 1.1000 + error(mpl, "error on closing table %s", 1.1001 + mpl->stmt->u.tab->name); 1.1002 + return; 1.1003 +} 1.1004 + 1.1005 +/* eof */