* Added getc(), fgetc(), fgets(), ungetc(), getline() and getdelim().

* sed now works properly.
This commit is contained in:
Sam Hocevar
2006-12-17 22:14:13 +00:00
committed by sam
parent 9e73ecf297
commit d81d47bbe0
+196 -22
View File
@@ -18,8 +18,7 @@
#include "config.h"
/* Can't remember what that's for */
#define _GNU_SOURCE
#define _GNU_SOURCE /* for getline() and getdelim() */
#if defined HAVE_STDINT_H
# include <stdint.h>
@@ -43,15 +42,34 @@ static FILE * (*fopen64_orig) (const char *path, const char *mode);
static int (*fseek_orig) (FILE *stream, long offset, int whence);
static size_t (*fread_orig) (void *ptr, size_t size, size_t nmemb,
FILE *stream);
static int (*getc_orig) (FILE *stream);
static int (*fgetc_orig) (FILE *stream);
static char * (*fgets_orig) (char *s, int size, FILE *stream);
static int (*ungetc_orig) (int c, FILE *stream);
static int (*fclose_orig) (FILE *fp);
/* Additional GNUisms */
static ssize_t (*getline_orig) (char **lineptr, size_t *n, FILE *stream);
static ssize_t (*getdelim_orig) (char **lineptr, size_t *n, int delim,
FILE *stream);
static ssize_t (*__getdelim_orig) (char **lineptr, size_t *n, int delim,
FILE *stream);
void zzuf_load_stream(void)
{
LOADSYM(fopen);
LOADSYM(fopen64);
LOADSYM(fseek);
LOADSYM(fread);
LOADSYM(getc);
LOADSYM(fgetc);
LOADSYM(fgets);
LOADSYM(ungetc);
LOADSYM(fclose);
LOADSYM(getline);
LOADSYM(getdelim);
LOADSYM(__getdelim);
}
/* Our function wrappers */
@@ -59,10 +77,11 @@ void zzuf_load_stream(void)
do \
{ \
if(!_zzuf_ready) \
{ \
LOADSYM(fn); \
return ORIG(fn)(path, mode); \
} \
ret = ORIG(fn)(path, mode); \
if(!_zzuf_ready) \
return ret; \
if(ret) \
{ \
if(_zzuf_include && \
@@ -97,14 +116,11 @@ int fseek(FILE *stream, long offset, int whence)
if(!_zzuf_ready)
LOADSYM(fseek);
ret = fseek_orig(stream, offset, whence);
if(!_zzuf_ready)
return ret;
fd = fileno(stream);
if(!files[fd].managed)
return ret;
if(!_zzuf_ready || !files[fd].managed)
return fseek_orig(stream, offset, whence);
ret = fseek_orig(stream, offset, whence);
debug("fseek(%p, %li, %i) = %i", stream, offset, whence, ret);
if(ret == 0)
{
@@ -125,14 +141,11 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
if(!_zzuf_ready)
LOADSYM(fread);
ret = fread_orig(ptr, size, nmemb, stream);
if(!_zzuf_ready)
return ret;
fd = fileno(stream);
if(!files[fd].managed)
return ret;
if(!_zzuf_ready || !files[fd].managed)
return fread_orig(ptr, size, nmemb, stream);
ret = fread_orig(ptr, size, nmemb, stream);
debug("fread(%p, %li, %li, %p) = %li",
ptr, (long int)size, (long int)nmemb, stream, (long int)ret);
if(ret > 0)
@@ -143,6 +156,102 @@ size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
return ret;
}
#define FGETC(fn) \
do { \
int fd; \
if(!_zzuf_ready) \
LOADSYM(fn); \
fd = fileno(stream); \
if(!_zzuf_ready || !files[fd].managed) \
return ORIG(fn)(stream); \
ret = ORIG(fn)(stream); \
if(ret != EOF) \
{ \
uint8_t ch = ret; \
zzuf_fuzz(fd, &ch, 1); \
files[fd].pos += 1; \
ret = ch; \
} \
debug(STR(fn)"(%p) = 0x%02x", stream, ret); \
} while(0)
int getc(FILE *stream)
{
int ret; FGETC(getc); return ret;
}
int fgetc(FILE *stream)
{
int ret; FGETC(fgetc); return ret;
}
char *fgets(char *s, int size, FILE *stream)
{
char *ret = s;
int i, fd;
if(!_zzuf_ready)
LOADSYM(fgets);
fd = fileno(stream);
if(!_zzuf_ready || !files[fd].managed)
return fgets_orig(s, size, stream);
if(size <= 0)
ret = NULL;
else if(size == 1)
s[0] = '\0';
else
{
for(i = 0; i < size - 1; i++)
{
int ch = fgetc_orig(stream);
if(ch == EOF)
{
s[i] = '\0';
if(!i)
ret = NULL;
break;
}
s[i] = (char)(unsigned char)ch;
zzuf_fuzz(fd, (uint8_t *)s + i, 1); /* rather inefficient */
files[fd].pos++;
if(s[i] == '\n')
{
s[i + 1] = '\0';
break;
}
}
}
debug("fgets(%p, %i, %p) = %p", s, size, stream, ret);
if(ret >= 0)
files[fd].pos += 1;
return ret;
}
int ungetc(int c, FILE *stream)
{
unsigned char ch = c;
int ret, fd;
if(!_zzuf_ready)
LOADSYM(ungetc);
fd = fileno(stream);
if(!_zzuf_ready || !files[fd].managed)
return ungetc_orig(c, stream);
files[fd].pos -= 1;
zzuf_fuzz(fd, &ch, 1);
ret = ungetc_orig((int)ch, stream);
if(ret >= 0)
ret = c;
else
files[fd].pos += 1; /* revert what we did */
debug("ungetc(0x%02x, %p) = 0x%02x", c, stream, ret);
return ret;
}
int fclose(FILE *fp)
{
int ret, fd;
@@ -150,16 +259,81 @@ int fclose(FILE *fp)
if(!_zzuf_ready)
LOADSYM(fclose);
fd = fileno(fp);
if(!_zzuf_ready || !files[fd].managed)
return fclose_orig(fp);
ret = fclose_orig(fp);
if(!_zzuf_ready)
return ret;
if(!files[fd].managed)
return ret;
debug("fclose(%p) = %i", fp, ret);
files[fd].managed = 0;
return ret;
}
#define GETDELIM(fn, delim, need_delim) \
do { \
char *line; \
ssize_t done, size; \
int fd, finished = 0; \
if(!_zzuf_ready) \
LOADSYM(fn); \
fd = fileno(stream); \
if(!_zzuf_ready || !files[fd].managed) \
return getdelim_orig(lineptr, n, delim, stream); \
line = *lineptr; \
size = line ? *n : 0; \
ret = done = finished = 0; \
for(;;) \
{ \
int ch; \
if(done >= size) /* highly inefficient but I don't care */ \
line = realloc(line, size = done + 1); \
if(finished) \
{ \
line[done] = '\0'; \
*n = size; \
*lineptr = line; \
break; \
} \
ch = fgetc_orig(stream); \
if(ch == EOF) \
{ \
finished = 1; \
ret = done; \
} \
else \
{ \
unsigned char c = ch; \
zzuf_fuzz(fd, &c, 1); /* even more inefficient */ \
line[done++] = c; \
files[fd].pos++; \
if(c == delim) \
{ \
finished = 1; \
ret = done; \
} \
} \
} \
if(need_delim) \
debug(STR(fn) "(%p, %p, 0x%02x, %p) = %li", \
lineptr, n, delim, stream, (long int)ret); \
else \
debug(STR(fn) "(%p, %p, %p) = %li", \
lineptr, n, stream, (long int)ret); \
return ret; \
} while(0)
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
{
ssize_t ret; GETDELIM(getline, '\n', 0); return ret;
}
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
{
ssize_t ret; GETDELIM(getdelim, delim, 1); return ret;
}
ssize_t __getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
{
ssize_t ret; GETDELIM(__getdelim, delim, 1); return ret;
}