/*
 * Copyright (c) 2000-2002, 2005 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 * Copyright (c) 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Chris Torek.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */


#include "sm/generic.h"
SM_IDSTR(id, "@(#)$Id: ungetc.c,v 1.15 2006/07/14 14:42:25 ca Exp $")
#include "sm/magic.h"
#include "sm/assert.h"
#include "sm/io.h"
#include "sm/heap.h"
#include "io-int.h"

/*
**  SM_IO_UNGETC -- place a character back into the buffer just read
**
**	Parameters:
**		fp -- the file pointer affected
**		c -- the character to place back
**
**	Results:
**		On success, returns value of character placed back, 0-255.
**		Returns SM_IO_EOF if c == SM_IO_EOF or if last operation
**		was a write and flush failed.
*/

sm_ret_T
sm_io_ungetc(sm_file_T *fp, int c)
{
	sm_ret_T res;

	SM_IS_FP(fp);
	if (c == SM_IO_EOF)
		return SM_IO_EOF;

	if ((f_flags(*fp) & SMRD) == 0)
	{
		/*
		**  Not already reading: no good unless reading-and-writing.
		**  Otherwise, flush any current write stuff.
		*/

		if ((f_flags(*fp) & SMRW) == 0)
			return sm_error_perm(SM_EM_IO, EBADF);
		if (f_flags(*fp) & SMWR)
		{
			res = sm_flush(fp);
			if (sm_is_err(res))
				return res;
			f_flags(*fp) &= ~SMWR;
			f_w(*fp) = 0;
		}
		f_flags(*fp) |= SMRD;
	}
	c = (uchar) c;

	/*
	**  If we can handle this by simply backing up, do so,
	**  but never replace the original character.
	**  (This makes sscanf() work when scanning `const' data.)
	*/

	if (f_bfbase(*fp) != NULL && f_p(*fp) > f_bfbase(*fp) &&
	    f_p(*fp)[-1] == c)
	{
		f_flags(*fp) &= ~SMFEOF;
		f_p(*fp)--;
		f_r(*fp)++;
		return c;
	}

	/*
	**  OOPS... someone puts a different char back or
	**  didn't read before ungetc.
	**  fixme: we could probably deal with a different char,
	**  but see above (`const' data).
	**  should we use another flag (similar to SMSTR)?
	*/

	return sm_error_perm(SM_EM_IO, EINVAL);
}


syntax highlighted by Code2HTML, v. 0.9.1