1 /* glpenv07.c (stream input/output) */
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
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>.
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.
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.
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 ***********************************************************************/
31 /***********************************************************************
34 * lib_err_msg - save error message string
39 * void lib_err_msg(const char *msg);
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). */
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';
58 /***********************************************************************
61 * xerrmsg - retrieve error message string
66 * const char *xerrmsg(void);
70 * The routine xerrmsg returns a pointer to an error message string
71 * previously set by some library routine to indicate an error. */
73 const char *xerrmsg(void)
74 { ENV *env = get_env_ptr();
75 return env->ioerr_msg;
78 /***********************************************************************
81 * xfopen - open a stream
86 * XFILE *xfopen(const char *fname, const char *mode);
90 * The routine xfopen opens the file whose name is a string pointed to
91 * by fname and associates a stream with it.
93 * The parameter mode points to a string, which indicates the open mode
94 * and should be one of the following:
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.
103 * The routine xfopen returns a pointer to the object controlling the
104 * stream. If the open operation fails, xfopen returns NULL. */
106 static void *c_fopen(const char *fname, const char *mode);
107 static void *z_fopen(const char *fname, const char *mode);
109 static int is_gz_file(const char *fname)
110 { char *ext = strrchr(fname, '.');
111 return ext != NULL && strcmp(ext, ".gz") == 0;
114 XFILE *xfopen(const char *fname, const char *mode)
115 { ENV *env = get_env_ptr();
119 if (!is_gz_file(fname))
121 fh = c_fopen(fname, mode);
125 fh = z_fopen(fname, mode);
131 fp = xmalloc(sizeof(XFILE));
135 fp->next = env->file_ptr;
136 if (fp->next != NULL) fp->next->prev = fp;
141 /***********************************************************************
144 * xfgetc - read character from the stream
148 * #include "glpenv.h"
149 * int xfgetc(XFILE *fp);
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
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.
168 * Note: An end-of-file and a read error can be distinguished by use of
169 * the routines xfeof and xferror. */
171 static int c_fgetc(void *fh);
172 static int z_fgetc(void *fh);
174 int xfgetc(XFILE *fp)
189 /***********************************************************************
192 * xfputc - write character to the stream
196 * #include "glpenv.h"
197 * int xfputc(int c, XFILE *fp);
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.
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
212 static int c_fputc(int c, void *fh);
213 static int z_fputc(int c, void *fh);
215 int xfputc(int c, XFILE *fp)
218 c = c_fputc(c, fp->fh);
221 c = z_fputc(c, fp->fh);
229 /***********************************************************************
232 * xferror - test error indicator for the stream
236 * #include "glpenv.h"
237 * int xferror(XFILE *fp);
241 * The routine xferror tests the error indicator for the stream
246 * The routine xferror returns non-zero if and only if the error
247 * indicator is set for the stream. */
249 static int c_ferror(void *fh);
250 static int z_ferror(void *fh);
252 int xferror(XFILE *fp)
256 ret = c_ferror(fp->fh);
259 ret = z_ferror(fp->fh);
267 /***********************************************************************
270 * xfeof - test end-of-file indicator for the stream
274 * #include "glpenv.h"
275 * int xfeof(XFILE *fp);
279 * The routine xfeof tests the end-of-file indicator for the stream
284 * The routine xfeof returns non-zero if and only if the end-of-file
285 * indicator is set for the stream. */
287 static int c_feof(void *fh);
288 static int z_feof(void *fh);
294 ret = c_feof(fp->fh);
297 ret = z_feof(fp->fh);
305 int xfprintf(XFILE *file, const char *fmt, ...)
306 { ENV *env = get_env_ptr();
310 cnt = vsprintf(env->term_buf, fmt, arg);
312 for (j = 0; j < cnt; j++)
313 { if (xfputc(env->term_buf[j], file) < 0)
321 /***********************************************************************
324 * xfflush - flush the stream
328 * #include "glpenv.h"
329 * int xfflush(XFILE *fp);
333 * The routine xfflush causes any unwritten data for the output stream
334 * pointed to by fp to be written to the associated file.
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. */
342 static int c_fflush(void *fh);
343 static int z_fflush(void *fh);
345 int xfflush(XFILE *fp)
349 ret = c_fflush(fp->fh);
352 ret = z_fflush(fp->fh);
360 /***********************************************************************
363 * xfclose - close the stream
367 * #include "glpenv.h"
368 * int xfclose(XFILE *fp);
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.
378 * The routine xfclose returns zero if the stream was successfully
379 * closed, or XEOF if any errors were detected. */
381 static int c_fclose(void *fh);
382 static int z_fclose(void *fh);
384 int xfclose(XFILE *fp)
385 { ENV *env = get_env_ptr();
389 ret = c_fclose(fp->fh);
392 ret = z_fclose(fp->fh);
398 if (fp->prev == NULL)
399 env->file_ptr = fp->next;
401 fp->prev->next = fp->next;
402 if (fp->next == NULL)
405 fp->next->prev = fp->prev;
410 /***********************************************************************
411 * The following routines implement stream input/output based on the
412 * standard C streams. */
414 static void *c_fopen(const char *fname, const char *mode)
416 if (strcmp(fname, "/dev/stdin") == 0)
418 else if (strcmp(fname, "/dev/stdout") == 0)
420 else if (strcmp(fname, "/dev/stderr") == 0)
423 fh = fopen(fname, mode);
425 lib_err_msg(strerror(errno));
429 static int c_fgetc(void *_fh)
432 if (ferror(fh) || feof(fh))
438 { lib_err_msg(strerror(errno));
444 xassert(0x00 <= c && c <= 0xFF);
448 static int c_fputc(int c, void *_fh)
454 c = (unsigned char)c;
457 { lib_err_msg(strerror(errno));
463 static int c_ferror(void *_fh)
468 static int c_feof(void *_fh)
473 static int c_fflush(void *_fh)
478 { lib_err_msg(strerror(errno));
484 static int c_fclose(void *_fh)
489 else if (fh == stdout || fh == stderr)
494 { lib_err_msg(strerror(errno));
500 /***********************************************************************
501 * The following routines implement stream input/output based on the
502 * zlib library, which provides processing .gz files "on the fly". */
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");
513 static int z_fgetc(void *fh)
518 static int z_fputc(int c, void *fh)
524 static int z_ferror(void *fh)
529 static int z_feof(void *fh)
534 static int z_fflush(void *fh)
539 static int z_fclose(void *fh)
549 { /* .gz file handle */
551 /* pointer to .gz stream */
553 /* i/o error indicator */
555 /* end-of-file indicator */
558 static void *z_fopen(const char *fname, const char *mode)
561 if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
563 else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
566 { lib_err_msg("Invalid open mode");
570 file = gzopen(fname, mode);
572 { lib_err_msg(strerror(errno));
576 fh = xmalloc(sizeof(struct z_file));
578 fh->err = fh->eof = 0;
582 static int z_fgetc(void *_fh)
583 { struct z_file *fh = _fh;
585 if (fh->err || fh->eof)
589 c = gzgetc(fh->file);
593 msg = gzerror(fh->file, &errnum);
594 if (errnum == Z_STREAM_END)
596 else if (errnum == Z_ERRNO)
598 lib_err_msg(strerror(errno));
607 xassert(0x00 <= c && c <= 0xFF);
611 static int z_fputc(int c, void *_fh)
612 { struct z_file *fh = _fh;
617 c = (unsigned char)c;
618 if (gzputc(fh->file, c) < 0)
622 msg = gzerror(fh->file, &errnum);
623 if (errnum == Z_ERRNO)
624 lib_err_msg(strerror(errno));
632 static int z_ferror(void *_fh)
633 { struct z_file *fh = _fh;
637 static int z_feof(void *_fh)
638 { struct z_file *fh = _fh;
642 static int z_fflush(void *_fh)
643 { struct z_file *fh = _fh;
645 ret = gzflush(fh->file, Z_FINISH);
652 msg = gzerror(fh->file, &errnum);
653 if (errnum == Z_ERRNO)
654 lib_err_msg(strerror(errno));
662 static int z_fclose(void *_fh)
663 { struct z_file *fh = _fh;