src/glpenv07.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     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 */