/* TA-LIB Copyright (c) 1999-2026, Mario Fortier * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * - Neither name of author nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* AUTO-GENERATED by ta_codegen — DO NOT EDIT. * Source of truth: ta_codegen/input// (regenerate: cd ta_codegen/generator && cargo run -- generate) */ #include #include #include "ta_func.h" #include "ta_utility.h" #include "ta_memory.h" #include "ta_func_stream_private.h" /* List of contributors: * * Initial Name/description * ------------------------------------------------------------------- * MF Mario Fortier * CC Claude Code (AI assistant) * * Change history: * * MMDDYY BY Description * ------------------------------------------------------------------- * 112400 MF Template creation. * 052603 MF Adapt code to compile with .NET Managed C++ * 070626 MF,CC Speed optimization: True Range computed inline in a * single pass (bit-exact, no temporary buffer). * 090326 MF,CC #338 Two-coefficient Wilder step; no divide in the * loop-carried chain. */ TA_LIB_API int TA_ATR_Lookback( int optInTimePeriod ) { if( (int)optInTimePeriod == TA_INTEGER_DEFAULT ) optInTimePeriod = 14; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return -1; /* The ATR lookback is the sum of: * 1 + (optInTimePeriod - 1) * * Where 1 is for the True Range, and * (optInTimePeriod-1) is for the simple * moving average. */ return optInTimePeriod + TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_ATR,Atr); } TA_FMA_MULTIVERSION TA_LIB_API TA_RetCode TA_ATR( int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { int i; int outIdx; int today; int lookbackTotal; int nbATR; double prevATR; double periodTotal; double wAlpha; double wBeta; double val2; double val3; double greatest; double tempCY; double tempLT; double tempHT; if( (startIdx < 0) || (startIdx > TA_MAX_INDEX) ) return TA_OUT_OF_RANGE_START_INDEX; if( (endIdx < 0) || (endIdx > TA_MAX_INDEX) || (endIdx < startIdx) ) return TA_OUT_OF_RANGE_END_INDEX; if( (int)optInTimePeriod == TA_INTEGER_DEFAULT ) optInTimePeriod = 14; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return TA_BAD_PARAM; if( !inHigh ) return TA_BAD_PARAM; if( !inLow ) return TA_BAD_PARAM; if( !inClose ) return TA_BAD_PARAM; if( !outBegIdx || !outNBElement ) return TA_BAD_PARAM; if( !outReal ) return TA_BAD_PARAM; /* Average True Range is the greatest of the following: * * val1 = distance from today's high to today's low. * val2 = distance from yesterday's close to today's high. * val3 = distance from yesterday's close to today's low. * * These value are averaged for the specified period using * Wilder method. This method have an unstable period comparable * to and Exponential Moving Average (EMA). */ *outBegIdx= 0; *outNBElement= 0; /* Adjust startIdx to account for the lookback period. */ lookbackTotal = TA_ATR_Lookback(optInTimePeriod); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } /* Make sure there is still something to evaluate. */ if( startIdx > endIdx ) { return TA_SUCCESS; } /* wAlpha is derived FROM wBeta, never the reverse: only that order makes * wAlpha + wBeta exactly 1 (Sterbenz -- wBeta lands in [0.5, 1)), and it * measures closer to the exact recursion than the 1/period-first spelling * at nearly every period. The order is a gated contract, not a preference: * swapping it reddens the frozen v0.6.4 comparison, and breaks the * bit-for-bit identity TA_RMA(TA_TRANGE(h,l,c),n) == TA_ATR(n). * The pair is exactly (1, 0) at period 1 -- hence no period-1 arm. */ wBeta = (double)(optInTimePeriod - 1) / (double)optInTimePeriod; wAlpha = 1.0 - wBeta; /* The True Range of each bar is computed inline in a single * pass. No temporary buffer is needed. * * The arithmetic order below is the bit-exactness contract * (do not reorder): * - True Range: start from high-low, then compare/replace * with the two previous-close distances, in that order. * - Seed: the first 'period' True Range values are summed, * accumulated from 0.0 in input order, then divided by * the period. * - Wilder smoothing: ONE statement. Splitting it back * unfuses the multiply-add and puts a second latency on * the recurrence's dependency chain. * * In-place (outReal being one of the input arrays) is * supported: each output is written only after every input * read at or before its bar, and the output index is always * smaller than the bar index of any remaining read. */ /* The first True Range needs the two price bars at * startIdx-lookbackTotal+1 (a previous close is consumed). */ today = startIdx - lookbackTotal + 1; /* Seed the ATR with a simple average of the True Range * for the first 'period' bars. */ periodTotal = 0.0; i = optInTimePeriod; while( i-- > 0 ) { /* Find the greatest of the 3 values. */ tempLT = inLow[today]; tempHT = inHigh[today]; tempCY = inClose[today - 1]; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } periodTotal += greatest; today += 1; } prevATR = periodTotal / optInTimePeriod; /* Skip the unstable period. */ i = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_ATR,Atr); while( i != 0 ) { /* Find the greatest of the 3 values. */ tempLT = inLow[today]; tempHT = inHigh[today]; tempCY = inClose[today - 1]; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } prevATR = fma(wBeta, prevATR, wAlpha * greatest); today += 1; i -= 1; } /* Now start to write the final ATR in the caller * provided outReal. */ outIdx = 1; outReal[0] = prevATR; /* Now do the number of requested ATR. */ nbATR = endIdx - startIdx + 1; while( --nbATR != 0 ) { /* Find the greatest of the 3 values. */ tempLT = inLow[today]; tempHT = inHigh[today]; tempCY = inClose[today - 1]; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } prevATR = fma(wBeta, prevATR, wAlpha * greatest); outReal[outIdx++] = prevATR; today += 1; } *outBegIdx= startIdx; *outNBElement= outIdx; return TA_SUCCESS; } TA_FMA_MULTIVERSION TA_RetCode TA_S_ATR( int startIdx, int endIdx, const float inHigh[], const float inLow[], const float inClose[], int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { int i; int outIdx; int today; int lookbackTotal; int nbATR; double prevATR; double periodTotal; double wAlpha; double wBeta; double val2; double val3; double greatest; double tempCY; double tempLT; double tempHT; if( (startIdx < 0) || (startIdx > TA_MAX_INDEX) ) return TA_OUT_OF_RANGE_START_INDEX; if( (endIdx < 0) || (endIdx > TA_MAX_INDEX) || (endIdx < startIdx) ) return TA_OUT_OF_RANGE_END_INDEX; if( (int)optInTimePeriod == TA_INTEGER_DEFAULT ) optInTimePeriod = 14; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return TA_BAD_PARAM; if( !inHigh ) return TA_BAD_PARAM; if( !inLow ) return TA_BAD_PARAM; if( !inClose ) return TA_BAD_PARAM; if( !outBegIdx || !outNBElement ) return TA_BAD_PARAM; if( !outReal ) return TA_BAD_PARAM; *outBegIdx= 0; *outNBElement= 0; lookbackTotal = TA_ATR_Lookback(optInTimePeriod); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } if( startIdx > endIdx ) { return TA_SUCCESS; } wBeta = (double)(optInTimePeriod - 1) / (double)optInTimePeriod; wAlpha = 1.0 - wBeta; today = startIdx - lookbackTotal + 1; periodTotal = 0.0; i = optInTimePeriod; while( i-- > 0 ) { tempLT = (double)inLow[today]; tempHT = (double)inHigh[today]; tempCY = (double)inClose[today - 1]; greatest = tempHT - tempLT; val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } periodTotal += greatest; today += 1; } prevATR = periodTotal / optInTimePeriod; i = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_ATR,Atr); while( i != 0 ) { tempLT = (double)inLow[today]; tempHT = (double)inHigh[today]; tempCY = (double)inClose[today - 1]; greatest = tempHT - tempLT; val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } prevATR = fma(wBeta, prevATR, wAlpha * greatest); today += 1; i -= 1; } outIdx = 1; outReal[0] = prevATR; nbATR = endIdx - startIdx + 1; while( --nbATR != 0 ) { tempLT = (double)inLow[today]; tempHT = (double)inHigh[today]; tempCY = (double)inClose[today - 1]; greatest = tempHT - tempLT; val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } prevATR = fma(wBeta, prevATR, wAlpha * greatest); outReal[outIdx++] = prevATR; today += 1; } *outBegIdx= startIdx; *outNBElement= outIdx; return TA_SUCCESS; } /**** Streaming API *****/ struct TA_ATR_Stream { /* The bars this handle has an output for (see TA_ATR_OutRange). */ int outRangeBegIdx; int outRangeCount; /* The value(s) at the last bar the stream counted (see TA_ATR_Value). */ double cur_outReal; int optInTimePeriod; double prevATR; double wAlpha; double wBeta; double lag1_inClose; }; /* Private function, not in public API. */ static void TA_ATR_StepImpl( struct TA_ATR_Stream *sp, double inHigh, double inLow, double inClose, double *outReal ) { double val2; double val3; double greatest; double tempCY; double tempLT; double tempHT; /* Find the greatest of the 3 values. */ tempLT = inLow; tempHT = inHigh; tempCY = sp->lag1_inClose; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } sp->prevATR = fma(sp->wBeta, sp->prevATR, sp->wAlpha * greatest); *outReal= sp->prevATR; sp->cur_outReal = *outReal; sp->lag1_inClose = inClose; } static TA_RetCode TA_ATR_OpenImpl( struct TA_ATR_Stream **stream, const double inHigh[], const double inLow[], const double inClose[], int startIdx, int historyLen, int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[], int outStride ) { struct TA_ATR_Stream *sp; int endIdx; if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( historyLen < 1 ) return TA_OUT_OF_RANGE_START_INDEX; if( historyLen > TA_MAX_INDEX + 1 ) return TA_OUT_OF_RANGE_END_INDEX; if( !inHigh || !inLow || !inClose || !outReal ) return TA_BAD_PARAM; if( (int)optInTimePeriod == TA_INTEGER_DEFAULT ) optInTimePeriod = 14; else if( (int)optInTimePeriod < 1 || (int)optInTimePeriod > 100000 ) return TA_BAD_PARAM; if( startIdx > historyLen - 1 ) { *outBegIdx = 0; *outNBElement = 0; return TA_INSUFFICIENT_HISTORY; } endIdx = historyLen - 1; { int i; int outIdx; int today; int lookbackTotal; int nbATR; double prevATR = 0.0; double periodTotal; double wAlpha = 0.0; double wBeta = 0.0; double val2; double val3; double greatest; double tempCY; double tempLT; double tempHT; /* Average True Range is the greatest of the following: * * val1 = distance from today's high to today's low. * val2 = distance from yesterday's close to today's high. * val3 = distance from yesterday's close to today's low. * * These value are averaged for the specified period using * Wilder method. This method have an unstable period comparable * to and Exponential Moving Average (EMA). */ *outBegIdx= 0; *outNBElement= 0; /* Adjust startIdx to account for the lookback period. */ lookbackTotal = TA_ATR_Lookback(optInTimePeriod); if( startIdx < lookbackTotal ) { startIdx = lookbackTotal; } /* Make sure there is still something to evaluate. */ if( startIdx > endIdx ) { return TA_INSUFFICIENT_HISTORY; } /* wAlpha is derived FROM wBeta, never the reverse: only that order makes * wAlpha + wBeta exactly 1 (Sterbenz -- wBeta lands in [0.5, 1)), and it * measures closer to the exact recursion than the 1/period-first spelling * at nearly every period. The order is a gated contract, not a preference: * swapping it reddens the frozen v0.6.4 comparison, and breaks the * bit-for-bit identity TA_RMA(TA_TRANGE(h,l,c),n) == TA_ATR(n). * The pair is exactly (1, 0) at period 1 -- hence no period-1 arm. */ wBeta = (double)(optInTimePeriod - 1) / (double)optInTimePeriod; wAlpha = 1.0 - wBeta; /* The True Range of each bar is computed inline in a single * pass. No temporary buffer is needed. * * The arithmetic order below is the bit-exactness contract * (do not reorder): * - True Range: start from high-low, then compare/replace * with the two previous-close distances, in that order. * - Seed: the first 'period' True Range values are summed, * accumulated from 0.0 in input order, then divided by * the period. * - Wilder smoothing: ONE statement. Splitting it back * unfuses the multiply-add and puts a second latency on * the recurrence's dependency chain. * * In-place (outReal being one of the input arrays) is * supported: each output is written only after every input * read at or before its bar, and the output index is always * smaller than the bar index of any remaining read. */ /* The first True Range needs the two price bars at * startIdx-lookbackTotal+1 (a previous close is consumed). */ today = startIdx - lookbackTotal + 1; /* Seed the ATR with a simple average of the True Range * for the first 'period' bars. */ periodTotal = 0.0; i = optInTimePeriod; while( i-- > 0 ) { /* Find the greatest of the 3 values. */ tempLT = inLow[today]; tempHT = inHigh[today]; tempCY = inClose[today - 1]; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } periodTotal += greatest; today += 1; } prevATR = periodTotal / optInTimePeriod; /* Skip the unstable period. */ i = TA_GLOBALS_UNSTABLE_PERIOD(TA_FUNC_UNST_ATR,Atr); while( i != 0 ) { /* Find the greatest of the 3 values. */ tempLT = inLow[today]; tempHT = inHigh[today]; tempCY = inClose[today - 1]; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } prevATR = fma(wBeta, prevATR, wAlpha * greatest); today += 1; i -= 1; } /* Now start to write the final ATR in the caller * provided outReal. */ outIdx = 1; outReal[0 * outStride] = prevATR; /* Now do the number of requested ATR. */ nbATR = endIdx - startIdx + 1; while( --nbATR != 0 ) { /* Find the greatest of the 3 values. */ tempLT = inLow[today]; tempHT = inHigh[today]; tempCY = inClose[today - 1]; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } prevATR = fma(wBeta, prevATR, wAlpha * greatest); outReal[outIdx++ * outStride] = prevATR; today += 1; } *outBegIdx= startIdx; *outNBElement= outIdx; /* Capture the live batch state into the handle. */ sp = (struct TA_ATR_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) { return TA_ALLOC_ERR; } memset( sp, 0, sizeof(*sp) ); sp->optInTimePeriod = optInTimePeriod; sp->prevATR = prevATR; sp->wAlpha = wAlpha; sp->wBeta = wBeta; sp->lag1_inClose = inClose[historyLen - 1]; sp->outRangeBegIdx = *outBegIdx; sp->outRangeCount = *outNBElement; sp->cur_outReal = outReal[(*outNBElement - 1) * outStride]; *stream = sp; return TA_SUCCESS; } } /* Private function, not in public API. */ TA_RetCode TA_ATR_OpenInternal( struct TA_ATR_Stream **stream, const double inHigh[], const double inLow[], const double inClose[], int startIdx, int historyLen, int optInTimePeriod, double *outReal ) { TA_RetCode retCode; int dummyBegIdx = 0; int dummyNBElement = 0; double sink_outReal = 0.0; retCode = TA_ATR_OpenImpl( stream, inHigh, inLow, inClose, startIdx, historyLen, optInTimePeriod, &dummyBegIdx, &dummyNBElement, &sink_outReal, 0 ); if( retCode == TA_SUCCESS ) { *outReal = sink_outReal; } return retCode; } TA_LIB_API TA_RetCode TA_ATR_Open( TA_ATR_Stream **stream, const double inHigh[], const double inLow[], const double inClose[], int historyLen, int optInTimePeriod, double *outReal ) { if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( historyLen < 1 ) return TA_OUT_OF_RANGE_START_INDEX; if( historyLen > TA_MAX_INDEX + 1 ) return TA_OUT_OF_RANGE_END_INDEX; if( !inHigh || !inLow || !inClose || !outReal ) return TA_BAD_PARAM; return TA_ATR_OpenInternal( stream, inHigh, inLow, inClose, 0, historyLen, optInTimePeriod, outReal ); } TA_LIB_API TA_RetCode TA_ATR_OpenAndFill( TA_ATR_Stream **stream, const double inHigh[], const double inLow[], const double inClose[], int historyLen, int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { if( !stream ) return TA_BAD_PARAM; *stream = NULL; if( historyLen < 1 ) return TA_OUT_OF_RANGE_START_INDEX; if( historyLen > TA_MAX_INDEX + 1 ) return TA_OUT_OF_RANGE_END_INDEX; if( !inHigh || !inLow || !inClose || !outBegIdx || !outNBElement || !outReal ) return TA_BAD_PARAM; if( (const void *)outReal == (const void *)inHigh || (const void *)outReal == (const void *)inLow || (const void *)outReal == (const void *)inClose ) return TA_BAD_PARAM; return TA_ATR_OpenAndFillInternal( stream, inHigh, inLow, inClose, 0, historyLen, optInTimePeriod, outBegIdx, outNBElement, outReal ); } /* Private function, not in public API. */ TA_RetCode TA_ATR_OpenAndFillInternal( struct TA_ATR_Stream **stream, const double inHigh[], const double inLow[], const double inClose[], int startIdx, int historyLen, int optInTimePeriod, int *outBegIdx, int *outNBElement, double outReal[] ) { return TA_ATR_OpenImpl( stream, inHigh, inLow, inClose, startIdx, historyLen, optInTimePeriod, outBegIdx, outNBElement, outReal, 1 ); } TA_LIB_API TA_RetCode TA_ATR_Update( TA_ATR_Stream *stream, double inHigh, double inLow, double inClose, double *outReal ) { if( !stream ) return TA_BAD_PARAM; if( stream->outRangeBegIdx + stream->outRangeCount > TA_MAX_INDEX ) return TA_OUT_OF_RANGE_END_INDEX; if( !outReal ) return TA_BAD_PARAM; if( !TA_IS_FINITE( inHigh ) || !TA_IS_FINITE( inLow ) || !TA_IS_FINITE( inClose ) ) return TA_BAD_PARAM; TA_ATR_StepImpl( stream, inHigh, inLow, inClose, outReal ); stream->outRangeCount++; return TA_SUCCESS; } TA_FMA_MULTIVERSION TA_LIB_API TA_RetCode TA_ATR_Peek( const TA_ATR_Stream *stream, double inHigh, double inLow, double inClose, double *outReal ) { const struct TA_ATR_Stream *sp = stream; double val2; double val3; double greatest; double tempCY; double tempLT; double tempHT; double prevATR; if( !stream || !outReal ) return TA_BAD_PARAM; if( !TA_IS_FINITE( inHigh ) || !TA_IS_FINITE( inLow ) || !TA_IS_FINITE( inClose ) ) return TA_BAD_PARAM; prevATR = sp->prevATR; /* Find the greatest of the 3 values. */ tempLT = inLow; tempHT = inHigh; tempCY = sp->lag1_inClose; greatest = tempHT - tempLT; /* val1 */ val2 = fabs(tempCY - tempHT); if( val2 > greatest ) { greatest = val2; } val3 = fabs(tempCY - tempLT); if( val3 > greatest ) { greatest = val3; } prevATR = fma(sp->wBeta, prevATR, sp->wAlpha * greatest); *outReal= prevATR; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_ATR_Close( TA_ATR_Stream *stream ) { if( stream ) TA_Free( stream ); return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_ATR_Value( const TA_ATR_Stream *stream, double *outReal ) { if( !stream || !outReal ) return TA_BAD_PARAM; *outReal = stream->cur_outReal; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_ATR_OutRange( const TA_ATR_Stream *stream, int *outBegIdx, int *outNBElement ) { if( !stream || !outBegIdx || !outNBElement ) return TA_BAD_PARAM; *outBegIdx = stream->outRangeBegIdx; *outNBElement = stream->outRangeCount; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_ATR_Advance( TA_ATR_Stream *stream ) { if( !stream ) return TA_BAD_PARAM; if( stream->outRangeBegIdx + stream->outRangeCount > TA_MAX_INDEX ) return TA_OUT_OF_RANGE_END_INDEX; stream->outRangeCount++; return TA_SUCCESS; } TA_LIB_API TA_RetCode TA_ATR_Clone( const TA_ATR_Stream *stream, TA_ATR_Stream **clone ) { struct TA_ATR_Stream *sp; if( !clone ) return TA_BAD_PARAM; *clone = NULL; if( !stream ) return TA_BAD_PARAM; sp = (struct TA_ATR_Stream *)TA_Malloc( sizeof(*sp) ); if( !sp ) return TA_ALLOC_ERR; *sp = *stream; *clone = sp; return TA_SUCCESS; }