Use in-memory buffers for reading files, and handle newlines better.

This commit is contained in:
David Anderson
2014-07-02 21:52:17 -07:00
parent e6f6e6df70
commit 10c8b78a16
3 changed files with 147 additions and 42 deletions
+138 -33
View File
@@ -1,3 +1,4 @@
// vim: set sts=8 ts=4 sw=4 tw=99 noet:
/* LIBPAWNC.C
*
* A "glue file" for building the Pawn compiler as a DLL or shared library.
@@ -24,6 +25,7 @@
*/
#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "sc.h"
@@ -91,6 +93,14 @@ static char *prefix[3]={ "error", "fatal error", "warning" };
return 0;
}
typedef struct src_file_s {
FILE *fp; // Set if writing.
char *buffer; // IO buffer.
char *pos; // IO position.
char *end; // End of buffer.
size_t maxlength; // Maximum length of the writable buffer.
} src_file_t;
/* pc_opensrc()
* Opens a source file (or include file) for reading. The "file" does not have
* to be a physical file, one might compile from memory.
@@ -105,7 +115,11 @@ static char *prefix[3]={ "error", "fatal error", "warning" };
*/
void *pc_opensrc(char *filename)
{
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN
FILE *fp = NULL;
long length;
src_file_t *src = NULL;
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN
struct stat fileInfo;
if (stat(filename, &fileInfo) != 0) {
return NULL;
@@ -114,9 +128,32 @@ void *pc_opensrc(char *filename)
if (S_ISDIR(fileInfo.st_mode)) {
return NULL;
}
#endif
#endif
return fopen(filename,"rt");
if ((fp = fopen(filename, "rb")) == NULL)
return NULL;
if (fseek(fp, 0, SEEK_END) == -1)
goto err;
if ((length = ftell(fp)) == -1)
goto err;
if (fseek(fp, 0, SEEK_SET) == -1)
goto err;
if ((src = (src_file_t *)calloc(1, sizeof(src_file_t))) == NULL)
goto err;
if ((src->buffer = (char *)calloc(length, sizeof(char))) == NULL)
goto err;
if (fread(src->buffer, length, 1, fp) != 1)
goto err;
src->pos = src->buffer;
src->end = src->buffer + length;
return src;
err:
pc_closesrc(src);
fclose(fp);
return NULL;
}
/* pc_createsrc()
@@ -133,7 +170,23 @@ void *pc_opensrc(char *filename)
*/
void *pc_createsrc(char *filename)
{
return fopen(filename,"wt");
src_file_t *src = (src_file_t *)calloc(1, sizeof(src_file_t));
if (!src)
return NULL;
if ((src->fp = fopen(filename, "wt")) == NULL) {
pc_closesrc(src);
return NULL;
}
src->maxlength = 1024;
if ((src->buffer = (char *)calloc(1, src->maxlength)) == NULL) {
pc_closesrc(src);
return NULL;
}
src->pos = src->buffer;
src->end = src->buffer;
return src;
}
/* pc_closesrc()
@@ -142,8 +195,15 @@ void *pc_createsrc(char *filename)
*/
void pc_closesrc(void *handle)
{
assert(handle!=NULL);
fclose((FILE*)handle);
src_file_t *src = (src_file_t *)handle;
if (!src)
return;
if (src->fp) {
fwrite(src->buffer, src->pos - src->buffer, 1, src->fp);
fclose(src->fp);
}
free(src->buffer);
free(src);
}
/* pc_readsrc()
@@ -152,7 +212,35 @@ void pc_closesrc(void *handle)
*/
char *pc_readsrc(void *handle,unsigned char *target,int maxchars)
{
return fgets((char*)target,maxchars,(FILE*)handle);
src_file_t *src = (src_file_t *)handle;
char *outptr = (char *)target;
char *outend = outptr + maxchars;
assert(!src->fp);
if (src->pos == src->end)
return NULL;
while (outptr < outend && src->pos < src->end) {
char c = *src->pos++;
*outptr++ = c;
if (c == '\n')
break;
if (c == '\r') {
// Handle CRLF.
if (src->pos < src->end && *src->pos == '\n') {
src->pos++;
if (outptr < outend)
*outptr++ = '\n';
}
break;
}
}
// Caller passes in a buffer of size >= maxchars+1.
*outptr = '\0';
return (char *)target;
}
/* pc_writesrc()
@@ -161,31 +249,43 @@ char *pc_readsrc(void *handle,unsigned char *target,int maxchars)
*/
int pc_writesrc(void *handle,unsigned char *source)
{
return fputs((char*)source,(FILE*)handle) >= 0;
}
char *str = (char *)source;
size_t len = strlen(str);
src_file_t *src = (src_file_t *)handle;
#define MAXPOSITIONS 4
static fpos_t srcpositions[MAXPOSITIONS];
static unsigned char srcposalloc[MAXPOSITIONS];
assert(src->fp && src->maxlength);
if (src->pos + len > src->end) {
char *newbuf;
size_t newmax = src->maxlength;
size_t newlen = (src->pos - src->buffer) + len;
while (newmax < newlen) {
// Grow by 1.5X
newmax += newmax + newmax / 2;
if (newmax < src->maxlength)
abort();
}
newbuf = (char *)realloc(src->buffer, newmax);
if (!newbuf)
abort();
src->pos = newbuf + (src->pos - src->buffer);
src->end = newbuf + newmax;
src->buffer = newbuf;
src->maxlength = newmax;
}
strcpy(src->pos, str);
src->pos += len;
return 0;
}
void *pc_getpossrc(void *handle,void *position)
{
if (position==NULL) {
/* allocate a new slot */
int i;
for (i=0; i<MAXPOSITIONS && srcposalloc[i]!=0; i++)
/* nothing */;
assert(i<MAXPOSITIONS); /* if not, there is a queue overrun */
if (i>=MAXPOSITIONS)
return NULL;
position=&srcpositions[i];
srcposalloc[i]=1;
} else {
/* use the gived slot */
assert((fpos_t*)position>=srcpositions && (fpos_t*)position<srcpositions+sizeof(srcpositions));
} /* if */
fgetpos((FILE*)handle,(fpos_t*)position);
return position;
src_file_t *src = (src_file_t *)handle;
assert(!src->fp);
return (void *)(ptrdiff_t)(src->pos - src->buffer);
}
/* pc_resetsrc()
@@ -194,15 +294,20 @@ void *pc_getpossrc(void *handle,void *position)
*/
void pc_resetsrc(void *handle,void *position)
{
assert(handle!=NULL);
assert(position!=NULL);
fsetpos((FILE*)handle,(fpos_t *)position);
/* note: the item is not cleared from the pool */
src_file_t *src = (src_file_t *)handle;
ptrdiff_t pos = (ptrdiff_t)position;
assert(!src->fp);
assert(pos >= 0 && src->buffer + pos <= src->end);
src->pos = src->buffer + pos;
}
int pc_eofsrc(void *handle)
{
return feof((FILE*)handle);
src_file_t *src = (src_file_t *)handle;
assert(!src->fp);
return src->pos == src->end;
}
/* should return a pointer, which is used as a "magic cookie" to all I/O