src/glpenv07.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

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