I've come up with the following routine to read data from a file stream, but I don't want any NULL
s in the stream to terminate the string early. This function will read in a "line", and allow it to be processed with normal C string functions. Does anyone see any inherent problems or potential bugs in this routine?
char *my_fgets(char *Buf, int iMaxCount, FILE *fp)
{
// Handle basic failures.
if(!Buf) return NULL;
if(iMaxCount < 1) return NULL;
if(!fp) return NULL;
// Create a buffer on the heap for our data to be read in
char *lbuf = (char*)malloc(iMaxCount);
char *p = lbuf;
// Zero out the buffer, no stray chars please.
memset(Buf, 0x00, iMaxCount);
// Where are we at in the file?
int b = ftell(fp);
// Read in the buffer, up to iMaxCount-1. Leave one char for a final NULL.
size_t read = fread((void*)&lbuf[0], sizeof(char), iMaxCount-1, fp);
lbuf[iMaxCount-1] = NULL;
// Failed.
if(!read) {
free(lbuf);
return NULL;
}
// Walk the buffer, looking for a newline char. Once we find it, we know we are at the end of the line,
// but we don't want to read past the number of bytes we originally read, in case we did not hit a newline.
size_t left = read;
while((left) && *(p++) != '\n') left--;
// Copy the data we read to the return Buffer, up to the newline char.
memcpy(Buf, lbuf, p - lbuf);
// Set the file pointer to the newline char + 1
fseek(fp, b+(p - lbuf), SEEK_SET);
// Setup how many bytes we have left in the buffer to look at.
left = (p - lbuf);
p = Buf;
while(left)
{
// Walk the buffer, looking for NULL chars.
if(*(p++) == NULL) {
char *p1;
// We hit a NULL, so shift the buffer left, eat the NULL, and continue our search.
for(p1 = p-1;p1 < (Buf + (iMaxCount-1));p1++) p1[0] = p1[1];
// We ate one char, so we need to step back one byte, and continue our search. This handles a case where two NULLs may be back to back.
p--;
}
left--;
}
// If our last char is not a NULL, we need to set it to NULL to properly terminate the string.
if((p > Buf) && *(p-1) != 0x0a && *p != NULL) *(--p) = 0x00;
// Free our work buffer, and return the new 'clean' data.
free(lbuf);
return Buf;
}
It might of importance to note that this code is called by a Kernel driver, and MUST be fast. Speed is totally of the essence here, which is why this is all in one function, and uses calls like fread()
over fgets()
to get a chunk of data in one shot. That might not matter in the final analysis, but I thought I would mention it.
malloc
andfread
. Does that even work? Does this code run in user address space or kernel address space? \$\endgroup\$