54 lines
1.3 KiB
C
54 lines
1.3 KiB
C
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include "fileutil.h"
|
|
|
|
int ungetc(int c, FILE *fp)
|
|
{
|
|
if(c == EOF)
|
|
return c;
|
|
if(!fp->readable) {
|
|
errno = EINVAL;
|
|
return EOF;
|
|
}
|
|
|
|
/* If there is no buffer, create a temporary one */
|
|
if(!fp->buf)
|
|
__fp_set_buffer(fp, NULL, 16);
|
|
|
|
__fp_buffer_mode_read(fp);
|
|
|
|
/* If there is a spot available in the buffer, use it */
|
|
if(fp->bufpos > 0) {
|
|
fp->buf[--fp->bufpos] = c;
|
|
fp->bufungetc++;
|
|
fp->eof = 0;
|
|
return c;
|
|
}
|
|
|
|
/* Otherwise, make some room. If the buffer is full of ungetc()
|
|
characters then we can't preserve the semantics, so we fail. */
|
|
if(fp->bufungetc >= (int)fp->bufsize)
|
|
return EOF;
|
|
|
|
/* If the buffer is full, discard read data that isn't ungetc()'d. */
|
|
if(fp->bufread >= fp->bufsize) {
|
|
int discarded = fp->bufread - fp->bufungetc;
|
|
if(fseek(fp, -discarded, SEEK_CUR))
|
|
return EOF;
|
|
fp->bufread -= discarded;
|
|
}
|
|
|
|
/* Then move whichever type of read data remains to the very end of the
|
|
buffer, so we have as much space as possible for more ungetc(). */
|
|
memmove(fp->buf + fp->bufsize - fp->bufread, fp->buf, fp->bufread);
|
|
fp->bufpos = fp->bufsize - fp->bufread;
|
|
fp->bufread = fp->bufsize;
|
|
|
|
/* Because we've made space, conclude like the first case */
|
|
fp->buf[--fp->bufpos] = c;
|
|
fp->bufungetc++;
|
|
fp->eof = 0;
|
|
return c;
|
|
}
|