glpmpl06.c 31 KB

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