xref: /freebsd/contrib/sendmail/libsm/ungetc.c (revision 4e4196cb)
140266059SGregory Neil Shapiro /*
2b6bacd31SGregory Neil Shapiro  * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers.
340266059SGregory Neil Shapiro  *      All rights reserved.
440266059SGregory Neil Shapiro  * Copyright (c) 1990, 1993
540266059SGregory Neil Shapiro  *	The Regents of the University of California.  All rights reserved.
640266059SGregory Neil Shapiro  *
740266059SGregory Neil Shapiro  * This code is derived from software contributed to Berkeley by
840266059SGregory Neil Shapiro  * Chris Torek.
940266059SGregory Neil Shapiro  *
1040266059SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
1140266059SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
1240266059SGregory Neil Shapiro  * the sendmail distribution.
1340266059SGregory Neil Shapiro  */
1440266059SGregory Neil Shapiro 
1540266059SGregory Neil Shapiro #include <sm/gen.h>
164e4196cbSGregory Neil Shapiro SM_IDSTR(id, "@(#)$Id: ungetc.c,v 1.31 2013-11-22 20:51:44 ca Exp $")
1740266059SGregory Neil Shapiro 
1840266059SGregory Neil Shapiro #include <stdlib.h>
1940266059SGregory Neil Shapiro #include <string.h>
2040266059SGregory Neil Shapiro #include <signal.h>
214e4196cbSGregory Neil Shapiro #include <sm/time.h>
2240266059SGregory Neil Shapiro #include <errno.h>
2340266059SGregory Neil Shapiro #include <sm/io.h>
2440266059SGregory Neil Shapiro #include <sm/heap.h>
2540266059SGregory Neil Shapiro #include <sm/assert.h>
2640266059SGregory Neil Shapiro #include <sm/conf.h>
2740266059SGregory Neil Shapiro #include "local.h"
2840266059SGregory Neil Shapiro 
29b6bacd31SGregory Neil Shapiro static void	sm_submore_x __P((SM_FILE_T *));
30b6bacd31SGregory Neil Shapiro 
3140266059SGregory Neil Shapiro /*
3240266059SGregory Neil Shapiro **  SM_SUBMORE_X -- expand ungetc buffer
3340266059SGregory Neil Shapiro **
3440266059SGregory Neil Shapiro **  Expand the ungetc buffer `in place'.  That is, adjust fp->f_p when
3540266059SGregory Neil Shapiro **  the buffer moves, so that it points the same distance from the end,
3640266059SGregory Neil Shapiro **  and move the bytes in the buffer around as necessary so that they
3740266059SGregory Neil Shapiro **  are all at the end (stack-style).
3840266059SGregory Neil Shapiro **
3940266059SGregory Neil Shapiro **	Parameters:
4040266059SGregory Neil Shapiro **		fp -- the file pointer
4140266059SGregory Neil Shapiro **
4240266059SGregory Neil Shapiro **	Results:
4340266059SGregory Neil Shapiro **		none.
4440266059SGregory Neil Shapiro **
4540266059SGregory Neil Shapiro **	Exceptions:
4640266059SGregory Neil Shapiro **		F:sm_heap -- out of memory
4740266059SGregory Neil Shapiro */
4840266059SGregory Neil Shapiro 
4940266059SGregory Neil Shapiro static void
sm_submore_x(fp)5040266059SGregory Neil Shapiro sm_submore_x(fp)
51b6bacd31SGregory Neil Shapiro 	SM_FILE_T *fp;
5240266059SGregory Neil Shapiro {
5340266059SGregory Neil Shapiro 	register int i;
5440266059SGregory Neil Shapiro 	register unsigned char *p;
5540266059SGregory Neil Shapiro 
5640266059SGregory Neil Shapiro 	if (fp->f_ub.smb_base == fp->f_ubuf)
5740266059SGregory Neil Shapiro 	{
5840266059SGregory Neil Shapiro 		/* Get a buffer; f_ubuf is fixed size. */
5940266059SGregory Neil Shapiro 		p = sm_malloc_x((size_t) SM_IO_BUFSIZ);
6040266059SGregory Neil Shapiro 		fp->f_ub.smb_base = p;
6140266059SGregory Neil Shapiro 		fp->f_ub.smb_size = SM_IO_BUFSIZ;
6240266059SGregory Neil Shapiro 		p += SM_IO_BUFSIZ - sizeof(fp->f_ubuf);
6340266059SGregory Neil Shapiro 		for (i = sizeof(fp->f_ubuf); --i >= 0;)
6440266059SGregory Neil Shapiro 			p[i] = fp->f_ubuf[i];
6540266059SGregory Neil Shapiro 		fp->f_p = p;
6640266059SGregory Neil Shapiro 		return;
6740266059SGregory Neil Shapiro 	}
6840266059SGregory Neil Shapiro 	i = fp->f_ub.smb_size;
6940266059SGregory Neil Shapiro 	p = sm_realloc_x(fp->f_ub.smb_base, i << 1);
7040266059SGregory Neil Shapiro 
7140266059SGregory Neil Shapiro 	/* no overlap (hence can use memcpy) because we doubled the size */
7240266059SGregory Neil Shapiro 	(void) memcpy((void *) (p + i), (void *) p, (size_t) i);
7340266059SGregory Neil Shapiro 	fp->f_p = p + i;
7440266059SGregory Neil Shapiro 	fp->f_ub.smb_base = p;
7540266059SGregory Neil Shapiro 	fp->f_ub.smb_size = i << 1;
7640266059SGregory Neil Shapiro }
7740266059SGregory Neil Shapiro 
7840266059SGregory Neil Shapiro /*
7940266059SGregory Neil Shapiro **  SM_IO_UNGETC -- place a character back into the buffer just read
8040266059SGregory Neil Shapiro **
8140266059SGregory Neil Shapiro **	Parameters:
8240266059SGregory Neil Shapiro **		fp -- the file pointer affected
8340266059SGregory Neil Shapiro **		timeout -- time to complete ungetc
8440266059SGregory Neil Shapiro **		c -- the character to place back
8540266059SGregory Neil Shapiro **
8640266059SGregory Neil Shapiro **	Results:
8740266059SGregory Neil Shapiro **		On success, returns value of character placed back, 0-255.
8840266059SGregory Neil Shapiro **		Returns SM_IO_EOF if c == SM_IO_EOF or if last operation
8940266059SGregory Neil Shapiro **		was a write and flush failed.
9040266059SGregory Neil Shapiro **
9140266059SGregory Neil Shapiro **	Exceptions:
9240266059SGregory Neil Shapiro **		F:sm_heap -- out of memory
9340266059SGregory Neil Shapiro */
9440266059SGregory Neil Shapiro 
9540266059SGregory Neil Shapiro int
sm_io_ungetc(fp,timeout,c)9640266059SGregory Neil Shapiro sm_io_ungetc(fp, timeout, c)
9740266059SGregory Neil Shapiro 	register SM_FILE_T *fp;
9840266059SGregory Neil Shapiro 	int timeout;
9940266059SGregory Neil Shapiro 	int c;
10040266059SGregory Neil Shapiro {
10140266059SGregory Neil Shapiro 	SM_REQUIRE_ISA(fp, SmFileMagic);
10240266059SGregory Neil Shapiro 	if (c == SM_IO_EOF)
10340266059SGregory Neil Shapiro 		return SM_IO_EOF;
10440266059SGregory Neil Shapiro 	if (timeout == SM_TIME_IMMEDIATE)
10540266059SGregory Neil Shapiro 	{
10640266059SGregory Neil Shapiro 		/*
10740266059SGregory Neil Shapiro 		**  Ungetting the buffer will take time and we are wanted to
10840266059SGregory Neil Shapiro 		**  return immediately. So...
10940266059SGregory Neil Shapiro 		*/
11040266059SGregory Neil Shapiro 
11140266059SGregory Neil Shapiro 		errno = EAGAIN;
11240266059SGregory Neil Shapiro 		return SM_IO_EOF;
11340266059SGregory Neil Shapiro 	}
11440266059SGregory Neil Shapiro 
11540266059SGregory Neil Shapiro 	if (!Sm_IO_DidInit)
11640266059SGregory Neil Shapiro 		sm_init();
11740266059SGregory Neil Shapiro 	if ((fp->f_flags & SMRD) == 0)
11840266059SGregory Neil Shapiro 	{
11940266059SGregory Neil Shapiro 		/*
12040266059SGregory Neil Shapiro 		**  Not already reading: no good unless reading-and-writing.
12140266059SGregory Neil Shapiro 		**  Otherwise, flush any current write stuff.
12240266059SGregory Neil Shapiro 		*/
12340266059SGregory Neil Shapiro 
12440266059SGregory Neil Shapiro 		if ((fp->f_flags & SMRW) == 0)
12540266059SGregory Neil Shapiro 			return SM_IO_EOF;
12640266059SGregory Neil Shapiro 		if (fp->f_flags & SMWR)
12740266059SGregory Neil Shapiro 		{
12840266059SGregory Neil Shapiro 			if (sm_flush(fp, &timeout))
12940266059SGregory Neil Shapiro 				return SM_IO_EOF;
13040266059SGregory Neil Shapiro 			fp->f_flags &= ~SMWR;
13140266059SGregory Neil Shapiro 			fp->f_w = 0;
13240266059SGregory Neil Shapiro 			fp->f_lbfsize = 0;
13340266059SGregory Neil Shapiro 		}
13440266059SGregory Neil Shapiro 		fp->f_flags |= SMRD;
13540266059SGregory Neil Shapiro 	}
13640266059SGregory Neil Shapiro 	c = (unsigned char) c;
13740266059SGregory Neil Shapiro 
13840266059SGregory Neil Shapiro 	/*
13940266059SGregory Neil Shapiro 	**  If we are in the middle of ungetc'ing, just continue.
14040266059SGregory Neil Shapiro 	**  This may require expanding the current ungetc buffer.
14140266059SGregory Neil Shapiro 	*/
14240266059SGregory Neil Shapiro 
14340266059SGregory Neil Shapiro 	if (HASUB(fp))
14440266059SGregory Neil Shapiro 	{
14540266059SGregory Neil Shapiro 		if (fp->f_r >= fp->f_ub.smb_size)
14640266059SGregory Neil Shapiro 			sm_submore_x(fp);
14740266059SGregory Neil Shapiro 		*--fp->f_p = c;
14840266059SGregory Neil Shapiro 		fp->f_r++;
14940266059SGregory Neil Shapiro 		return c;
15040266059SGregory Neil Shapiro 	}
15140266059SGregory Neil Shapiro 	fp->f_flags &= ~SMFEOF;
15240266059SGregory Neil Shapiro 
15340266059SGregory Neil Shapiro 	/*
15440266059SGregory Neil Shapiro 	**  If we can handle this by simply backing up, do so,
15540266059SGregory Neil Shapiro 	**  but never replace the original character.
15640266059SGregory Neil Shapiro 	**  (This makes sscanf() work when scanning `const' data.)
15740266059SGregory Neil Shapiro 	*/
15840266059SGregory Neil Shapiro 
15940266059SGregory Neil Shapiro 	if (fp->f_bf.smb_base != NULL && fp->f_p > fp->f_bf.smb_base &&
16040266059SGregory Neil Shapiro 	    fp->f_p[-1] == c)
16140266059SGregory Neil Shapiro 	{
16240266059SGregory Neil Shapiro 		fp->f_p--;
16340266059SGregory Neil Shapiro 		fp->f_r++;
16440266059SGregory Neil Shapiro 		return c;
16540266059SGregory Neil Shapiro 	}
16640266059SGregory Neil Shapiro 
16740266059SGregory Neil Shapiro 	/*
16840266059SGregory Neil Shapiro 	**  Create an ungetc buffer.
16940266059SGregory Neil Shapiro 	**  Initially, we will use the `reserve' buffer.
17040266059SGregory Neil Shapiro 	*/
17140266059SGregory Neil Shapiro 
17240266059SGregory Neil Shapiro 	fp->f_ur = fp->f_r;
17340266059SGregory Neil Shapiro 	fp->f_up = fp->f_p;
17440266059SGregory Neil Shapiro 	fp->f_ub.smb_base = fp->f_ubuf;
17540266059SGregory Neil Shapiro 	fp->f_ub.smb_size = sizeof(fp->f_ubuf);
17640266059SGregory Neil Shapiro 	fp->f_ubuf[sizeof(fp->f_ubuf) - 1] = c;
17740266059SGregory Neil Shapiro 	fp->f_p = &fp->f_ubuf[sizeof(fp->f_ubuf) - 1];
17840266059SGregory Neil Shapiro 	fp->f_r = 1;
17940266059SGregory Neil Shapiro 
18040266059SGregory Neil Shapiro 	return c;
18140266059SGregory Neil Shapiro }
182