|
|
1.1 root 1: /*
2: Copyright (C) 1993 Free Software Foundation
3:
4: This file is part of the GNU IO Library. This library is free
5: software; you can redistribute it and/or modify it under the
6: terms of the GNU General Public License as published by the
7: Free Software Foundation; either version 2, or (at your option)
8: any later version.
9:
10: This library is distributed in the hope that it will be useful,
11: but WITHOUT ANY WARRANTY; without even the implied warranty of
12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: GNU General Public License for more details.
14:
15: You should have received a copy of the GNU General Public License
16: along with GNU CC; see the file COPYING. If not, write to
17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18:
19: As a special exception, if you link this library with files
20: compiled with a GNU compiler to produce an executable, this does not cause
21: the resulting executable to be covered by the GNU General Public License.
22: This exception does not however invalidate any other reasons why
23: the executable file might be covered by the GNU General Public License. */
24:
25: /* written by Per Bothner ([email protected]) */
26:
27: #define _POSIX_SOURCE
28: #include "libioP.h"
29: #include <fcntl.h>
30: #include <sys/types.h>
31: #include <sys/stat.h>
32: #include <string.h>
33: #include <errno.h>
34: #ifndef errno
35: extern int errno;
36: #endif
37:
38: /* An fstream can be in at most one of put mode, get mode, or putback mode.
39: Putback mode is a variant of get mode.
40:
41: In a filebuf, there is only one current position, instead of two
42: separate get and put pointers. In get mode, the current posistion
43: is that of gptr(); in put mode that of pptr().
44:
45: The position in the buffer that corresponds to the position
46: in external file system is file_ptr().
47: This is normally egptr(), except in putback mode, when it is _save_egptr.
48: If the field _fb._offset is >= 0, it gives the offset in
49: the file as a whole corresponding to eGptr(). (???)
50:
51: PUT MODE:
52: If a filebuf is in put mode, pbase() is non-NULL and equal to base().
53: Also, epptr() == ebuf().
54: Also, eback() == gptr() && gptr() == egptr().
55: The un-flushed character are those between pbase() and pptr().
56: GET MODE:
57: If a filebuf is in get or putback mode, eback() != egptr().
58: In get mode, the unread characters are between gptr() and egptr().
59: The OS file position corresponds to that of egptr().
60: PUTBACK MODE:
61: Putback mode is used to remember "excess" characters that have
62: been sputbackc'd in a separate putback buffer.
63: In putback mode, the get buffer points to the special putback buffer.
64: The unread characters are the characters between gptr() and egptr()
65: in the putback buffer, as well as the area between save_gptr()
66: and save_egptr(), which point into the original reserve buffer.
67: (The pointers save_gptr() and save_egptr() are the values
68: of gptr() and egptr() at the time putback mode was entered.)
69: The OS position corresponds to that of save_egptr().
70:
71: LINE BUFFERED OUTPUT:
72: During line buffered output, pbase()==base() && epptr()==base().
73: However, ptr() may be anywhere between base() and ebuf().
74: This forces a call to filebuf::overflow(int C) on every put.
75: If there is more space in the buffer, and C is not a '\n',
76: then C is inserted, and pptr() incremented.
77:
78: UNBUFFERED STREAMS:
79: If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
80: */
81:
82: #define CLOSED_FILEBUF_FLAGS \
83: (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
84:
85:
86: void
87: _IO_file_init(fp)
88: register _IO_FILE *fp;
89: {
90: fp->_offset = _IO_pos_0;
91:
92: _IO_link_in(fp);
93: fp->_fileno = -1;
94: }
95:
96: int
97: _IO_file_close_it(fp)
98: register _IO_FILE* fp;
99: {
100: int status;
101: if (!_IO_file_is_open(fp))
102: return EOF;
103:
104: /* This flushes as well as switching mode. */
105: if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode(fp))
106: if (_IO_switch_to_get_mode(fp))
107: return EOF;
108:
109: _IO_unsave_markers(fp);
110:
111: status = fp->_jumps->__close(fp);
112:
113: /* Free buffer. */
114: _IO_setb(fp, NULL, NULL, 0);
115: _IO_setg(fp, NULL, NULL, NULL);
116: _IO_setp(fp, NULL, NULL);
117:
118: _IO_un_link(fp);
119: fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
120: fp->_fileno = EOF;
121: fp->_offset = _IO_pos_0;
122:
123: return status;
124: }
125:
126: void
127: _IO_file_finish(fp)
128: register _IO_FILE* fp;
129: {
130: if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
131: _IO_file_close_it(fp);
132: _IO_default_finish(fp);
133: }
134:
135: _IO_FILE *
136: _IO_file_fopen(fp, filename, mode)
137: register _IO_FILE *fp;
138: const char *filename;
139: const char *mode;
140: {
141: int oflags = 0, omode;
142: int read_write, fdesc;
143: int oprot = 0666;
144: if (_IO_file_is_open (fp))
145: return 0;
146: switch (*mode++) {
147: case 'r':
148: omode = O_RDONLY;
149: read_write = _IO_NO_WRITES;
150: break;
151: case 'w':
152: omode = O_WRONLY;
153: oflags = O_CREAT|O_TRUNC;
154: read_write = _IO_NO_READS;
155: break;
156: case 'a':
157: omode = O_WRONLY;
158: oflags = O_CREAT|O_APPEND;
159: read_write = _IO_NO_READS|_IO_IS_APPENDING;
160: break;
161: default:
162: errno = EINVAL;
163: return NULL;
164: }
165: if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+')) {
166: omode = O_RDWR;
167: read_write &= _IO_IS_APPENDING;
168: }
169: fdesc = open(filename, omode|oflags, oprot);
170: if (fdesc < 0)
171: return NULL;
172: fp->_fileno = fdesc;
173: fp->_IO_file_flags =
174: _IO_mask_flags(fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
175: if (read_write & _IO_IS_APPENDING)
176: if (fp->_jumps->__seekoff(fp, (_IO_off_t)0, _IO_seek_end) == _IO_pos_BAD)
177: return NULL;
178: _IO_link_in(fp);
179: return fp;
180: }
181:
182: _IO_FILE*
183: _IO_file_attach(fp, fd)
184: _IO_FILE *fp;
185: int fd;
186: {
187: if (_IO_file_is_open(fp))
188: return NULL;
189: fp->_fileno = fd;
190: fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
191: fp->_offset = _IO_pos_BAD;
192: return fp;
193: }
194:
195: int
196: _IO_file_setbuf(fp, p, len)
197: register _IO_FILE *fp;
198: char* p;
199: _IO_ssize_t len;
200: {
201: if (_IO_default_setbuf(fp, p, len) == EOF)
202: return EOF;
203:
204: fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
205: = fp->_IO_buf_base;
206: _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
207:
208: return 0;
209: }
210:
211: int
212: _IO_do_write(fp, data, to_do)
213: register _IO_FILE *fp;
214: const char* data;
215: _IO_size_t to_do;
216: {
217: _IO_size_t count;
218: if (to_do == 0)
219: return 0;
220: if (fp->_flags & _IO_IS_APPENDING)
221: /* On a system without a proper O_APPEND implementation,
222: you would need to sys_seek(0, SEEK_END) here, but is
223: is not needed nor desirable for Unix- or Posix-like systems.
224: Instead, just indicate that offset (before and after) is
225: unpredictable. */
226: fp->_offset = _IO_pos_BAD;
227: else if (fp->_IO_read_end != fp->_IO_write_base)
228: {
229: _IO_pos_t new_pos = fp->_jumps->__seek(fp, fp->_IO_write_base - fp->_IO_read_end, 1);
230: if (new_pos == _IO_pos_BAD)
231: return EOF;
232: fp->_offset = new_pos;
233: }
234: count = fp->_jumps->__write(fp, data, to_do);
235: if (fp->_cur_column)
236: fp->_cur_column = _IO_adjust_column(fp->_cur_column - 1, data, to_do) + 1;
237: _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
238: fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
239: fp->_IO_write_end = (fp->_flags & _IO_LINE_BUF+_IO_UNBUFFERED) ? fp->_IO_buf_base
240: : fp->_IO_buf_end;
241: return count != to_do ? EOF : 0;
242: }
243:
244: int
245: _IO_file_underflow(fp)
246: register _IO_FILE *fp;
247: {
248: _IO_size_t count;
249: #if 0
250: /* SysV does not make this test; take it out for compatibility */
251: if (fp->_flags & _IO_EOF_SEEN)
252: return (EOF);
253: #endif
254:
255: if (fp->_flags & _IO_NO_READS)
256: return EOF;
257: if (fp->_IO_read_ptr < fp->_IO_read_end)
258: return *(unsigned char*)fp->_IO_read_ptr;
259:
260: if (fp->_IO_buf_base == NULL)
261: _IO_doallocbuf(fp);
262:
263: /* Flush all line buffered files before reading. */
264: /* FIXME This can/should be moved to genops ?? */
265: if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
266: _IO_flush_all_linebuffered();
267:
268: _IO_switch_to_get_mode(fp);
269:
270: count = fp->_jumps->__read(fp, fp->_IO_buf_base,
271: fp->_IO_buf_end - fp->_IO_buf_base);
272: if (count <= 0)
273: {
274: if (count == 0)
275: fp->_flags |= _IO_EOF_SEEN;
276: else
277: fp->_flags |= _IO_ERR_SEEN, count = 0;
278: }
279: fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
280: fp->_IO_read_end = fp->_IO_buf_base + count;
281: fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
282: = fp->_IO_buf_base;
283: if (count == 0)
284: return EOF;
285: if (fp->_offset != _IO_pos_BAD)
286: _IO_pos_adjust(fp->_offset, count);
287: return *(unsigned char*)fp->_IO_read_ptr;
288: }
289:
290: int _IO_file_overflow (f, ch)
291: register _IO_FILE* f;
292: int ch;
293: {
294: if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
295: return EOF;
296: /* If current reading or no buffer allocated. */
297: if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
298: {
299: /* Allocate a buffer if needed. */
300: if (f->_IO_buf_base == 0)
301: {
302: _IO_doallocbuf(f);
303: f->_IO_read_end = f->_IO_buf_base;
304: f->_IO_write_ptr = f->_IO_buf_base;
305: }
306: else /* Must be currently reading. */
307: f->_IO_write_ptr = f->_IO_read_ptr;
308: f->_IO_write_base = f->_IO_write_ptr;
309: f->_IO_write_end = f->_IO_buf_end;
310: f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
311:
312: if (f->_flags & _IO_LINE_BUF+_IO_UNBUFFERED)
313: f->_IO_write_end = f->_IO_write_ptr;
314: f->_flags |= _IO_CURRENTLY_PUTTING;
315: }
316: if (ch == EOF)
317: return _IO_do_flush(f);
318: if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
319: if (_IO_do_flush(f) == EOF)
320: return EOF;
321: *f->_IO_write_ptr++ = ch;
322: if ((f->_flags & _IO_UNBUFFERED)
323: || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
324: if (_IO_do_flush(f) == EOF)
325: return EOF;
326: return (unsigned char)ch;
327: }
328:
329: int
330: _IO_file_sync(fp)
331: register _IO_FILE* fp;
332: {
333: _IO_size_t delta;
334: /* char* ptr = cur_ptr(); */
335: if (fp->_IO_write_ptr > fp->_IO_write_base)
336: if (_IO_do_flush(fp)) return EOF;
337: delta = fp->_IO_read_ptr - fp->_IO_read_end;
338: if (delta != 0)
339: {
340: #ifdef TODO
341: if (_IO_in_backup(fp))
342: delta -= eGptr() - Gbase();
343: #endif
344: _IO_off_t new_pos = fp->_jumps->__seek(fp, delta, 1);
345: if (new_pos == (_IO_off_t)EOF)
346: return EOF;
347: fp->_offset = new_pos;
348: fp->_IO_read_end = fp->_IO_read_ptr;
349: }
350: /* FIXME: Cleanup - can this be shared? */
351: /* setg(base(), ptr, ptr); */
352: return 0;
353: }
354:
355: _IO_pos_t
356: _IO_file_seekoff(fp, offset, mode)
357: register _IO_FILE *fp;
358: _IO_off_t offset;
359: _IO_seekflags mode;
360: {
361: _IO_pos_t result;
362: _IO_off_t delta, new_offset;
363: long count;
364: int dir = mode & 3;
365:
366: if ((mode & _IO_seek_not_in) && (mode & _IO_seek_not_out))
367: dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
368:
369: /* Flush unwritten characters.
370: (This may do an unneeded write if we seek within the buffer.
371: But to be able to switch to reading, we would need to set
372: egptr to ptr. That can't be done in the current design,
373: which assumes file_ptr() is eGptr. Anyway, since we probably
374: end up flushing when we close(), it doesn't make much difference.)
375: FIXME: simulate mem-papped files. */
376:
377: if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode(fp))
378: if (_IO_switch_to_get_mode(fp)) return EOF;
379:
380: if (fp->_IO_buf_base == NULL)
381: {
382: _IO_doallocbuf(fp);
383: _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
384: _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
385: }
386:
387: switch (dir)
388: {
389: case _IO_seek_cur:
390: if (fp->_offset == _IO_pos_BAD)
391: goto dumb;
392: /* Adjust for read-ahead (bytes is buffer). */
393: offset -= fp->_IO_read_end - fp->_IO_read_ptr;
394: /* Make offset absolute, assuming current pointer is file_ptr(). */
395: offset += _IO_pos_as_off(fp->_offset);
396:
397: dir = _IO_seek_set;
398: break;
399: case _IO_seek_set:
400: break;
401: case _IO_seek_end:
402: {
403: struct stat st;
404: if (fp->_jumps->__stat(fp, &st) == 0 && S_ISREG(st.st_mode))
405: {
406: offset += st.st_size;
407: dir = _IO_seek_set;
408: }
409: else
410: goto dumb;
411: }
412: }
413: /* At this point, dir==_IO_seek_set. */
414:
415: #ifdef TODO
416: /* If destination is within current buffer, optimize: */
417: if (fp->_offset != IO_pos_BAD && fp->_IO_read_base != NULL)
418: {
419: /* Offset relative to start of main get area. */
420: _IO_pos_t rel_offset = offset - _fb._offset
421: + (eGptr()-Gbase());
422: if (rel_offset >= 0)
423: {
424: if (_IO_in_backup(fp))
425: _IO_switch_to_main_get_area(fp);
426: if (rel_offset <= _IO_read_end - _IO_read_base)
427: {
428: _IO_setg(fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
429: fp->_IO_read_end);
430: _IO_setp(fp->_IO_buf_base, fp->_IO_buf_base);
431: return offset;
432: }
433: /* If we have streammarkers, seek forward by reading ahead. */
434: if (_IO_have_markers(fp))
435: {
436: int to_skip = rel_offset
437: - (fp->_IO_read_ptr - fp->_IO_read_base);
438: if (ignore(to_skip) != to_skip)
439: goto dumb;
440: return offset;
441: }
442: }
443: if (rel_offset < 0 && rel_offset >= Bbase() - Bptr())
444: {
445: if (!_IO_in_backup(fp))
446: _IO_switch_to_backup_area(fp);
447: gbump(fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
448: return offset;
449: }
450: }
451:
452: _IO_unsave_markers(fp);
453: #endif
454:
455: /* Try to seek to a block boundary, to improve kernel page management. */
456: new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
457: delta = offset - new_offset;
458: if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
459: {
460: new_offset = offset;
461: delta = 0;
462: }
463: result = fp->_jumps->__seek(fp, new_offset, 0);
464: if (result < 0)
465: return EOF;
466: if (delta == 0)
467: count = 0;
468: else
469: {
470: count = fp->_jumps->__read(fp, fp->_IO_buf_base,
471: fp->_IO_buf_end - fp->_IO_buf_base);
472: if (count < delta)
473: {
474: /* We weren't allowed to read, but try to seek the remainder. */
475: offset = count == EOF ? delta : delta-count;
476: dir = _IO_seek_cur;
477: goto dumb;
478: }
479: }
480: _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base+delta, fp->_IO_buf_base+count);
481: _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
482: fp->_offset = result + count;
483: _IO_mask_flags(fp, 0, _IO_EOF_SEEN);
484: return offset;
485: dumb:
486:
487: _IO_unsave_markers(fp);
488: result = fp->_jumps->__seek(fp, offset, dir);
489: if (result != EOF)
490: _IO_mask_flags(fp, 0, _IO_EOF_SEEN);
491: fp->_offset = result;
492: _IO_setg(fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
493: _IO_setp(fp, fp->_IO_buf_base, fp->_IO_buf_base);
494: return result;
495: }
496:
497: _IO_ssize_t
498: _IO_file_read(fp, buf, size)
499: register _IO_FILE* fp;
500: void* buf;
501: _IO_ssize_t size;
502: {
503: for (;;)
504: {
505: _IO_ssize_t count = _IO_read(fp->_fileno, buf, size);
506: #ifdef EINTR
507: if (errno == EINTR && count == -1)
508: continue;
509: #endif
510: return count;
511: }
512: }
513:
514: _IO_pos_t
515: _IO_file_seek(fp, offset, dir)
516: _IO_FILE *fp;
517: _IO_off_t offset;
518: int dir;
519: {
520: return _IO_lseek(fp->_fileno, offset, dir);
521: }
522:
523: int
524: _IO_file_stat(fp, st)
525: _IO_FILE *fp;
526: void* st;
527: {
528: return _IO_fstat(fp->_fileno, (struct stat*)st);
529: }
530:
531: int
532: _IO_file_close(fp)
533: _IO_FILE* fp;
534: {
535: return _IO_close(fp->_fileno);
536: }
537:
538: _IO_ssize_t
539: _IO_file_write(f, data, n)
540: register _IO_FILE* f;
541: const void* data;
542: _IO_ssize_t n;
543: {
544: _IO_ssize_t to_do = n;
545: while (to_do > 0)
546: {
547: _IO_ssize_t count = _IO_write(f->_fileno, data, to_do);
548: if (count == EOF)
549: {
550: #ifdef EINTR
551: if (errno == EINTR)
552: continue;
553: else
554: #endif
555: {
556: f->_flags |= _IO_ERR_SEEN;
557: break;
558: }
559: }
560: to_do -= count;
561: data = (void*)((char*)data + count);
562: }
563: n -= to_do;
564: if (f->_offset >= 0)
565: f->_offset += n;
566: return n;
567: }
568:
569: _IO_size_t
570: _IO_file_xsputn(f, data, n)
571: _IO_FILE *f;
572: const void *data;
573: _IO_size_t n;
574: {
575: register const char *s = data;
576: _IO_size_t to_do = n;
577: int must_flush = 0;
578: _IO_size_t count;
579:
580: if (n <= 0)
581: return 0;
582: /* This is an optimized implementation.
583: If the amount to be written straddles a block boundary
584: (or the filebuf is unbuffered), use sys_write directly. */
585:
586: /* First figure out how much space is available in the buffer. */
587: count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
588: if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
589: {
590: count = f->_IO_buf_end - f->_IO_write_ptr;
591: if (count >= n)
592: { register const char *p;
593: for (p = s + n; p > s; )
594: {
595: if (*--p == '\n') {
596: count = p - s + 1;
597: must_flush = 1;
598: break;
599: }
600: }
601: }
602: }
603: /* Then fill the buffer. */
604: if (count > 0)
605: {
606: if (count > to_do)
607: count = to_do;
608: if (count > 20) {
609: memcpy(f->_IO_write_ptr, s, count);
610: s += count;
611: }
612: else
613: {
614: register char *p = f->_IO_write_ptr;
615: register int i = (int)count;
616: while (--i >= 0) *p++ = *s++;
617: }
618: f->_IO_write_ptr += count;
619: to_do -= count;
620: }
621: if (to_do + must_flush > 0)
622: { _IO_size_t block_size, dont_write;
623: /* Next flush the (full) buffer. */
624: if (__overflow(f, EOF) == EOF)
625: return n - to_do;
626:
627: /* Try to maintain alignment: write a whole number of blocks.
628: dont_write is what gets left over. */
629: block_size = f->_IO_buf_end - f->_IO_buf_base;
630: dont_write = block_size >= 128 ? to_do % block_size : 0;
631:
632: count = to_do - dont_write;
633: if (_IO_do_write(f, s, count) == EOF)
634: return n - to_do;
635: to_do = dont_write;
636:
637: /* Now write out the remainder. Normally, this will fit in the
638: buffer, but it's somewhat messier for line-buffered files,
639: so we let _IO_xsputn handle the general case. */
640: if (dont_write)
641: to_do -= _IO_default_xsputn(f, s+count, dont_write);
642: }
643: return n - to_do;
644: }
645:
646: struct _IO_jump_t _IO_file_jumps = {
647: _IO_file_overflow,
648: _IO_file_underflow,
649: _IO_file_xsputn,
650: _IO_default_xsgetn,
651: _IO_file_read,
652: _IO_file_write,
653: _IO_file_doallocate,
654: _IO_default_pbackfail,
655: _IO_file_setbuf,
656: _IO_file_sync,
657: _IO_file_finish,
658: _IO_file_close,
659: _IO_file_stat,
660: _IO_file_seek,
661: _IO_file_seekoff,
662: _IO_default_seekpos,
663: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.