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 */ |
---|