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