96 lines
2.7 KiB
C
96 lines
2.7 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_string.h"
|
|
|
|
#include "stringpool.h"
|
|
#include "op.h"
|
|
#include <stdarg.h>
|
|
|
|
#define MAX_NUM_LEN 64
|
|
|
|
GBLREF spdesc stringpool;
|
|
|
|
void op_cat(UNIX_ONLY_COMMA(int srcargs) mval *dst, ...)
|
|
{
|
|
va_list var;
|
|
mval *in, *src;
|
|
int maxlen, i;
|
|
VMS_ONLY(int srcargs;)
|
|
unsigned char *cp, *base;
|
|
error_def(ERR_MAXSTRLEN);
|
|
|
|
VAR_START(var, dst);
|
|
VMS_ONLY(va_count(srcargs);)
|
|
srcargs -= 1; /* account for dst */
|
|
/* determine if garbage collection is required */
|
|
maxlen = 0;
|
|
for (i = 0; i < srcargs ; i++)
|
|
{
|
|
/* Sum the lengths of all the strings;
|
|
use MAX_NUM_LEN to estimate lengths of strings from to-be-converted numbers.
|
|
*/
|
|
in = va_arg(var, mval *);
|
|
maxlen += (MV_IS_STRING(in)) ? (in)->str.len : MAX_NUM_LEN;
|
|
if (maxlen > MAX_STRLEN)
|
|
{
|
|
va_end(var);
|
|
rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
|
|
}
|
|
}
|
|
va_end(var);
|
|
ENSURE_STP_FREE_SPACE(maxlen);
|
|
base = cp = stringpool.free;
|
|
/* if the first string is at the end of the stringpool, then don't recopy the first string */
|
|
VAR_START(var, dst);
|
|
in = va_arg(var, mval *);
|
|
if (MV_IS_STRING(in) && (unsigned char *)in->str.addr + in->str.len == cp)
|
|
{
|
|
/* If the first string is at the end of the stringpool, no sense in copying it. */
|
|
base = (unsigned char *)in->str.addr;
|
|
in = va_arg(var, mval *);
|
|
srcargs--;
|
|
}
|
|
for (i = 0; ;)
|
|
{
|
|
MV_FORCE_DEFINED(in);
|
|
/* Now that we have ensured enough space in the stringpool, we dont expect any more
|
|
* garbage collections or expansions until we are done with the concatenation. We need
|
|
* to do this AFTER the MV_FORCE_DEFINED since that can trigger an error and in that case
|
|
* we dont want this debug global variable set for post-error-trap M code.
|
|
*/
|
|
DBG_MARK_STRINGPOOL_UNEXPANDABLE;
|
|
if (MV_IS_STRING(in))
|
|
memcpy(cp, in->str.addr, in->str.len);
|
|
else
|
|
{
|
|
stringpool.free = cp;
|
|
n2s(in);
|
|
/* Convert to string, rely on the fact that it will be converted exactly at the end of the stringpool. */
|
|
}
|
|
cp += in->str.len;
|
|
i++;
|
|
/* Now that we are done with stringpool.free initializations for this iteration, mark as free for expansion */
|
|
DBG_MARK_STRINGPOOL_EXPANDABLE;
|
|
if (i >= srcargs)
|
|
break;
|
|
in = va_arg(var, mval *);
|
|
}
|
|
va_end(var);
|
|
dst->mvtype = MV_STR;
|
|
dst->str.addr = (char *) base;
|
|
dst->str.len = INTCAST(cp - base);
|
|
stringpool.free = cp;
|
|
return;
|
|
}
|