/farmR/src/glplib08.c

https://code.google.com/p/javawfm/ · C · 593 lines · 353 code · 53 blank · 187 comment · 75 complexity · e5b317e07a43e99218fe8b33ccbf0d95 MD5 · raw file

  1. /* glplib08.c (stream input/output) */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Copyright (C) 2000,01,02,03,04,05,06,07,08,2009 Andrew Makhorin,
  6. * Department for Applied Informatics, Moscow Aviation Institute,
  7. * Moscow, Russia. All rights reserved. E-mail: <mao@mai2.rcnet.ru>.
  8. *
  9. * GLPK is free software: you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  17. * License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  21. ***********************************************************************/
  22. #define _GLPSTD_ERRNO
  23. #define _GLPSTD_STDIO
  24. #include "glplib.h"
  25. /***********************************************************************
  26. * NAME
  27. *
  28. * xfopen - open a stream
  29. *
  30. * SYNOPSIS
  31. *
  32. * #include "glplib.h"
  33. * XFILE *xfopen(const char *fname, const char *mode);
  34. *
  35. * DESCRIPTION
  36. *
  37. * The routine xfopen opens the file whose name is a string pointed to
  38. * by fname and associates a stream with it.
  39. *
  40. * The parameter mode points to a string, which indicates the open mode
  41. * and should be one of the following:
  42. *
  43. * "r" open text file for reading;
  44. * "w" truncate to zero length or create text file for writing;
  45. * "rb" open binary file for reading;
  46. * "wb" truncate to zero length or create binary file for writing.
  47. *
  48. * RETURNS
  49. *
  50. * The routine xfopen returns a pointer to the object controlling the
  51. * stream. If the open operation fails, xfopen returns NULL. */
  52. static void *c_fopen(const char *fname, const char *mode);
  53. static void *z_fopen(const char *fname, const char *mode);
  54. static int is_gz_file(const char *fname)
  55. { char *ext = strrchr(fname, '.');
  56. return ext != NULL && strcmp(ext, ".gz") == 0;
  57. }
  58. XFILE *xfopen(const char *fname, const char *mode)
  59. { LIBENV *env = lib_link_env();
  60. XFILE *fp;
  61. int type;
  62. void *fh;
  63. if (!is_gz_file(fname))
  64. { type = FH_FILE;
  65. fh = c_fopen(fname, mode);
  66. }
  67. else
  68. { type = FH_ZLIB;
  69. fh = z_fopen(fname, mode);
  70. }
  71. if (fh == NULL)
  72. { fp = NULL;
  73. goto done;
  74. }
  75. fp = xmalloc(sizeof(XFILE));
  76. fp->type = type;
  77. fp->fh = fh;
  78. fp->prev = NULL;
  79. fp->next = env->file_ptr;
  80. if (fp->next != NULL) fp->next->prev = fp;
  81. env->file_ptr = fp;
  82. done: return fp;
  83. }
  84. /***********************************************************************
  85. * NAME
  86. *
  87. * xfgetc - read character from the stream
  88. *
  89. * SYNOPSIS
  90. *
  91. * #include "glplib.h"
  92. * int xfgetc(XFILE *fp);
  93. *
  94. * DESCRIPTION
  95. *
  96. * If the end-of-file indicator for the input stream pointed to by fp
  97. * is not set and a next character is present, the routine xfgetc
  98. * obtains that character as an unsigned char converted to an int and
  99. * advances the associated file position indicator for the stream (if
  100. * defined).
  101. *
  102. * RETURNS
  103. *
  104. * If the end-of-file indicator for the stream is set, or if the
  105. * stream is at end-of-file, the end-of-file indicator for the stream
  106. * is set and the routine xfgetc returns XEOF. Otherwise, the routine
  107. * xfgetc returns the next character from the input stream pointed to
  108. * by fp. If a read error occurs, the error indicator for the stream is
  109. * set and the xfgetc routine returns XEOF.
  110. *
  111. * Note: An end-of-file and a read error can be distinguished by use of
  112. * the routines xfeof and xferror. */
  113. static int c_fgetc(void *fh);
  114. static int z_fgetc(void *fh);
  115. int xfgetc(XFILE *fp)
  116. { int c;
  117. switch (fp->type)
  118. { case FH_FILE:
  119. c = c_fgetc(fp->fh);
  120. break;
  121. case FH_ZLIB:
  122. c = z_fgetc(fp->fh);
  123. break;
  124. default:
  125. xassert(fp != fp);
  126. }
  127. return c;
  128. }
  129. /***********************************************************************
  130. * NAME
  131. *
  132. * xfputc - write character to the stream
  133. *
  134. * SYNOPSIS
  135. *
  136. * #include "glplib.h"
  137. * int xfputc(int c, XFILE *fp);
  138. *
  139. * DESCRIPTION
  140. *
  141. * The routine xfputc writes the character specified by c (converted
  142. * to an unsigned char) to the output stream pointed to by fp, at the
  143. * position indicated by the associated file position indicator (if
  144. * defined), and advances the indicator appropriately.
  145. *
  146. * RETURNS
  147. *
  148. * The routine xfputc returns the character written. If a write error
  149. * occurs, the error indicator for the stream is set and xfputc returns
  150. * XEOF. */
  151. static int c_fputc(int c, void *fh);
  152. static int z_fputc(int c, void *fh);
  153. int xfputc(int c, XFILE *fp)
  154. { switch (fp->type)
  155. { case FH_FILE:
  156. c = c_fputc(c, fp->fh);
  157. break;
  158. case FH_ZLIB:
  159. c = z_fputc(c, fp->fh);
  160. break;
  161. default:
  162. xassert(fp != fp);
  163. }
  164. return c;
  165. }
  166. /***********************************************************************
  167. * NAME
  168. *
  169. * xferror - test error indicator for the stream
  170. *
  171. * SYNOPSIS
  172. *
  173. * #include "glplib.h"
  174. * int xferror(XFILE *fp);
  175. *
  176. * DESCRIPTION
  177. *
  178. * The routine xferror tests the error indicator for the stream
  179. * pointed to by fp.
  180. *
  181. * RETURNS
  182. *
  183. * The routine xferror returns non-zero if and only if the error
  184. * indicator is set for the stream. */
  185. static int c_ferror(void *fh);
  186. static int z_ferror(void *fh);
  187. int xferror(XFILE *fp)
  188. { int ret;
  189. switch (fp->type)
  190. { case FH_FILE:
  191. ret = c_ferror(fp->fh);
  192. break;
  193. case FH_ZLIB:
  194. ret = z_ferror(fp->fh);
  195. break;
  196. default:
  197. xassert(fp != fp);
  198. }
  199. return ret;
  200. }
  201. /***********************************************************************
  202. * NAME
  203. *
  204. * xfeof - test end-of-file indicator for the stream
  205. *
  206. * SYNOPSIS
  207. *
  208. * #include "glplib.h"
  209. * int xfeof(XFILE *fp);
  210. *
  211. * DESCRIPTION
  212. *
  213. * The routine xfeof tests the end-of-file indicator for the stream
  214. * pointed to by fp.
  215. *
  216. * RETURNS
  217. *
  218. * The routine xfeof returns non-zero if and only if the end-of-file
  219. * indicator is set for the stream. */
  220. static int c_feof(void *fh);
  221. static int z_feof(void *fh);
  222. int xfeof(XFILE *fp)
  223. { int ret;
  224. switch (fp->type)
  225. { case FH_FILE:
  226. ret = c_feof(fp->fh);
  227. break;
  228. case FH_ZLIB:
  229. ret = z_feof(fp->fh);
  230. break;
  231. default:
  232. xassert(fp != fp);
  233. }
  234. return ret;
  235. }
  236. /***********************************************************************
  237. * NAME
  238. *
  239. * xfflush - flush the stream
  240. *
  241. * SYNOPSIS
  242. *
  243. * #include "glplib.h"
  244. * int xfflush(XFILE *fp);
  245. *
  246. * DESCRIPTION
  247. *
  248. * The routine xfflush causes any unwritten data for the output stream
  249. * pointed to by fp to be written to the associated file.
  250. *
  251. * RETURNS
  252. *
  253. * The routine xfflush returns zero if the stream was successfully
  254. * flushed. Otherwise, xfflush sets the error indicator for the stream
  255. * and returns XEOF. */
  256. static int c_fflush(void *fh);
  257. static int z_fflush(void *fh);
  258. int xfflush(XFILE *fp)
  259. { int ret;
  260. switch (fp->type)
  261. { case FH_FILE:
  262. ret = c_fflush(fp->fh);
  263. break;
  264. case FH_ZLIB:
  265. ret = z_fflush(fp->fh);
  266. break;
  267. default:
  268. xassert(fp != fp);
  269. }
  270. return ret;
  271. }
  272. /***********************************************************************
  273. * NAME
  274. *
  275. * xfclose - close the stream
  276. *
  277. * SYNOPSIS
  278. *
  279. * #include "glplib.h"
  280. * int xfclose(XFILE *fp);
  281. *
  282. * DESCRIPTION
  283. *
  284. * A successful call to the routine xfclose causes the stream pointed
  285. * to by fp to be flushed and the associated file to be closed. Whether
  286. * or not the call succeeds, the stream is disassociated from the file.
  287. *
  288. * RETURNS
  289. *
  290. * The routine xfclose returns zero if the stream was successfully
  291. * closed, or XEOF if any errors were detected. */
  292. static int c_fclose(void *fh);
  293. static int z_fclose(void *fh);
  294. int xfclose(XFILE *fp)
  295. { LIBENV *env = lib_link_env();
  296. int ret;
  297. switch (fp->type)
  298. { case FH_FILE:
  299. ret = c_fclose(fp->fh);
  300. break;
  301. case FH_ZLIB:
  302. ret = z_fclose(fp->fh);
  303. break;
  304. default:
  305. xassert(fp != fp);
  306. }
  307. fp->type = 0xF00BAD;
  308. if (fp->prev == NULL)
  309. env->file_ptr = fp->next;
  310. else
  311. fp->prev->next = fp->next;
  312. if (fp->next == NULL)
  313. ;
  314. else
  315. fp->next->prev = fp->prev;
  316. xfree(fp);
  317. return ret;
  318. }
  319. /***********************************************************************
  320. * The following routines implement stream input/output based on the
  321. * standard C streams. */
  322. static void *c_fopen(const char *fname, const char *mode)
  323. { FILE *fh;
  324. fh = fopen(fname, mode);
  325. if (fh == NULL)
  326. lib_err_msg(strerror(errno));
  327. return fh;
  328. }
  329. static int c_fgetc(void *_fh)
  330. { FILE *fh = _fh;
  331. int c;
  332. if (ferror(fh) || feof(fh))
  333. { c = XEOF;
  334. goto done;
  335. }
  336. c = fgetc(fh);
  337. if (ferror(fh))
  338. { lib_err_msg(strerror(errno));
  339. c = XEOF;
  340. }
  341. else if (feof(fh))
  342. c = XEOF;
  343. else
  344. xassert(0x00 <= c && c <= 0xFF);
  345. done: return c;
  346. }
  347. static int c_fputc(int c, void *_fh)
  348. { FILE *fh = _fh;
  349. if (ferror(fh))
  350. { c = XEOF;
  351. goto done;
  352. }
  353. c = (unsigned char)c;
  354. fputc(c, fh);
  355. if (ferror(fh))
  356. { lib_err_msg(strerror(errno));
  357. c = XEOF;
  358. }
  359. done: return c;
  360. }
  361. static int c_ferror(void *_fh)
  362. { FILE *fh = _fh;
  363. return ferror(fh);
  364. }
  365. static int c_feof(void *_fh)
  366. { FILE *fh = _fh;
  367. return feof(fh);
  368. }
  369. static int c_fflush(void *_fh)
  370. { FILE *fh = _fh;
  371. int ret;
  372. ret = fflush(fh);
  373. if (ret != 0)
  374. { lib_err_msg(strerror(errno));
  375. ret = XEOF;
  376. }
  377. return ret;
  378. }
  379. static int c_fclose(void *_fh)
  380. { FILE *fh = _fh;
  381. int ret;
  382. ret = fclose(fh);
  383. if (ret != 0)
  384. { lib_err_msg(strerror(errno));
  385. ret = XEOF;
  386. }
  387. return ret;
  388. }
  389. /***********************************************************************
  390. * The following routines implement stream input/output based on the
  391. * zlib library, which provides processing .gz files "on the fly". */
  392. #ifndef HAVE_ZLIB
  393. static void *z_fopen(const char *fname, const char *mode)
  394. { xassert(fname == fname);
  395. xassert(mode == mode);
  396. lib_err_msg("Compressed files not supported");
  397. return NULL;
  398. }
  399. static int z_fgetc(void *fh)
  400. { xassert(fh != fh);
  401. return 0;
  402. }
  403. static int z_fputc(int c, void *fh)
  404. { xassert(c != c);
  405. xassert(fh != fh);
  406. return 0;
  407. }
  408. static int z_ferror(void *fh)
  409. { xassert(fh != fh);
  410. return 0;
  411. }
  412. static int z_feof(void *fh)
  413. { xassert(fh != fh);
  414. return 0;
  415. }
  416. static int z_fflush(void *fh)
  417. { xassert(fh != fh);
  418. return 0;
  419. }
  420. static int z_fclose(void *fh)
  421. { xassert(fh != fh);
  422. return 0;
  423. }
  424. #else
  425. #include <zlib.h>
  426. struct z_file
  427. { /* .gz file handle */
  428. gzFile file;
  429. /* pointer to .gz stream */
  430. int err;
  431. /* i/o error indicator */
  432. int eof;
  433. /* end-of-file indicator */
  434. };
  435. static void *z_fopen(const char *fname, const char *mode)
  436. { struct z_file *fh;
  437. gzFile file;
  438. if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
  439. mode = "rb";
  440. else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
  441. mode = "wb";
  442. else
  443. { lib_err_msg("Invalid open mode");
  444. fh = NULL;
  445. goto done;
  446. }
  447. file = gzopen(fname, mode);
  448. if (file == NULL)
  449. { lib_err_msg(strerror(errno));
  450. fh = NULL;
  451. goto done;
  452. }
  453. fh = xmalloc(sizeof(struct z_file));
  454. fh->file = file;
  455. fh->err = fh->eof = 0;
  456. done: return fh;
  457. }
  458. static int z_fgetc(void *_fh)
  459. { struct z_file *fh = _fh;
  460. int c;
  461. if (fh->err || fh->eof)
  462. { c = XEOF;
  463. goto done;
  464. }
  465. c = gzgetc(fh->file);
  466. if (c < 0)
  467. { int errnum;
  468. const char *msg;
  469. msg = gzerror(fh->file, &errnum);
  470. if (errnum == Z_STREAM_END)
  471. fh->eof = 1;
  472. else if (errnum == Z_ERRNO)
  473. { fh->err = 1;
  474. lib_err_msg(strerror(errno));
  475. }
  476. else
  477. { fh->err = 1;
  478. lib_err_msg(msg);
  479. }
  480. c = XEOF;
  481. }
  482. else
  483. xassert(0x00 <= c && c <= 0xFF);
  484. done: return c;
  485. }
  486. static int z_fputc(int c, void *_fh)
  487. { struct z_file *fh = _fh;
  488. if (fh->err)
  489. { c = XEOF;
  490. goto done;
  491. }
  492. c = (unsigned char)c;
  493. if (gzputc(fh->file, c) < 0)
  494. { int errnum;
  495. const char *msg;
  496. fh->err = 1;
  497. msg = gzerror(fh->file, &errnum);
  498. if (errnum == Z_ERRNO)
  499. lib_err_msg(strerror(errno));
  500. else
  501. lib_err_msg(msg);
  502. c = XEOF;
  503. }
  504. done: return c;
  505. }
  506. static int z_ferror(void *_fh)
  507. { struct z_file *fh = _fh;
  508. return fh->err;
  509. }
  510. static int z_feof(void *_fh)
  511. { struct z_file *fh = _fh;
  512. return fh->eof;
  513. }
  514. static int z_fflush(void *_fh)
  515. { struct z_file *fh = _fh;
  516. int ret;
  517. ret = gzflush(fh->file, Z_FINISH);
  518. if (ret == Z_OK)
  519. ret = 0;
  520. else
  521. { int errnum;
  522. const char *msg;
  523. fh->err = 1;
  524. msg = gzerror(fh->file, &errnum);
  525. if (errnum == Z_ERRNO)
  526. lib_err_msg(strerror(errno));
  527. else
  528. lib_err_msg(msg);
  529. ret = XEOF;
  530. }
  531. return ret;
  532. }
  533. static int z_fclose(void *_fh)
  534. { struct z_file *fh = _fh;
  535. gzclose(fh->file);
  536. xfree(fh);
  537. return 0;
  538. }
  539. #endif
  540. /* eof */