blob: 1da1fd2a08a3d921766c287fc94e9d4f524b57f7 [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "util.h"
#include "ReadLine.h"
/* Pass in a pointer to a token list. Is freed and then set to null */
void
FreeTokens(INOUTP char ***TokensPtr)
{
assert(*TokensPtr);
assert(**TokensPtr);
free(**TokensPtr); /* Free the string data */
free(*TokensPtr); /* Free token list */
*TokensPtr = NULL; /* Invalidate pointer since mem is gone */
}
/* Returns number of tokens in list. Zero if null list */
int
CountTokens(INP char **Tokens)
{
int count = 0;
if(NULL == Tokens)
{
return 0;
};
while(Tokens[count])
{
++count;
};
return count;
}
/* Reads in a single line from file, splits into tokens and allocates
* a list of tokens. Returns the an array of character arrays with the
* final item being marked by an empty string.
* Returns NULL on EOF
* NB: Token list is does as two allocations, one for pointer list
* and one for character array. Free what pointer points to and then
* free the pointer itself */
char **
ReadLineTokens(INOUTP FILE * InFile,
INOUTP int *LineNum)
{
enum
{ BUFFSIZE = 65536 }; /* This is much more than enough */
char Buffer[BUFFSIZE]; /* Must match BUFFSIZE */
char *Res;
char *Last;
char *Cur;
char *Dst;
char **Tokens;
int TokenCount;
int Len;
int CurToken;
boolean InToken;
do
{
/* Read the string */
Res = fgets(Buffer, BUFFSIZE, InFile);
if(NULL == Res)
{
if(feof(InFile))
{
return NULL; /* Return NULL on EOF */
}
else
{
printf(ERRTAG "Unexpected error reading file\n");
exit(1);
}
}
++(*LineNum);
/* Strip newline if any */
Last = Buffer + strlen(Buffer);
if((Last > Buffer) && ('\n' == Last[-1]))
{
--Last;
}
if((Last > Buffer) && ('\r' == Last[-1]))
{
--Last;
}
/* Handle continued lines */
while((Last > Buffer) && ('\\' == Last[-1]))
{
/* Strip off the backslash */
--Last;
/* Read next line by giving pointer to null-char as start for next */
Res = fgets(Last, (BUFFSIZE - (Last - Buffer)), InFile);
if(NULL == Res)
{
if(feof(InFile))
{
return NULL; /* Return NULL on EOF */
}
else
{
printf(ERRTAG
"Unexpected error reading file\n");
exit(1);
}
}
++(*LineNum);
/* Strip newline */
Last = Buffer + strlen(Buffer);
if((Last > Buffer) && ('\n' == Last[-1]))
{
--Last;
}
if((Last > Buffer) && ('\r' == Last[-1]))
{
--Last;
}
}
/* Strip comment if any */
Cur = Buffer;
while(Cur < Last)
{
if('#' == *Cur)
{
Last = Cur;
break;
}
++Cur;
}
/* Count tokens and find size */
assert(Last < (Buffer + BUFFSIZE));
Len = 0;
TokenCount = 0;
Cur = Buffer;
InToken = FALSE;
while(Cur < Last)
{
if(InToken)
{
if((' ' == *Cur) || ('\t' == *Cur))
{
InToken = FALSE;
}
else
{
++Len;
}
}
else
{
if((' ' != *Cur) && ('\t' != *Cur))
{
++TokenCount;
++Len;
InToken = TRUE;
}
}
++Cur; /* Advance pointer */
}
}
while(0 == TokenCount);
/* Find the size of mem to alloc. Use a contiguous block so is
* easy to deallocate */
Len = (sizeof(char) * Len) + /* Length of actual data */
(sizeof(char) * TokenCount); /* Null terminators */
/* Alloc the pointer list and data list. Count the final
* empty string we will use as list terminator */
Tokens = (char **)my_malloc(sizeof(char *) * (TokenCount + 1));
*Tokens = (char *)my_malloc(sizeof(char) * Len);
/* Copy tokens to result */
Cur = Buffer;
Dst = *Tokens;
InToken = FALSE;
CurToken = 0;
while(Cur < Last)
{
if(InToken)
{
if((' ' == *Cur) || ('\t' == *Cur))
{
InToken = FALSE;
*Dst = '\0'; /* Null term token */
++Dst;
++CurToken;
}
else
{
*Dst = *Cur; /* Copy char */
++Dst;
}
}
else
{
if((' ' != *Cur) && ('\t' != *Cur))
{
Tokens[CurToken] = Dst; /* Set token start pointer */
*Dst = *Cur; /* Copy char */
++Dst;
InToken = TRUE;
}
}
++Cur; /* Advance pointer */
}
if(InToken)
{
*Dst = '\0'; /* Null term final token */
++Dst;
++CurToken;
}
assert(CurToken == TokenCount);
/* Set the final empty string entry */
Tokens[CurToken] = NULL;
/* Return the string list */
return Tokens;
}