123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /* Copyright (C) 1993, 2000 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
- /*$Id: sfxstdio.c,v 1.4 2000/09/19 19:00:50 lpd Exp $ */
- /* File stream implementation using stdio */
- #include "stdio_.h" /* includes std.h */
- #include "memory_.h"
- #include "gdebug.h"
- #include "gpcheck.h"
- #include "stream.h"
- #include "strimpl.h"
- /* Forward references for file stream procedures */
- private int
- s_file_available(P2(stream *, long *)),
- s_file_read_seek(P2(stream *, long)),
- s_file_read_close(P1(stream *)),
- s_file_read_process(P4(stream_state *, stream_cursor_read *,
- stream_cursor_write *, bool));
- private int
- s_file_write_seek(P2(stream *, long)),
- s_file_write_flush(P1(stream *)),
- s_file_write_close(P1(stream *)),
- s_file_write_process(P4(stream_state *, stream_cursor_read *,
- stream_cursor_write *, bool));
- private int
- s_file_switch(P2(stream *, bool));
- /* ------ File reading ------ */
- /* Initialize a stream for reading an OS file. */
- void
- sread_file(register stream * s, FILE * file, byte * buf, uint len)
- {
- static const stream_procs p = {
- s_file_available, s_file_read_seek, s_std_read_reset,
- s_std_read_flush, s_file_read_close, s_file_read_process,
- s_file_switch
- };
- /*
- * There is no really portable way to test seekability, but this should
- * work on most systems. Note that if our probe sets the ferror bit for
- * the stream, we have to clear it again to avoid trouble later.
- */
- int had_error = ferror(file);
- long curpos = ftell(file);
- bool seekable = (curpos != -1L && fseek(file, curpos, SEEK_SET) == 0);
- if (!had_error)
- clearerr(file);
- s_std_init(s, buf, len, &p,
- (seekable ? s_mode_read + s_mode_seek : s_mode_read));
- if_debug1('s', "[s]read file=0x%lx\n", (ulong) file);
- s->file = file;
- s->file_modes = s->modes;
- s->file_offset = 0;
- s->file_limit = max_long;
- }
- /* Confine reading to a subfile. This is primarily for reusable streams. */
- int
- sread_subfile(stream *s, long start, long length)
- {
- if (s->file == 0 || s->modes != s_mode_read + s_mode_seek ||
- s->file_offset != 0 || s->file_limit != max_long ||
- ((s->position < start || s->position > start + length) &&
- sseek(s, start) < 0)
- )
- return ERRC;
- s->position -= start;
- s->file_offset = start;
- s->file_limit = length;
- return 0;
- }
- /* Procedures for reading from a file */
- private int
- s_file_available(register stream * s, long *pl)
- {
- long max_avail = s->file_limit - stell(s);
- long buf_avail = sbufavailable(s);
- *pl = min(max_avail, buf_avail);
- if (sseekable(s)) {
- long pos, end;
- pos = ftell(s->file);
- if (fseek(s->file, 0L, SEEK_END))
- return ERRC;
- end = ftell(s->file);
- if (fseek(s->file, pos, SEEK_SET))
- return ERRC;
- buf_avail += end - pos;
- *pl = min(max_avail, buf_avail);
- if (*pl == 0)
- *pl = -1; /* EOF */
- } else {
- if (*pl == 0 && feof(s->file))
- *pl = -1; /* EOF */
- }
- return 0;
- }
- private int
- s_file_read_seek(register stream * s, long pos)
- {
- uint end = s->srlimit - s->cbuf + 1;
- long offset = pos - s->position;
- if (offset >= 0 && offset <= end) { /* Staying within the same buffer */
- s->srptr = s->cbuf + offset - 1;
- return 0;
- }
- if (pos < 0 || pos > s->file_limit ||
- fseek(s->file, s->file_offset + pos, SEEK_SET) != 0
- )
- return ERRC;
- s->srptr = s->srlimit = s->cbuf - 1;
- s->end_status = 0;
- s->position = pos;
- return 0;
- }
- private int
- s_file_read_close(stream * s)
- {
- FILE *file = s->file;
- if (file != 0) {
- s->file = 0;
- return (fclose(file) ? ERRC : 0);
- }
- return 0;
- }
- /*
- * Process a buffer for a file reading stream.
- * This is the first stream in the pipeline, so pr is irrelevant.
- */
- private int
- s_file_read_process(stream_state * st, stream_cursor_read * ignore_pr,
- stream_cursor_write * pw, bool last)
- {
- stream *s = (stream *)st; /* no separate state */
- FILE *file = s->file;
- uint max_count = pw->limit - pw->ptr;
- int status = 1;
- int count;
- if (s->file_limit < max_long) {
- long limit_count = s->file_offset + s->file_limit - ftell(file);
- if (max_count > limit_count)
- max_count = limit_count, status = EOFC;
- }
- count = fread(pw->ptr + 1, 1, max_count, file);
- if (count < 0)
- count = 0;
- pw->ptr += count;
- process_interrupts();
- return (ferror(file) ? ERRC : feof(file) ? EOFC : status);
- }
- /* ------ File writing ------ */
- /* Initialize a stream for writing an OS file. */
- void
- swrite_file(register stream * s, FILE * file, byte * buf, uint len)
- {
- static const stream_procs p = {
- s_std_noavailable, s_file_write_seek, s_std_write_reset,
- s_file_write_flush, s_file_write_close, s_file_write_process,
- s_file_switch
- };
- s_std_init(s, buf, len, &p,
- (file == stdout ? s_mode_write : s_mode_write + s_mode_seek));
- if_debug1('s', "[s]write file=0x%lx\n", (ulong) file);
- s->file = file;
- s->file_modes = s->modes;
- s->file_offset = 0; /* in case we switch to reading later */
- s->file_limit = max_long; /* ibid. */
- }
- /* Initialize for appending to an OS file. */
- void
- sappend_file(register stream * s, FILE * file, byte * buf, uint len)
- {
- swrite_file(s, file, buf, len);
- s->modes = s_mode_write + s_mode_append; /* no seek */
- s->file_modes = s->modes;
- fseek(file, 0L, SEEK_END);
- s->position = ftell(file);
- }
- /* Procedures for writing on a file */
- private int
- s_file_write_seek(stream * s, long pos)
- {
- /* We must flush the buffer to reposition. */
- int code = sflush(s);
- if (code < 0)
- return code;
- if (fseek(s->file, pos, SEEK_SET) != 0)
- return ERRC;
- s->position = pos;
- return 0;
- }
- private int
- s_file_write_flush(register stream * s)
- {
- int result = s_process_write_buf(s, false);
- fflush(s->file);
- return result;
- }
- private int
- s_file_write_close(register stream * s)
- {
- s_process_write_buf(s, true);
- return s_file_read_close(s);
- }
- /*
- * Process a buffer for a file writing stream.
- * This is the last stream in the pipeline, so pw is irrelevant.
- */
- private int
- s_file_write_process(stream_state * st, stream_cursor_read * pr,
- stream_cursor_write * ignore_pw, bool last)
- {
- uint count = pr->limit - pr->ptr;
- /*
- * The DEC C library on AXP architectures gives an error on
- * fwrite if the count is zero!
- */
- if (count != 0) {
- FILE *file = ((stream *) st)->file;
- int written = fwrite(pr->ptr + 1, 1, count, file);
- if (written < 0)
- written = 0;
- pr->ptr += written;
- process_interrupts();
- return (ferror(file) ? ERRC : 0);
- } else {
- process_interrupts();
- return 0;
- }
- }
- /* ------ File switching ------ */
- /* Switch a file stream to reading or writing. */
- private int
- s_file_switch(stream * s, bool writing)
- {
- uint modes = s->file_modes;
- FILE *file = s->file;
- long pos;
- if (writing) {
- if (!(s->file_modes & s_mode_write))
- return ERRC;
- pos = stell(s);
- if_debug2('s', "[s]switch 0x%lx to write at %ld\n",
- (ulong) s, pos);
- fseek(file, pos, SEEK_SET);
- if (modes & s_mode_append) {
- sappend_file(s, file, s->cbuf, s->cbsize); /* sets position */
- } else {
- swrite_file(s, file, s->cbuf, s->cbsize);
- s->position = pos;
- }
- s->modes = modes;
- } else {
- if (!(s->file_modes & s_mode_read))
- return ERRC;
- pos = stell(s);
- if_debug2('s', "[s]switch 0x%lx to read at %ld\n",
- (ulong) s, pos);
- if (sflush(s) < 0)
- return ERRC;
- fseek(file, 0L, SEEK_CUR); /* pacify C library */
- sread_file(s, file, s->cbuf, s->cbsize);
- s->modes |= modes & s_mode_append; /* don't lose append info */
- s->position = pos;
- }
- s->file_modes = modes;
- return 0;
- }
|