/*
diskio.c Fast file buffering
(C) Copyright 1998 by Brian Boyle
Version 1.3
*/
#include "conf.h"
#include "sysdep.h"
#include <sys/stat.h>
#include "diskio.h"
int fbgetline(FBFILE *fbfl, char *line)
{
char *r = fbfl->ptr, *w = line;
if(!fbfl || !line || !*fbfl->ptr)
return FALSE;
for(; *r && *r != '\n' && r <= fbfl->buf + fbfl->size; r++)
*(w++) = *r;
while(*r == '\r' || *r == '\n')
r++;
*w = '\0';
if(r > fbfl->buf + fbfl->size)
return FALSE;
else {
fbfl->ptr = r;
return TRUE;
}
}
int find_string_size(char *str)
{
int i;
char *p;
if(!str || !*str || *str == '~')
return 0;
for(i = 1, p = str; *p; i++) {
switch(*p) {
case '\r':
i++;
if(*(++p) == '\n')
p++;
break;
case '\n':
i++;
if(*(++p) == '\r') {
*(p - 1) = '\r';
*(p++) = '\n';
} else
p++;
break;
case '~':
if(*(p - 1) == '\r' || *(p - 1) == '\n' ||
*(p + 1) == '\r' || *(p + 1) == '\n' || *(p + 1) == '\0')
return i;
else
p++;
break;
default:
p++;
}
}
return i;
}
char *fbgetstring(FBFILE *fl)
{
int size;
char *str, *r, *w;
if(!fl || !*fl->ptr)
return NULL;
if(!(size = find_string_size(fl->ptr)))
return NULL;
str = (char *)malloc(size + 1);
*str = '\0';
r = fl->ptr;
w = str;
for( ; *r; r++, w++) {
switch(*r) {
case '\r':
*(w++) = '\r';
*w = '\n';
if(*(r + 1) == '\n')
r++;
break;
case '\n':
*(w++) = '\r';
*w = '\n';
break;
case '~':
if(*(r - 1) == '\r' || *(r - 1) == '\n' ||
*(r + 1) == '\r' || *(r + 1) == '\n' || *(r + 1) == '\0') {
*w = '\0';
for(r++; *r == '\r' || *r == '\n'; r++);
fl->ptr = r;
return str;
} else
*w = *r;
break;
case '\0':
*w = '\0';
fl->ptr = r;
return str;
default:
*w = *r;
}
}
fl->ptr = r;
return str;
}
FBFILE *fbopen_for_read(char *fname)
{
int err;
FILE *fl;
struct stat sb;
FBFILE *fbfl;
if(!(fbfl = (FBFILE *)malloc(sizeof(FBFILE))))
return NULL;
if(!(fl = fopen(fname, "r"))) {
free(fbfl);
return NULL;
}
err = fstat(fileno(fl), &sb);
if(err < 0 || sb.st_size <= 0) {
free(fbfl);
fclose(fl);
return NULL;
}
fbfl->size = sb.st_size;
if(!(fbfl->buf = malloc(fbfl->size))) {
free(fbfl);
return NULL;
}
if(!(fbfl->name = malloc(strlen(fname) + 1))) {
free(fbfl->buf);
free(fbfl);
return NULL;
}
fbfl->ptr = fbfl->buf;
fbfl->flags = FB_READ;
strcpy(fbfl->name, fname);
fread(fbfl->buf, sizeof(char), fbfl->size, fl);
fclose(fl);
return fbfl;
}
FBFILE *fbopen_for_write(char *fname, int mode)
{
FBFILE *fbfl;
if(!(fbfl = (FBFILE *)malloc(sizeof(FBFILE))))
return NULL;
if(!(fbfl->buf = malloc(FB_STARTSIZE))) {
free(fbfl);
return NULL;
}
if(!(fbfl->name = malloc(strlen(fname) + 1))) {
free(fbfl->buf);
free(fbfl);
return NULL;
}
strcpy(fbfl->name, fname);
fbfl->ptr = fbfl->buf;
fbfl->size = FB_STARTSIZE;
fbfl->flags = mode;
return fbfl;
}
FBFILE *fbopen(char *fname, int mode)
{
if(!fname || !*fname || !mode)
return NULL;
if(IS_SET(mode, FB_READ))
return fbopen_for_read(fname);
else if(IS_SET(mode, FB_WRITE) || IS_SET(mode, FB_APPEND))
return fbopen_for_write(fname, mode);
else
return NULL;
}
int fbclose_for_read(FBFILE *fbfl)
{
if(!fbfl)
return 0;
if(fbfl->buf)
free(fbfl->buf);
if(fbfl->name)
free(fbfl->name);
free(fbfl);
return 1;
}
int fbclose_for_write(FBFILE *fbfl)
{
char *arg, *tname;
int len, bytes_written;
FILE *fl;
if(!fbfl || !fbfl->name || fbfl->ptr == fbfl->buf)
return 0;
if(IS_SET(fbfl->flags, FB_APPEND))
arg = "wa";
else
arg = "w";
if(!(tname = malloc(strlen(fbfl->name) + 6)))
return 0;
len = strlen(fbfl->buf);
if(!len)
return 0;
sprintf(tname, "%s.tmp", fbfl->name);
if(!(fl = fopen(tname, arg))) {
free(tname);
return 0;
}
if((bytes_written = fwrite(fbfl->buf, sizeof(char), len, fl)) < len) {
fclose(fl);
remove(tname);
free(tname);
return 0;
}
fclose(fl);
remove(fbfl->name);
rename(tname, fbfl->name);
free(tname);
free(fbfl->name);
free(fbfl->buf);
free(fbfl);
return bytes_written;
}
int fbclose(FBFILE *fbfl)
{
if(!fbfl)
return 0;
if(IS_SET(fbfl->flags, FB_READ))
return fbclose_for_read(fbfl);
else if(IS_SET(fbfl->flags, FB_WRITE | FB_APPEND))
return fbclose_for_write(fbfl);
else
return 0;
}
int fbprintf(FBFILE *fbfl, const char *format, ...)
{
int bytes_written = 0, length = 0;
va_list args;
if(fbfl->ptr - fbfl->buf > (FB_STARTSIZE * 3) / 4) {
length = fbfl->ptr - fbfl->buf;
if(!(fbfl->buf = realloc(fbfl->buf, fbfl->size + FB_STARTSIZE)))
return 0;
fbfl->ptr = fbfl->buf + length;
fbfl->size += FB_STARTSIZE;
}
va_start(args, format);
bytes_written = vsprintf(fbfl->ptr, format, args);
va_end(args);
fbfl->ptr += bytes_written;
return bytes_written;
}
void fbrewind(FBFILE *fbfl)
{
fbfl->ptr = fbfl->buf;
}
int fbcat(char *fromfilename, FBFILE *tofile)
{
struct stat sb;
FILE *fromfile;
char *in_buf = 0;
int errnum = 0, length = 0;
if(!fromfilename || !*fromfilename || !tofile)
return 0;
if(!(fromfile = fopen(fromfilename, "r+b")))
return 0;
errnum = fstat(fileno(fromfile), &sb);
if(errnum < 0 || sb.st_size <= 0)
return 0;
length = tofile->ptr - tofile->buf;
tofile->buf = realloc(tofile->buf, tofile->size + sb.st_size);
tofile->ptr = tofile->buf + length;
tofile->size += sb.st_size;
in_buf = malloc(sb.st_size + 1);
in_buf[0] = 0;
errnum = fread(in_buf, sb.st_size, 1, fromfile);
fbprintf(tofile, "%s", in_buf);
fclose(fromfile);
free(in_buf);
return 1;
}