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