=H scriba_NewSbArgs()
Whenever you want to handle the variable values that are returned by the scriba subroutine
you have to call R<scriba_CallArgEx()>. This function needs the arguments passed in an array of T<SbDtata> type.
This function is a usefuly tool to convert C variables to an array of T<SbData>
/*FUNCTION*/
SCRIBA_MAIN_LIBSPEC pSbData scriba_NewSbArgs(pSbProgram pProgram,
char *pszFormat, ...
){
/*noverbatim
The arguments passed are
=itemize
=item T<pProgram> is the class variable
=item T<pszFormat> is the format string
=noitemize
The format string is case insensitive. The characters T<u>, T<i>, T<r>, T<b> and T<s> have meaning.
All other characters are ignored. The format characters define the type of the arguments
from left to right.
=itemize
=item T<u> means to pass an T<undef> to the SUB. This format character is exceptional that it does not
consume any function argument.
=item T<i> means that the next argument has to be T<long> and it is passed to the BASIC SUB as an integer.
=item T<r> means that the next argument has to be T<double> and it is passed to the BASIC SUB as a real.
=item T<s> means that the next argument has to be T<char *> and it is passed to the BASIC SUB as a string.
=item T<b> means that the next two arguments has to be T<long cbBuffer> and T<unsigned char *Buffer>.
The T<cbBuffer> defines the leng of the T<Buffer>.
=noitemize
Example:
=verbatim
pSbData MyArgs;
MyArgs = scriba_NewSbArgs(pProgram,"i i r s b",13,14,3.14,"string",2,"two character string");
if( MyArgs == NULL )error("memory alloc");
scriba_CallArgEx(pProgram,lEntry,NULL,5,MyArgs);
=noverbatim
This example passes five arguments to the ScriptBasic subroutine. Note that the last one is only
two character string, the rest of the characters are ignored.
CUT*/
va_list marker;
unsigned long cArgs,i;
char *s;
char *arg;
pSbData p;
if( pszFormat == NULL )return NULL;
cArgs = 0;
s = pszFormat;
while( *s ){
switch( *s++ ){
case 'U': /* undef argument */
case 'u': /* It eats no actual C level caller argument */
case 'B': /* byte argument */
case 'b': /* it eats two arguments: a length and the pointer to the byte stream */
case 'S': /* string argument */
case 's':
case 'I': /* Integer argument */
case 'i':
case 'R': /* Real number argument */
case 'r':
cArgs ++;
break;
default:; /* ignore all non-format characters */
}
}
p = alloc_Alloc(sizeof(SbData)*cArgs,pProgram->pMEM);
if( p == NULL )return NULL;
i = 0;
va_start(marker,pszFormat);
s = pszFormat;
while( *s ){
switch( *s++ ){
case 'U':
case 'u':
p[i].type = SBT_UNDEF;
i++;
break;
case 'B': /* byte stream argument */
case 'b':
p[i].type = SBT_STRING;
p[i].size = va_arg(marker, long);
arg = va_arg(marker, char *);
if( arg == NULL && p[i].size != 0 ){
p[i++].type = SBT_UNDEF;
break;
}
p[i].size = strlen(arg);
if( p[i].size ){
p[i].v.s = alloc_Alloc(p[i].size,pProgram->pMEM);
if( p[i].v.s == NULL ){
while( i ){
if( p[i].type == SBT_STRING && p[i].v.s )alloc_Free(p[i].v.s,pProgram->pMEM);
i--;
}
alloc_Free(p,pProgram->pMEM);
return NULL;
}
memcpy(p[i].v.s,arg,p[i].size);
}else{
p[i].v.s = NULL;
}
i++;
break;
case 'S': /* string argument */
case 's':
p[i].type = SBT_STRING;
arg = va_arg(marker, char *);
if( arg == NULL )arg = "";
p[i].size = strlen(arg);
if( p[i].size ){
p[i].v.s = alloc_Alloc(p[i].size,pProgram->pMEM);
if( p[i].v.s == NULL ){
while( i ){
if( p[i].type == SBT_STRING && p[i].v.s )alloc_Free(p[i].v.s,pProgram->pMEM);
i--;
}
alloc_Free(p,pProgram->pMEM);
return NULL;
}
memcpy(p[i].v.s,arg,p[i].size);
}else{
p[i].v.s = NULL;
}
i++;
break;
case 'I': /* Integer argument */
case 'i':
p[i].type = SBT_LONG;
p[i].v.l = va_arg(marker, long);
i++;
break;
case 'R': /* Real number argument */
case 'r':
p[i].type = SBT_DOUBLE;
p[i].v.d = va_arg(marker, double);
i++;
break;
}
}
return p;
}
/*POD
=H scriba_CallArgEx()
This is the most sophisticated function of the ones that call a ScriptBasic subroutine.
This function is capable handling parameters to scriba subroutines, and returning the
modified argument variables and the return value.
/*FUNCTION*/
SCRIBA_MAIN_LIBSPEC int scriba_CallArgEx(pSbProgram pProgram,
unsigned long lEntryNode,
pSbData ReturnValue,
unsigned long cArgs,
pSbData Args
){
/*noverbatim
The arguments:
=itemize
=item T<pProgram> is the program object pointer.
=item T<lEntryNode> is the entry node index where the BASIC subroutine or function starts
(See R<scriba_Call()> note on how to get the entry node value.)
=item T<ReturnValue> is the return value of the function or subroutine
=item T<cArgs> is the number of argments passed to the function
=item T<Args> argument data array
=noitemize
CUT*/
int iError;
VARIABLE vArgs;
VARIABLE vReturn;
unsigned long i;
if( cArgs )
vArgs = memory_NewArray(pProgram->pEXE->pMo,0,cArgs-1);
else
vArgs = NULL;
if( vArgs ){
for( i = 0 ; i < cArgs ; i ++ ){
switch( Args[i].type ){
case SBT_UNDEF:
vArgs->Value.aValue[i] = NULL;
break;
case SBT_STRING:
vArgs->Value.aValue[i] = memory_NewString(pProgram->pEXE->pMo,Args[i].size);
memcpy(STRINGVALUE(vArgs->Value.aValue[i]),Args[i].v.s,Args[i].size);
alloc_Free(Args[i].v.s,pProgram->pMEM);
break;
case SBT_LONG: /* Integer argument */
vArgs->Value.aValue[i] = memory_NewLong(pProgram->pEXE->pMo);
LONGVALUE(vArgs->Value.aValue[i]) = Args[i].v.l;
break;
case SBT_DOUBLE: /* Real number argument */
vArgs->Value.aValue[i] = memory_NewDouble(pProgram->pEXE->pMo);
DOUBLEVALUE(vArgs->Value.aValue[i]) = Args[i].v.d;
break;
}
}
}
execute_ExecuteFunction(pProgram->pEXE,lEntryNode,cArgs,vArgs ? vArgs->Value.aValue : NULL ,&vReturn,&iError);
scriba_UndefSbData(pProgram,ReturnValue);
if( ! iError && vReturn ){
switch( vReturn->vType ){
case VTYPE_LONG:
ReturnValue->type = SBT_LONG;
ReturnValue->v.l = LONGVALUE(vReturn);
break;
case VTYPE_DOUBLE:
ReturnValue->type = SBT_DOUBLE;
ReturnValue->v.d = DOUBLEVALUE(vReturn);
break;
case VTYPE_STRING:
ReturnValue->type = SBT_STRING;
/* we allocate a one byte longer buffer and append a terminating zero */
ReturnValue->size=STRLEN(vReturn);/* size is w/o the terminating zero */
ReturnValue->v.s = alloc_Alloc(ReturnValue->size+1,pProgram->pMEM);
if( ReturnValue->v.s ){
memcpy(ReturnValue->v.s,STRINGVALUE(vReturn),ReturnValue->size);
ReturnValue->v.s[ReturnValue->size] = (char)0;
}
break;
default:
ReturnValue->type = SBT_UNDEF;
break;
}
}
if( vArgs && ! iError ){
for( i = 0 ; i < cArgs ; i ++ ){
if( vArgs->Value.aValue[i] == NULL ){
Args[i].type = SBT_UNDEF;
continue;
}
switch( vArgs->Value.aValue[i]->vType ){
case VTYPE_LONG:
Args[i].type = SBT_LONG;
Args[i].v.l = LONGVALUE(vArgs->Value.aValue[i]);
break;
case VTYPE_DOUBLE:
Args[i].type = SBT_DOUBLE;
Args[i].v.d = DOUBLEVALUE(vArgs->Value.aValue[i]);
break;
case VTYPE_STRING:
/* we allocate a one byte longer buffer and append a terminating zero */
Args[i].type = SBT_STRING;
Args[i].size=STRLEN(vArgs->Value.aValue[i]);/* size is w/o the terminating zero */
Args[i].v.s = alloc_Alloc(Args[i].size+1,pProgram->pMEM);
if( Args[i].v.s ){
memcpy(Args[i].v.s,STRINGVALUE(vArgs->Value.aValue[i]),Args[i].size);
Args[i].v.s[Args[i].size] = (char)0;
}
break;
default:
Args[i].type = SBT_UNDEF;
break;
}
}
}
memory_ReleaseVariable(pProgram->pEXE->pMo,vArgs);
memory_ReleaseVariable(pProgram->pEXE->pMo,vReturn); /*Tomasz Lacki realised its missing*/
return iError;
}