/*-----------------------------------------------------------------------------
** Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
**
** winutil.h
**
** Description: A set of utilities which are specific to the windows development
** environment.
**
** Modification History:
** + Created Aug 03, 2001 -- bkusy
**---------------------------------------------------------------------------*/
/*----------------------------------------
** System Includes
**--------------------------------------*/
#include <string.h>
#include <stdio.h>
#include <assert.h>
/*----------------------------------------
** Project Includes
**--------------------------------------*/
#include "util.h"
/*----------------------------------------
** Constants
**--------------------------------------*/
#define BUFFER_SIZE 512
/*----------------------------------------
** Globals
**--------------------------------------*/
char* util_optarg;
int util_optind;
int util_opterr = 1;
int util_optopt;
/*-----------------------------------------------------------------------------
** u t i l _ b a s e n a m e
**
** Synopsis: Determine the basename in a file path. ( eg/ would return
** "newfile.c" from the path "/usr/home/newfile.c".
**
** Parameters: buffer - buffer to receive basename.
** size - size of buffer.
** path - path to determine basename from.
**
** Returns: non-zero if successful, 0 if buffer is too small.
**
** Constraints: path must use '/' and not '\' as directory separators.
**
**---------------------------------------------------------------------------*/
int util_basename( char* buffer, int size, const char* path )
{
char* d;
char* n;
char* e;
int length;
int result = 0;
assert( buffer );
util_decomposeFilePath( path, &d, &n, &e );
length = strlen( n ) + strlen( e ) + 1;
if ( length < size )
{
strcpy( buffer, n );
strcat( buffer, "." );
strcat( buffer, e );
result = 1;
}
return result;
}
/*-----------------------------------------------------------------------------
** u t i l _ c h a n g e F i l e E x t e n s i o n
**
** Synopsis: Changes the file extension in the given buffer to the given
** given extension.
**
** Parameters: buffer - the file path to be modified.
** ext - the new file extension.
**
** Returns: NOTHING
**
** Constraints: If the original file path does not have an extension, as
** identified by the presence of a "." character, no change will
** take place.
** If the new extension is longer than the old extension, no
** change will take place.
**
**---------------------------------------------------------------------------*/
void util_changeFileExtension( char* buffer, const char* ext )
{
char* oldExt = 0;
assert( buffer );
assert( ext );
oldExt = (char*)(util_rindex( buffer, '.' ));
if ( oldExt )
{
oldExt++;
if ( strlen( oldExt ) <= strlen( ext ) )
{
strcpy( oldExt, ext );
}
}
}
/*-----------------------------------------------------------------------------
** u t i l _ d e c o m p o s e F i l e P a t h
**
** Synopsis: Decompose a file path into its directory, filename and extension.
**
** Parameters: path - the path to decompose.
** dir - a pointer which will be set to the start of the directory.
** name - a pointer which will be set to the start of the name.
** ext - a pointer which will be set to the start of the extension.
**
** Returns: NOTHING
**
** Constraints: path must use '/' and not '\' as directory separators. The pointers
** returned in dir, name, and ext are only valid until the next call
** to util_DecomposePath().
**
**---------------------------------------------------------------------------*/
void util_decomposeFilePath( const char* path, char** dir, char** name, char** ext )
{
static char buffer[ BUFFER_SIZE + 1 ];
strncpy( buffer, path, BUFFER_SIZE );
*ext = strrchr( buffer, '.' );
if ( *ext )
{
/*
* Remove the extension by replacing '.' with a NULL character.
*/
**ext = '\0';
/*
* The extension will be in the next position.
*/
(*ext)++;
}
*name = strrchr( buffer, '/' );
if ( *name )
{
/*
* Remove the name by replacing the last '/' with a NULL character.
*/
**name = '\0';
/*
* The name will be in the next position.
*/
(*name)++;
/*
* Set dir to the start of the string and we are done.
*/
*dir = buffer;
}
else
{
/*
* Name must extend to the beginning of the path. Set the name pointer
* accordingly and set dir to null.
*/
*name = buffer;
*dir = 0;
}
}
/*-----------------------------------------------------------------------------
** u t i l _ d i r n a m e
**
** Synopsis: Determine the directory in a file path.
**
** Parameters: buffer - buffer to recieve directory.
** size - size of buffer.
** path - the path to retrieve the directory from.
**
** Returns: non-zero if successful, zero if buffer is too small to receive
** the directory.
**
** Constraints: path must use '/' and not '\' as directory separators.
**
**---------------------------------------------------------------------------*/
int util_dirname( char* buffer, int size, const char* path )
{
char* d;
char* n;
char* e;
int length;
int result = 0;
util_decomposeFilePath( path, &d, &n, &e );
length = strlen( d );
if ( length < size )
{
strcpy( buffer, d );
result = 1;
}
return result;
}
/*-----------------------------------------------------------------------------
** u t i l _ f i l e E x i s t s
**
** Synopsis: Determines if the give file exists.
**
** Parameters: filename - the name of the file to check for existence.
**
** Returns: 0 if file does not exist, non-zero otherwise.
**
** Constraints:
**
**---------------------------------------------------------------------------*/
int util_fileExists( const char* filename )
{
FILE *fp;
assert( filename );
fp = fopen( filename, "r" );
if ( fp )
{
fclose( fp );
return 1;
}
return 0;
}
/*-----------------------------------------------------------------------------
** u t i l _ g e t o p t _ i n i t
**
** Synopsis: Initializes the getopt parser.
**
** Parameters: NONE
**
** Returns: NOTHING
**
** Constraints: NONE
**
** Author: Angus Mackay
**
**---------------------------------------------------------------------------*/
void util_getopt_init()
{
util_optind = 1;
}
/*-----------------------------------------------------------------------------
** u t i l _ g e t o p t
**
** Synopsis: Used to parse command line arguments based on a specified
** syntax. The argument for the current option is stored in
** the global variable "util_optarg".
**
** Parameters: argc - the number of arguments in the array.
** argv - the argumnet array.
** opts - option specifier string. Options can be of two forms:
** boolean flags ( its either there or it isn't ) and
** flag value pairs in which a flag is always followed
** by some value. Options which require an argument
** must be followed by a ":" in the option specifier
** string. So for a command which can have two boolean
** flags, "h" and "i", and two argument flags, "t" and
** "u", the following option specifier string would be
** used: "hit:u:".
**
** Returns: the option character found, or -1 if no more option
** characters.
**
** Constraints: NONE
**
** Author: Angus Mackay
**
**---------------------------------------------------------------------------*/
int util_getopt( int argc, char* const* argv, const char* opts )
{
static int init_done = 0;
static int suboptionpos = 1;
if(!init_done) { util_getopt_init(); init_done = 1; }
util_optarg = NULL;
if(util_optind == argc)
{
/* we are done */
return(-1);
}
if(argv[util_optind][0] == '-')
{
char *argp;
/* test for end of arg marker */
if(argv[util_optind][1] == '-' && argv[util_optind][2] == '\0')
{
suboptionpos = 1;
util_optind++;
return(-1);
}
for(argp=&(argv[util_optind][suboptionpos]); *argp != '\0'; argp++)
{
char *optp;
int numcolon = 0;
char *p;
if((optp=strchr(opts, *argp)) == NULL)
{
if(util_opterr != 0)
{
fprintf(stderr, "%s: illegal option -- %c\n", argv[0], *argp);
}
util_optopt = *argp;
suboptionpos++;
if(argv[util_optind][suboptionpos] == '\0')
{
suboptionpos = 1;
util_optind++;
}
return('?');
}
/* zero, one or two colons? */
for(p=(optp+1); *p == ':'; p++) { numcolon++; }
switch(numcolon)
{
/* no argument */
case 0:
suboptionpos++;
if(argv[util_optind][suboptionpos] == '\0')
{
suboptionpos = 1;
util_optind++;
}
return(*optp);
break;
/* manditory argument */
case 1:
/* the argument is seperated by a space */
if(argp[1] == '\0')
{
/* ther are more args */
if(util_optind+1 == argc)
{
suboptionpos++;
if(argv[util_optind][suboptionpos] == '\0')
{
suboptionpos = 1;
util_optind++;
}
if(util_opterr != 0)
{
fprintf(stderr, "%s: option requires an argument -- %c\n",
argv[0], *argp);
}
util_optopt = *argp;
return('?');
}
util_optind++;
suboptionpos = 1;
util_optarg = argv[util_optind];
util_optind++;
return(*optp);
}
/* the argument is attached */
util_optarg = argp+1;
suboptionpos = 1;
util_optind++;
return(*optp);
break;
/* optional argument */
case 2:
/* the argument is seperated by a space */
if(argp[1] == '\0')
{
util_optind++;
suboptionpos = 1;
util_optarg = NULL;
return(*optp);
}
/* the argument is attached */
suboptionpos = 1;
util_optarg = argp+1;
util_optind++;
return(*optp);
break;
/* a case of too many colons */
default:
suboptionpos++;
if(argv[util_optind][suboptionpos] == '\0')
{
suboptionpos = 1;
util_optind++;
}
util_optopt = '?';
return('?');
break;
}
}
suboptionpos = 1;
}
else
{
/* we are done */
return(-1);
}
/* we shouldn't get here */
return(-1);
}
/*-----------------------------------------------------------------------------
** u t i l _ i n d e x
**
** Synopsis: returns a pointer to the first occurrence of the character
** "c" in the string "s".
**
** Parameters: s - the string to search.
** c - the character to search for.
**
** Returns: a pointer to the matched character, or NULL if the character
** is not found.
**
** Constraints: NONE
**
**---------------------------------------------------------------------------*/
const char* util_index( const char* s, int c )
{
const char* result = 0;
const char* sp = 0;
assert( s );
sp = s;
while ( *sp != '\0' )
{
if ( *sp == c )
{
result = sp;
break;
}
sp++;
}
return result;
}
/*-----------------------------------------------------------------------------
** u t i l _ p o s i x F i l e P a t h
**
** Synopsis: Ensures the given path uses POSIX style slashes.
**
** Parameters: path - the path to "posixfy".
**
** Returns: NOTHING
**
** Constraints: NONE
**
**---------------------------------------------------------------------------*/
void util_posixFilePath( char* path )
{
char* pp = path;
while ( *pp )
{
if ( '\\' == *pp ) *pp = '/';
pp++;
}
}
/*-----------------------------------------------------------------------------
** u t i l _ r e p l a c e C h a r a c t e r s
**
** Synopsis: Replace characters in a string.
**
** Parameters: find - the character to find.
** replace - the charcter to replace the found character with.
** string - the string within which to do the find/replace.
**
** Returns: NOTHING
**
** Constraints: NONE
**
**---------------------------------------------------------------------------*/
void util_replaceCharacters( char find, char replace, char* string )
{
char* p = 0;
if ( string )
{
while ( p = strchr( string, find ) )
{
*p = replace;
}
}
}
/*-----------------------------------------------------------------------------
** u t i l _ r e v e r s e S p a n
**
** Synopsis: Finds the suffix which is composed completely of characters in
** in the spanSet in the specified string.
**
** Example: end = util_ReverseSpan( "name123", "312" );
** *
** * end now points to "123".
** *
** end = util_ReverseSpan( "name123", "21" );
** *
** * end would point to NULL because the character "3" is not
** * in the spanSet.
**
** Parameters: string - the string to be searched.
** spanSet - a string of characters that can be in the suffix.
**
** Returns: a pointer to the suffix string, or NULL if there is no
** suffix.
**
** Constraints: NONE
**
**---------------------------------------------------------------------------*/
const char* util_reverseSpan( const char* string, const char* spanSet )
{
const char* sp = 0;
const char* next_sp = 0;
int isEndSpan = 0;
/*
* Set a pointer to the end of the string to be searched.
*/
sp = string + strlen( string );
/*
* If the string passed in is empty, we are done.
*/
if ( sp == string ) return sp;
while( sp > string && !isEndSpan )
{
next_sp = sp - 1;
if ( strchr( spanSet, *next_sp ) )
{
sp--;
}
else
{
isEndSpan = 1;
}
}
return sp;
}
/*-----------------------------------------------------------------------------
** u t i l _ r i n d e x
**
** Synopsis: returns a pointer to the last occurrence of the character
** "c" in the string "s".
**
** Parameters: s - the string to search.
** c - the character to search for.
**
** Returns: a pointer to the matched character, or NULL if the character
** is not found.
**
** Constraints: NONE
**
**---------------------------------------------------------------------------*/
const char* util_rindex( const char* s, int c )
{
const char* result = 0;
const char* sp = 0;
int length;
assert( s );
length = strlen(s);
sp = s + length;
if ( length > 0 )
{
while ( sp != s )
{
sp--;
if ( *sp == c )
{
result = sp;
break;
}
}
}
return result;
}
/*-----------------------------------------------------------------------------
** u t i l _ s u b s t i t u t e
**
** Synopsis: Substitue strings matchin "find" with "replace" in "string".
** If this cannot be done without exceeding the size of "string"
** An error will be returned and "string" will be as it was
** when util_substitute was originally called.
**
** Parameters: find - the substring to find.
** replace - the substring to insert in place of found strings.
** string - the string to operate on.
** stringSize - the maximum size the string can grow to.
** firstOnly - flag. If non-zero only the first occurence of
** "find" will be replaced. If zero, all occurences
** will be replaced.
**
** Returns: 0 on error, the new size of the string on success.
**
** Constraints: NONE
**
**---------------------------------------------------------------------------*/
int util_substitute( const char* find,
const char* replace,
char* string,
int stringSize,
int firstOnly
)
{
char buffer[ BUFFER_SIZE + 1 ];
char* sp;
char* bp;
char* p;
int findLength = strlen( find );
int replaceLength = strlen( replace );
int count = 0;
int total = 0;
int tooBig = 0;
int status = 0;
assert( stringSize <= BUFFER_SIZE );
bp = buffer;
sp = string;
while( !tooBig && (p = strstr( sp, find )) )
{
/*
* Determine the number of characters since last find.
* Add to total characters.
* If total characters exceeds "stringSize" then break and return
* error. Otherwise copy characters since last find to buffer.
*/
count = p - sp;
total += count;
if ( total >= stringSize )
{
tooBig = 1;
continue;
}
strncpy( bp, sp, count );
bp += count;
*bp = '\0';
/*
* If adding the replace string causes buffer to exceed "stringSize"
* break and return error. Otherwise copy the replace string into
* buffer.
*/
total += replaceLength;
if ( total >= stringSize )
{
tooBig = 1;
continue;
}
strcpy( bp, replace );
bp += replaceLength;
/*
* Update the position of sp so that it points to next character
* after the last found "find" string.
*/
sp += count + findLength;
}
if ( !tooBig )
{
/*
* Attempt to copy the remaining portion of string into buffer.
* If successful, copy buffer into string and return success.
* Otherwise return error.
*/
total += strlen( sp );
if ( total < stringSize )
{
strcpy( bp, sp );
strcpy( string, buffer );
status = strlen( string );
}
}
return status;
}