src/glpenv07.c
changeset 1 c445c931472f
     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 */