CircFile.c
/* CircFile.c */
/* Copyright(c) 1991-2006 by Motion Engineering, Inc. All rights reserved.
*
* This software contains proprietary and confidential information of
* Motion Engineering Inc., and its suppliers. Except as may be set forth
* in the license agreement under which this software is supplied, use,
* disclosure, or reproduction is prohibited without the prior express
* written consent of Motion Engineering, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#define IS_TRUE(x) ((x)!=FALSE)
#define IS_FALSE(x) ((x)==FALSE)
#define LINE_HEADER_LENGTH (8)
#define MAX_LINE_COUNT (499999)
#define MAX_LINE_VAL (1000000)
typedef struct CircFile
{
FILE* cFile;
long lineLength;
long lineCount;
long currentLine;
long writeLine;
long writable;
long eof;
} CircFile;
CircFile* circFileOpenForWrite(const char* name, long lineLength, long lineCount)
{
CircFile* file;
if ((lineLength < 2) || (lineCount < 1) || (lineCount > MAX_LINE_COUNT))
{
return NULL;
}
file = (CircFile*) malloc(sizeof(CircFile));
if (file != NULL)
{
file->cFile = fopen(name, "wb");
if (file->cFile == NULL)
{
free(file);
file = NULL;
}
}
if (file != NULL)
{
file->lineLength = lineLength+LINE_HEADER_LENGTH+1;
file->lineCount = lineCount;
file->currentLine = 0;
file->writeLine = 0;
file->writable = TRUE;
file->eof = FALSE;
}
return file;
}
CircFile* circFileOpenForRead(const char* name)
{
CircFile* file = (CircFile*) malloc(sizeof(CircFile));
if (file != NULL)
{
file->cFile = fopen(name, "rb");
if (file->cFile == NULL)
{
free(file);
file = NULL;
}
}
if (file != NULL)
{
long fileLength;
file->writable = FALSE;
fseek(file->cFile, 0, SEEK_END);
fileLength = ftell(file->cFile);
if (fileLength == 0)
{
file->lineLength = 0;
file->lineCount = 0;
}
else
{
long lineA, lineB, lineC, idA, idB, idC, difLineAB, difLineBC, difLineAC;
fseek(file->cFile, 0, SEEK_SET);
while(fgetc(file->cFile)!='\n');
file->lineLength = ftell(file->cFile);
file->lineCount = fileLength/file->lineLength;
fseek(file->cFile, 0, SEEK_SET);
fscanf(file->cFile, "%06d", &idA);
lineA = 0;
fseek(file->cFile, (file->lineCount/2)*file->lineLength, SEEK_SET);
fscanf(file->cFile, "%06d", &idB);
lineB = file->lineCount/2;
fseek(file->cFile, (file->lineCount-1)*file->lineLength, SEEK_SET);
fscanf(file->cFile, "%06d", &idC);
lineC = file->lineCount-1;
difLineAC = idC-idA;
if (difLineAC > MAX_LINE_COUNT) {difLineAC -= MAX_LINE_VAL;}
if (difLineAC < -MAX_LINE_COUNT) {difLineAC += MAX_LINE_VAL;}
if ((difLineAC > 0) || (file->lineCount == 1))
{
file->writeLine = 0;
}
else
{
for(;;)
{
difLineAB = idB-idA;
if (difLineAB > MAX_LINE_COUNT) {difLineAB -= MAX_LINE_VAL;}
if (difLineAB < -MAX_LINE_COUNT) {difLineAB += MAX_LINE_VAL;}
difLineBC = idC-idB;
if (difLineBC > MAX_LINE_COUNT) {difLineBC -= MAX_LINE_VAL;}
if (difLineBC < -MAX_LINE_COUNT) {difLineBC += MAX_LINE_VAL;}
if (difLineAB < 0)
{
if (lineB == lineA + 1)
{
file->writeLine = lineB;
break;
}
idC = idB;
lineC = lineB;
}
else if (difLineBC < 0)
{
if (lineC == lineB + 1)
{
file->writeLine = lineC;
break;
}
idA = idB;
lineA = lineB;
}
else
{
file->writeLine = -1;
break;
}
lineB = (lineA + lineC)/2;
fseek(file->cFile, lineB*file->lineLength, SEEK_SET);
fscanf(file->cFile, "%06d", &idB);
}
}
}
fseek(file->cFile, file->writeLine*file->lineLength + LINE_HEADER_LENGTH, SEEK_SET);
file->currentLine = 0;
file->eof = FALSE;
}
return file;
}
void circFileClose(CircFile* file)
{
if (file != NULL)
{
if (IS_TRUE(file->writable))
{
long position;
position = ftell(file->cFile) % file->lineLength;
if (position > 0)
{
while (position < file->lineLength-1)
{
fputc(' ', file->cFile);
++position;
}
fputc('\n', file->cFile);
}
}
fclose(file->cFile);
free(file);
}
}
long circFileLineLength(CircFile* file)
{
if (file != NULL)
{
return file->lineLength - LINE_HEADER_LENGTH - 1;
}
return -1;
}
long circFileLineCount(CircFile* file)
{
if (file != NULL)
{
return file->lineCount;
}
return -1;
}
long circFileSize(CircFile* file)
{
if (file != NULL)
{
return (file->lineLength - LINE_HEADER_LENGTH)*file->lineCount;
}
return -1;
}
/* Used internally -- don't need error checking */
long _circFileSizeAbs(CircFile* file)
{
return file->lineLength*file->lineCount;
}
/* Used internally -- don't need error checking */
long _circFilePositionOffset(CircFile* file)
{
return file->lineLength*file->writeLine;
}
/* Used internally -- don't need error checking */
long _circFileTellAbs(CircFile* file)
{
long position = ftell(file->cFile) - file->writeLine*file->lineLength;
if (position<0)
{
position += file->lineCount*file->lineLength;
}
return position;
}
/* Used internally -- don't need error checking */
long _circFileTellFromAbs(CircFile* file, long absPosition)
{
return absPosition - LINE_HEADER_LENGTH*(1 + absPosition/file->lineLength);
}
/* Used internally -- don't need error checking */
long _circFileTellToAbs(CircFile* file, long position)
{
return position + LINE_HEADER_LENGTH*(1 + position/(circFileLineLength(file)+1));
}
long circFileTell(CircFile* file)
{
if (file != NULL)
{
long absPosition = _circFileTellAbs(file);
return _circFileTellFromAbs(file, absPosition);
}
return -1;
}
long circFileTellLine(CircFile* file)
{
if (file != NULL)
{
return circFileTell(file)/(circFileLineLength(file)+1);
}
return -1;
}
int circFileEof(CircFile* file)
{
if (file != NULL)
{
if (feof(file->cFile) || (file->lineLength == 0) || (file->lineCount == 0))
{
return TRUE;
}
return ((int) file->eof);
}
return -1;
}
char* circFileGets(CircFile* file, char* buffer, int length)
{
if (file != NULL)
{
if (IS_TRUE(file->eof))
{
buffer[0]='\0';
}
else
{
fgets(buffer, length, file->cFile);
if ((ftell(file->cFile) % file->lineLength) == 0)
{
++file->currentLine;
if (file->currentLine == file->lineCount)
{
file->eof = TRUE;
file->currentLine;
}
file->currentLine %= file->lineCount;
fseek(file->cFile, ((file->writeLine+file->currentLine)%file->lineCount)*file->lineLength + LINE_HEADER_LENGTH, SEEK_SET);
}
}
}
else
{
buffer[0]='\0';
}
return buffer;
}
int circFileGetc(CircFile* file)
{
if (file != NULL)
{
int c;
long position;
if (IS_TRUE(file->eof))
{
return EOF;
}
position = ftell(file->cFile);
c = fgetc(file->cFile);
if (ftell(file->cFile)%file->lineLength == 0)
{
++file->currentLine;
if (file->currentLine == file->lineCount)
{
file->eof = TRUE;
file->currentLine;
}
fseek(file->cFile, ((file->writeLine+file->currentLine)%file->lineCount)*file->lineLength + LINE_HEADER_LENGTH, SEEK_SET);
}
return c;
}
return EOF;
}
int circFileSeek(CircFile* file, long count, int seek)
{
if (file != NULL)
{
int returnValue;
long position;
if (seek == SEEK_CUR)
{
count += circFileTell(file);
}
else if (seek == SEEK_END)
{
count += circFileSize(file);
}
else if (seek != SEEK_SET)
{
return -1; /* Error */
}
if ((count < 0) || (count > circFileSize(file)))
{
return -1; /* Error */
}
else if (count == circFileSize(file))
{
file->eof = TRUE;
}
else
{
file->eof = FALSE;
}
position = (_circFilePositionOffset(file) + _circFileTellToAbs(file, count)) %
_circFileSizeAbs(file);
returnValue = fseek(file->cFile, position, SEEK_SET);
file->currentLine = (position/file->lineLength)-(file->writeLine);
if (file->currentLine < 0)
{
file->currentLine += file->lineCount;
}
return returnValue;
}
return -1;
}
int circFileSeekLine(CircFile* file, long lineCount, int seek)
{
if (file != NULL)
{
int returnValue;
long position;
if (seek == SEEK_CUR)
{
lineCount += circFileTellLine(file);
}
else if (seek == SEEK_END)
{
lineCount += file->lineCount;
}
else if (seek != SEEK_SET)
{
return -1; /* Error */
}
if ((lineCount < 0) || (lineCount > file->lineCount))
{
return -1; /* Error */
}
else if (lineCount == file->lineCount)
{
file->eof = TRUE;
}
else
{
file->eof = FALSE;
}
file->currentLine = lineCount;
position = (_circFilePositionOffset(file) + _circFileTellToAbs(file, (circFileLineLength(file)+1)*lineCount)) %
_circFileSizeAbs(file);
returnValue = fseek(file->cFile, position, SEEK_SET);
return returnValue;
}
return -1;
}
void circFileWrite(CircFile* file, const char* buffer)
{
if (file != NULL)
{
long position;
if (IS_FALSE(file->writable))
{
return;
}
if (*buffer == '\0')
{
return;
}
position = ftell(file->cFile) % file->lineLength;
if (position == 0)
{
fprintf(file->cFile, "%06d: ", file->writeLine % 10000000);
position = LINE_HEADER_LENGTH;
}
while (*buffer != '\0')
{
while ((position < file->lineLength-1) && (*buffer != '\0') && (*buffer != '\n'))
{
fputc(*buffer, file->cFile);
++buffer;
++position;
}
if (*buffer != '\0')
{
if (*buffer == '\n')
{
while (position < file->lineLength-1)
{
fputc(' ', file->cFile);
++position;
}
++buffer;
}
fputc('\n', file->cFile);
++file->currentLine;
++file->writeLine;
position = LINE_HEADER_LENGTH;
if (file->currentLine >= file->lineCount)
{
fseek(file->cFile, 0, SEEK_SET);
file->currentLine = 0;
}
if (*buffer != '\0')
{
fprintf(file->cFile, "%06d: ", file->writeLine % 10000000);
}
}
}
}
}
void circFilePrint(CircFile* file, const char* format, ...)
{
va_list marker;
va_start( marker, format ); /* Initialize variable arguments. */
if (file != NULL)
{
if (IS_FALSE(file->writable))
{
return;
}
else
{
char buffer[4096]; // TODO: Change this to a dynamically allocated buffer */
_vsnprintf(buffer, 4096, format, marker);
circFileWrite(file, buffer);
}
}
}
void circFileWriteLine(CircFile* file, const char* buffer)
{
if (file != NULL)
{
long position;
if (IS_FALSE(file->writable))
{
return;
}
position = ftell(file->cFile) % file->lineLength;
if (position > 0)
{
while (position < file->lineLength-1)
{
fputc(' ', file->cFile);
++position;
}
fputc('\n', file->cFile);
++file->currentLine;
++file->writeLine;
position = LINE_HEADER_LENGTH;
if (file->currentLine >= file->lineCount)
{
fseek(file->cFile, 0, SEEK_SET);
file->currentLine = 0;
}
}
fprintf(file->cFile, "%06d: ", file->writeLine % 10000000);
while ((position < file->lineLength-1) && (*buffer != '\0') && (*buffer != '\n'))
{
fputc(*buffer, file->cFile);
++buffer;
++position;
}
while (position < file->lineLength-1)
{
fputc(' ', file->cFile);
++position;
}
fputc('\n', file->cFile);
++file->currentLine;
++file->writeLine;
if (file->currentLine >= file->lineCount)
{
fseek(file->cFile, 0, SEEK_SET);
file->currentLine = 0;
}
}
}
void circFilePrintLine(CircFile* file, const char* format, ...)
{
va_list marker;
va_start( marker, format ); /* Initialize variable arguments. */
if (file != NULL)
{
long index = 0;
char* buffer;
buffer = (char*) malloc(file->lineLength);
if (IS_FALSE(file->writable))
{
return;
}
if (buffer != NULL)
{
index = _vsnprintf(buffer, file->lineLength-1, format, marker);
if (index = -1)
{
index = file->lineLength-1;
}
buffer[index]='\0';
circFileWriteLine(file, buffer);
free(buffer);
}
}
}
|