1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/glpenv07.c Mon Dec 06 13:09:21 2010 +0100
1.3 @@ -0,0 +1,671 @@
1.4 +/* glpenv07.c (stream input/output) */
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 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 +#ifdef HAVE_CONFIG_H
1.29 +#include <config.h>
1.30 +#endif
1.31 +
1.32 +#include "glpenv.h"
1.33 +
1.34 +/***********************************************************************
1.35 +* NAME
1.36 +*
1.37 +* lib_err_msg - save error message string
1.38 +*
1.39 +* SYNOPSIS
1.40 +*
1.41 +* #include "glpenv.h"
1.42 +* void lib_err_msg(const char *msg);
1.43 +*
1.44 +* DESCRIPTION
1.45 +*
1.46 +* The routine lib_err_msg saves an error message string specified by
1.47 +* the parameter msg. The message is obtained by some library routines
1.48 +* with a call to strerror(errno). */
1.49 +
1.50 +void lib_err_msg(const char *msg)
1.51 +{ ENV *env = get_env_ptr();
1.52 + int len = strlen(msg);
1.53 + if (len >= IOERR_MSG_SIZE)
1.54 + len = IOERR_MSG_SIZE - 1;
1.55 + memcpy(env->ioerr_msg, msg, len);
1.56 + if (len > 0 && env->ioerr_msg[len-1] == '\n') len--;
1.57 + env->ioerr_msg[len] = '\0';
1.58 + return;
1.59 +}
1.60 +
1.61 +/***********************************************************************
1.62 +* NAME
1.63 +*
1.64 +* xerrmsg - retrieve error message string
1.65 +*
1.66 +* SYNOPSIS
1.67 +*
1.68 +* #include "glpenv.h"
1.69 +* const char *xerrmsg(void);
1.70 +*
1.71 +* RETURNS
1.72 +*
1.73 +* The routine xerrmsg returns a pointer to an error message string
1.74 +* previously set by some library routine to indicate an error. */
1.75 +
1.76 +const char *xerrmsg(void)
1.77 +{ ENV *env = get_env_ptr();
1.78 + return env->ioerr_msg;
1.79 +}
1.80 +
1.81 +/***********************************************************************
1.82 +* NAME
1.83 +*
1.84 +* xfopen - open a stream
1.85 +*
1.86 +* SYNOPSIS
1.87 +*
1.88 +* #include "glpenv.h"
1.89 +* XFILE *xfopen(const char *fname, const char *mode);
1.90 +*
1.91 +* DESCRIPTION
1.92 +*
1.93 +* The routine xfopen opens the file whose name is a string pointed to
1.94 +* by fname and associates a stream with it.
1.95 +*
1.96 +* The parameter mode points to a string, which indicates the open mode
1.97 +* and should be one of the following:
1.98 +*
1.99 +* "r" open text file for reading;
1.100 +* "w" truncate to zero length or create text file for writing;
1.101 +* "rb" open binary file for reading;
1.102 +* "wb" truncate to zero length or create binary file for writing.
1.103 +*
1.104 +* RETURNS
1.105 +*
1.106 +* The routine xfopen returns a pointer to the object controlling the
1.107 +* stream. If the open operation fails, xfopen returns NULL. */
1.108 +
1.109 +static void *c_fopen(const char *fname, const char *mode);
1.110 +static void *z_fopen(const char *fname, const char *mode);
1.111 +
1.112 +static int is_gz_file(const char *fname)
1.113 +{ char *ext = strrchr(fname, '.');
1.114 + return ext != NULL && strcmp(ext, ".gz") == 0;
1.115 +}
1.116 +
1.117 +XFILE *xfopen(const char *fname, const char *mode)
1.118 +{ ENV *env = get_env_ptr();
1.119 + XFILE *fp;
1.120 + int type;
1.121 + void *fh;
1.122 + if (!is_gz_file(fname))
1.123 + { type = FH_FILE;
1.124 + fh = c_fopen(fname, mode);
1.125 + }
1.126 + else
1.127 + { type = FH_ZLIB;
1.128 + fh = z_fopen(fname, mode);
1.129 + }
1.130 + if (fh == NULL)
1.131 + { fp = NULL;
1.132 + goto done;
1.133 + }
1.134 + fp = xmalloc(sizeof(XFILE));
1.135 + fp->type = type;
1.136 + fp->fh = fh;
1.137 + fp->prev = NULL;
1.138 + fp->next = env->file_ptr;
1.139 + if (fp->next != NULL) fp->next->prev = fp;
1.140 + env->file_ptr = fp;
1.141 +done: return fp;
1.142 +}
1.143 +
1.144 +/***********************************************************************
1.145 +* NAME
1.146 +*
1.147 +* xfgetc - read character from the stream
1.148 +*
1.149 +* SYNOPSIS
1.150 +*
1.151 +* #include "glpenv.h"
1.152 +* int xfgetc(XFILE *fp);
1.153 +*
1.154 +* DESCRIPTION
1.155 +*
1.156 +* If the end-of-file indicator for the input stream pointed to by fp
1.157 +* is not set and a next character is present, the routine xfgetc
1.158 +* obtains that character as an unsigned char converted to an int and
1.159 +* advances the associated file position indicator for the stream (if
1.160 +* defined).
1.161 +*
1.162 +* RETURNS
1.163 +*
1.164 +* If the end-of-file indicator for the stream is set, or if the
1.165 +* stream is at end-of-file, the end-of-file indicator for the stream
1.166 +* is set and the routine xfgetc returns XEOF. Otherwise, the routine
1.167 +* xfgetc returns the next character from the input stream pointed to
1.168 +* by fp. If a read error occurs, the error indicator for the stream is
1.169 +* set and the xfgetc routine returns XEOF.
1.170 +*
1.171 +* Note: An end-of-file and a read error can be distinguished by use of
1.172 +* the routines xfeof and xferror. */
1.173 +
1.174 +static int c_fgetc(void *fh);
1.175 +static int z_fgetc(void *fh);
1.176 +
1.177 +int xfgetc(XFILE *fp)
1.178 +{ int c;
1.179 + switch (fp->type)
1.180 + { case FH_FILE:
1.181 + c = c_fgetc(fp->fh);
1.182 + break;
1.183 + case FH_ZLIB:
1.184 + c = z_fgetc(fp->fh);
1.185 + break;
1.186 + default:
1.187 + xassert(fp != fp);
1.188 + }
1.189 + return c;
1.190 +}
1.191 +
1.192 +/***********************************************************************
1.193 +* NAME
1.194 +*
1.195 +* xfputc - write character to the stream
1.196 +*
1.197 +* SYNOPSIS
1.198 +*
1.199 +* #include "glpenv.h"
1.200 +* int xfputc(int c, XFILE *fp);
1.201 +*
1.202 +* DESCRIPTION
1.203 +*
1.204 +* The routine xfputc writes the character specified by c (converted
1.205 +* to an unsigned char) to the output stream pointed to by fp, at the
1.206 +* position indicated by the associated file position indicator (if
1.207 +* defined), and advances the indicator appropriately.
1.208 +*
1.209 +* RETURNS
1.210 +*
1.211 +* The routine xfputc returns the character written. If a write error
1.212 +* occurs, the error indicator for the stream is set and xfputc returns
1.213 +* XEOF. */
1.214 +
1.215 +static int c_fputc(int c, void *fh);
1.216 +static int z_fputc(int c, void *fh);
1.217 +
1.218 +int xfputc(int c, XFILE *fp)
1.219 +{ switch (fp->type)
1.220 + { case FH_FILE:
1.221 + c = c_fputc(c, fp->fh);
1.222 + break;
1.223 + case FH_ZLIB:
1.224 + c = z_fputc(c, fp->fh);
1.225 + break;
1.226 + default:
1.227 + xassert(fp != fp);
1.228 + }
1.229 + return c;
1.230 +}
1.231 +
1.232 +/***********************************************************************
1.233 +* NAME
1.234 +*
1.235 +* xferror - test error indicator for the stream
1.236 +*
1.237 +* SYNOPSIS
1.238 +*
1.239 +* #include "glpenv.h"
1.240 +* int xferror(XFILE *fp);
1.241 +*
1.242 +* DESCRIPTION
1.243 +*
1.244 +* The routine xferror tests the error indicator for the stream
1.245 +* pointed to by fp.
1.246 +*
1.247 +* RETURNS
1.248 +*
1.249 +* The routine xferror returns non-zero if and only if the error
1.250 +* indicator is set for the stream. */
1.251 +
1.252 +static int c_ferror(void *fh);
1.253 +static int z_ferror(void *fh);
1.254 +
1.255 +int xferror(XFILE *fp)
1.256 +{ int ret;
1.257 + switch (fp->type)
1.258 + { case FH_FILE:
1.259 + ret = c_ferror(fp->fh);
1.260 + break;
1.261 + case FH_ZLIB:
1.262 + ret = z_ferror(fp->fh);
1.263 + break;
1.264 + default:
1.265 + xassert(fp != fp);
1.266 + }
1.267 + return ret;
1.268 +}
1.269 +
1.270 +/***********************************************************************
1.271 +* NAME
1.272 +*
1.273 +* xfeof - test end-of-file indicator for the stream
1.274 +*
1.275 +* SYNOPSIS
1.276 +*
1.277 +* #include "glpenv.h"
1.278 +* int xfeof(XFILE *fp);
1.279 +*
1.280 +* DESCRIPTION
1.281 +*
1.282 +* The routine xfeof tests the end-of-file indicator for the stream
1.283 +* pointed to by fp.
1.284 +*
1.285 +* RETURNS
1.286 +*
1.287 +* The routine xfeof returns non-zero if and only if the end-of-file
1.288 +* indicator is set for the stream. */
1.289 +
1.290 +static int c_feof(void *fh);
1.291 +static int z_feof(void *fh);
1.292 +
1.293 +int xfeof(XFILE *fp)
1.294 +{ int ret;
1.295 + switch (fp->type)
1.296 + { case FH_FILE:
1.297 + ret = c_feof(fp->fh);
1.298 + break;
1.299 + case FH_ZLIB:
1.300 + ret = z_feof(fp->fh);
1.301 + break;
1.302 + default:
1.303 + xassert(fp != fp);
1.304 + }
1.305 + return ret;
1.306 +}
1.307 +
1.308 +int xfprintf(XFILE *file, const char *fmt, ...)
1.309 +{ ENV *env = get_env_ptr();
1.310 + int cnt, j;
1.311 + va_list arg;
1.312 + va_start(arg, fmt);
1.313 + cnt = vsprintf(env->term_buf, fmt, arg);
1.314 + va_end(arg);
1.315 + for (j = 0; j < cnt; j++)
1.316 + { if (xfputc(env->term_buf[j], file) < 0)
1.317 + { cnt = -1;
1.318 + break;
1.319 + }
1.320 + }
1.321 + return cnt;
1.322 +}
1.323 +
1.324 +/***********************************************************************
1.325 +* NAME
1.326 +*
1.327 +* xfflush - flush the stream
1.328 +*
1.329 +* SYNOPSIS
1.330 +*
1.331 +* #include "glpenv.h"
1.332 +* int xfflush(XFILE *fp);
1.333 +*
1.334 +* DESCRIPTION
1.335 +*
1.336 +* The routine xfflush causes any unwritten data for the output stream
1.337 +* pointed to by fp to be written to the associated file.
1.338 +*
1.339 +* RETURNS
1.340 +*
1.341 +* The routine xfflush returns zero if the stream was successfully
1.342 +* flushed. Otherwise, xfflush sets the error indicator for the stream
1.343 +* and returns XEOF. */
1.344 +
1.345 +static int c_fflush(void *fh);
1.346 +static int z_fflush(void *fh);
1.347 +
1.348 +int xfflush(XFILE *fp)
1.349 +{ int ret;
1.350 + switch (fp->type)
1.351 + { case FH_FILE:
1.352 + ret = c_fflush(fp->fh);
1.353 + break;
1.354 + case FH_ZLIB:
1.355 + ret = z_fflush(fp->fh);
1.356 + break;
1.357 + default:
1.358 + xassert(fp != fp);
1.359 + }
1.360 + return ret;
1.361 +}
1.362 +
1.363 +/***********************************************************************
1.364 +* NAME
1.365 +*
1.366 +* xfclose - close the stream
1.367 +*
1.368 +* SYNOPSIS
1.369 +*
1.370 +* #include "glpenv.h"
1.371 +* int xfclose(XFILE *fp);
1.372 +*
1.373 +* DESCRIPTION
1.374 +*
1.375 +* A successful call to the routine xfclose causes the stream pointed
1.376 +* to by fp to be flushed and the associated file to be closed. Whether
1.377 +* or not the call succeeds, the stream is disassociated from the file.
1.378 +*
1.379 +* RETURNS
1.380 +*
1.381 +* The routine xfclose returns zero if the stream was successfully
1.382 +* closed, or XEOF if any errors were detected. */
1.383 +
1.384 +static int c_fclose(void *fh);
1.385 +static int z_fclose(void *fh);
1.386 +
1.387 +int xfclose(XFILE *fp)
1.388 +{ ENV *env = get_env_ptr();
1.389 + int ret;
1.390 + switch (fp->type)
1.391 + { case FH_FILE:
1.392 + ret = c_fclose(fp->fh);
1.393 + break;
1.394 + case FH_ZLIB:
1.395 + ret = z_fclose(fp->fh);
1.396 + break;
1.397 + default:
1.398 + xassert(fp != fp);
1.399 + }
1.400 + fp->type = 0xF00BAD;
1.401 + if (fp->prev == NULL)
1.402 + env->file_ptr = fp->next;
1.403 + else
1.404 + fp->prev->next = fp->next;
1.405 + if (fp->next == NULL)
1.406 + ;
1.407 + else
1.408 + fp->next->prev = fp->prev;
1.409 + xfree(fp);
1.410 + return ret;
1.411 +}
1.412 +
1.413 +/***********************************************************************
1.414 +* The following routines implement stream input/output based on the
1.415 +* standard C streams. */
1.416 +
1.417 +static void *c_fopen(const char *fname, const char *mode)
1.418 +{ FILE *fh;
1.419 + if (strcmp(fname, "/dev/stdin") == 0)
1.420 + fh = stdin;
1.421 + else if (strcmp(fname, "/dev/stdout") == 0)
1.422 + fh = stdout;
1.423 + else if (strcmp(fname, "/dev/stderr") == 0)
1.424 + fh = stderr;
1.425 + else
1.426 + fh = fopen(fname, mode);
1.427 + if (fh == NULL)
1.428 + lib_err_msg(strerror(errno));
1.429 + return fh;
1.430 +}
1.431 +
1.432 +static int c_fgetc(void *_fh)
1.433 +{ FILE *fh = _fh;
1.434 + int c;
1.435 + if (ferror(fh) || feof(fh))
1.436 + { c = XEOF;
1.437 + goto done;
1.438 + }
1.439 + c = fgetc(fh);
1.440 + if (ferror(fh))
1.441 + { lib_err_msg(strerror(errno));
1.442 + c = XEOF;
1.443 + }
1.444 + else if (feof(fh))
1.445 + c = XEOF;
1.446 + else
1.447 + xassert(0x00 <= c && c <= 0xFF);
1.448 +done: return c;
1.449 +}
1.450 +
1.451 +static int c_fputc(int c, void *_fh)
1.452 +{ FILE *fh = _fh;
1.453 + if (ferror(fh))
1.454 + { c = XEOF;
1.455 + goto done;
1.456 + }
1.457 + c = (unsigned char)c;
1.458 + fputc(c, fh);
1.459 + if (ferror(fh))
1.460 + { lib_err_msg(strerror(errno));
1.461 + c = XEOF;
1.462 + }
1.463 +done: return c;
1.464 +}
1.465 +
1.466 +static int c_ferror(void *_fh)
1.467 +{ FILE *fh = _fh;
1.468 + return ferror(fh);
1.469 +}
1.470 +
1.471 +static int c_feof(void *_fh)
1.472 +{ FILE *fh = _fh;
1.473 + return feof(fh);
1.474 +}
1.475 +
1.476 +static int c_fflush(void *_fh)
1.477 +{ FILE *fh = _fh;
1.478 + int ret;
1.479 + ret = fflush(fh);
1.480 + if (ret != 0)
1.481 + { lib_err_msg(strerror(errno));
1.482 + ret = XEOF;
1.483 + }
1.484 + return ret;
1.485 +}
1.486 +
1.487 +static int c_fclose(void *_fh)
1.488 +{ FILE *fh = _fh;
1.489 + int ret;
1.490 + if (fh == stdin)
1.491 + ret = 0;
1.492 + else if (fh == stdout || fh == stderr)
1.493 + fflush(fh), ret = 0;
1.494 + else
1.495 + ret = fclose(fh);
1.496 + if (ret != 0)
1.497 + { lib_err_msg(strerror(errno));
1.498 + ret = XEOF;
1.499 + }
1.500 + return ret;
1.501 +}
1.502 +
1.503 +/***********************************************************************
1.504 +* The following routines implement stream input/output based on the
1.505 +* zlib library, which provides processing .gz files "on the fly". */
1.506 +
1.507 +#ifndef HAVE_ZLIB
1.508 +
1.509 +static void *z_fopen(const char *fname, const char *mode)
1.510 +{ xassert(fname == fname);
1.511 + xassert(mode == mode);
1.512 + lib_err_msg("Compressed files not supported");
1.513 + return NULL;
1.514 +}
1.515 +
1.516 +static int z_fgetc(void *fh)
1.517 +{ xassert(fh != fh);
1.518 + return 0;
1.519 +}
1.520 +
1.521 +static int z_fputc(int c, void *fh)
1.522 +{ xassert(c != c);
1.523 + xassert(fh != fh);
1.524 + return 0;
1.525 +}
1.526 +
1.527 +static int z_ferror(void *fh)
1.528 +{ xassert(fh != fh);
1.529 + return 0;
1.530 +}
1.531 +
1.532 +static int z_feof(void *fh)
1.533 +{ xassert(fh != fh);
1.534 + return 0;
1.535 +}
1.536 +
1.537 +static int z_fflush(void *fh)
1.538 +{ xassert(fh != fh);
1.539 + return 0;
1.540 +}
1.541 +
1.542 +static int z_fclose(void *fh)
1.543 +{ xassert(fh != fh);
1.544 + return 0;
1.545 +}
1.546 +
1.547 +#else
1.548 +
1.549 +#include <zlib.h>
1.550 +
1.551 +struct z_file
1.552 +{ /* .gz file handle */
1.553 + gzFile file;
1.554 + /* pointer to .gz stream */
1.555 + int err;
1.556 + /* i/o error indicator */
1.557 + int eof;
1.558 + /* end-of-file indicator */
1.559 +};
1.560 +
1.561 +static void *z_fopen(const char *fname, const char *mode)
1.562 +{ struct z_file *fh;
1.563 + gzFile file;
1.564 + if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
1.565 + mode = "rb";
1.566 + else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
1.567 + mode = "wb";
1.568 + else
1.569 + { lib_err_msg("Invalid open mode");
1.570 + fh = NULL;
1.571 + goto done;
1.572 + }
1.573 + file = gzopen(fname, mode);
1.574 + if (file == NULL)
1.575 + { lib_err_msg(strerror(errno));
1.576 + fh = NULL;
1.577 + goto done;
1.578 + }
1.579 + fh = xmalloc(sizeof(struct z_file));
1.580 + fh->file = file;
1.581 + fh->err = fh->eof = 0;
1.582 +done: return fh;
1.583 +}
1.584 +
1.585 +static int z_fgetc(void *_fh)
1.586 +{ struct z_file *fh = _fh;
1.587 + int c;
1.588 + if (fh->err || fh->eof)
1.589 + { c = XEOF;
1.590 + goto done;
1.591 + }
1.592 + c = gzgetc(fh->file);
1.593 + if (c < 0)
1.594 + { int errnum;
1.595 + const char *msg;
1.596 + msg = gzerror(fh->file, &errnum);
1.597 + if (errnum == Z_STREAM_END)
1.598 + fh->eof = 1;
1.599 + else if (errnum == Z_ERRNO)
1.600 + { fh->err = 1;
1.601 + lib_err_msg(strerror(errno));
1.602 + }
1.603 + else
1.604 + { fh->err = 1;
1.605 + lib_err_msg(msg);
1.606 + }
1.607 + c = XEOF;
1.608 + }
1.609 + else
1.610 + xassert(0x00 <= c && c <= 0xFF);
1.611 +done: return c;
1.612 +}
1.613 +
1.614 +static int z_fputc(int c, void *_fh)
1.615 +{ struct z_file *fh = _fh;
1.616 + if (fh->err)
1.617 + { c = XEOF;
1.618 + goto done;
1.619 + }
1.620 + c = (unsigned char)c;
1.621 + if (gzputc(fh->file, c) < 0)
1.622 + { int errnum;
1.623 + const char *msg;
1.624 + fh->err = 1;
1.625 + msg = gzerror(fh->file, &errnum);
1.626 + if (errnum == Z_ERRNO)
1.627 + lib_err_msg(strerror(errno));
1.628 + else
1.629 + lib_err_msg(msg);
1.630 + c = XEOF;
1.631 + }
1.632 +done: return c;
1.633 +}
1.634 +
1.635 +static int z_ferror(void *_fh)
1.636 +{ struct z_file *fh = _fh;
1.637 + return fh->err;
1.638 +}
1.639 +
1.640 +static int z_feof(void *_fh)
1.641 +{ struct z_file *fh = _fh;
1.642 + return fh->eof;
1.643 +}
1.644 +
1.645 +static int z_fflush(void *_fh)
1.646 +{ struct z_file *fh = _fh;
1.647 + int ret;
1.648 + ret = gzflush(fh->file, Z_FINISH);
1.649 + if (ret == Z_OK)
1.650 + ret = 0;
1.651 + else
1.652 + { int errnum;
1.653 + const char *msg;
1.654 + fh->err = 1;
1.655 + msg = gzerror(fh->file, &errnum);
1.656 + if (errnum == Z_ERRNO)
1.657 + lib_err_msg(strerror(errno));
1.658 + else
1.659 + lib_err_msg(msg);
1.660 + ret = XEOF;
1.661 + }
1.662 + return ret;
1.663 +}
1.664 +
1.665 +static int z_fclose(void *_fh)
1.666 +{ struct z_file *fh = _fh;
1.667 + gzclose(fh->file);
1.668 + xfree(fh);
1.669 + return 0;
1.670 +}
1.671 +
1.672 +#endif
1.673 +
1.674 +/* eof */