190792Sgshapiro/* 2261363Sgshapiro * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * Copyright (c) 1990, 1993 590792Sgshapiro * The Regents of the University of California. All rights reserved. 690792Sgshapiro * 790792Sgshapiro * This code is derived from software contributed to Berkeley by 890792Sgshapiro * Chris Torek. 990792Sgshapiro * 1090792Sgshapiro * By using this file, you agree to the terms and conditions set 1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of 1290792Sgshapiro * the sendmail distribution. 1390792Sgshapiro */ 1490792Sgshapiro 1590792Sgshapiro#include <sm/gen.h> 16266692SgshapiroSM_IDSTR(id, "@(#)$Id: ungetc.c,v 1.31 2013-11-22 20:51:44 ca Exp $") 1790792Sgshapiro 1890792Sgshapiro#include <stdlib.h> 1990792Sgshapiro#include <string.h> 2090792Sgshapiro#include <signal.h> 21157001Sgshapiro#include <sm/time.h> 2290792Sgshapiro#include <errno.h> 2390792Sgshapiro#include <sm/io.h> 2490792Sgshapiro#include <sm/heap.h> 2590792Sgshapiro#include <sm/assert.h> 2690792Sgshapiro#include <sm/conf.h> 2790792Sgshapiro#include "local.h" 2890792Sgshapiro 29141858Sgshapirostatic void sm_submore_x __P((SM_FILE_T *)); 30141858Sgshapiro 3190792Sgshapiro/* 3290792Sgshapiro** SM_SUBMORE_X -- expand ungetc buffer 3390792Sgshapiro** 3490792Sgshapiro** Expand the ungetc buffer `in place'. That is, adjust fp->f_p when 3590792Sgshapiro** the buffer moves, so that it points the same distance from the end, 3690792Sgshapiro** and move the bytes in the buffer around as necessary so that they 3790792Sgshapiro** are all at the end (stack-style). 3890792Sgshapiro** 3990792Sgshapiro** Parameters: 4090792Sgshapiro** fp -- the file pointer 4190792Sgshapiro** 4290792Sgshapiro** Results: 4390792Sgshapiro** none. 4490792Sgshapiro** 4590792Sgshapiro** Exceptions: 4690792Sgshapiro** F:sm_heap -- out of memory 4790792Sgshapiro*/ 4890792Sgshapiro 4990792Sgshapirostatic void 5090792Sgshapirosm_submore_x(fp) 51141858Sgshapiro SM_FILE_T *fp; 5290792Sgshapiro{ 5390792Sgshapiro register int i; 5490792Sgshapiro register unsigned char *p; 5590792Sgshapiro 5690792Sgshapiro if (fp->f_ub.smb_base == fp->f_ubuf) 5790792Sgshapiro { 5890792Sgshapiro /* Get a buffer; f_ubuf is fixed size. */ 5990792Sgshapiro p = sm_malloc_x((size_t) SM_IO_BUFSIZ); 6090792Sgshapiro fp->f_ub.smb_base = p; 6190792Sgshapiro fp->f_ub.smb_size = SM_IO_BUFSIZ; 6290792Sgshapiro p += SM_IO_BUFSIZ - sizeof(fp->f_ubuf); 6390792Sgshapiro for (i = sizeof(fp->f_ubuf); --i >= 0;) 6490792Sgshapiro p[i] = fp->f_ubuf[i]; 6590792Sgshapiro fp->f_p = p; 6690792Sgshapiro return; 6790792Sgshapiro } 6890792Sgshapiro i = fp->f_ub.smb_size; 6990792Sgshapiro p = sm_realloc_x(fp->f_ub.smb_base, i << 1); 7090792Sgshapiro 7190792Sgshapiro /* no overlap (hence can use memcpy) because we doubled the size */ 7290792Sgshapiro (void) memcpy((void *) (p + i), (void *) p, (size_t) i); 7390792Sgshapiro fp->f_p = p + i; 7490792Sgshapiro fp->f_ub.smb_base = p; 7590792Sgshapiro fp->f_ub.smb_size = i << 1; 7690792Sgshapiro} 7790792Sgshapiro 7890792Sgshapiro/* 7990792Sgshapiro** SM_IO_UNGETC -- place a character back into the buffer just read 8090792Sgshapiro** 8190792Sgshapiro** Parameters: 8290792Sgshapiro** fp -- the file pointer affected 8390792Sgshapiro** timeout -- time to complete ungetc 8490792Sgshapiro** c -- the character to place back 8590792Sgshapiro** 8690792Sgshapiro** Results: 8790792Sgshapiro** On success, returns value of character placed back, 0-255. 8890792Sgshapiro** Returns SM_IO_EOF if c == SM_IO_EOF or if last operation 8990792Sgshapiro** was a write and flush failed. 9090792Sgshapiro** 9190792Sgshapiro** Exceptions: 9290792Sgshapiro** F:sm_heap -- out of memory 9390792Sgshapiro*/ 9490792Sgshapiro 9590792Sgshapiroint 9690792Sgshapirosm_io_ungetc(fp, timeout, c) 9790792Sgshapiro register SM_FILE_T *fp; 9890792Sgshapiro int timeout; 9990792Sgshapiro int c; 10090792Sgshapiro{ 10190792Sgshapiro SM_REQUIRE_ISA(fp, SmFileMagic); 10290792Sgshapiro if (c == SM_IO_EOF) 10390792Sgshapiro return SM_IO_EOF; 10490792Sgshapiro if (timeout == SM_TIME_IMMEDIATE) 10590792Sgshapiro { 10690792Sgshapiro /* 10790792Sgshapiro ** Ungetting the buffer will take time and we are wanted to 10890792Sgshapiro ** return immediately. So... 10990792Sgshapiro */ 11090792Sgshapiro 11190792Sgshapiro errno = EAGAIN; 11290792Sgshapiro return SM_IO_EOF; 11390792Sgshapiro } 11490792Sgshapiro 11590792Sgshapiro if (!Sm_IO_DidInit) 11690792Sgshapiro sm_init(); 11790792Sgshapiro if ((fp->f_flags & SMRD) == 0) 11890792Sgshapiro { 11990792Sgshapiro /* 12090792Sgshapiro ** Not already reading: no good unless reading-and-writing. 12190792Sgshapiro ** Otherwise, flush any current write stuff. 12290792Sgshapiro */ 12390792Sgshapiro 12490792Sgshapiro if ((fp->f_flags & SMRW) == 0) 12590792Sgshapiro return SM_IO_EOF; 12690792Sgshapiro if (fp->f_flags & SMWR) 12790792Sgshapiro { 12890792Sgshapiro if (sm_flush(fp, &timeout)) 12990792Sgshapiro return SM_IO_EOF; 13090792Sgshapiro fp->f_flags &= ~SMWR; 13190792Sgshapiro fp->f_w = 0; 13290792Sgshapiro fp->f_lbfsize = 0; 13390792Sgshapiro } 13490792Sgshapiro fp->f_flags |= SMRD; 13590792Sgshapiro } 13690792Sgshapiro c = (unsigned char) c; 13790792Sgshapiro 13890792Sgshapiro /* 13990792Sgshapiro ** If we are in the middle of ungetc'ing, just continue. 14090792Sgshapiro ** This may require expanding the current ungetc buffer. 14190792Sgshapiro */ 14290792Sgshapiro 14390792Sgshapiro if (HASUB(fp)) 14490792Sgshapiro { 14590792Sgshapiro if (fp->f_r >= fp->f_ub.smb_size) 14690792Sgshapiro sm_submore_x(fp); 14790792Sgshapiro *--fp->f_p = c; 14890792Sgshapiro fp->f_r++; 14990792Sgshapiro return c; 15090792Sgshapiro } 15190792Sgshapiro fp->f_flags &= ~SMFEOF; 15290792Sgshapiro 15390792Sgshapiro /* 15490792Sgshapiro ** If we can handle this by simply backing up, do so, 15590792Sgshapiro ** but never replace the original character. 15690792Sgshapiro ** (This makes sscanf() work when scanning `const' data.) 15790792Sgshapiro */ 15890792Sgshapiro 15990792Sgshapiro if (fp->f_bf.smb_base != NULL && fp->f_p > fp->f_bf.smb_base && 16090792Sgshapiro fp->f_p[-1] == c) 16190792Sgshapiro { 16290792Sgshapiro fp->f_p--; 16390792Sgshapiro fp->f_r++; 16490792Sgshapiro return c; 16590792Sgshapiro } 16690792Sgshapiro 16790792Sgshapiro /* 16890792Sgshapiro ** Create an ungetc buffer. 16990792Sgshapiro ** Initially, we will use the `reserve' buffer. 17090792Sgshapiro */ 17190792Sgshapiro 17290792Sgshapiro fp->f_ur = fp->f_r; 17390792Sgshapiro fp->f_up = fp->f_p; 17490792Sgshapiro fp->f_ub.smb_base = fp->f_ubuf; 17590792Sgshapiro fp->f_ub.smb_size = sizeof(fp->f_ubuf); 17690792Sgshapiro fp->f_ubuf[sizeof(fp->f_ubuf) - 1] = c; 17790792Sgshapiro fp->f_p = &fp->f_ubuf[sizeof(fp->f_ubuf) - 1]; 17890792Sgshapiro fp->f_r = 1; 17990792Sgshapiro 18090792Sgshapiro return c; 18190792Sgshapiro} 182