ungetc.c revision 266527
1147997Srwatson/* 2147997Srwatson * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers. 3147997Srwatson * All rights reserved. 4147997Srwatson * Copyright (c) 1990, 1993 5147997Srwatson * The Regents of the University of California. All rights reserved. 6147997Srwatson * 7147997Srwatson * This code is derived from software contributed to Berkeley by 8147997Srwatson * Chris Torek. 9147997Srwatson * 10147997Srwatson * By using this file, you agree to the terms and conditions set 11147997Srwatson * forth in the LICENSE file which can be found at the top level of 12147997Srwatson * the sendmail distribution. 13147997Srwatson */ 14147997Srwatson 15147997Srwatson#include <sm/gen.h> 16147997SrwatsonSM_IDSTR(id, "@(#)$Id: ungetc.c,v 1.31 2013-11-22 20:51:44 ca Exp $") 17147997Srwatson 18147997Srwatson#include <stdlib.h> 19147997Srwatson#include <string.h> 20147997Srwatson#include <signal.h> 21147997Srwatson#include <sm/time.h> 22147997Srwatson#include <errno.h> 23147997Srwatson#include <sm/io.h> 24147997Srwatson#include <sm/heap.h> 25147997Srwatson#include <sm/assert.h> 26147997Srwatson#include <sm/conf.h> 27261726Sglebius#include "local.h" 28206622Suqs 29147997Srwatsonstatic void sm_submore_x __P((SM_FILE_T *)); 30147997Srwatson 31147997Srwatson/* 32147997Srwatson** SM_SUBMORE_X -- expand ungetc buffer 33147997Srwatson** 34147997Srwatson** Expand the ungetc buffer `in place'. That is, adjust fp->f_p when 35147997Srwatson** the buffer moves, so that it points the same distance from the end, 36147997Srwatson** and move the bytes in the buffer around as necessary so that they 37147997Srwatson** are all at the end (stack-style). 38148359Srwatson** 39152650Sru** Parameters: 40148359Srwatson** fp -- the file pointer 41147997Srwatson** 42152650Sru** Results: 43147997Srwatson** none. 44152650Sru** 45147997Srwatson** Exceptions: 46152650Sru** F:sm_heap -- out of memory 47147997Srwatson*/ 48152650Sru 49152650Srustatic void 50152650Srusm_submore_x(fp) 51152650Sru SM_FILE_T *fp; 52147997Srwatson{ 53147997Srwatson register int i; 54148358Srwatson register unsigned char *p; 55148358Srwatson 56147997Srwatson if (fp->f_ub.smb_base == fp->f_ubuf) 57147997Srwatson { 58148789Srwatson /* Get a buffer; f_ubuf is fixed size. */ 59148789Srwatson p = sm_malloc_x((size_t) SM_IO_BUFSIZ); 60148789Srwatson fp->f_ub.smb_base = p; 61148789Srwatson fp->f_ub.smb_size = SM_IO_BUFSIZ; 62148627Srwatson p += SM_IO_BUFSIZ - sizeof(fp->f_ubuf); 63148627Srwatson for (i = sizeof(fp->f_ubuf); --i >= 0;) 64147997Srwatson p[i] = fp->f_ubuf[i]; 65147997Srwatson fp->f_p = p; 66147997Srwatson return; 67147997Srwatson } 68147997Srwatson i = fp->f_ub.smb_size; 69147997Srwatson p = sm_realloc_x(fp->f_ub.smb_base, i << 1); 70152650Sru 71147997Srwatson /* no overlap (hence can use memcpy) because we doubled the size */ 72147997Srwatson (void) memcpy((void *) (p + i), (void *) p, (size_t) i); 73147997Srwatson fp->f_p = p + i; 74147997Srwatson fp->f_ub.smb_base = p; 75147997Srwatson fp->f_ub.smb_size = i << 1; 76147997Srwatson} 77147997Srwatson 78147997Srwatson/* 79147997Srwatson** SM_IO_UNGETC -- place a character back into the buffer just read 80147997Srwatson** 81147997Srwatson** Parameters: 82147997Srwatson** fp -- the file pointer affected 83261726Sglebius** timeout -- time to complete ungetc 84261726Sglebius** c -- the character to place back 85147997Srwatson** 86147997Srwatson** Results: 87147997Srwatson** On success, returns value of character placed back, 0-255. 88147997Srwatson** Returns SM_IO_EOF if c == SM_IO_EOF or if last operation 89147997Srwatson** was a write and flush failed. 90147997Srwatson** 91147997Srwatson** Exceptions: 92147997Srwatson** F:sm_heap -- out of memory 93147997Srwatson*/ 94147997Srwatson 95147997Srwatsonint 96147997Srwatsonsm_io_ungetc(fp, timeout, c) 97147997Srwatson register SM_FILE_T *fp; 98147997Srwatson int timeout; 99147997Srwatson int c; 100152650Sru{ 101147997Srwatson SM_REQUIRE_ISA(fp, SmFileMagic); 102147997Srwatson if (c == SM_IO_EOF) 103152650Sru return SM_IO_EOF; 104152650Sru if (timeout == SM_TIME_IMMEDIATE) 105152650Sru { 106147997Srwatson /* 107147997Srwatson ** Ungetting the buffer will take time and we are wanted to 108147997Srwatson ** return immediately. So... 109152650Sru */ 110152650Sru 111152650Sru errno = EAGAIN; 112147997Srwatson return SM_IO_EOF; 113147997Srwatson } 114147997Srwatson 115148170Srwatson if (!Sm_IO_DidInit) 116148170Srwatson sm_init(); 117147997Srwatson if ((fp->f_flags & SMRD) == 0) 118147997Srwatson { 119147997Srwatson /* 120147997Srwatson ** Not already reading: no good unless reading-and-writing. 121147997Srwatson ** Otherwise, flush any current write stuff. 122147997Srwatson */ 123147997Srwatson 124147997Srwatson if ((fp->f_flags & SMRW) == 0) 125147997Srwatson return SM_IO_EOF; 126152650Sru if (fp->f_flags & SMWR) 127152650Sru { 128152650Sru if (sm_flush(fp, &timeout)) 129152650Sru return SM_IO_EOF; 130147997Srwatson fp->f_flags &= ~SMWR; 131152650Sru fp->f_w = 0; 132152650Sru fp->f_lbfsize = 0; 133152650Sru } 134147997Srwatson fp->f_flags |= SMRD; 135152650Sru } 136152650Sru c = (unsigned char) c; 137152650Sru 138147997Srwatson /* 139152650Sru ** If we are in the middle of ungetc'ing, just continue. 140152650Sru ** This may require expanding the current ungetc buffer. 141152650Sru */ 142147997Srwatson 143147997Srwatson if (HASUB(fp)) 144147997Srwatson { 145147997Srwatson if (fp->f_r >= fp->f_ub.smb_size) 146147997Srwatson sm_submore_x(fp); 147147997Srwatson *--fp->f_p = c; 148147997Srwatson fp->f_r++; 149147997Srwatson return c; 150147997Srwatson } 151147997Srwatson fp->f_flags &= ~SMFEOF; 152147997Srwatson 153147997Srwatson /* 154147997Srwatson ** If we can handle this by simply backing up, do so, 155147997Srwatson ** but never replace the original character. 156152650Sru ** (This makes sscanf() work when scanning `const' data.) 157147997Srwatson */ 158147997Srwatson 159147997Srwatson if (fp->f_bf.smb_base != NULL && fp->f_p > fp->f_bf.smb_base && 160147997Srwatson fp->f_p[-1] == c) 161152650Sru { 162147997Srwatson fp->f_p--; 163152650Sru fp->f_r++; 164147997Srwatson return c; 165147997Srwatson } 166147997Srwatson 167147997Srwatson /* 168147997Srwatson ** Create an ungetc buffer. 169147997Srwatson ** Initially, we will use the `reserve' buffer. 170148789Srwatson */ 171148789Srwatson 172148627Srwatson fp->f_ur = fp->f_r; 173147997Srwatson fp->f_up = fp->f_p; 174147997Srwatson fp->f_ub.smb_base = fp->f_ubuf; 175147997Srwatson fp->f_ub.smb_size = sizeof(fp->f_ubuf); 176147997Srwatson fp->f_ubuf[sizeof(fp->f_ubuf) - 1] = c; 177147997Srwatson fp->f_p = &fp->f_ubuf[sizeof(fp->f_ubuf) - 1]; 178147997Srwatson fp->f_r = 1; 179148358Srwatson 180148358Srwatson return c; 181148359Srwatson} 182148359Srwatson