tl.c
/* tl.c - TEXTLINES implementation file
** MG 9.16.97
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "tl.h"
/******************************************************************
** Name: TLConstruct
** Descr: Constructs an empty TEXTLINES structure
** Author: MG 9/16/97
*******************************************************************/
TEXTLINES * TLConstruct( void )
{
return( calloc( 1, sizeof( TEXTLINES )));
}
/******************************************************************
** Name: TLDestruct
** Descr: Removes a TEXTLINES structure from memory
** Params: Dest = Struct to be removed
** Author: MG 9/16/97
*******************************************************************/
void TLDestruct( TEXTLINES * Dest )
{
if( Dest )
{
TLClear( Dest );
free( Dest );
}
}
/******************************************************************
** Name: TLResize
** Descr: Resizes a TXTLINES struct to be able to contain a certain number of lines.
** Params: Dest = Struct to be resized
** Count = New # of lines to be held
** Returns: ERR_OK upon success, or error code upon failure
** Author: MG 9/16/97
*******************************************************************/
int TLResize( TEXTLINES * Dest, int Count )
{
char ** Tmp;
while( Dest->LineCount > Count )
free( Dest->Lines[ --Dest->LineCount ] );
if( (Tmp = realloc( Dest->Lines, Count*sizeof(char*))) == NULL )
return( ERR_NOMEM );
Dest->Lines = Tmp;
Dest->Max = Count;
return( ERR_OK );
}
/******************************************************************
** Name: TLInsert
** Descr: Inserts a copy of a string into a TEXTLINES structure
** Params: Dest = Struct to be added to
** Index = Position to place new string. -1 means at 'end'
** Src = new string to be copied
** Returns: ERR_OK upon success, or an error code upon failure
** Author: MG 9/16/97
*******************************************************************/
int TLInsert( TEXTLINES * Dest, int Index, char *Src )
{
int Err, i;
char *New;
if( Index==-1 )
Index=Dest->LineCount;
if( Index<0 || Index > Dest->LineCount )
return( ERR_BADINDEX );
if( (New=strdup( Src )) == NULL )
return( ERR_NOMEM );
if( Dest->LineCount+1 >= Dest->Max )
if( (Err=TLResize( Dest, Dest->Max+TLGROWBY )) != ERR_OK )
{
free( New );
return( Err );
}
for( i=Dest->LineCount; i>Index; i-- )
Dest->Lines[i]=Dest->Lines[i-1];
Dest->Lines[Index]=New;
Dest->LineCount++;
return( ERR_OK );
}
/******************************************************************
** Name: TLRemove
** Descr: Removes a line from a TEXTLINES structure
** Params: Dest = Struct to have line removed from
** Index = Position of line to be removed
** Returns: ERR_OK upon success, or error code upon failure
** Author: MG 9/16/97
*******************************************************************/
int TLRemove( TEXTLINES * Dest, int Index )
{
int i;
if( Dest->LineCount == 0 )
return( ERR_BADINDEX );
if( Index==-1 )
Index=Dest->LineCount-1;
for( i=Index; i < Dest->LineCount; i++ )
Dest->Lines[i]=Dest->Lines[i+1];
Dest->LineCount--;
#ifdef TLSHRINK
if( Dest->Max - Dest->LineCount > TLGROWBY )
return( TLResize( Dest, Dest->Max - TLGROWBY ) );
#endif
return( ERR_OK );
}
/******************************************************************
** Name: TLClear
** Descr: Removes all lines from a TEXTLINES structure
** Params: Dest = Struct to be cleared
** Author: MG 9/16/97
*******************************************************************/
void TLClear( TEXTLINES * Dest )
{
if( Dest->LineCount )
{
while( Dest->LineCount-- )
free( Dest->Lines[ Dest->LineCount ] );
free( Dest->Lines );
Dest->Lines = NULL;
Dest->Max = 0;
}
}
/******************************************************************
** Name: TLSwap
** Descr: Swaps to lines from a TEXTLINES structure
** Params: Dest = Struct to have elements swapped
** A = Location of first element to swap
** B = Location of second element to swap
** Returns: ERR_OK upon success, or error code upon failure
** Author: MG 9/16/97
*******************************************************************/
int TLSwap( TEXTLINES * Dest, int A, int B )
{
char * Tmp;
if( A<0 || A >=Dest->LineCount || B < 0 || B >=Dest->LineCount )
return( ERR_BADINDEX );
Tmp = Dest->Lines[A];
Dest->Lines[A] = Dest->Lines[B];
Dest->Lines[B] = Tmp;
return( ERR_OK );
}
/******************************************************************
** Name: TLLoadFromFile
** Descr: Loads the lines of text from a file into a TEXTLINES structure
** Params: Dest = Struct to be loaded with file data
** Filename = name of file to be loaded
** ClearFirst = if true, then previous contents of Dest are cleared,
** otherwise they aren't
** Returns: ERR_OK upon success, or error code upon failure
** Author: MG 9/16/97
*******************************************************************/
int TLLoadFromFile( TEXTLINES * Dest, char * Filename, int ClearFirst )
{
FILE * Input;
char * Buffer, * Tmp;
int BufferSize=512, Extra=0, Err=ERR_OK;
if( (Input=fopen( Filename, "r" )) == NULL )
return( ERR_NOOPEN );
if( (Buffer=malloc( BufferSize )) == NULL )
{
fclose( Input );
return( ERR_NOMEM );
}
if( ClearFirst )
TLClear( Dest );
while( Err==ERR_OK && fgets( Buffer+Extra, BufferSize-Extra, Input ) )
{
if( Buffer[ strlen(Buffer)-1 ] != '\n' ) /* Didn't read whole line */
{
BufferSize += 512;
if( (Tmp=realloc( Buffer, BufferSize )) == NULL )
{
free( Buffer );
fclose( Input );
return( ERR_NOMEM );
}
Buffer = Tmp;
Extra += 512;
continue; /* get more of the line */
}
Extra = 0;
Trim(Buffer);
Err = TLAppend( Dest, Buffer );
}
fclose( Input );
free( Buffer );
if( Err )
TLClear( Dest );
return( Err );
}
/******************************************************************
** Name: TLSaveToFile
** Descr: Save a TEXTLINES structure's lines to a file
** Params: Dest = Struct to be saved
** Filename = name of file to be saved to
** Returns: ERR_OK upon success, or error code upon failure
** Author: MG 9/16/97
*******************************************************************/
int TLSaveToFile( TEXTLINES * Src, char * Filename )
{
FILE * Output;
int i;
if( (Output=fopen(Filename,"w+"))==NULL )
return( ERR_NOOPEN );
for( i=0; i < Src->LineCount; i++ )
fprintf( Output, "%s\n", Src->Lines[i] );
fclose( Output );
return( ERR_OK );
}
/******************************************************************
** Name: TLEzSortICmp
** Descr: A callback function for TLEZSort to compare elements insensitive
** Params: A = Address of first element to compare
** B = Address of second element to compare
** Returns: 0 if items are identical, <0 if A < B, or >0 if A > B
** Author: MG 9/16/97
*******************************************************************/
int TLEzSortICmp( const void* A, const void* B )
{
return( stricmp( *(const char**)A, *(const char**)B ) );
}
/******************************************************************
** Name: TLEzSortCmp
** Descr: A callback function for TLEZSort to compare elements sensitive
** Params: A = Address of first element to compare
** B = Address of second element to compare
** Returns: 0 if items are identical, <0 if A < B, or >0 if A > B
** Author: MG 9/16/97
*******************************************************************/
int TLEzSortCmp( const void* A, const void* B )
{
return( strcmp( *(const char**)A, *(const char**)B ) );
}
/******************************************************************
** Name: TLEzSort
** Descr: A simple sorting routine to sort lines in a TEXTLINES structure
** Params: Dest = Struct to be sorted
** Sensitive = True to perform case sensitive sort, false for insensitive
** Author: MG 9/16/97
*******************************************************************/
void TLEzSort( TEXTLINES * Dest, int Sensitive )
{
if(Sensitive)
qsort( Dest->Lines, Dest->LineCount, sizeof(char*), TLEzSortCmp );
else
qsort( Dest->Lines, Dest->LineCount, sizeof(char*), TLEzSortICmp );
}
/******************************************************************
** Name: Trim
** Descr: Removes trailing white space from a string
** Params: Src = String to be modified
** Returns: True if string is not blank, false if it is blank
** Author: MG 9/16/97
*******************************************************************/
int Trim( char *Src )
{
char *End = Src+strlen(Src)-1;
for( ; End>=Src && isspace(*End); End-- )
*End='\0';
return( *Src );
}
/******************************************************************
** Name: ErrMsg
** Descr: Prints an error message, if applicable, and optionally terminates
** program
** Params: ErrCode = Error code to be tested. ERR_OK will result in no action
** Exit = If True, then function will terminate program, otherwise it doesn't
** Author: MG 9/16/97
*******************************************************************/
void ErrMsg( int ErrCode, int Exit )
{
switch( ErrCode )
{
case ERR_OK:
return;
case ERR_BADINDEX:
perror( "Bad index" );
break;
case ERR_NOMEM:
perror( "Out of memory" );
break;
case ERR_NOOPEN:
perror( "Can't open file" );
break;
default:
perror( "Unknown error" );
}
if( Exit )
exit( ErrCode );
}