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> 18SM_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 31static 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 51static void 52sm_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 97int 98sm_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