unsigned int TA_ReadOpToField( TA_ReadOp readOp ) { if( TA_IS_REAL_CMD(readOp) ) { switch( TA_GET_IDX(readOp) ) { case TA_CLOSE_IDX: return TA_CLOSE; case TA_OPEN_IDX: return TA_OPEN; case TA_HIGH_IDX: return TA_HIGH; case TA_LOW_IDX: return TA_LOW; } } else if( TA_IS_INTEGER_CMD(readOp) ) { switch( TA_GET_IDX(readOp) ) { case TA_VOLUME_IDX: return TA_VOLUME; case TA_OPENINTEREST_IDX: return TA_OPENINTEREST; default: return TA_TIMESTAMP; } } TA_FATAL_RET( NULL, readOp, 0, TA_ALL ); /* Unreachable code: * return TA_ALL; */ }
TA_RetCode TA_ReadOp_Do( TA_FileHandle *fileHandle, const TA_ReadOpInfo *readOpInfo, TA_Period period, const TA_Timestamp *start, const TA_Timestamp *end, unsigned int minimumNbBar, TA_Field fieldToAlloc, TA_ParamForAddData *paramForAddData, unsigned int *nbBarAdded ) { TA_PROLOG TA_RetCode retCode; TA_EstimateInfo estimationInfo; unsigned int nbElementToAllocate; unsigned int memoryNeeded; /* Boolean */ unsigned int timeNeeded; /* Boolean */ TA_Real *arrayReal[TA_REAL_ARRAY_SIZE]; TA_Integer *arrayInteger[TA_INTEGER_ARRAY_SIZE]; TA_Timestamp *timestamp; TA_Real *openBeg, *highBeg, *lowBeg, *closeBeg; TA_Integer *volumeBeg, *openInterestBeg; TA_Timestamp *timestampBeg; TA_Timestamp tmpTimestamp; TA_ReadOp op; TA_Field fieldToProcess; unsigned int year, month, day, hour, min, sec; TA_Integer curOp; unsigned int nbTotalByteDone, nbTotalBarDone; unsigned int nbBarAddedInTheBlock; char monthChar[4]; char cnvtArray[CNVT_ARRAY_SIZE]; unsigned int cnvtArrayIdx; unsigned int nbByteToAllocReal; unsigned int nbByteToAllocInteger; unsigned int fileSize; unsigned int skipField; unsigned int lineToSkip; unsigned int nbByteRead; unsigned int nbLetter; TA_Real lastValidClose; const char *car; register TA_Real tmpReal; register TA_Integer tmpInt; register unsigned int tmpIdx; register unsigned int nbCharToRead; unsigned int lastOpFieldIncremented; TA_TRACE_BEGIN( TA_PriceBarRead ); /* Initialization of local variables. */ openBeg = highBeg = lowBeg = closeBeg = NULL; timestampBeg = NULL; volumeBeg = openInterestBeg = NULL; timestamp = NULL; retCode = TA_SUCCESS; lastValidClose = 0.0; fieldToProcess = readOpInfo->fieldProvided & fieldToAlloc; if( (fieldToProcess & fieldToAlloc) != fieldToAlloc ) { /* Nothing to read because not all the requested * fields are provided by this data source! */ return TA_SUCCESS; } /* Estimate the initial amount of memory to allocate. */ fileSize = TA_FileSize( fileHandle ); retCode = TA_EstimateAllocInit( start, end, period, minimumNbBar, 2048, &estimationInfo, &nbElementToAllocate ); if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } if( nbElementToAllocate == 0 ) { TA_TRACE_RETURN( TA_SUCCESS ); /* Nothing to read!? Just return... */ } memset( arrayInteger, 0, sizeof( arrayInteger ) ); memset( arrayReal, 0, sizeof( arrayReal ) ); /* Set the date/time pointers to where the information will be stored. */ arrayInteger[TA_HOUR_IDX] = (TA_Integer *)&hour; arrayInteger[TA_MIN_IDX] = (TA_Integer *)&min; arrayInteger[TA_SEC_IDX] = (TA_Integer *)&sec; arrayInteger[TA_MONTH_IDX] = (TA_Integer *)&month; arrayInteger[TA_YEAR_IDX] = (TA_Integer *)&year; arrayInteger[TA_DAY_IDX] = (TA_Integer *)&day; /* Set default time/date. */ year = 1900; month = day = 1; hour = 23; min = sec = 59; /* Check if the processing of the time will be needed. */ timeNeeded = isTimeNeeded( readOpInfo->arrayReadOp); /* 'car' always point to the character being currently handled. */ nbByteRead = 0; car = TA_FileSeqRead( fileHandle, &nbByteRead ); if( (car == NULL) || (nbByteRead == 0) ) return TA_SUCCESS; /* End of file! */ --nbByteRead; nbTotalByteDone = 0; nbTotalBarDone = 0; nbBarAddedInTheBlock = 0; memoryNeeded = 1; curOp = 0; skipField = 0; monthChar[3] = '\0'; /* When requested, skip header lines. */ lineToSkip = readOpInfo->nbHeaderLineToSkip; while( lineToSkip-- ) { while( *car != '\n' ) { GET_CHAR; if( car == NULL ) goto exit_loops; } } line_loop: /* Always jump here when end-of-line is found (EOL). */ /* If curOp != 0, the last operations are canceled. */ REVERT_OPERATIONS; curOp = 0; lastOpFieldIncremented = 0; /* Start over a new line. */ if( memoryNeeded ) { /* Allocate the memory. */ nbByteToAllocReal = nbElementToAllocate * sizeof( TA_Real ); nbByteToAllocInteger = nbElementToAllocate * sizeof( TA_Integer ); timestamp = (TA_Timestamp *)TA_Malloc( nbElementToAllocate * sizeof( TA_Timestamp ) ); timestampBeg = timestamp; if( !timestampBeg ) { retCode = TA_ALLOC_ERR; goto exit_loops; } #define TA_ALLOC_MEM(upperc,lowerc,typepar) \ { \ if( fieldToProcess & TA_##upperc ) \ { \ lowerc##Beg = (TA_##typepar *)TA_Malloc( nbByteToAlloc##typepar ); \ array##typepar[TA_##upperc##_IDX] = lowerc##Beg; \ if( !lowerc##Beg ) \ { \ retCode = TA_ALLOC_ERR; \ goto exit_loops; \ } \ } \ } TA_ALLOC_MEM( OPEN, open, Real ); TA_ALLOC_MEM( HIGH, high, Real ); TA_ALLOC_MEM( LOW, low, Real ); TA_ALLOC_MEM( CLOSE, close, Real ); TA_ALLOC_MEM( VOLUME, volume, Integer ); TA_ALLOC_MEM( OPENINTEREST, openInterest, Integer ); #undef TA_ALLOC_MEM memoryNeeded = 0; } op_loop: /* Jump here when ready to proceed with the next command. */ op = readOpInfo->arrayReadOp[curOp]; if( !(op&TA_CMD_READ_MONTH_CHAR) ) { /* Skip leading non-numeric character. */ SKIP_UNTIL_NUMERIC; } /* Shall we skip this field? */ if( TA_IS_SKIP_SET(op) ) { if( (op&(TA_CMD_READ_REAL|TA_CMD_READ_INTEGER)) == 0 ) { tmpInt = TA_GET_NB_NUMERIC(op); curOp++; while( tmpInt-- ) { GET_CHAR; CHECK_EOL_EOF; } } else { if( skipField == 0 ) { skipField = TA_GET_NB_NUMERIC(op); TA_ASSERT( skipField > 0 ); } if( --skipField == 0 ) curOp++; SKIP_NUMERIC; if( (op&TA_CMD_READ_REAL) && (*car == '.') ) { GET_CHAR; CHECK_EOL_EOF; SKIP_NUMERIC; } } } else { cnvtArrayIdx = 0; if( TA_IS_REAL_CMD(op) ) { /* Extract a numeric into cnvtArray. */ READ_IN_CNVT_ARRAY; /* This is a TA_Real. */ if( car && (*car == '.') ) { /* Read rest of the float after the '.' */ READ_IN_CNVT_ARRAY; } cnvtArray[cnvtArrayIdx] = '\0'; tmpReal = atof( &cnvtArray[0] ); /* Write the TA_Real in memory. */ tmpIdx = TA_GET_IDX(op); TA_ASSERT( tmpIdx < TA_REAL_ARRAY_SIZE ); TA_ASSERT( arrayReal[tmpIdx] != NULL ); if( tmpReal != 0.0 ) { *(arrayReal[tmpIdx]) = tmpReal; if( tmpIdx == TA_CLOSE_IDX ) lastValidClose = tmpReal; } else if( TA_IS_REPLACE_ZERO(op) ) { /* Replace this zero value with the last known close. * If there is no previous close, this line is ignored. */ if( lastValidClose != 0.0 ) *(arrayReal[tmpIdx]) = lastValidClose; else { SKIP_LINE; } } else { /* Zero are not expected, consider this as a failure * and ignore all further data from this file. */ retCode = TA_PRICE_BAR_CONTAINS_ZERO; goto exit_loops; } arrayReal[tmpIdx]++; curOp++; } else { /* This is a TA_Integer. */ if( !(op&TA_CMD_READ_MONTH_CHAR) ) { nbCharToRead = TA_GET_NB_NUMERIC(op); if( nbCharToRead ) { READ_N_CHAR_IN_CNVT_ARRAY(nbCharToRead); } else { READ_IN_CNVT_ARRAY; } cnvtArray[cnvtArrayIdx] = '\0'; tmpInt = atoi( &cnvtArray[0] ); } else { /* Try to find a 3 letters month string. * Translate it to a [1..12] integer. */ nbLetter = 1; do { CHECK_EOL_EOF; monthChar[nbLetter] = (char)toupper(*car); GET_CHAR; nbLetter++; } while( nbLetter != 3 ); do { CHECK_EOL_EOF; monthChar[0] = monthChar[1]; monthChar[1] = monthChar[2]; monthChar[2] = (char)toupper(*car); if( strncmp("JAN",monthChar,3) == 0 ) tmpInt = 1; else if( strncmp("FEB",monthChar,3) == 0 ) tmpInt = 2; else if( strncmp("MAR",monthChar,3) == 0 ) tmpInt = 3; else if( strncmp("APR",monthChar,3) == 0 ) tmpInt = 4; else if( strncmp("MAY",monthChar,3) == 0 ) tmpInt = 5; else if( strncmp("JUN",monthChar,3) == 0 ) tmpInt = 6; else if( strncmp("JUL",monthChar,3) == 0 ) tmpInt = 7; else if( strncmp("AUG",monthChar,3) == 0 ) tmpInt = 8; else if( strncmp("SEP",monthChar,3) == 0 ) tmpInt = 9; else if( strncmp("OCT",monthChar,3) == 0 ) tmpInt = 10; else if( strncmp("NOV",monthChar,3) == 0 ) tmpInt = 11; else if( strncmp("DEC",monthChar,3) == 0 ) tmpInt = 12; else tmpInt = 0; GET_CHAR; } while( tmpInt == 0 ); } /* Write the TA_Integer in memory. */ tmpIdx = TA_GET_IDX(op); TA_ASSERT( tmpIdx < TA_INTEGER_ARRAY_SIZE ); TA_ASSERT( arrayInteger[tmpIdx] != NULL ); *(arrayInteger[tmpIdx]) = tmpInt; if( tmpIdx > TA_YEAR_IDX ) arrayInteger[tmpIdx]++; curOp++; if( TA_IS_TIMESTAMP_COMPLETE(op) ) { /* Build the timestamp. */ retCode = TA_SetDate( year, month, day, &tmpTimestamp ); if( retCode != TA_SUCCESS ) goto exit_loops; /* Invalid date */ if( !timeNeeded ) { /* Ignore time in comparison and use default to build the price bar. */ tmpTimestamp.time = 23595900; /* Default EOD time */ if( start && (tmpTimestamp.date < start->date) ) { /* This price bar is not needed, jump to the next line. */ retCode = TA_SUCCESS; SKIP_LINE; } if( end && (tmpTimestamp.date > end->date) ) { /* This price bar is beyond the upper limit, just exit. */ goto exit_loops; } } else { retCode = TA_SetTime( hour, min, sec, &tmpTimestamp ); if( retCode != TA_SUCCESS ) goto exit_loops; /* Invalid time */ if( start && TA_TimestampLess(&tmpTimestamp,start) ) { /* This price bar is not needed, jump to the next line. */ retCode = TA_SUCCESS; SKIP_LINE; } if( end && TA_TimestampGreater(&tmpTimestamp, end) ) { /* This price bar is beyond the upper limit, just exit. */ goto exit_loops; } } /* Write the timestamp in memory. */ *timestamp = tmpTimestamp; } } if( TA_IS_READ_STOP_FLAG_SET(op) ) { #ifdef DEBUG_PRINTF printf( "(%d%d%d,%e,%e,%e,%e,%d)\n", timestampBeg?TA_GetYear(×tampBeg[nbBarAddedInTheBlock]):0, timestampBeg?TA_GetMonth(×tampBeg[nbBarAddedInTheBlock]):0, timestampBeg?TA_GetDay(×tampBeg[nbBarAddedInTheBlock]):0, openBeg?openBeg[nbBarAddedInTheBlock]:0.0, highBeg?highBeg[nbBarAddedInTheBlock]:0.0, lowBeg?lowBeg[nbBarAddedInTheBlock]:0.0, closeBeg?closeBeg[nbBarAddedInTheBlock]:0.0, volumeBeg?volumeBeg[nbBarAddedInTheBlock]:0 ); #endif /* At this point, the price bar is completely written in memory. */ timestamp++; curOp = 0; nbBarAddedInTheBlock++; if( nbBarAddedInTheBlock < nbElementToAllocate ) { /* Go to next line. */ SKIP_LINE; } else { /* There is not enough memory for another bar, so re-allocate * some more. */ retCode = TA_HistoryAddData( paramForAddData, nbBarAddedInTheBlock, period, timestampBeg, openBeg, highBeg, lowBeg, closeBeg, volumeBeg, openInterestBeg ); /* TA_HistoryAddData is ALWAYS the owner of these memory block * when called. So we set these to NULL to make sure there will * be no attempt to free these from this function. */ openBeg = highBeg = lowBeg = closeBeg = NULL; timestampBeg = NULL; volumeBeg = openInterestBeg = NULL; nbTotalBarDone += nbBarAddedInTheBlock; nbBarAddedInTheBlock = 0; if( retCode != TA_SUCCESS ) goto exit_loops; retCode = TA_EstimateAllocNext( &estimationInfo, &nbElementToAllocate ); if( retCode != TA_SUCCESS ) goto exit_loops; memoryNeeded = 1; SKIP_LINE; } } else { /* Make sure we did not hit an EOL or EOF prematurly, if yes, * this line will be silently ignored. */ CHECK_EOL_EOF; } } goto op_loop; exit_loops: /* Jump here when the end-of-file is hit (or an error occured) */ /* On succesful exit, process possibly remaining data. */ if( (retCode == TA_SUCCESS) && (nbBarAddedInTheBlock != 0) ) { retCode = TA_HistoryAddData( paramForAddData, nbBarAddedInTheBlock, period, timestampBeg, openBeg, highBeg, lowBeg, closeBeg, volumeBeg, openInterestBeg ); openBeg = highBeg = lowBeg = closeBeg = NULL; timestampBeg = NULL; volumeBeg = openInterestBeg = NULL; nbTotalBarDone += nbBarAddedInTheBlock; } /* ALWAYS verify if locally allocated memory needs to be freed. ALWAYS. */ FREE_IF_NOT_NULL( openBeg ); FREE_IF_NOT_NULL( highBeg ); FREE_IF_NOT_NULL( lowBeg ); FREE_IF_NOT_NULL( closeBeg ); FREE_IF_NOT_NULL( volumeBeg ); FREE_IF_NOT_NULL( openInterestBeg ); FREE_IF_NOT_NULL( timestampBeg ); /* An indication that no more data needs to be provided is not a failure. */ if( retCode == TA_ENOUGH_DATA ) retCode = TA_SUCCESS; /* Return the number of added price bar to the caller. */ if( nbBarAdded ) *nbBarAdded = nbTotalBarDone; TA_TRACE_RETURN( retCode ); }
TA_RetCode TA_ReadOpInfoAlloc( const char *sourceInfo, TA_ReadOpInfo **allocatedInfo, unsigned int readOpFlags ) { TA_PROLOG TA_RetCode retCode; TA_ReadOp readOp; TA_ReadOp *arrayReadOp; TA_ReadOpInfo *newReadOpInfo; TA_Field fieldMask, fieldProvided; unsigned int timeframeIdx; unsigned int intraDayIncPeriod; TA_TokenId intraDayIncToken; TA_TokenId tempToken; unsigned int tempInt; unsigned int period; unsigned int errorOccurred; const char *pos; unsigned int inField; unsigned int nbField; unsigned int nbCharInField; unsigned int skipNonDigitLine; const char *ptrFirstCarInField; unsigned char localBuf[10]; unsigned int bufIdx, opIdx, i; register unsigned int flagSet; register TA_ReadOp *ptrReadOp; TA_TRACE_BEGIN( TA_BuildArrayReadOp ); newReadOpInfo = (TA_ReadOpInfo *)TA_Malloc( sizeof( TA_ReadOpInfo ) ); /* These variables are resolved within this function. */ memset( newReadOpInfo, 0, sizeof( TA_ReadOpInfo ) ); /* At this point, TA_ReadOpInfoFree can be safely called. */ /* Keep track of some user provided parameter. */ newReadOpInfo->sourceInfo = sourceInfo; newReadOpInfo->readOpFlags = readOpFlags; /* Initialize some defaults. */ newReadOpInfo->openInterestMult = 100; newReadOpInfo->volumeMult = 100; nbField = 0; intraDayIncPeriod = 0; intraDayIncToken = TA_TOK_END; pos = newReadOpInfo->sourceInfo; if( !pos || (*pos == '\0') ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_MISSING_FIELD ); } /* Find how many fields are defined and check some syntax * at the same time. */ if( *pos != '[' ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } inField = 0; nbCharInField = 0; skipNonDigitLine = 0; ptrFirstCarInField = NULL; while( *pos != '\0' ) { switch( *pos ) { case '[': if( inField ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } inField = 1; break; case ']': if( (!inField) || (nbCharInField == 0) ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } nbField++; /* Exclude fields not generating a TA_ReadOp. * For the time being that means only the -H and -NDL field. */ if( nbCharInField >= 2 ) { TA_ASSERT( ptrFirstCarInField != NULL ); if( ptrFirstCarInField[0] == '-' ) { if( toupper(ptrFirstCarInField[1]) == 'H' ) nbField--; else if( (toupper(ptrFirstCarInField[1]) == 'N') && (toupper(ptrFirstCarInField[2]) == 'D') && (toupper(ptrFirstCarInField[3]) == 'L') ) { skipNonDigitLine = 1; nbField--; } } } inField = 0; nbCharInField = 0; ptrFirstCarInField = NULL; break; default: if( !inField ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } if( nbCharInField == 0 ) ptrFirstCarInField = pos; nbCharInField++; break; } pos++; } if( inField || *(pos-1) != ']' ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } /* Build the TA_ReadOp array */ arrayReadOp = (TA_ReadOp *)TA_Malloc( sizeof( TA_ReadOp ) * nbField ); if( !arrayReadOp ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_ALLOC_ERR ); } newReadOpInfo->arrayReadOp = arrayReadOp; pos = TA_StringToChar(newReadOpInfo->sourceInfo); bufIdx = 0; opIdx = 0; while( *pos != '\0' && (opIdx < nbField) ) { switch( *pos ) { case '[': break; case ']': localBuf[bufIdx] ='\0'; bufIdx = 0; /* Identify the field and build the TA_ReadOp. */ tempInt = 0; retCode = buildReadOp( newReadOpInfo, (const char *)&localBuf[0], &arrayReadOp[opIdx], &tempToken, &tempInt ); if( retCode != TA_SUCCESS ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( retCode ); } if( arrayReadOp[opIdx] != 0 ) { /* Set the replace zero flag as needed */ if( TA_IS_REPLACE_ZERO(readOpFlags) && TA_IS_REAL_CMD(arrayReadOp[opIdx]) ) { TA_SET_REPLACE_ZERO(arrayReadOp[opIdx]); } /* Set the skipNonDigitLine flag as needed. */ if( skipNonDigitLine == 1 ) { TA_SET_SKIP_NDL_FLAG(arrayReadOp[opIdx]); } /* Ooof... this readOp is now all build! */ opIdx++; } /* If this is a time token, make sure this * is not in contradiction with an already * specified increment. */ if( intraDayIncPeriod ) { errorOccurred = 0; switch( tempToken ) { case TA_TOK_SEC: case TA_TOK_SS: if( (intraDayIncToken == TA_TOK_MIN) || (intraDayIncToken == TA_TOK_MN) ) errorOccurred = 1; /* no break */ case TA_TOK_MIN: case TA_TOK_MN: if( (intraDayIncToken == TA_TOK_HOUR) || (intraDayIncToken == TA_TOK_HH) ) errorOccurred = 1; break; case TA_TOK_HOUR: case TA_TOK_HH: errorOccurred = 1; break; default: /* Do nothing */ break; } if( errorOccurred ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } } /* Check if a period increment is specified. */ if( (tempInt != 0) && (tempInt != 1) ) { if( intraDayIncPeriod != 0 ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } intraDayIncPeriod = tempInt; intraDayIncToken = tempToken; } break; default: if( bufIdx >= sizeof(localBuf)-1 ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } localBuf[bufIdx++] = *pos; break; } pos++; } if( opIdx != nbField ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INTERNAL_ERROR(89) ); } arrayReadOp[opIdx-1] |= TA_CMD_LAST_FLAG; /* Build the mask representing the fields provided. */ fieldProvided = 0; timeframeIdx = TA_INTEGER_ARRAY_SIZE; for( opIdx=0; opIdx < nbField; opIdx++ ) { readOp = arrayReadOp[opIdx]; TA_ASSERT( readOp != 0 ); /* Parano test */ if( !TA_IS_PERMANENT_SKIP_SET(readOp) ) { /* Make sure this field was not specified twice. */ for( i=opIdx+1; i < nbField; i++ ) { if( (TA_IS_REAL_CMD(readOp) && TA_IS_REAL_CMD(arrayReadOp[i])) || (TA_IS_INTEGER_CMD(readOp) && TA_IS_INTEGER_CMD(arrayReadOp[i])) ) { if( (TA_GET_IDX(readOp) == TA_GET_IDX(arrayReadOp[i])) && !TA_IS_PERMANENT_SKIP_SET(arrayReadOp[i]) ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_REDUNDANT_FIELD ); } } } /* Parano test: Double-check redundant field in a different way. */ fieldMask = TA_ReadOpToField( readOp ); TA_ASSERT( fieldMask != 0 ); if( !(fieldMask & TA_TIMESTAMP) && (fieldProvided & fieldMask) ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_REDUNDANT_FIELD ); } /* Set the field. */ fieldProvided |= fieldMask; /* Keep track of the smallest granularity of the timestamp. */ if( fieldMask & TA_TIMESTAMP ) { if( (timeframeIdx == TA_INTEGER_ARRAY_SIZE) || (TA_GET_IDX(readOp) < timeframeIdx) ) timeframeIdx = TA_GET_IDX(readOp); } } } /* No date/time reference provided!? This is considered an error * in the current implementation. */ if( timeframeIdx == TA_INTEGER_ARRAY_SIZE ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_MISSING_DATE_OR_TIME_FIELD ); } /* Determine at which point the timestamp is completed. */ flagSet = 0; for( opIdx=nbField; opIdx > 0; opIdx-- ) { ptrReadOp = &arrayReadOp[opIdx-1]; readOp = *ptrReadOp; if( !flagSet && TA_IS_INTEGER_CMD(readOp) && (TA_GET_IDX(readOp)<=TA_YEAR_IDX) && !TA_IS_PERMANENT_SKIP_SET(readOp) ) { TA_SET_TIMESTAMP_COMPLETE(*ptrReadOp); flagSet = 1; } else { TA_CLR_TIMESTAMP_COMPLETE(*ptrReadOp); } } /* Validate and identify the period. */ period = 0; if( intraDayIncPeriod ) { errorOccurred = 0; switch( timeframeIdx ) { case TA_YEAR_IDX: case TA_MONTH_IDX: case TA_DAY_IDX: errorOccurred = 1; break; case TA_HOUR_IDX: if( (intraDayIncPeriod < TA_1HOUR) || (intraDayIncPeriod >= TA_DAILY) ) errorOccurred = 1; break; case TA_MIN_IDX: if( (intraDayIncPeriod < TA_1MIN) || (intraDayIncPeriod >= TA_1HOUR) ) errorOccurred = 1; break; case TA_SEC_IDX: if( (intraDayIncPeriod < TA_1SEC) || (intraDayIncPeriod >= TA_1MIN) ) errorOccurred = 1; break; default: TA_ReadOpInfoFree( newReadOpInfo ); TA_FATAL( NULL, timeframeIdx, fieldProvided ); } if( errorOccurred ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } period = intraDayIncPeriod; } else { switch( timeframeIdx ) { case TA_YEAR_IDX: period = TA_YEARLY; break; case TA_MONTH_IDX: period = TA_MONTHLY; break; case TA_DAY_IDX: period = TA_DAILY; break; case TA_HOUR_IDX: period = TA_1HOUR; break; case TA_MIN_IDX: period = TA_1MIN; break; case TA_SEC_IDX: period = TA_1SEC; break; default: TA_FATAL( NULL, timeframeIdx, fieldProvided ); } } /* A last check... */ if( period == 0 ) { TA_ReadOpInfoFree( newReadOpInfo ); TA_TRACE_RETURN( TA_INVALID_FIELD ); } /* Everything is fine, let's return the information. */ newReadOpInfo->arrayReadOp = arrayReadOp; newReadOpInfo->fieldProvided = fieldProvided; newReadOpInfo->nbReadOp = nbField; newReadOpInfo->period = period; *allocatedInfo = newReadOpInfo; TA_TRACE_RETURN( TA_SUCCESS ); }