1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)ungetc.c 5.6 (Berkeley) 05/04/91"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include "local.h" 19 20 /* 21 * Expand the ungetc buffer `in place'. That is, adjust fp->_p when 22 * the buffer moves, so that it points the same distance from the end, 23 * and move the bytes in the buffer around as necessary so that they 24 * are all at the end (stack-style). 25 */ 26 static 27 __submore(fp) 28 register FILE *fp; 29 { 30 register int i; 31 register unsigned char *p; 32 33 if (fp->_ub._base == fp->_ubuf) { 34 /* 35 * Get a new buffer (rather than expanding the old one). 36 */ 37 if ((p = malloc((size_t)BUFSIZ)) == NULL) 38 return (EOF); 39 fp->_ub._base = p; 40 fp->_ub._size = BUFSIZ; 41 p += BUFSIZ - sizeof(fp->_ubuf); 42 for (i = sizeof(fp->_ubuf); --i >= 0;) 43 p[i] = fp->_ubuf[i]; 44 fp->_p = p; 45 return (0); 46 } 47 i = fp->_ub._size; 48 p = realloc(fp->_ub._base, i << 1); 49 if (p == NULL) 50 return (EOF); 51 (void) bcopy((void *)p, (void *)(p + i), (size_t)i); 52 fp->_p = p + i; 53 fp->_ub._base = p; 54 fp->_ub._size = i << 1; 55 return (0); 56 } 57 58 ungetc(c, fp) 59 int c; 60 register FILE *fp; 61 { 62 if (c == EOF) 63 return (EOF); 64 if (!__sdidinit) 65 __sinit(); 66 if ((fp->_flags & __SRD) == 0) { 67 /* 68 * Not already reading: no good unless reading-and-writing. 69 * Otherwise, flush any current write stuff. 70 */ 71 if ((fp->_flags & __SRW) == 0) 72 return (EOF); 73 if (fp->_flags & __SWR) { 74 if (__sflush(fp)) 75 return (EOF); 76 fp->_flags &= ~__SWR; 77 fp->_w = 0; 78 fp->_lbfsize = 0; 79 } 80 fp->_flags |= __SRD; 81 } 82 c = (unsigned char)c; 83 84 /* 85 * If we are in the middle of ungetc'ing, just continue. 86 * This may require expanding the current ungetc buffer. 87 */ 88 if (HASUB(fp)) { 89 if (fp->_r >= fp->_ub._size && __submore(fp)) 90 return (EOF); 91 *--fp->_p = c; 92 fp->_r++; 93 return (c); 94 } 95 96 /* 97 * If we can handle this by simply backing up, do so, 98 * but never replace the original character. 99 * (This makes sscanf() work when scanning `const' data.) 100 */ 101 if (fp->_bf._base != NULL && fp->_p > fp->_bf._base && 102 fp->_p[-1] == c) { 103 fp->_p--; 104 fp->_r++; 105 return (c); 106 } 107 108 /* 109 * Create an ungetc buffer. 110 * Initially, we will use the `reserve' buffer. 111 */ 112 fp->_ur = fp->_r; 113 fp->_up = fp->_p; 114 fp->_ub._base = fp->_ubuf; 115 fp->_ub._size = sizeof(fp->_ubuf); 116 fp->_ubuf[sizeof(fp->_ubuf) - 1] = c; 117 fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1]; 118 fp->_r = 1; 119 return (c); 120 } 121