/* idl_rpc_client.c - Client side routines for the IDL RPC feature */ /* Copyright (c) 1988-1997, Research Systems Inc. All rights reserved. This software includes information which is proprietary to and a trade secret of Research Systems, Inc. It is not to be disclosed to anyone outside of this organization. Reproduction by any means whatsoever is prohibited without express written permission. */ static char rcsid[] = "$Id: rpc_clnt.c,v 1.5 1997/01/29 21:17:45 kirk Exp $"; /* * Contents: * This file contains routines that are used on the client side * of the IDL RPC routines. This includes all API functions as * well as API support routines. */ /* * Header files */ #include "idl_rpc.h" #include "rpc_xdr.h" #include #include #include /* * Declare the global timeout variable and set a default value */ static struct timeval s_rpcTimeOut = { 60, 0 }; /* default of 60 secs */ /* * local functions */ void idl_rpc_delvar(IDL_VPTR pVar); /* deletes dynamic memory */ void idl_rpc_strup(char * dst, char * src); /* upcases an char string */ int idl_rpc_valid_str(char *s); /* syntax check a command line */ /* * Declare the rpc buffer size */ #define RPC_BUF_SIZE (8*1024) /********************************************************************* * IDL_RPCInit() * * Purpose: * This function is used to perform the connection to the rpc server * and other startup initialization of the rpc client. All idl rpc * clients should call this routine before executing any IDL rpc * operations. * * entry: * lServerId - integer ID of the rpc server. 0 => use default * pszHostname - the hostname of the server. NULL => localhost * * exit: * Function returns a CLIENT pointer that references the client/server * connection or returns NULL if there was an error. */ CLIENT *IDL_RPCInit( long lServerId, char* pszHostname) { int iSock = RPC_ANYSOCK; struct hostent *pHostent; struct sockaddr_in ServerAddr; CLIENT *pClient; /* * Check input parameters */ if(lServerId == 0) lServerId = IDL_RPC_DEFAULT_ID; if( (pszHostname == (char*)NULL) || (*pszHostname == '\0')) pszHostname = "localhost"; /* * Get the host information */ if( (pHostent = gethostbyname(pszHostname)) == (struct hostent*)NULL){ perror("gethostbyname"); return (CLIENT*)NULL; } /* * Copy the host address into the server address struct */ bcopy(pHostent->h_addr, (caddr_t)&ServerAddr.sin_addr, pHostent->h_length); ServerAddr.sin_family = AF_INET; /* address type */ ServerAddr.sin_port = 0; /* * Connect to the client usign TCP/IP */ if( (pClient = (CLIENT*)clnttcp_create(&ServerAddr, lServerId, IDL_RPC_DEFAULT_VERSION, &iSock, RPC_BUF_SIZE, RPC_BUF_SIZE)) == (CLIENT*)NULL){ clnt_pcreateerror("clnttcp_create"); } return pClient; /* return the client struct */ } /****************************************************************** * IDL_RPCCleanup() * * Purpose: * This routine should be called when the user no longer desires to * use the rpc server. This routine will unregister the client and * if desired by the user, halt the rpc server. * * entry: * pClient - The CLIENT ^ that refs the server/client connection * that will be affected. * iKill - If true the RPC server will be killed. * * exit: * RPC client unregistered and if iKill was set, the server is killed. * */ int IDL_RPCCleanup( CLIENT *pClient, int iKill) { enum clnt_stat rpcResult=RPC_SUCCESS; /* * Does the user want to kill the server? */ if(iKill) rpcResult = clnt_call(pClient, IDL_RPC_CLEANUP, /* kill server */ (xdrproc_t)xdr_void, 0, (xdrproc_t)xdr_void, 0, s_rpcTimeOut); if(pClient != (CLIENT*)NULL) clnt_destroy(pClient); return (rpcResult == RPC_SUCCESS ? 1 : 0); } /****************************************************************** * IDL_RPCTimeout() * * Purpose: * This routine is used to set the value of the rpc timeout being * used in the rpc calls to the server. The timeout value units * are seconds. Returns 0 on failure. * * entry: * lTimeOut - New timeout value in seconds. * * exit: * Returns 1 on success, 0 on failure. * */ int IDL_RPCTimeout(long lTimeOut) { /* * make sure that the timeout value looks "sane". */ if(lTimeOut <= 0) return 0; s_rpcTimeOut.tv_sec = lTimeOut; return 1; } /*************************************************************************** * idl_rpc_valid_str() * * Purpose: * This function checks to make sure that a string contains * a valid IDL command. Commands the start with $ or contain * "$" that are used for line continuations can cause the IDL * server to hang. This function is used to validate command * lines before they are sent to the server. * * entry: * s - command string to check. * * exit: * 0 - command string is ok * -1 - command string is invalid */ int idl_rpc_valid_str(char *s) { if(s == (char*)NULL) return 0; /* valid */ if(*s == '$') return -1; /* invalid */ /* * Loop thru and check for a '$' */ while(*++s){ if( *s == '$'){ /* * if this is preceeded by a alpha or an '_' it should be a * variable name, otherwise signal an error. */ if( !isalpha(*(s-1)) && *(s-1) != '_' && *(s-1) != '$') return -1; } } return 0; /* command string is OK */ } /********************************************************************** * IDL_RPCExecuteStr() * * Purpose: * This routine is used to send an IDL command string to the rpc * server. This string should be in the form of a single IDL command line. * The return value of this function is the value of !ERROR after * the completion of the command. * * entry: * pClient - The CLIENT ^ that refs the client/server connection. * pszCommand - The command line to send to the server * * exit: * Return Value: * 0 - Command executed ok. * -1 - Invalid command line. * other - Value of !ERROR in the IDL server. * */ int IDL_RPCExecuteStr( CLIENT *pClient, char * pszCommand) { enum clnt_stat rpcResult; int iCmdResult; /* * check for a null command...why send it. */ if(pszCommand == (char*)NULL) return 1; /* null commands are ok */ /* * A command spawn using $ can cause problems and should not be sent * to the server. Lets check for this. */ if(idl_rpc_valid_str(pszCommand)){ fprintf(stderr, "IDL_RPCExecuteStr: %s\n", "Shell command and line continue symbols not allowed"); return 0; } /* * Send the command string to the server. */ rpcResult = clnt_call(pClient, IDL_RPC_EXE_STR, (xdrproc_t)xdr_wrapstring, (char*)&pszCommand, (xdrproc_t)xdr_int, (char*)&iCmdResult, s_rpcTimeOut); if(rpcResult != RPC_SUCCESS){ clnt_perror( pClient, "IDL_RPCExecuteStr"); iCmdResult = 0; } return iCmdResult; } /***************************************************************** * IDL_RPCOutputCapture() * * Purpose: * This routine is used to enable and disable the capture of the * output lines from IDL on the server side. If the input argument * is greater than zero, the capture of output lines is enabled with * the size of the output queue (in lines) equal to the input parameter. * If the input parameter is <= zero, the caputure queue is emptied and * the capture of output lines is disabled. * * entry: * pClient - The CLIENT ^ that refs the client/server connection. * n_lines - The number of output lines to store. A value <=0 * disables the storage of output lines. * exit: * Return Values: * 1 - All is ok * 0 - an error occurred. */ int IDL_RPCOutputCapture( CLIENT *pClient, int n_lines) { enum clnt_stat rpcResult; int iResult; /* * Send the number of lines to capture to the server. */ rpcResult = clnt_call(pClient, IDL_RPC_OUT_CAPTURE, (xdrproc_t)xdr_int, (char*)&n_lines, (xdrproc_t)xdr_int, (char*)&iResult, s_rpcTimeOut); if(rpcResult != RPC_SUCCESS){ clnt_perror(pClient, "IDL_RPCOutputCapture"); return 0; } return 1; /* thats it */ } /******************************************************************* * IDL_RPCSetMainVariable() * * Purpose: * This function is used to set the value of a variable that * is at the main level of the IDL RPC server. If the variable * doesnt exist at the main level on the server side, the server * will create it. * * entry: * pClient - The CLIENT ^ that refs the client/server connection. * Name - The name of the variable to be set. * pVar - An IDL_VPTR that contains the value that the variable * should be set to. * exit: * Return Values: * 0 - ok * 1 - Error occurred */ int IDL_RPCSetMainVariable( CLIENT *pClient, char *Name, IDL_VPTR pVar) { enum clnt_stat rpcResult; IDL_RPC_VARIABLE rpcVar; /* struct that holds vptr and Name */ int iResult=0; char szBuffer[124]; /* * Put the information in the rpc variable structure and send it * to the server. */ idl_rpc_strup(szBuffer, Name); /* upcase name */ rpcVar.name = szBuffer; rpcVar.pVariable = pVar; /* * If the variable is a string that is dynamically allocated, make * sure that the V_DYNAMIC flag is set. With out this flag set, * there can be problems on the server side. */ if(pVar->type == IDL_TYP_STRING){ if(pVar->value.str.stype){ pVar->flags |= IDL_V_DYNAMIC; } } /* * Send this info to the server. */ rpcResult = clnt_call(pClient, IDL_RPC_SET_MAIN_VAR, (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar, (xdrproc_t)xdr_void, 0, s_rpcTimeOut); if(rpcResult != RPC_SUCCESS){ clnt_perror(pClient, "IDL_RPCSetMainVariable"); return 0; } return 1; } /************************************************************* * IDL_RPCGetMainVariable() * * Purpose: * This function is used to get the value of a variable * that is located at the main IDL level on the IDL RPC server. * The IDL_VPTR that is returned from this function is dynamically * allocated and should be deallocated using the IDL_RPCDeltmp() * function when the user is finished with it. * * entry: * pClient - The CLIENT ^ that refs the client/server connection. * Name - The name of the desired variable. * * exit: * Return Value: * On success this function returns an IDL_VPTR that points * to an IDL_VARIABLE structure that contains the value of * the requested variable. On failure this function returns * NULL. */ IDL_VPTR IDL_RPCGetMainVariable(CLIENT *pClient, char *Name) { IDL_VPTR pVar; IDL_RPC_VARIABLE rpcVar; enum clnt_stat rpcResult; char szBuffer[124]; char *pChar; idl_rpc_strup(szBuffer, Name); /* make sure it is uppercase */ bzero((char*)&rpcVar, sizeof(IDL_RPC_VARIABLE)); /* clear out */ pChar = (char*)szBuffer; /* * Request the variable from the server */ rpcResult = clnt_call(pClient, IDL_RPC_GET_MAIN_VAR, (xdrproc_t)xdr_wrapstring, (char*)&pChar, (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar, s_rpcTimeOut); if(rpcResult != RPC_SUCCESS){ clnt_perror(pClient, "IDL_RPCGetMainVariable"); return (IDL_VPTR)NULL; } return rpcVar.pVariable; /* return the value */ } /******************************************************************* * IDL_RPCSetVariable() * * Purpose: * This function is used to set the value of a variable that * is in the current scope of the IDL RPC server. If the variable * doesnt exist at this level on the server side, the server * will create it. * * entry: * pClient - The CLIENT ^ that refs the client/server connection. * Name - The name of the variable to be set. * pVar - An IDL_VPTR that contains the value that the variable * should be set to. * exit: * Return Values: * 0 - ok * 1 - Error occurred */ int IDL_RPCSetVariable( CLIENT *pClient, char *Name, IDL_VPTR pVar) { enum clnt_stat rpcResult; IDL_RPC_VARIABLE rpcVar; int iResult=0; char szBuffer[124]; /* * Put the information in the rpc variable structure and send it * to the server. */ idl_rpc_strup(szBuffer, Name); rpcVar.name = Name; rpcVar.pVariable = pVar; /* * If the variable is a string that is dynamically allocated, make * sure that the V_DYNAMIC flag is set. With out this flag set, * there can be problems on the server side. */ if(pVar->type == IDL_TYP_STRING){ if(pVar->value.str.stype){ pVar->flags |= IDL_V_DYNAMIC; } } /* * Send this info to the server. */ rpcResult = clnt_call(pClient, IDL_RPC_SET_VAR, (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar, (xdrproc_t)xdr_void, 0, s_rpcTimeOut); if(rpcResult != RPC_SUCCESS){ clnt_perror(pClient, "IDL_RPCSetVariable"); iResult=0; } return 1; } /************************************************************* * IDL_RPCGetVariable() * * Purpose: * This function is used to get the value of a variable * that is located in the current IDL scope on the IDL RPC server. * The IDL_VPTR that is returned from this function is dynamically * allocated and should be deallocated using the IDL_RPCDeltmp() * function when the user is finished with it. * * entry: * pClient - The CLIENT ^ that refs the client/server connection. * Name - The name of the desired variable. * * exit: * Return Value: * On success this function returns an IDL_VPTR that points * to an IDL_VARIABLE structure that contains the value of * the requested variable. On failure this function returns * NULL. */ IDL_VPTR IDL_RPCGetVariable(CLIENT *pClient, char *Name) { IDL_VPTR pVar; IDL_RPC_VARIABLE rpcVar; enum clnt_stat rpcResult; char szBuffer[124]; char *pChar; idl_rpc_strup(szBuffer, Name); /* make sure it is uppercase */ pChar = (char*)szBuffer; bzero((char*)&rpcVar, sizeof(IDL_RPC_VARIABLE)); /* clear out */ rpcResult = clnt_call(pClient, IDL_RPC_GET_VAR, (xdrproc_t)xdr_wrapstring, (char*)&pChar, (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar, s_rpcTimeOut); if(rpcResult != RPC_SUCCESS){ clnt_perror(pClient, "IDL_RPCGetVariable"); return (IDL_VPTR)NULL; } return rpcVar.pVariable; } /************************************************************* * IDL_RPCOuputGetStr() * * Purpose: * This function is used to get a line from the output queue that * is being kept on the RPC server. The routine IDL_RPCOutputCapture() * MUST have been called with a positive arguement before this routine. * * entry: * pClient - The CLIENT ^ that refs the client/server connection. * pLine - A ^ to a valid structure of type pLine. This * structure will be filled with the next line * and information about this line. * first - If not 0, the value should be popped from the * output queue, not dequeued. */ int IDL_RPCOutputGetStr(CLIENT *pClient, IDL_RPC_LINE_S *pLine, int first) { enum clnt_stat rpcResult; /* * Get the line from the server */ rpcResult = clnt_call(pClient, IDL_RPC_OUT_STR, (xdrproc_t)xdr_int, (char*)&first, (xdrproc_t)IDL_RPC_xdr_line_s, (char*)pLine, s_rpcTimeOut); if(rpcResult != RPC_SUCCESS){ clnt_perror(pClient, "IDL_RPCOutputGetStr"); return 0; } /* * A flag value of -1 indicates that there are no more values * in the ouput queue */ return (pLine->flags == -1 ? 0 : 1); } /************************************************************* * IDL_RPCVarCopy() * * Purpose: * Used to emulate IDL_VarCopy() on the client side. The value * of the source variable is copied to the destination variable. * If the source variable has the IDL_V_TMP flag set, any dynamic * part of the source variable is moved to the destination variable * and not copied. * * Any dynamic memory associated with the destination variable * is freed before the copy is performed. * * entry: * src - ^ to variable to be copied. * dst - ^ to variable that will have info copied to it. * * exit: * src - not changed * dst - Any original dynamic data has been deallocated and it now * contains the value that was in src. * */ void IDL_RPCVarCopy(IDL_VPTR src, IDL_VPTR dst) { int flags; flags = dst->flags; /* save the destination flags */ /* * Free up any dynamic memory used by the dst variable */ idl_rpc_delvar(dst); dst->flags = flags & ~(IDL_V_ARR & IDL_V_DYNAMIC); /* save some flags */ dst->type = src->type; /* get the type of the copied var */ /* * Is the variable an array? */ if( src->flags & IDL_V_ARR){ /* * Is the source variable a *temporary* variable (or at least * marked as such)? If so, just copy the arr pointer to the * src variable. */ if(src->flags & IDL_V_TEMP){ dst->value.arr = src->value.arr; src->flags &= ~(IDL_V_NOT_SCALAR); /* take out array bit */ idl_rpc_delvar(src); /* free any other memory being used */ }else{ /* need to copy over the data! */ dst->value.arr = (IDL_ARRAY*)malloc((unsigned)sizeof(IDL_ARRAY)); if(!dst->value.arr){ perror("malloc"); return; } /* * Copy over the array info. */ bcopy((char*)src->value.arr,(char*)dst->value.arr, sizeof(IDL_ARRAY)); dst->value.arr->data = (UCHAR*)malloc(src->value.arr->arr_len); if(!dst->value.arr->data){ perror("malloc"); free((char*)dst->value.arr); return; } /* * Copy over the array info */ bcopy((char*)src->value.arr->data, (char*)dst->value.arr->data, src->value.arr->arr_len); dst->flags |= IDL_V_DYNAMIC; } dst->flags |= IDL_V_ARR; }else { /* a scalar */ /* * just copy over the alltypes union */ bcopy((char*)&dst->value, (char*)&src->value, sizeof(IDL_ALLTYPES)); dst->flags = dst->flags & ~(IDL_V_NOT_SCALAR); } } /******************************************************************** * IDL_RPCDeltmp() * * Purpose: * This function emulates the IDL_Deltmp() function. This is used * to delete any dynamic memory that is allocated to create * a variable. This function calls idl_rpc_delvar() which keys off * the IDL_V_DYNAMIC flag or if a scalar is a string. * * If the IDL_V_TEMP bit is set, the IDL_VARIABLE will also be * deallocated. * * entry: * vTmp - A variable that will have its memory freed. * * exit: * vTmp - Any dynamic memory associated with vTmp is freed. */ void IDL_RPCDeltmp( IDL_VPTR vTmp) { if(!vTmp) return; /* * Free up any dynamic memory in the variable */ idl_rpc_delvar(vTmp); /* * If the IDL_V_TEMP bit is not set, return. */ if(!(vTmp->flags & IDL_V_TEMP)) return; free((char*)vTmp); /* free the IDL_VARIABLE */ } /********************************************************************* * IDL_RPCGettmp() * * Purpose: * Used to emulate the IDL function IDL_Gettmp(). Allocates * memory for an IDL_VARIABLE struct and returns a pointer * to this value. The IDL_V_TEMP flag is set to indicate * that this value will need to be free'd later in the program. * * entry: * Nothing. * * exit: * Return Value: * Returns an IDL_VPTR that points to an IDL_VARIABLE * struct with the IDL_V_TEMP bit set in the flags field. * On an error a NULL is returned. */ IDL_VPTR IDL_RPCGettmp(void) { IDL_VPTR vTmp; vTmp = (IDL_VPTR)malloc((unsigned)sizeof(IDL_VARIABLE)); if(!vTmp){ perror("malloc"); return (IDL_VPTR)NULL; } bzero((char*)vTmp, sizeof(IDL_VARIABLE)); vTmp->flags = IDL_V_TEMP; /* used to mark the IDL_VARIABLE as dynamic */ return vTmp; } /********************************************************************* * IDL_RPCStoreScalar() * * Purpose: * This function is used to store a scalar value into an * IDL_VPTR variable. This function emulates the Callable IDL * function IDL_StoreScalar. * * entry: * dest - The ^ to the IDL_VARIABLE struct where the scalar * value is stored. Any dynamic memory that is contained * in dest will be deallocated before the store takes place. * type - The type of the value to be stored. * value - A ^ to an IDL_ALLTYPES union that contains the * scalar value to store in the destination variable. * * exit: * The scalar value is stored in the destination variable. */ void IDL_RPCStoreScalar(IDL_VPTR dest, int type, IDL_ALLTYPES *value) { int i; IDL_STRING *pStr; /* * Free up any dynamic memory being used by the variable */ if(dest->flags & IDL_V_DYNAMIC) idl_rpc_delvar(dest); dest->flags=0; /* * Switch on the variable type and do the store. */ switch(dest->type = type){ case IDL_TYP_BYTE: dest->value.c = value->c; break; case IDL_TYP_INT: dest->value.i = value->i; break; case IDL_TYP_LONG: dest->value.l = value->l; break; case IDL_TYP_FLOAT: dest->value.f = value->f; break; case IDL_TYP_DOUBLE: dest->value.d = value->d; break; case IDL_TYP_COMPLEX: dest->value.cmp = value->cmp; break; case IDL_TYP_DCOMPLEX: dest->value.dcmp = value->dcmp; break; case IDL_TYP_STRING: dest->value.str = value->str; IDL_RPCStrDup( &(dest->value.str), 1L); dest->flags = IDL_V_DYNAMIC; break; default: fprintf(stderr,"IDL_RPCStoreScalar: Unknown Type"); } return; /* thats it, fairly simple */ } /************************************************************** * IDL_RPCMakeArray() * * Purpose: * This function is used to emulate the IDL function * IDL_MakeTempArray() on the client side of the IDL RPC system. * This routine accepts parameters that describe the desired array, * and then creates a variable and allocates memory for the array. * * The resulting array is marked such that all dynamic memory * will be deallocated by IDL_RPCDeltmp(), IDL_RPCVarCopy()..ect. * * entry: * type - The IDL type code of the desired array. * n_dim - The number of dimensions of the array. * dim - An array that contains the size of each dimension. * init - The type of initialization that is performed on the * data block. If the value is set to IDL_BARR_INI_ZERO * the data block is cleared, otherwise no initialization * is done. * var - A ^ to an IDL_VPTR. The address of the created variable * is placed in the location referenced by var. * * exit: * var - referances the IDL_VPTR of the created variable. * Return Value: * On success the function returns the poniter to the array * data block. On failure, a NULL is returned. * */ char * IDL_RPCMakeArray( int type, int n_dim, IDL_LONG dim[], int init, IDL_VPTR *var) { int i; char *pData; IDL_VPTR vTmp; /* * Get a new IDL_VPTR */ if( (vTmp = IDL_RPCGettmp()) == (IDL_VPTR)NULL) return (char *)NULL; /* * Alloc the array struct */ vTmp->value.arr = (IDL_ARRAY*)calloc(1, sizeof(IDL_ARRAY)); if(!vTmp->value.arr){ IDL_RPCDeltmp(vTmp); perror("calloc"); return((char*)NULL); } /* * Set up the vptr flags. */ vTmp->flags |= IDL_V_ARR | IDL_V_DYNAMIC; vTmp->type = type; /* * Get the element size. Depends on the type. */ switch(type){ case IDL_TYP_BYTE: vTmp->value.arr->elt_len = sizeof(UCHAR); break; case IDL_TYP_INT: vTmp->value.arr->elt_len = sizeof(short); break; case IDL_TYP_LONG: vTmp->value.arr->elt_len = sizeof(IDL_LONG); break; case IDL_TYP_FLOAT: vTmp->value.arr->elt_len = sizeof(float); break; case IDL_TYP_DOUBLE: vTmp->value.arr->elt_len = sizeof(double); break; case IDL_TYP_COMPLEX: vTmp->value.arr->elt_len = sizeof(IDL_COMPLEX); break; case IDL_TYP_DCOMPLEX: vTmp->value.arr->elt_len = sizeof(IDL_DCOMPLEX); break; case IDL_TYP_STRING: vTmp->value.arr->elt_len = sizeof(IDL_STRING); break; default: break; } /* * Set the rest of the array fields, start with the number of * elements. */ vTmp->value.arr->n_elts = 1; for(i=0;i < n_dim; i++){ vTmp->value.arr->n_elts *= dim[i]; vTmp->value.arr->dim[i] = dim[i]; } vTmp->value.arr->arr_len = vTmp->value.arr->elt_len * vTmp->value.arr->n_elts; vTmp->value.arr->n_dim = n_dim; /* * Now allocate space for the data */ pData = (char*)malloc(vTmp->value.arr->arr_len); if(!pData){ perror("malloc"); IDL_RPCDeltmp(vTmp); return((char*)NULL); } /* * Does the user want to initialize this to zero? */ if(init == IDL_BARR_INI_ZERO) bzero(pData, vTmp->value.arr->arr_len); vTmp->value.arr->data = (UCHAR*)pData; *var = vTmp; /* assign vptr to output */ return pData; } /*************************************************************************** *IDL_RPCImportArray() * * Purpose: * This function is used to emulate the IDL function IDL_ImportArray() * on the client side of the IDL RPC system. This routine accepts * a pointer to a data block that the user whishes to import into an * IDL variable as well as parameters that describe the attributes of * the data. In addition to this information, the function accepts a * a pointer to a user supplied function that can be used to free * the memory associated with the imported data. * * The resulting array is marked such that all dynamic memory * will be deallocated by IDL_RPCDeltmp(), IDL_RPCVarCopy()..ect. as * well as calling a user supplied memory deallocation call back function. * * Note: This function does not support structure def. pointers as * does IDL_ImportArray(). Structures are not supported by the * RPC system. * entry: * n_dim - The number of dimesions in the array. * dim - The number of elements of each dimension. * type - The type of the array. * data - Pointer to the array block that is being imported. * free_cb - Pointer to a function that should be called * when freeing the data. If left null free() will be * called. * * exit: * Return Value: * On success, the function returns an IDL_VPTR that * references the IDL_VARIABLE the contains the imported * array. On failure, NULL is returned. */ IDL_VPTR IDL_RPCImportArray(int n_dim, IDL_LONG dim[], int type, UCHAR *data, IDL_ARRAY_FREE_CB free_cb) { IDL_VPTR pVptr; /* vptr */ long n_elements=1; long szElement; int i; /* * Are there any dimensions? */ if(n_dim <= 0){ fprintf(stderr, "IDL_RPCImportArray: Invalid Number of dimensions"); return (IDL_VPTR)NULL; } /* * What is the size of an element? */ switch(type){ case IDL_TYP_INT: szElement=sizeof(short); break; case IDL_TYP_LONG: szElement=sizeof(IDL_LONG); break; case IDL_TYP_FLOAT: szElement=sizeof(float); break; case IDL_TYP_DOUBLE: szElement=sizeof(double); break; case IDL_TYP_COMPLEX: szElement=sizeof(IDL_COMPLEX); break; case IDL_TYP_DCOMPLEX: szElement=sizeof(IDL_DCOMPLEX); break; case IDL_TYP_STRING: szElement=sizeof(IDL_STRING); break; default: fprintf(stderr, "IDL_RPCImportArray: Unknown Type\n"); return (IDL_VPTR)NULL; } /* * Get a temporary Variable */ pVptr = IDL_RPCGettmp(); /* * Alloc an array block */ pVptr->value.arr = (IDL_ARRAY*)calloc(1, sizeof(IDL_ARRAY)); if(!pVptr->value.arr){ IDL_RPCDeltmp(pVptr); return (IDL_VPTR)NULL; } /* * Set-up the correct flags for the variable. */ pVptr->flags |= IDL_V_ARR | IDL_V_DYNAMIC; pVptr->type = type; for(i=0; ivalue.arr->dim[i] = dim[i]; n_elements *= dim[i]; } pVptr->value.arr->elt_len = szElement; pVptr->value.arr->n_dim = (UCHAR)n_dim; pVptr->value.arr->arr_len = szElement*n_elements; pVptr->value.arr->n_elts = n_elements; pVptr->value.arr->free_cb = free_cb; pVptr->value.arr->data = data; /* * That's all */ return pVptr; } /*************************************************************************** * idl_rpc_delvar * * Purpose: * This routine is used to free all of the dynamic memory associated * with a variable. This routine doesnt free the variable. This routine * should not be called by the user, but is used internally by the rpc * client side functions * entry: * pVar - A IDL_VPTR to the variable to have dynamic memory freed. * * exit: * pVar - All dynamic memory associated with the variable( array * and/or strings) is deallocated or a user call-back has been * called. */ void idl_rpc_delvar(IDL_VPTR pVar) { int i; IDL_STRING *pStr; int flags=0; flags = (IDL_V_TEMP & pVar->flags); /* * Check for an array. */ if(pVar->flags & IDL_V_ARR){ if(pVar->flags & IDL_V_DYNAMIC){ /* * was a Free callback function declared? */ if(pVar->value.arr->free_cb != (IDL_ARRAY_FREE_CB)NULL){ pVar->value.arr->free_cb((UCHAR*)pVar->value.arr->data); }else{ /* * Have a dynamic array that needs to be free'd. Is this a string * array? */ if(pVar->type == IDL_TYP_STRING){ IDL_RPCStrDelete((IDL_STRING*)pVar->value.arr->data, pVar->value.arr->n_elts); } free(pVar->value.arr->data); } } free(pVar->value.arr); /* the array block is always dynamic */ }else if(pVar->type == IDL_TYP_STRING){ if(pVar->value.str.stype) free(pVar->value.str.s); } /* * Now just clear out the variable. */ bzero((char*)pVar, sizeof(IDL_VARIABLE)); pVar->flags = flags; /* save temp flag. it is used to indicate */ /* that the variable struct is dynamic */ } /**************** * String Section. *********************************************************************** * idl_rpc_strup() * * Purpose: * Used to upcase a string. * * entry: * dst - The destination of the string variable. * src - The source string * * exit: * dst contains a upcased version of src. * */ void idl_rpc_strup(char * dst, char * src) { char c; do{ c = *src++; if(islower(c)) c = toupper(c); }while(*dst++ = c); } /**************************************************************************** * IDL_RPCStrDup() * * Purpose: * * This function is used to emulate the Callable IDL function * IDL_RPCStrDup(). This function should only be used on the client * side of the RPC routines. * * entry: * str - A ^ to an IDL_STRING struct array. * n - The number of elements in the str. * * exit: * str contains copies of the string values that where contained * in the IDL_STRING structures. * If an error is detected, the string struct is cleared. */ void IDL_RPCStrDup(IDL_STRING *str, IDL_LONG n) { for(;n--; str++){ if(str->slen && str->stype){ if((str->s = (char*)strdup(str->s))==(char*)NULL) bzero( (char*)str, sizeof(IDL_STRING)); else str->stype = 1; /* flag for dynamic */ } } } /*************************************************************************** * IDL_RPCStrDelete() * * Purpose: * This routine is used to free any dynamic memory contained in the * string descriptors. * * entry: * str - A ^ to an IDL_STRING struct array. * n - The number of elements in str. * * exit: * All dynamic values in the strings are deallocated and the * IDL_STRING structs are set to reflect this. * */ void IDL_RPCStrDelete(IDL_STRING *str, IDL_LONG n) { for(;n--; str++){ /* * Free the string if it is dynamic and has a length */ if(str->slen && str->stype){ free(str->s); bzero((char*)str, sizeof(IDL_STRING)); } } } /*************************************************************************** * IDL_RPCStrStore() * * Purpose: * This routine is used to store a C string into an IDL String. The * C string is strdup'd. * * entry: * s - The ^ to a IDL_STRING struct that will get copy of the * C string. * fs - The C string to copy. * exit: * s contains a copy of the C string or has been cleared if fs = null. */ void IDL_RPCStrStore( IDL_STRING *s, char *fs) { int len; if((len=strlen(fs))){ s->s = (char*)strdup(fs); s->slen = len; s->stype=1; } else bzero((char*)s, sizeof(IDL_STRING)); } /*************************************************************************** * IDL_RPCStrEnsureLength() * * Purpose: * Used to ensure that a string is of a certain length. * * entry: * s - A ^ to a IDL_STRING struct that will get the string. * n - The lenght to be allocated. * * exit: * The string field of the IDL_STRING struct is set to the desired length. */ void IDL_RPCStrEnsureLength(IDL_STRING *s, int n) { if(n){ /* make a non-null dynamic string */ if( ((int)s->slen < n) || !(s->stype)){ IDL_RPCStrDelete(s, 1L); s->s = (char*)malloc((unsigned)sizeof(char)*n+1); if(!s->s){ bzero((char*)s, sizeof(IDL_STRING)); return; } s->stype=1; } s->slen = n; }else { /* Want a null string */ if(s->slen){ IDL_RPCStrDelete(s, 1L); bzero((char*)s, sizeof(IDL_STRING)); } } } /*************************************************************************** */ void IDL_RPCVarGetData(IDL_VPTR v, IDL_LONG *n, char **pd, int ensure_simple) /* * Given a pointer to a varible, return the number of elements * and a pointer to the data area. This routine takes care of the * distinction between arrays and scalars. * * entry: * v - Variable for which data is desired. * n - Address of variable to receive # of elements. * pd - Address of variable to receive pointer to data. * ensure_simple - If TRUE, this routine calls the ENSURE_SIMPLE * macro on the argument v to screen out variables of the * types it prevents. Otherwise, EXCLUDE_FILE is called, * because file variables have no data area to return. * * exit: * *n - Receives count of elements. * *pd - Receives pointer to data. */ { if(!v->type) return; if (ensure_simple) { if((v->flags &(IDL_V_FILE|IDL_V_STRUCT))|| (v->type & (IDL_TYP_OBJREF|IDL_TYP_PTR))) return; } else { if(v->flags & IDL_V_FILE) return; } if (v->flags & IDL_V_ARR) { /* Array? */ *n = v->value.arr->n_elts; /* Return values */ *pd = (char *) v->value.arr->data; } else { *n = 1; /* Scalar, one element */ *pd = (char *) &v->value; } }