1 /* 2 * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * By using this file, you agree to the terms and conditions set 11 * forth in the LICENSE file which can be found at the top level of 12 * the sendmail distribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include <sm/gen.h> 18 SM_IDSTR(id, "@(#)$Id: ungetc.c,v 1.30 2005/06/14 23:07:20 ca Exp $") 19 20 #include <stdlib.h> 21 #include <string.h> 22 #include <signal.h> 23 #include <sm/time.h> 24 #include <errno.h> 25 #include <sm/io.h> 26 #include <sm/heap.h> 27 #include <sm/assert.h> 28 #include <sm/conf.h> 29 #include "local.h" 30 31 static void sm_submore_x __P((SM_FILE_T *)); 32 33 /* 34 ** SM_SUBMORE_X -- expand ungetc buffer 35 ** 36 ** Expand the ungetc buffer `in place'. That is, adjust fp->f_p when 37 ** the buffer moves, so that it points the same distance from the end, 38 ** and move the bytes in the buffer around as necessary so that they 39 ** are all at the end (stack-style). 40 ** 41 ** Parameters: 42 ** fp -- the file pointer 43 ** 44 ** Results: 45 ** none. 46 ** 47 ** Exceptions: 48 ** F:sm_heap -- out of memory 49 */ 50 51 static void 52 sm_submore_x(fp) 53 SM_FILE_T *fp; 54 { 55 register int i; 56 register unsigned char *p; 57 58 if (fp->f_ub.smb_base == fp->f_ubuf) 59 { 60 /* Get a buffer; f_ubuf is fixed size. */ 61 p = sm_malloc_x((size_t) SM_IO_BUFSIZ); 62 fp->f_ub.smb_base = p; 63 fp->f_ub.smb_size = SM_IO_BUFSIZ; 64 p += SM_IO_BUFSIZ - sizeof(fp->f_ubuf); 65 for (i = sizeof(fp->f_ubuf); --i >= 0;) 66 p[i] = fp->f_ubuf[i]; 67 fp->f_p = p; 68 return; 69 } 70 i = fp->f_ub.smb_size; 71 p = sm_realloc_x(fp->f_ub.smb_base, i << 1); 72 73 /* no overlap (hence can use memcpy) because we doubled the size */ 74 (void) memcpy((void *) (p + i), (void *) p, (size_t) i); 75 fp->f_p = p + i; 76 fp->f_ub.smb_base = p; 77 fp->f_ub.smb_size = i << 1; 78 } 79 80 /* 81 ** SM_IO_UNGETC -- place a character back into the buffer just read 82 ** 83 ** Parameters: 84 ** fp -- the file pointer affected 85 ** timeout -- time to complete ungetc 86 ** c -- the character to place back 87 ** 88 ** Results: 89 ** On success, returns value of character placed back, 0-255. 90 ** Returns SM_IO_EOF if c == SM_IO_EOF or if last operation 91 ** was a write and flush failed. 92 ** 93 ** Exceptions: 94 ** F:sm_heap -- out of memory 95 */ 96 97 int 98 sm_io_ungetc(fp, timeout, c) 99 register SM_FILE_T *fp; 100 int timeout; 101 int c; 102 { 103 SM_REQUIRE_ISA(fp, SmFileMagic); 104 if (c == SM_IO_EOF) 105 return SM_IO_EOF; 106 if (timeout == SM_TIME_IMMEDIATE) 107 { 108 /* 109 ** Ungetting the buffer will take time and we are wanted to 110 ** return immediately. So... 111 */ 112 113 errno = EAGAIN; 114 return SM_IO_EOF; 115 } 116 117 if (!Sm_IO_DidInit) 118 sm_init(); 119 if ((fp->f_flags & SMRD) == 0) 120 { 121 /* 122 ** Not already reading: no good unless reading-and-writing. 123 ** Otherwise, flush any current write stuff. 124 */ 125 126 if ((fp->f_flags & SMRW) == 0) 127 return SM_IO_EOF; 128 if (fp->f_flags & SMWR) 129 { 130 if (sm_flush(fp, &timeout)) 131 return SM_IO_EOF; 132 fp->f_flags &= ~SMWR; 133 fp->f_w = 0; 134 fp->f_lbfsize = 0; 135 } 136 fp->f_flags |= SMRD; 137 } 138 c = (unsigned char) c; 139 140 /* 141 ** If we are in the middle of ungetc'ing, just continue. 142 ** This may require expanding the current ungetc buffer. 143 */ 144 145 if (HASUB(fp)) 146 { 147 if (fp->f_r >= fp->f_ub.smb_size) 148 sm_submore_x(fp); 149 *--fp->f_p = c; 150 fp->f_r++; 151 return c; 152 } 153 fp->f_flags &= ~SMFEOF; 154 155 /* 156 ** If we can handle this by simply backing up, do so, 157 ** but never replace the original character. 158 ** (This makes sscanf() work when scanning `const' data.) 159 */ 160 161 if (fp->f_bf.smb_base != NULL && fp->f_p > fp->f_bf.smb_base && 162 fp->f_p[-1] == c) 163 { 164 fp->f_p--; 165 fp->f_r++; 166 return c; 167 } 168 169 /* 170 ** Create an ungetc buffer. 171 ** Initially, we will use the `reserve' buffer. 172 */ 173 174 fp->f_ur = fp->f_r; 175 fp->f_up = fp->f_p; 176 fp->f_ub.smb_base = fp->f_ubuf; 177 fp->f_ub.smb_size = sizeof(fp->f_ubuf); 178 fp->f_ubuf[sizeof(fp->f_ubuf) - 1] = c; 179 fp->f_p = &fp->f_ubuf[sizeof(fp->f_ubuf) - 1]; 180 fp->f_r = 1; 181 182 return c; 183 } 184