Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1993, 2000 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: sfxstdio.c,v 1.9 2004/08/05 17:02:36 stefan Exp $ */
18
/* File stream implementation using stdio */
19
#include "stdio_.h"		/* includes std.h */
20
#include "memory_.h"
21
#include "gdebug.h"
22
#include "gpcheck.h"
23
#include "stream.h"
24
#include "strimpl.h"
25
 
26
/* Forward references for file stream procedures */
27
private int
28
    s_file_available(stream *, long *),
29
    s_file_read_seek(stream *, long),
30
    s_file_read_close(stream *),
31
    s_file_read_process(stream_state *, stream_cursor_read *,
32
			stream_cursor_write *, bool);
33
private int
34
    s_file_write_seek(stream *, long),
35
    s_file_write_flush(stream *),
36
    s_file_write_close(stream *),
37
    s_file_write_process(stream_state *, stream_cursor_read *,
38
			 stream_cursor_write *, bool);
39
private int
40
    s_file_switch(stream *, bool);
41
 
42
/* ------ File reading ------ */
43
 
44
/* Initialize a stream for reading an OS file. */
45
void
46
sread_file(register stream * s, FILE * file, byte * buf, uint len)
47
{
48
    static const stream_procs p = {
49
	s_file_available, s_file_read_seek, s_std_read_reset,
50
	s_std_read_flush, s_file_read_close, s_file_read_process,
51
	s_file_switch
52
    };
53
    /*
54
     * There is no really portable way to test seekability, but this should
55
     * work on most systems.  Note that if our probe sets the ferror bit for
56
     * the stream, we have to clear it again to avoid trouble later.
57
     */
58
    int had_error = ferror(file);
59
    long curpos = ftell(file);
60
    bool seekable = (curpos != -1L && fseek(file, curpos, SEEK_SET) == 0);
61
 
62
    if (!had_error)
63
	clearerr(file);
64
    s_std_init(s, buf, len, &p,
65
	       (seekable ? s_mode_read + s_mode_seek : s_mode_read));
66
    if_debug1('s', "[s]read file=0x%lx\n", (ulong) file);
67
    s->file = file;
68
    s->file_modes = s->modes;
69
    s->file_offset = 0;
70
    s->file_limit = max_long;
71
}
72
 
73
/* Confine reading to a subfile.  This is primarily for reusable streams. */
74
int
75
sread_subfile(stream *s, long start, long length)
76
{
77
    if (s->file == 0 || s->modes != s_mode_read + s_mode_seek ||
78
	s->file_offset != 0 || s->file_limit != max_long ||
79
	((s->position < start || s->position > start + length) &&
80
	 sseek(s, start) < 0)
81
	)
82
	return ERRC;
83
    s->position -= start;
84
    s->file_offset = start;
85
    s->file_limit = length;
86
    return 0;
87
}
88
 
89
/* Procedures for reading from a file */
90
private int
91
s_file_available(register stream * s, long *pl)
92
{
93
    long max_avail = s->file_limit - stell(s);
94
    long buf_avail = sbufavailable(s);
95
 
96
    *pl = min(max_avail, buf_avail);
97
    if (sseekable(s)) {
98
	long pos, end;
99
 
100
	pos = ftell(s->file);
101
	if (fseek(s->file, 0L, SEEK_END))
102
	    return ERRC;
103
	end = ftell(s->file);
104
	if (fseek(s->file, pos, SEEK_SET))
105
	    return ERRC;
106
	buf_avail += end - pos;
107
	*pl = min(max_avail, buf_avail);
108
	if (*pl == 0)
109
	    *pl = -1;		/* EOF */
110
    } else {
111
	if (*pl == 0 && feof(s->file))
112
	    *pl = -1;		/* EOF */
113
    }
114
    return 0;
115
}
116
private int
117
s_file_read_seek(register stream * s, long pos)
118
{
119
    uint end = s->srlimit - s->cbuf + 1;
120
    long offset = pos - s->position;
121
 
122
    if (offset >= 0 && offset <= end) {  /* Staying within the same buffer */
123
	s->srptr = s->cbuf + offset - 1;
124
	return 0;
125
    }
126
    if (pos < 0 || pos > s->file_limit ||
127
	fseek(s->file, s->file_offset + pos, SEEK_SET) != 0
128
	)
129
	return ERRC;
130
    s->srptr = s->srlimit = s->cbuf - 1;
131
    s->end_status = 0;
132
    s->position = pos;
133
    return 0;
134
}
135
private int
136
s_file_read_close(stream * s)
137
{
138
    FILE *file = s->file;
139
 
140
    if (file != 0) {
141
	s->file = 0;
142
	return (fclose(file) ? ERRC : 0);
143
    }
144
    return 0;
145
}
146
 
147
/*
148
 * Process a buffer for a file reading stream.
149
 * This is the first stream in the pipeline, so pr is irrelevant.
150
 */
151
private int
152
s_file_read_process(stream_state * st, stream_cursor_read * ignore_pr,
153
		    stream_cursor_write * pw, bool last)
154
{
155
    stream *s = (stream *)st;	/* no separate state */
156
    FILE *file = s->file;
157
    uint max_count = pw->limit - pw->ptr;
158
    int status = 1;
159
    int count;
160
 
161
    if (s->file_limit < max_long) {
162
	long limit_count = s->file_offset + s->file_limit - ftell(file);
163
 
164
	if (max_count > limit_count)
165
	    max_count = limit_count, status = EOFC;
166
    }
167
    count = fread(pw->ptr + 1, 1, max_count, file);
168
    if (count < 0)
169
	count = 0;
170
    pw->ptr += count;
171
    process_interrupts(s->memory);
172
    return (ferror(file) ? ERRC : feof(file) ? EOFC : status);
173
}
174
 
175
/* ------ File writing ------ */
176
 
177
/* Initialize a stream for writing an OS file. */
178
void
179
swrite_file(register stream * s, FILE * file, byte * buf, uint len)
180
{
181
    static const stream_procs p = {
182
	s_std_noavailable, s_file_write_seek, s_std_write_reset,
183
	s_file_write_flush, s_file_write_close, s_file_write_process,
184
	s_file_switch
185
    };
186
 
187
    s_std_init(s, buf, len, &p,
188
	       (file == stdout ? s_mode_write : s_mode_write + s_mode_seek));
189
    if_debug1('s', "[s]write file=0x%lx\n", (ulong) file);
190
    s->file = file;
191
    s->file_modes = s->modes;
192
    s->file_offset = 0;		/* in case we switch to reading later */
193
    s->file_limit = max_long;	/* ibid. */
194
}
195
/* Initialize for appending to an OS file. */
196
void
197
sappend_file(register stream * s, FILE * file, byte * buf, uint len)
198
{
199
    swrite_file(s, file, buf, len);
200
    s->modes = s_mode_write + s_mode_append;	/* no seek */
201
    s->file_modes = s->modes;
202
    fseek(file, 0L, SEEK_END);
203
    s->position = ftell(file);
204
}
205
/* Procedures for writing on a file */
206
private int
207
s_file_write_seek(stream * s, long pos)
208
{
209
    /* We must flush the buffer to reposition. */
210
    int code = sflush(s);
211
 
212
    if (code < 0)
213
	return code;
214
    if (fseek(s->file, pos, SEEK_SET) != 0)
215
	return ERRC;
216
    s->position = pos;
217
    return 0;
218
}
219
private int
220
s_file_write_flush(register stream * s)
221
{
222
    int result = s_process_write_buf(s, false);
223
 
224
    fflush(s->file);
225
    return result;
226
}
227
private int
228
s_file_write_close(register stream * s)
229
{
230
    s_process_write_buf(s, true);
231
    return s_file_read_close(s);
232
}
233
 
234
/*
235
 * Process a buffer for a file writing stream.
236
 * This is the last stream in the pipeline, so pw is irrelevant.
237
 */
238
private int
239
s_file_write_process(stream_state * st, stream_cursor_read * pr,
240
		     stream_cursor_write * ignore_pw, bool last)
241
{
242
    uint count = pr->limit - pr->ptr;
243
 
244
    /*
245
     * The DEC C library on AXP architectures gives an error on
246
     * fwrite if the count is zero!
247
     */
248
    if (count != 0) {
249
	FILE *file = ((stream *) st)->file;
250
	int written = fwrite(pr->ptr + 1, 1, count, file);
251
 
252
	if (written < 0)
253
	    written = 0;
254
	pr->ptr += written;
255
	process_interrupts(NULL);
256
	return (ferror(file) ? ERRC : 0);
257
    } else {
258
	process_interrupts(NULL);
259
	return 0;
260
    }
261
}
262
 
263
/* ------ File switching ------ */
264
 
265
/* Switch a file stream to reading or writing. */
266
private int
267
s_file_switch(stream * s, bool writing)
268
{
269
    uint modes = s->file_modes;
270
    FILE *file = s->file;
271
    long pos;
272
 
273
    if (writing) {
274
	if (!(s->file_modes & s_mode_write))
275
	    return ERRC;
276
	pos = stell(s);
277
	if_debug2('s', "[s]switch 0x%lx to write at %ld\n",
278
		  (ulong) s, pos);
279
	fseek(file, pos, SEEK_SET);
280
	if (modes & s_mode_append) {
281
	    sappend_file(s, file, s->cbuf, s->cbsize);	/* sets position */
282
	} else {
283
	    swrite_file(s, file, s->cbuf, s->cbsize);
284
	    s->position = pos;
285
	}
286
	s->modes = modes;
287
    } else {
288
	if (!(s->file_modes & s_mode_read))
289
	    return ERRC;
290
	pos = stell(s);
291
	if_debug2('s', "[s]switch 0x%lx to read at %ld\n",
292
		  (ulong) s, pos);
293
	if (sflush(s) < 0)
294
	    return ERRC;
295
	fseek(file, 0L, SEEK_CUR);	/* pacify C library */
296
	sread_file(s, file, s->cbuf, s->cbsize);
297
	s->modes |= modes & s_mode_append;	/* don't lose append info */
298
	s->position = pos;
299
    }
300
    s->file_modes = modes;
301
    return 0;
302
}