/* Allocate dyamically a copy of string. * Eliminate also all whitespace in the copy. */ TA_String *TA_StringAllocTrim( TA_StringCache *stringCache, const char *string ) { char *str; char *ptrCharTmp1; const char *ptrCharTmp2; unsigned int trimmedSize; unsigned int nonTrimmedSize; TA_StringCachePriv *stringCachePriv; if( stringCache == NULL ) return NULL; stringCachePriv = (TA_StringCachePriv *)stringCache; if( !string ) return NULL; /* Evaluate the size and see if any trimming is needed. */ trimmedSize = 0; nonTrimmedSize = 0; ptrCharTmp2 = string; while( *ptrCharTmp2++ != '\0' ) { if( !isspace(*ptrCharTmp2) ) trimmedSize++; nonTrimmedSize++; } if( trimmedSize == nonTrimmedSize ) return TA_StringAlloc( stringCache, string ); trimmedSize = (trimmedSize + 1)*sizeof( unsigned char ); str = (char *)TA_Malloc( trimmedSize ); if( str != NULL ) { /* Eliminate all whitespaces (not speed optimize...) */ ptrCharTmp1 = &str[0]; ptrCharTmp2 = string; while( *ptrCharTmp2 != '\0' ) { if( !isspace(*ptrCharTmp2) ) { *ptrCharTmp1 = *ptrCharTmp2; ptrCharTmp1++; } ptrCharTmp2++; } *ptrCharTmp1 = '\0'; return TA_StringAlloc( stringCache, str ); } /* Allocation error. */ return (TA_String *)NULL; }
/* Allows to dynamically add a mini-driver. */ TA_RetCode TA_SQL_AddMinidriver( const char scheme[], const TA_SQL_Minidriver *minidriver ) { TA_PROLOG TA_String *schemeStr; TA_StringCache *cache; TA_RetCode retCode; TA_TRACE_BEGIN( TA_SQL_AddMinidriver ); if( !minidriverDict ) { minidriverDict = TA_DictAlloc( TA_DICT_KEY_ONE_STRING, NULL ); if( !minidriverDict ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } } cache = TA_GetGlobalStringCache(); TA_ASSERT( cache != NULL ); schemeStr = TA_StringAlloc( cache, scheme ); if( !schemeStr ) { TA_DictFree(minidriverDict); TA_TRACE_RETURN( TA_ALLOC_ERR ); } retCode = TA_DictAddPair_S( minidriverDict, schemeStr, (void *)minidriver ); TA_StringFree( cache, schemeStr ); TA_TRACE_RETURN( retCode ); }
/**** Global functions definitions. ****/ TA_RetCode TA_AllocStringFromLibName( TA_Libc *libHandle, const TA_String *category, const TA_String *symbol, TA_String **allocatedYahooName ) { TA_PROLOG; TA_RetCode retCode; TA_StringCache *stringCache; char buffer[200]; TA_TRACE_BEGIN( libHandle, TA_AllocStringFromLibName ); buffer[199] = '\0'; /* Just to be safe. */ /* Translate the category/symbol into the yahoo! name. */ retCode = translateToYahooName( libHandle, category, symbol, &buffer[0], 199 ); if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } stringCache = TA_GetGlobalStringCache( libHandle ); *allocatedYahooName = TA_StringAlloc( stringCache, buffer ); if( !*allocatedYahooName ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_FileIndexAddTreeValue( TA_FileIndexPriv *data, TA_String *string, TA_ValueTreeNode **added ) { TA_PROLOG; TA_ValueTreeNode *node; unsigned int allocateEmptyString; TA_Libc *libHandle; TA_StringCache *stringCache; libHandle = data->libHandle; TA_TRACE_BEGIN( libHandle, TA_FileIndexAddTreeValue ); stringCache = TA_GetGlobalStringCache( libHandle ); allocateEmptyString = 0; TA_ASSERT( libHandle, data != NULL ); if( added ) *added = NULL; if( !string ) { string = TA_StringAlloc( stringCache, "" ); if( !string ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } allocateEmptyString = 1; } /* Alloc the TA_ValueTreeNode */ node = allocTreeNode( libHandle, data->currentNode, string ); if( allocateEmptyString ) TA_StringFree( stringCache, string ); if( !node ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } data->currentNode = node; if( added ) *added = node; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_DirectoryAlloc( const char *path, TA_Directory **directory ) { #if defined( USE_WIN32_API ) HANDLE handle; WIN32_FIND_DATA data; DWORD win32Error; #endif #if defined( USE_OSLAYER ) DIRST dirHandle; const char *filePattern; char *basePath; #endif unsigned pathLength; int findNextRetCode; TA_Directory *dir; TA_String *string; TA_RetCode retCode; TA_SystemGlobal *global; const char *entryName; unsigned int entryIsDirectory; *directory = NULL; if( (path == NULL) || (directory == NULL) ) return TA_BAD_PARAM; retCode = TA_GetGlobal( &TA_SystemGlobalControl, (void **)&global ); if( retCode != TA_SUCCESS ) return retCode; dir = (TA_Directory *)TA_Malloc( sizeof( TA_Directory ) ); if( dir == NULL ) return TA_ALLOC_ERR; dir->nbFile = 0; dir->nbDirectory = 0; dir->listOfFile = TA_ListAlloc(); dir->listOfDirectory = TA_ListAlloc(); if( (dir->listOfFile == NULL) || (dir->listOfDirectory == NULL) ) { TA_DirectoryFree( dir ); return TA_ALLOC_ERR; } /* Verify that the path is valid. */ pathLength = strlen( path ); if( (pathLength == 0) || (pathLength >= MAX_PATH) ) { TA_DirectoryFree( dir ); return TA_BAD_PARAM; } /* Now get the directory from the operating system. */ #if defined( USE_WIN32_API ) handle = FindFirstFile( path, &data ); if( handle == INVALID_HANDLE_VALUE ) { win32Error = GetLastError(); global->lastError = win32Error; if( (win32Error != ERROR_FILE_NOT_FOUND) && (win32Error != ERROR_PATH_NOT_FOUND) ) { TA_DirectoryFree( dir ); return TA_ACCESS_FAILED; } /* No files or directory... but still have to pass the result * to the caller. */ *directory = dir; return TA_SUCCESS; } entryName = data.cFileName; entryIsDirectory = data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; #endif #if defined( USE_OSLAYER ) /* Split the path into the basePath and the filePattern. */ basePath = TA_Malloc( pathLength+1 ); memcpy( basePath, path, pathLength+1 ); filePattern = split_path_and_file( basePath ); if( !filePattern ) { /* With no filePattern, no file can be found... * so return an empty directory to the caller. */ *directory = dir; TA_Free( basePath ); return TA_SUCCESS; } /* Look for last separetor. */ if( !open_dir(&dirHandle, basePath ) ) { /* Errors, or no files or no directory... but * still have to pass the result to the caller. */ TA_Free( basePath ); *directory = dir; return TA_SUCCESS; } entryName = dirHandle.file_name; entryIsDirectory = dirHandle.file_attrs & ATTR_SUBDIR; #endif do { #if defined( USE_OSLAYER ) if( file_matches( entryName, filePattern ) ) { #endif if( entryIsDirectory ) { if( entryName[0] != '.' ) { string = TA_StringAlloc( global->dirnameCache, entryName ); if( string == NULL ) { #if defined( USE_OSLAYER ) close_dir(&dirHandle); TA_Free( basePath ); #endif TA_DirectoryFree( dir ); return TA_ALLOC_ERR; } retCode = TA_ListAddTail( dir->listOfDirectory, (void *)string ); if( retCode != TA_SUCCESS ) { #if defined( USE_OSLAYER ) close_dir(&dirHandle); TA_Free( basePath ); #endif TA_DirectoryFree( dir ); return retCode; } dir->nbDirectory++; } } else { string = TA_StringAlloc( global->filenameCache, entryName ); if( string == NULL ) { #if defined( USE_OSLAYER ) close_dir(&dirHandle); TA_Free( basePath ); #endif TA_DirectoryFree( dir ); return TA_ALLOC_ERR; } retCode = TA_ListAddTail( dir->listOfFile, (void *)string ); if( retCode != TA_SUCCESS ) { #if defined( USE_OSLAYER ) close_dir(&dirHandle); TA_Free( basePath ); #endif TA_DirectoryFree( dir ); return retCode; } dir->nbFile++; } #if defined( USE_OSLAYER ) } #endif #if defined( USE_WIN32_API ) findNextRetCode = FindNextFile( handle, &data ); entryName = data.cFileName; entryIsDirectory = data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; #endif #if defined( USE_OSLAYER ) findNextRetCode = read_dir( &dirHandle ); entryName = dirHandle.file_name; entryIsDirectory = dirHandle.file_attrs & ATTR_SUBDIR; #endif } while( findNextRetCode == TRUE ); #if defined( USE_OSLAYER ) TA_Free( basePath ); if( !close_dir(&dirHandle) ) { TA_DirectoryFree( dir ); return TA_INTERNAL_ERROR(11); } #endif #if defined( USE_WIN32_API ) if( FindClose( handle ) != TRUE ) { global->lastError = GetLastError(); TA_DirectoryFree( dir ); return TA_INTERNAL_ERROR(12); } #endif /* Pass the result to the caller. */ *directory = dir; return TA_SUCCESS; }
TA_RetCode TA_SIMULATOR_OpenSource( const TA_AddDataSourceParamPriv *param, TA_DataSourceHandle **handle ) { TA_PROLOG TA_DataSourceHandle *tmpHandle; TA_PrivateHandle *privData; TA_StringCache *stringCache; *handle = NULL; TA_TRACE_BEGIN( TA_SIMULATOR_OpenSource ); stringCache = TA_GetGlobalStringCache(); if( !stringCache ) { TA_TRACE_RETURN( TA_INTERNAL_ERROR(91) ); } /* Verify that the requested functionality is supported or not. */ if( param->flags & TA_REPLACE_ZERO_PRICE_BAR ) { TA_TRACE_RETURN( TA_NOT_SUPPORTED ); } /* Allocate and initialize the handle. This function will also allocate the * private handle (opaque data). */ tmpHandle = (TA_DataSourceHandle *)TA_Malloc( sizeof( TA_DataSourceHandle ) ); if( tmpHandle == NULL ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } memset( tmpHandle, 0, sizeof( TA_DataSourceHandle ) ); privData = (TA_PrivateHandle *)TA_Malloc( sizeof( TA_PrivateHandle ) ); if( !privData ) { TA_Free( tmpHandle ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } memset( privData, 0, sizeof( TA_PrivateHandle ) ); tmpHandle->opaqueData = privData; /* Copy some parameters in the private handle. */ privData->categoryIter = 0; privData->catRefIter = 0; privData->catMrgIter = 0; if( param->info == NULL ) { privData->mrgInstance = 0; tmpHandle->nbCategory = 1; } else { privData->mrgInstance = atoi( TA_StringToChar( param->info ) ); if( (privData->mrgInstance < 1) || (privData->mrgInstance > 4) ) { TA_Free( tmpHandle ); TA_Free( privData ); TA_TRACE_RETURN( TA_BAD_PARAM ); } tmpHandle->nbCategory = 2; /* Allocate the data. */ } /* Pre-allocate all the string used in this data source. */ privData->ta_sim_ref_cat = TA_StringAlloc(stringCache, "TA_SIM_REF"); privData->ta_sim_mrg_cat = TA_StringAlloc(stringCache, "TA_SIM_MRG"); privData->daily_ref_0 = TA_StringAlloc(stringCache, "DAILY_REF_0"); privData->intra_ref_0 = TA_StringAlloc(stringCache, "INTRA_REF_0"); privData->mrg_0 = TA_StringAlloc(stringCache, "MRG_0"); if( !privData->ta_sim_ref_cat || !privData->ta_sim_mrg_cat || !privData->daily_ref_0 || !privData->intra_ref_0 || !privData->mrg_0 ) { freePrivateHandle( privData ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } /* Everything is fine, return the handle to the caller. */ *handle = tmpHandle; TA_TRACE_RETURN( TA_SUCCESS ); }
TA_RetCode TA_TradeLogAdd( TA_TradeLog *tradeLog, const TA_Transaction *newTransaction ) { TA_TradeLogPriv *tradeLogPriv; TA_Instrument *id; TA_Dict *theDict; TA_DataLog *dataLog; TA_TradeDictEntry *dictEntry; TA_StringCache *stringCache; TA_String *catString; TA_String *symString; const char *catCharPtr; const char *symCharPtr; TA_RetCode retCode; int quantity, entryTradeQuantity; TA_List *entryListToUse; TA_DataLog *entryTradeLog; TA_Real highestLow, highestHigh, lowestLow, lowestHigh; TA_Real entryPrice, tempReal; int i; retCode = TA_INTERNAL_ERROR(120); /* This function will transform the TA_Transaction into * an "entry" or multiple "trades" (because an exit can * be translated into multiple trade if there was multiple * entry point). */ if( !tradeLog || !newTransaction ) return TA_BAD_PARAM; /* Check that the TA_Transaction makes sense. */ if( (newTransaction->price <= 0.0) || (newTransaction->quantity <= 0) || (TA_TimestampValidate(&newTransaction->timestamp) != TA_SUCCESS) || (newTransaction->type >= TA_NB_TRADE_TYPE)) return TA_BAD_PARAM; /* Get access to the hidden data of the TA_TradeLog. */ tradeLogPriv = (TA_TradeLogPriv *)tradeLog->hiddenData; /* Make sure this is a valid object. */ if( !tradeLogPriv || (tradeLogPriv->magicNb != TA_TRADELOGPRIV_MAGIC_NB) ) return TA_BAD_OBJECT; /* Find the TA_TradeDictEntry corresponding to * the TA_Instrument. * * Use the dictionary corresponding to the type of * key of the TA_Instrument. * * If TA_Instrument is NULL, use the pre-allocated * default TA_TradeDictEntry. */ id = newTransaction->id; if( !id ) { dictEntry = &tradeLogPriv->defaultDictEntry; catCharPtr = NULL; symCharPtr = NULL; theDict = NULL; } else { catCharPtr = id->catString; symCharPtr = id->symString; if( catCharPtr ) { if( symCharPtr ) { theDict = tradeLogPriv->tradeDictCATSYM; dictEntry = TA_DictGetValue_S2( theDict, catCharPtr, symCharPtr ); } else { theDict = tradeLogPriv->tradeDictCAT; dictEntry = TA_DictGetValue_S( theDict, catCharPtr ); } } else if( symCharPtr ) { theDict = tradeLogPriv->tradeDictCAT; dictEntry = TA_DictGetValue_S( theDict, symCharPtr ); } else { theDict = tradeLogPriv->tradeDictUserKey; dictEntry = TA_DictGetValue_I( theDict, id->userKey ); } } if( !dictEntry ) { if( !theDict ) return TA_INTERNAL_ERROR(146); /* The TA_TradeDictEntry was not found, create it! */ dictEntry = TA_Malloc( sizeof( TA_TradeDictEntry ) ); if( !dictEntry ) return TA_ALLOC_ERR; memset( &dictEntry->id, 0, sizeof(TA_Instrument) ); TA_ListInit( &dictEntry->shortEntryPrivList ); TA_ListInit( &dictEntry->longEntryPrivList ); /* Add the dictEntry to the corresponding dictionary. */ stringCache = TA_GetGlobalStringCache(); if( catCharPtr ) { catString = TA_StringAlloc( stringCache, catCharPtr ); if( !catString ) { TA_Free( dictEntry ); return TA_ALLOC_ERR; } if( symCharPtr ) { symString = TA_StringAlloc( stringCache, symCharPtr ); if( !symString ) { TA_Free( dictEntry ); TA_StringFree( stringCache, catString ); return TA_ALLOC_ERR; } retCode = TA_DictAddPair_S2( theDict, catString, symString, dictEntry ); dictEntry->id.symString = TA_StringToChar(symString); } else retCode = TA_DictAddPair_S( theDict, catString, dictEntry ); dictEntry->id.catString = TA_StringToChar(catString); } else if( symCharPtr ) { symString = TA_StringAlloc( stringCache, symCharPtr ); if( !symString ) { TA_Free( dictEntry ); return TA_ALLOC_ERR; } retCode = TA_DictAddPair_S( theDict, symString, dictEntry ); dictEntry->id.symString = TA_StringToChar(symString); } else { retCode = TA_DictAddPair_I( theDict, id->userKey, dictEntry ); dictEntry->id.userKey = id->userKey; } /* Check the retCode of the TA_DictAddXXXXX function. */ if( retCode != TA_SUCCESS ) { TA_Free( dictEntry ); return TA_ALLOC_ERR; } } /* Identify the approriate list of entry. */ switch( newTransaction->type ) { case TA_LONG_ENTRY: case TA_LONG_EXIT: entryListToUse = &dictEntry->longEntryPrivList; break; case TA_SHORT_ENTRY: case TA_SHORT_EXIT: entryListToUse = &dictEntry->shortEntryPrivList; break; default: return TA_BAD_PARAM; } /* The sign of the quantity indicates if the * data log is a completed trade (+) or an * entry (-). */ switch( newTransaction->type ) { case TA_LONG_ENTRY: case TA_SHORT_ENTRY: /* Allocate a data log and add it to the list. */ dataLog = TA_AllocatorForDataLog_Alloc( &tradeLogPriv->allocator ); if( !dataLog ) return TA_ALLOC_ERR; dataLog->u.entry.quantity = -(newTransaction->quantity); dataLog->u.entry.entryPrice = newTransaction->price; TA_TimestampCopy( &dataLog->u.entry.entryTimestamp, &newTransaction->timestamp ); TA_ListNodeAddTail( entryListToUse, &dataLog->u.entry.node, dataLog ); break; case TA_LONG_EXIT: case TA_SHORT_EXIT: /* Invalidate cached calculation of this trade log. */ tradeLogPriv->flags &= ~TA_PMVALUECACHE_CALCULATED; /* Transform this transaction into one or * multiple trade(s). */ entryTradeLog = TA_ListRemoveHead( entryListToUse ); if( !entryTradeLog ) return TA_ENTRY_TRANSACTION_MISSING; quantity = newTransaction->quantity; while( quantity ) { entryTradeQuantity = -entryTradeLog->u.trade.quantity; if( entryTradeQuantity == quantity ) { /* This entry have exactly the right amount of * position for what needs to be closed. * Just transform the entry into a trade. */ entryTradeLog->u.trade.quantity = quantity; entryTradeLog->u.trade.id = id; TA_TimestampCopy( &entryTradeLog->u.trade.exitTimestamp, &newTransaction->timestamp ); /* Calculate the profit and make the entryPrice * negative if this is a short trade. * Both are multiplied by the quantity being * traded. */ entryPrice = entryTradeLog->u.entry.entryPrice; if( newTransaction->type == TA_LONG_EXIT ) { entryTradeLog->u.trade.profit = (newTransaction->price-entryPrice)*quantity; CALC_EXCURSION_LONG; } else { entryTradeLog->u.trade.profit = (entryPrice-newTransaction->price)*quantity; entryPrice = -entryPrice; CALC_EXCURSION_SHORT; } entryTradeLog->u.entry.entryPrice = entryPrice * quantity; return TA_SUCCESS; /* Done! */ } else if( entryTradeQuantity < quantity ) { /* This entry have less than the amount of * position that needs to be closed. * Just transform the entry into a trade * and move to the next entry. */ entryTradeLog->u.trade.quantity = entryTradeQuantity; quantity -= entryTradeQuantity; entryTradeLog->u.trade.id = id; TA_TimestampCopy( &entryTradeLog->u.trade.exitTimestamp, &newTransaction->timestamp ); /* Calculate the profit and make the entryPrice * negative if this is a short trade. * Both are multiplied by the quantity being * traded. */ entryPrice = entryTradeLog->u.trade.entryPrice; if( newTransaction->type == TA_LONG_EXIT ) { entryTradeLog->u.trade.profit = (newTransaction->price-entryPrice)*entryTradeQuantity; CALC_EXCURSION_LONG; } else { entryTradeLog->u.trade.profit = (entryPrice-newTransaction->price)*entryTradeQuantity; entryPrice = -entryPrice; CALC_EXCURSION_SHORT; } entryTradeLog->u.trade.entryPrice = entryPrice * entryTradeQuantity; /* Move to the next entry. If none available, that means there * was more "exit" than "entry" and this is considered an * error. */ entryTradeLog = TA_ListRemoveHead( entryListToUse ); if( !entryTradeLog ) return TA_ENTRY_TRANSACTION_MISSING; } else { /* This entry have more position than what the * exit requires, so the entry must be preserved. * Consequently, a new tradeLog must be allocated. */ dataLog = TA_AllocatorForDataLog_Alloc( &tradeLogPriv->allocator ); if( !dataLog ) return TA_ALLOC_ERR; TA_TimestampCopy( &dataLog->u.trade.entryTimestamp, &entryTradeLog->u.trade.entryTimestamp ); TA_TimestampCopy( &dataLog->u.trade.exitTimestamp, &newTransaction->timestamp ); dataLog->u.trade.quantity = quantity; entryPrice = entryTradeLog->u.trade.entryPrice; if( newTransaction->type == TA_LONG_EXIT ) { dataLog->u.trade.profit = (newTransaction->price-entryPrice)*quantity; CALC_EXCURSION_LONG; } else { dataLog->u.trade.profit = (entryPrice-newTransaction->price)*quantity; entryPrice = -entryPrice; CALC_EXCURSION_SHORT; } dataLog->u.trade.entryPrice = entryPrice*quantity; dataLog->u.trade.id = id; /* Adjust the entry and put it back for being process * again later. */ entryTradeLog->u.trade.quantity += quantity; TA_ListNodeAddHead( entryListToUse, &entryTradeLog->u.entry.node, entryTradeLog ); return TA_SUCCESS; /* Done! */ } } break; default: return TA_INTERNAL_ERROR(121); } return TA_SUCCESS; }
/**** Global functions definitions. ****/ TA_FileIndexPriv *TA_FileIndexPrivAlloc( TA_Libc *libHandle, TA_String *initialCategory, TA_String *initialCategoryCountry, TA_String *initialCategoryExchange, TA_String *initialCategoryType ) { TA_FileIndexPriv *fileIndexPrivData; TA_StringCache *stringCache; stringCache = TA_GetGlobalStringCache( libHandle ); /* Initialize the TA_FileIndexPriv element. */ fileIndexPrivData = (TA_FileIndexPriv *)TA_Malloc( libHandle, sizeof( TA_FileIndexPriv ) ); if( !fileIndexPrivData ) return NULL; /* initialize all fields to NULL. */ memset( fileIndexPrivData, 0, sizeof( TA_FileIndexPriv ) ); /* Now attempt to allocate all sub-elements. */ fileIndexPrivData->libHandle = libHandle; stringCache = TA_GetGlobalStringCache( libHandle ); fileIndexPrivData->initialCategoryString = TA_StringDup( stringCache, initialCategory ); fileIndexPrivData->initialCategoryCountryString = TA_StringDup( stringCache, initialCategoryCountry); fileIndexPrivData->initialCategoryExchangeString = TA_StringDup( stringCache, initialCategoryExchange ); fileIndexPrivData->initialCategoryTypeString = TA_StringDup( stringCache, initialCategoryType ); if( (fileIndexPrivData->initialCategoryString == NULL) || (fileIndexPrivData->initialCategoryCountryString == NULL) || (fileIndexPrivData->initialCategoryExchangeString == NULL) || (fileIndexPrivData->initialCategoryTypeString == NULL) ) { freeFileIndexPriv( (void *)fileIndexPrivData ); return NULL; } fileIndexPrivData->scratchPad = (char *)TA_Malloc( libHandle, TA_SOURCELOCATION_MAX_LENGTH+2 ); if( !fileIndexPrivData->scratchPad ) { freeFileIndexPriv( (void *)fileIndexPrivData ); return NULL; } fileIndexPrivData->listLocationToken = TA_ListAlloc( libHandle ); if( !fileIndexPrivData->listLocationToken ) { freeFileIndexPriv( (void *)fileIndexPrivData ); return NULL; } fileIndexPrivData->listCategory = TA_ListAlloc( libHandle ); if( !fileIndexPrivData->listCategory ) { freeFileIndexPriv( (void *)fileIndexPrivData ); return NULL; } fileIndexPrivData->root = allocTreeNode( libHandle, NULL, NULL ); if( !fileIndexPrivData->root ) { freeFileIndexPriv( (void *)fileIndexPrivData ); return NULL; } fileIndexPrivData->currentNode = fileIndexPrivData->root; fileIndexPrivData->wildOneChar = TA_StringAlloc( stringCache, "?" ); fileIndexPrivData->wildZeroOrMoreChar = TA_StringAlloc( stringCache, "*" ); fileIndexPrivData->wildOneOrMoreChar = TA_StringAlloc( stringCache, "?*" ); if( (!fileIndexPrivData->wildOneChar) || (!fileIndexPrivData->wildZeroOrMoreChar) || (!fileIndexPrivData->wildOneOrMoreChar) ) { freeFileIndexPriv( (void *)fileIndexPrivData ); return NULL; } return fileIndexPrivData; }