* n variadic
* We use just A, I, N, or X, choosing the most general for each parameter.
*
- * When FldInvalid is shown as the return type, it indicates that the type
- * of the function is determined by the type of the first parameter.
+ * When FldInvalid is shown as the return type, it indicates that the Integer
+ * vs. Numeric type of the function is determined by the type of the first
+ * parameter.
+ *
+ * FldGroup is used when the first argument determines the encoding of the
+ * temporary. This is for functions that can be Alphanumeric or National.
*
* We use FldNumericBin5 for functions of type "Integer", and FldFloat for
* functions of type "Numeric",
*/
+ #define IntOrNum FldInvalid
+ #define AnumOrNat FldGroup
+
static const function_descr_t function_descrs[] = {
{ ABS, "ABS",
- "__gg__abs", "N", {}, FldInvalid },
+ "__gg__abs", "N", {}, IntOrNum },
{ ACOS, "ACOS",
"__gg__acos", "N", {}, FldFloat },
{ ANNUITY, "ANNUITY",
"__gg__asin", "N", {}, FldFloat },
{ ATAN, "ATAN",
"__gg__atan", "N", {}, FldFloat },
- { BASECONVERT, "BASECONVERT",
+ { BASECONVERT, "BASECONVERT", // See parse.y
"__gg__baseconvert", "XII", {}, FldAlphanumeric },
{ BIT_OF, "BIT-OF",
"__gg__bit_of", "X", {}, FldAlphanumeric },
{ COMBINED_DATETIME, "COMBINED-DATETIME",
"__gg__combined_datetime", "IN", {}, FldFloat },
{ CONCAT, "CONCAT",
- "__gg__concat", "n", {}, FldAlphanumeric },
+ "__gg__concat", "n", {}, AnumOrNat },
{ CONVERT, "CONVERT",
- "__gg__convert", "XII", {}, FldAlphanumeric },
+ "__gg__convert", "XII", {}, AnumOrNat },
{ COS, "COS",
"__gg__cos", "N", {}, FldFloat },
{ CURRENT_DATE, "CURRENT-DATE",
{ FIND_STRING, "FIND-STRING",
"__gg__find_string", "AXI", {}, FldNumericBin5 },
{ FORMATTED_CURRENT_DATE, "FORMATTED-CURRENT-DATE",
- "__gg__formatted_current_date", "X", {}, FldAlphanumeric },
+ "__gg__formatted_current_date", "X", {}, AnumOrNat },
{ FORMATTED_DATE, "FORMATTED-DATE",
- "__gg__formatted_date", "XX", {}, FldAlphanumeric },
+ "__gg__formatted_date", "XX", {}, AnumOrNat },
{ FORMATTED_DATETIME, "FORMATTED-DATETIME",
- "__gg__formatted_datetime", "XINI", {}, FldAlphanumeric },
+ "__gg__formatted_datetime", "XINI", {}, AnumOrNat },
{ FORMATTED_TIME, "FORMATTED-TIME",
- "__gg__formatted_time", "INI", {}, FldAlphanumeric },
+ "__gg__formatted_time", "INI", {}, AnumOrNat },
{ FRACTION_PART, "FRACTION-PART",
"__gg__fraction_part", "N", {}, FldFloat },
{ HEX_OF, "HEX-OF",
{ HEX_TO_CHAR, "HEX-TO-CHAR",
"__gg__hex_to_char", "X", {}, FldAlphanumeric },
{ HIGHEST_ALGEBRAIC, "HIGHEST-ALGEBRAIC",
- "__gg__highest_algebraic", "N", {}, FldInvalid },
+ "__gg__highest_algebraic", "N", {}, IntOrNum },
{ INTEGER, "INTEGER",
"__gg__integer", "N", {}, FldNumericBin5 },
// requires FldBoolean
{ LOG10, "LOG10",
"__gg__log10", "N", {}, FldFloat },
{ LOWER_CASE, "LOWER-CASE",
- "__gg__lower_case", "X", {}, FldAlphanumeric },
+ "__gg__lower_case", "X", {}, AnumOrNat },
{ LOWEST_ALGEBRAIC, "LOWEST-ALGEBRAIC",
- "__gg__lowest_algebraic", "N", {}, FldInvalid },
+ "__gg__lowest_algebraic", "N", {}, IntOrNum },
{ MAXX, "MAX",
- "__gg__max", "n", {}, FldInvalid },
+ "__gg__max", "n", {}, IntOrNum },
{ MEAN, "MEAN",
"__gg__mean", "n", {}, FldFloat },
{ MEDIAN, "MEDIAN",
{ MIDRANGE, "MIDRANGE",
"__gg__midrange", "n", {}, FldFloat },
{ MINN, "MIN",
- "__gg__min", "n", {}, FldInvalid },
+ "__gg__min", "n", {}, IntOrNum },
{ MOD, "MOD",
"__gg__mod", "IN", {}, FldNumericBin5 },
{ MODULE_NAME, "MODULE-NAME",
{ RANDOM, "RANDOM",
"__gg__random", "I", {}, FldFloat },
{ RANGE, "RANGE",
- "__gg__range", "n", {}, FldInvalid },
+ "__gg__range", "n", {}, IntOrNum },
{ REM, "REM",
"__gg__rem", "NN", {}, FldFloat },
{ REVERSE, "REVERSE",
- "__gg__reverse", "X", {}, FldAlphanumeric },
+ "__gg__reverse", "X", {}, AnumOrNat },
{ SECONDS_FROM_FORMATTED_TIME, "SECONDS-FROM-FORMATTED-TIME",
"__gg__seconds_from_formatted_time", "XX", {}, FldFloat },
{ SECONDS_PAST_MIDNIGHT, "SECONDS_PAST_MIDNIGHT",
{ SIN, "SIN",
"__gg__sin", "N", {}, FldFloat },
{ SMALLEST_ALGEBRAIC, "SMALLEST-ALGEBRAIC",
- "__gg__smallest_algebraic", "N", {}, FldInvalid },
+ "__gg__smallest_algebraic", "N", {}, IntOrNum },
{ SQRT, "SQRT",
"__gg__sqrt", "N", {}, FldFloat },
{ STANDARD_COMPARE, "STANDARD-COMPARE",
{ STANDARD_DEVIATION, "STANDARD-DEVIATION",
"__gg__standard_deviation", "n", {}, FldFloat },
{ SUBSTITUTE, "SUBSTITUTE",
- "__gg__substitute", "XXX", {}, FldAlphanumeric },
+ "__gg__substitute", "XXX", {}, AnumOrNat },
{ SUM, "SUM",
- "__gg__sum", "n", {}, FldInvalid },
+ "__gg__sum", "n", {}, IntOrNum },
{ TAN, "TAN",
"__gg__tan", "N", {}, FldFloat },
{ TEST_DATE_YYYYMMDD, "TEST-DATE-YYYYMMDD",
"__gg__test_numval_c", "XXU", {}, FldNumericBin5 },
{ TEST_NUMVAL_F, "TEST-NUMVAL-F",
"__gg__test_numval_f", "X", {}, FldNumericBin5 },
- { TRIM, "TRIM",
- "__gg__trim", "XI", {}, FldNumericBin5 },
+ { TRIM, "TRIM", // See parse.y
+ "__gg__trim", "XI", {}, FldAlphanumeric },
{ ULENGTH, "ULENGTH",
"__gg__ulength", "X", {}, FldAlphanumeric },
{ UPOS, "UPOS",
retval = new_tempnumeric_float();
break;
case FldInvalid:
- // This is a flag that a function takes the type of its first input
+ // This is a flag that a function takes the Numeric vs Int type of its
+ // first argument
assert( args.size() );
switch(args[0].field->type)
{
case FldAlphanumeric:
case FldAlphaEdited:
case FldLiteralA:
- retval = new_alphanumeric();
+ retval = new_alphanumeric(NULL, args[0].field->codeset.encoding);
break;
case FldNumericBinary:
case FldPacked:
break;
}
break;
+
+ case FldGroup:
+ // This is a flag that an alphanumeric function takes the encoding of the
+ // first argument
+ assert( args.size() );
+ switch(args[0].field->type)
+ {
+ case FldGroup:
+ case FldAlphanumeric:
+ case FldAlphaEdited:
+ case FldLiteralA:
+ case FldNumericBinary:
+ case FldPacked:
+ case FldNumericDisplay:
+ case FldNumericBin5:
+ case FldLiteralN:
+ case FldIndex:
+ case FldPointer:
+ retval = new_alphanumeric(NULL, args[0].field->codeset.encoding);
+ break;
+ case FldFloat:
+ retval = new_tempnumeric_float();
+ break;
+ default:
+ retval = NULL;
+ gcc_unreachable();
+ break;
+ }
+ break;
+
default:
retval = NULL;
gcc_unreachable();
size_t arg2_offset,
size_t arg2_size)
{
- cbl_encoding_t from = arg1->encoding;
- cbl_encoding_t to = dest->encoding;
- charmap_t *charmap = __gg__get_charmap(to);
+ // We assume that dest is an intermediate_e with the same encoding as arg1.
+ assert( dest->type == FldAlphanumeric
+ && (dest->attr & intermediate_e)
+ && dest->encoding == arg1->encoding );
+ charmap_t *charmap = __gg__get_charmap(arg1->encoding);
int stride = charmap->stride();
cbl_char_t mapped_space = charmap->mapped_character(ascii_space);
arg2_offset,
arg2_size);
//static const int BOTH = 0;
- static const int LEADING = 1; // Remove leading spaces
- static const int TRAILING = 2; // Remove trailing spaces
-
- if( dest->type != FldAlphanumeric ||
- !(dest->attr & intermediate_e) )
- {
- fprintf(stderr,
- "We expect the target of a FUNCTION TRIM to "
- "be an intermediate alphanumeric\n");
- abort();
- }
+ #define LEADING 1 // Remove leading spaces
+ #define TRAILING 2 // Remove trailing spaces
- // What is this all about?
- dest->capacity = dest->offset;
-
- // Make a copy of the input:
- char *copy = static_cast<char *>(malloc(arg1_size));
- massert(copy);
- memcpy(copy, arg1->data+arg1_offset, arg1_size);
-
- // Convert it to the destination encoding
- __gg__convert_encoding_length(copy, arg1_size, from, to);
-
- // No matter what, we want to find the leftmost non-space and the
- // rightmost non-space:
-
- char *left = copy;
- char *right = left + arg1_size-stride;
-
- // Find left and right: the first and last non-spaces
- while( left <= right )
+ char *left = reinterpret_cast<char *>(arg1->data) + arg1_offset;
+ char *right = left + arg1_size-stride; // Points AT the character, not beyond
+ switch(type)
{
- cbl_char_t cleft = charmap->getch(left, (size_t)0);
- cbl_char_t cright = charmap->getch(right, (size_t)0);
-
- if( cleft != mapped_space && cright != mapped_space )
- {
+ case 0: // Strip off leading and trailing spaces
+ while(left <= right)
+ {
+ if( charmap->getch(left, (size_t)0) != mapped_space )
+ {
+ break;
+ }
+ left += stride;
+ }
+ while(left <= right)
+ {
+ if( charmap->getch(right, (size_t)0) != mapped_space )
+ {
+ break;
+ }
+ right -= stride;
+ }
break;
- }
- if( cleft == mapped_space )
+
+ case LEADING: // Just leading
{
- left += stride;
+ while(left <= right)
+ {
+ if( charmap->getch(left, (size_t)0) != mapped_space )
+ {
+ break;
+ }
+ left += stride;
+ }
+ break;
}
- if( cright == mapped_space )
+
+ case TRAILING: // Just trailing
{
- right -= stride;
+ while(left <= right)
+ {
+ if( charmap->getch(right, (size_t)0) != mapped_space )
+ {
+ break;
+ }
+ right -= stride;
+ }
+ break;
}
}
- if( type == LEADING )
- {
- // We want to leave any trailing spaces, so we return 'right' to its
- // original value:
- right = copy + arg1_size-1;
- }
- else if( type == TRAILING )
- {
- // We want to leave any leading spaces, so we return 'left' to its
- // original value:
- left = copy;
- }
-
- if( left > right )
- {
- // When the arg1 input string was empty, we want left to be right+1.
- // The left/right loop can sometimes end up with left equal to right+2.
- // That needs to be fixed:
- left = right+stride;
- }
-
size_t ncount = right+stride - left;
__gg__adjust_dest_size(dest, ncount);
-
memmove(dest->data, left, ncount);
- free(copy);
}
#if HAVE_INITSTATE_R && HAVE_SRANDOM_R && HAVE_RANDOM_R