source: trunk/third/sendmail/libsm/ungetc.c @ 19204

Revision 19204, 3.9 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1990, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENSE file which can be found at the top level of
12 * the sendmail distribution.
13 */
14
15#include <sm/gen.h>
16SM_IDSTR(id, "@(#)$Id: ungetc.c,v 1.1.1.1 2003-04-08 15:06:05 zacheiss Exp $")
17
18#include <stdlib.h>
19#include <string.h>
20#include <signal.h>
21#include <sys/time.h>
22#include <errno.h>
23#include <sm/io.h>
24#include <sm/heap.h>
25#include <sm/assert.h>
26#include <sm/conf.h>
27#include "local.h"
28
29/*
30**  SM_SUBMORE_X -- expand ungetc buffer
31**
32**  Expand the ungetc buffer `in place'.  That is, adjust fp->f_p when
33**  the buffer moves, so that it points the same distance from the end,
34**  and move the bytes in the buffer around as necessary so that they
35**  are all at the end (stack-style).
36**
37**      Parameters:
38**              fp -- the file pointer
39**
40**      Results:
41**              none.
42**
43**      Exceptions:
44**              F:sm_heap -- out of memory
45*/
46
47static void
48sm_submore_x(fp)
49        register SM_FILE_T *fp;
50{
51        register int i;
52        register unsigned char *p;
53
54        if (fp->f_ub.smb_base == fp->f_ubuf)
55        {
56                /* Get a buffer; f_ubuf is fixed size. */
57                p = sm_malloc_x((size_t) SM_IO_BUFSIZ);
58                fp->f_ub.smb_base = p;
59                fp->f_ub.smb_size = SM_IO_BUFSIZ;
60                p += SM_IO_BUFSIZ - sizeof(fp->f_ubuf);
61                for (i = sizeof(fp->f_ubuf); --i >= 0;)
62                        p[i] = fp->f_ubuf[i];
63                fp->f_p = p;
64                return;
65        }
66        i = fp->f_ub.smb_size;
67        p = sm_realloc_x(fp->f_ub.smb_base, i << 1);
68
69        /* no overlap (hence can use memcpy) because we doubled the size */
70        (void) memcpy((void *) (p + i), (void *) p, (size_t) i);
71        fp->f_p = p + i;
72        fp->f_ub.smb_base = p;
73        fp->f_ub.smb_size = i << 1;
74}
75
76/*
77**  SM_IO_UNGETC -- place a character back into the buffer just read
78**
79**      Parameters:
80**              fp -- the file pointer affected
81**              timeout -- time to complete ungetc
82**              c -- the character to place back
83**
84**      Results:
85**              On success, returns value of character placed back, 0-255.
86**              Returns SM_IO_EOF if c == SM_IO_EOF or if last operation
87**              was a write and flush failed.
88**
89**      Exceptions:
90**              F:sm_heap -- out of memory
91*/
92
93int
94sm_io_ungetc(fp, timeout, c)
95        register SM_FILE_T *fp;
96        int timeout;
97        int c;
98{
99        SM_REQUIRE_ISA(fp, SmFileMagic);
100        if (c == SM_IO_EOF)
101                return SM_IO_EOF;
102        if (timeout == SM_TIME_IMMEDIATE)
103        {
104                /*
105                **  Ungetting the buffer will take time and we are wanted to
106                **  return immediately. So...
107                */
108
109                errno = EAGAIN;
110                return SM_IO_EOF;
111        }
112
113        if (!Sm_IO_DidInit)
114                sm_init();
115        if ((fp->f_flags & SMRD) == 0)
116        {
117                /*
118                **  Not already reading: no good unless reading-and-writing.
119                **  Otherwise, flush any current write stuff.
120                */
121
122                if ((fp->f_flags & SMRW) == 0)
123                        return SM_IO_EOF;
124                if (fp->f_flags & SMWR)
125                {
126                        if (sm_flush(fp, &timeout))
127                                return SM_IO_EOF;
128                        fp->f_flags &= ~SMWR;
129                        fp->f_w = 0;
130                        fp->f_lbfsize = 0;
131                }
132                fp->f_flags |= SMRD;
133        }
134        c = (unsigned char) c;
135
136        /*
137        **  If we are in the middle of ungetc'ing, just continue.
138        **  This may require expanding the current ungetc buffer.
139        */
140
141        if (HASUB(fp))
142        {
143                if (fp->f_r >= fp->f_ub.smb_size)
144                        sm_submore_x(fp);
145                *--fp->f_p = c;
146                fp->f_r++;
147                return c;
148        }
149        fp->f_flags &= ~SMFEOF;
150
151        /*
152        **  If we can handle this by simply backing up, do so,
153        **  but never replace the original character.
154        **  (This makes sscanf() work when scanning `const' data.)
155        */
156
157        if (fp->f_bf.smb_base != NULL && fp->f_p > fp->f_bf.smb_base &&
158            fp->f_p[-1] == c)
159        {
160                fp->f_p--;
161                fp->f_r++;
162                return c;
163        }
164
165        /*
166        **  Create an ungetc buffer.
167        **  Initially, we will use the `reserve' buffer.
168        */
169
170        fp->f_ur = fp->f_r;
171        fp->f_up = fp->f_p;
172        fp->f_ub.smb_base = fp->f_ubuf;
173        fp->f_ub.smb_size = sizeof(fp->f_ubuf);
174        fp->f_ubuf[sizeof(fp->f_ubuf) - 1] = c;
175        fp->f_p = &fp->f_ubuf[sizeof(fp->f_ubuf) - 1];
176        fp->f_r = 1;
177
178        return c;
179}
Note: See TracBrowser for help on using the repository browser.