agent/native/ext/util.cpp (147 lines of code) (raw):
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "util.h"
#include <stdlib.h>
#include "TextOutputStream.h"
#define ELASTIC_APM_CURRENT_LOG_CATEGORY ELASTIC_APM_LOG_CATEGORY_UTIL
StringView trimStringView( StringView src )
{
size_t beginIndex = 0;
size_t endIndex = src.length;
for ( ; beginIndex < src.length && ( isWhiteSpace( src.begin[ beginIndex ] ) ) ; ++beginIndex );
for ( ; endIndex > beginIndex && ( isWhiteSpace( src.begin[ endIndex - 1 ] ) ) ; --endIndex );
return makeStringView( src.begin + beginIndex, endIndex - beginIndex );
}
StringView findEndOfLineSequence( StringView text )
{
// The order in endOfLineSequences is important because we need to check longer sequences first
StringView endOfLineSequences[] =
{
ELASTIC_APM_STRING_LITERAL_TO_VIEW( "\r\n" )
, ELASTIC_APM_STRING_LITERAL_TO_VIEW( "\n" )
, ELASTIC_APM_STRING_LITERAL_TO_VIEW( "\r" )
};
ELASTIC_APM_FOR_EACH_INDEX( textPos, text.length )
{
ELASTIC_APM_FOR_EACH_INDEX( eolSeqIndex, ELASTIC_APM_STATIC_ARRAY_SIZE( endOfLineSequences ) )
{
if ( text.length - textPos < endOfLineSequences[ eolSeqIndex ].length ) continue;
StringView eolSeqCandidate = makeStringView( &( text.begin[ textPos ] ), endOfLineSequences[ eolSeqIndex ].length );
if ( areStringViewsEqual( eolSeqCandidate, endOfLineSequences[ eolSeqIndex ] ) )
{
return eolSeqCandidate;
}
}
}
return ELASTIC_APM_EMPTY_STRING_VIEW;
}
bool findCharByPredicate( StringView src, CharPredicate predicate, size_t* foundPosition )
{
ELASTIC_APM_FOR_EACH_INDEX( pos, src.length )
{
if ( predicate( src.begin[ pos ] ) )
{
*foundPosition = pos;
return true;
}
}
return false;
}
ResultCode parseDecimalInteger( StringView inputString, /* out */ Int64* result )
{
char* pastLastInterpretedChar = NULL;
StringView trimmedInputString = trimStringView( inputString );
if ( isEmptyStringView( trimmedInputString ) )
{
return resultParsingFailed;
}
long parsedNumber = strtol( trimmedInputString.begin, /* out */ &pastLastInterpretedChar, /* base */ 10 );
if ( pastLastInterpretedChar != stringViewEnd( trimmedInputString ) )
{
return resultParsingFailed;
}
*result = parsedNumber;
return resultSuccess;
}
static
ResultCode parseUnits( StringView inputString, StringView unitNames[], size_t numberOfUnits, /* out */ size_t* unitsIndex )
{
ELASTIC_APM_ASSERT_VALID_PTR( unitsIndex );
StringView trimmedInputString = trimStringView( inputString );
ELASTIC_APM_FOR_EACH_INDEX( i, numberOfUnits )
{
if ( areStringViewsEqualIgnoringCase( trimmedInputString, unitNames[ i ] ) )
{
*unitsIndex = i;
return resultSuccess;
}
}
return resultParsingFailed;
}
ResultCode parseDecimalIntegerWithUnits( StringView inputString, StringView unitNames[], size_t numberOfUnits, /* out */ Int64* valueInUnits, /* out */ size_t* unitsIndex )
{
ELASTIC_APM_ASSERT_VALID_PTR( valueInUnits );
ELASTIC_APM_ASSERT_VALID_PTR( unitsIndex );
ResultCode resultCode;
StringView trimmedInputString = trimStringView( inputString );
size_t firstNotDecimalDigit;
size_t unitsIndexLocal = numberOfUnits;
StringView numericPart = trimmedInputString;
Int64 numericValue;
if ( findCharByPredicate( trimmedInputString, isNotDecimalDigitOrSign, /* out */ &firstNotDecimalDigit ) )
{
ELASTIC_APM_CALL_IF_FAILED_GOTO( parseUnits( subStringView( trimmedInputString, /* offset */ firstNotDecimalDigit ), unitNames, numberOfUnits, /* out */ &unitsIndexLocal ) );
numericPart = trimStringView( makeStringView( trimmedInputString.begin, firstNotDecimalDigit ) );
}
else
{
unitsIndexLocal = numberOfUnits;
}
ELASTIC_APM_CALL_IF_FAILED_GOTO( parseDecimalInteger( numericPart, /* out */ &numericValue ) );
*valueInUnits = numericValue;
*unitsIndex = unitsIndexLocal;
resultCode = resultSuccess;
finally:
return resultCode;
failure:
goto finally;
}
StringView sizeUnitsNames[ numberOfSizeUnits ] =
{
[ sizeUnits_byte ] = ELASTIC_APM_STRING_LITERAL_TO_VIEW( "B" ),
[ sizeUnits_kibibyte ] = ELASTIC_APM_STRING_LITERAL_TO_VIEW( "KB" ),
[ sizeUnits_mebibyte ] = ELASTIC_APM_STRING_LITERAL_TO_VIEW( "MB" ),
[ sizeUnits_gibibyte ] = ELASTIC_APM_STRING_LITERAL_TO_VIEW( "GB" ),
};
ResultCode parseSize( StringView inputString, SizeUnits defaultUnits, /* out */ Size* result )
{
ELASTIC_APM_ASSERT_VALID_PTR( result );
size_t unitsIndex;
ResultCode resultCode = parseDecimalIntegerWithUnits( inputString, sizeUnitsNames, numberOfSizeUnits, &result->valueInUnits, &unitsIndex );
if ( resultCode == resultSuccess )
{
result->units = ( unitsIndex == numberOfSizeUnits ? defaultUnits : (SizeUnits)unitsIndex );
}
return resultCode;
}
String streamSize( Size size, TextOutputStream* txtOutStream )
{
return isValidSizeUnits( size.units )
? streamPrintf( txtOutStream, "%" PRId64 "%s", size.valueInUnits, sizeUnitsToString( size.units ) )
: streamPrintf( txtOutStream, "%" PRId64 "<invalid units as int: %d>", size.valueInUnits, size.units );
}
static const Int64 sizeKibiFactor = 1024;
Int64 sizeToBytes( Size size )
{
switch (size.units)
{
case sizeUnits_byte:
return size.valueInUnits;
case sizeUnits_kibibyte:
return size.valueInUnits * sizeKibiFactor;
case sizeUnits_mebibyte:
return size.valueInUnits * sizeKibiFactor * sizeKibiFactor;
case sizeUnits_gibibyte:
return size.valueInUnits * sizeKibiFactor * sizeKibiFactor * sizeKibiFactor;
default:
ELASTIC_APM_ASSERT( false, "Unknown size units (as int): %d", size.units );
return size.valueInUnits;
}
}