/* * Copyright (c) 2010,2011 Joshua V Dillon * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * Neither the name of the author nor the names of its * contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY JOSHUA V DILLON ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOSHUA * V DILLON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include "sharedmatrix.h" /* ------------------------------------------------------------------------- */ /* Matlab gateway function */ /* */ /* (see sharedmatrix.m for description) */ /* ------------------------------------------------------------------------- */ void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { /* mex inputs */ const mxArray *mxDirective; /* directive {clone, attach, detach, free} */ const mxArray *mxShmKey; /* name of the shared memory segment */ const mxArray *mxInput; /* input array (for clone) */ /* mex outputs */ mxArray *mxOutput=NULL; /* for storing directive (string) input */ char directive[MAXDIRECTIVELEN+1]; /* for working with shared memory ... */ key_t shmkey=0; size_t shmsiz=0; /* apparently you can attach w/o specifying this */ size_t shmsiz_tmp=0; /* for shallowrestore recursion */ int shmid; char *shm=NULL; /* for storing the mxArrays ... */ header_t hdr; data_t dat; /* check min number of arguments */ if ( nrhs<2 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix", "Minimum input arguments missing; must supply directive and key."); /* assign inputs */ mxDirective = prhs[0]; mxShmKey = prhs[1]; /* get directive (ARGUMENT 0) */ if ( mxGetString(mxDirective,directive,MAXDIRECTIVELEN)!=0 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix", "First input argument must be {'clone','attach','detach','free'}."); /* get key (ARGUMENT 1) */ if ( mxIsNumeric(mxShmKey) && mxGetNumberOfElements(mxShmKey)==1 ) shmkey = (key_t)mxGetScalar(mxShmKey); else mexErrMsgIdAndTxt("MATLAB:sharedmatrix", "Second input argument must be a valid key (numeric scalar)."); /* check outputs */ if ( nlhs > 1 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix", "Function returns only one value."); /* clone, attach, detach, free */ switch ( tolower(directive[0]) ) { /* --------------------------------------------------------------------- */ /* Clone */ /* --------------------------------------------------------------------- */ case 'c': if ( nrhs<3 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone", "Required third argument missing (variable)."); if ( mxGetNumberOfElements(prhs[2])<2 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone", "Required third argument (variable) must have at least two elements."); /* Assign (ARGUMENT 2) */ mxInput = prhs[2]; bool allocate_only = false; if (nrhs>3) { int * tmp = (int*)mxGetData(prhs[3]); allocate_only = tmp[0]; } /* scan input data */ shmsiz = deepscan(&hdr,&dat,mxInput); mydebug("clone: deepscan done (%u)",(unsigned)shmsiz); /* create the segment */ if ( (shmid=shmget(shmkey,shmsiz,IPC_CREAT|IPC_EXCL|0644 )) < 0 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone", "Unable to create shared memory segment."); /* attach the segment to this dataspace */ shm = (char*)shmat(shmid,NULL,0); if ( shm==(char*)-1 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone", "Unable to attach shared memory to data space."); mydebug("clone: shared memory at: 0x%llx",shm); /* copy data to the shared memory */ deepcopy(&hdr,&dat,shm, allocate_only); mydebug("clone: deep copy successful"); /* free temporary allocation */ deepfree(&dat); shmdt(shm); /* return its size */ mxOutput = mxCreateDoubleScalar((double)shmsiz); break; /* --------------------------------------------------------------------- */ /* Attach */ /* --------------------------------------------------------------------- */ case 'a': /* get SM id */ if ( (shmid=shmget(shmkey,shmsiz,IPC_CREAT|0644)) < 0 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach", "Unable to get shared memory id."); /* attach the segment to this dataspace */ shm = (char*)shmat(shmid,NULL,0); if ( shm==(char*)-1 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach", "Unable to attach shared memory to data space."); mydebug("attach: shared memory at: 0x%llx",shm); /* restore the segments (ignore return value) */ shmsiz_tmp=shallowrestore(shm,&mxOutput); mydebug("attach: done"); break; /* --------------------------------------------------------------------- */ /* Detach */ /* --------------------------------------------------------------------- */ case 'd': if ( nrhs<3 || mxIsEmpty(prhs[2]) ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:detach", "Required third argument (variable) missing or empty."); /* Assign */ mxInput = prhs[2]; shm = deepdetach((mxArray*)mxInput); /* Abuse const */ mxOutput = mxCreateDoubleMatrix(0,0,mxREAL); mydebug("detach: shared memory at: 0x%llx",shm); if ( shmdt(shm) != 0 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:detach", "Unable to detach shared memory."); break; /* --------------------------------------------------------------------- */ /* Free */ /* --------------------------------------------------------------------- */ case 'f': /* get SM id */ if ( (shmid=shmget(shmkey,shmsiz,0644)) < 0 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:free", "Unable to get shared memory id."); /* free SM */ if ( (shmctl(shmid,IPC_RMID,(struct shmid_ds *)NULL)) != 0 ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:free", "Unable to destroy shared memory."); mxOutput = mxCreateDoubleMatrix(0,0,mxREAL); break; /* --------------------------------------------------------------------- */ /* Error */ /* --------------------------------------------------------------------- */ default: mexErrMsgIdAndTxt("MATLAB:sharedmatrix", "Unrecognized directive."); } /* assign the output */ plhs[0] = mxOutput; } /* ------------------------------------------------------------------------- */ /* deepdetach */ /* */ /* Remove shared memory references to input matrix (in-situ), recursively */ /* if needed. */ /* */ /* Arguments: */ /* Input matrix to remove references. */ /* Returns: */ /* Pointer to start of shared memory segment. */ /* ------------------------------------------------------------------------- */ char* deepdetach(mxArray *mxInput) { /* uses side-effects! */ mwSize dims[] = {0,0}; mwSize nzmax = 0; size_t elemsiz; size_t i,j,n,m; size_t offset=0; char *shm=(char*)NULL,*tmp=(char*)NULL; /* restore matlab memory */ if ( mxInput==(mxArray*)NULL || mxIsEmpty(mxInput) ) { /* do nothing */ } else if ( mxIsStruct(mxInput) ) { /* struct case */ /* detach each field for each element */ m = mxGetNumberOfElements(mxInput); n = mxGetNumberOfFields(mxInput); for ( i=0; inDims); if ( hdr->isStruct ) { /* struct case */ mydebug("shallowrestore: found structure %d x %d",pSize[0],pSize[1]); /* Pull out the field names, they follow the size*/ ret = NumFieldsFromString(shm, &nFields, &strBytes); /* check the recovery */ if ((ret) || (nFields != hdr->nFields)) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach", "Structure fields have not been recovered properly."); /* And convert to something matlab understands */ pFieldStr = (char**)mxCalloc(nFields, sizeof(char*)); PointCharArrayAtString(pFieldStr, shm, nFields); /* skip over the stored field string */ shm += strBytes; /*create the matrix */ *p_mxInput = mxCreateStructArray(hdr->nDims, pSize, hdr->nFields, (const char**)pFieldStr); mxFree(pFieldStr); /* no longer need it */ for ( i=0; inzmax; i++ ) { /* each element */ for ( field_num=0; field_numnFields; field_num++ ) { /* each field */ mydebug("shallowrestore: working on %d field %d at 0x%llx",i,field_num, *p_mxInput); /* And fill it */ shmsiz = shallowrestore(shm,&mxChild); /* restore the mxArray */ mxSetFieldByNumber(*p_mxInput, i, field_num, mxChild); /* and pop it in */ shm += shmsiz; mydebug("shallowrestore: completed %d field %d",i, field_num); } } } else if ( hdr->isCell ) { /* cell case */ mydebug("shallowrestore: found cell %d x %d",pSize[0], pSize[1]); /* Create the array */ *p_mxInput = mxCreateCellArray(hdr->nDims, pSize); for ( i=0; inzmax; i++ ) { mydebug("shallowrestore: working on %d at 0x%llx",i,mxChild); /* And fill it */ shmsiz = shallowrestore(shm,&mxChild); mxSetCell(*p_mxInput, i, mxChild); shm += shmsiz; mydebug("shallowrestore: completed %d at 0x%llx",i,mxChild); } } else { /* matrix case */ /* this is the address of the first data */ pr = (void*)shm; shm += pad_to_align((hdr->nzmax)*(hdr->elemsiz)); /* takes us to the end of the real data */ /* if complex get a pointer to the complex data */ if ( hdr->isComplex ) { pi = (void*)shm; shm += pad_to_align((hdr->nzmax)*(hdr->elemsiz)); /* takes us to the end of the complex data */ } /* if sparse get a list of the elements */ // if ( hdr->isSparse ) { // mydebug("shallowrestore: found non-cell, sparse 0x%llx",*p_mxInput); // // ir = (mwIndex*)shm; // shm += pad_to_align((hdr->nzmax)*sizeof(mwIndex)); // // jc = (mwIndex*)shm; // shm += pad_to_align((pSize[1]+1)*sizeof(mwIndex)); // // /* need to create sparse logical differently */ // if ( hdr->classid==mxLOGICAL_CLASS ) // *p_mxInput = mxCreateSparseLogicalMatrix(0,0,0); // else // *p_mxInput = mxCreateSparse(0,0,0,(hdr->isComplex)?mxCOMPLEX:mxREAL); // // /* free the memory it was created with */ // mxFree(mxGetIr(*p_mxInput)); // mxFree(mxGetJc(*p_mxInput)); // // /* set the size */ // if (mxSetDimensions(*p_mxInput, pSize, hdr->nDims)) // mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach", // "Unable to resize the sparse array."); // // /* set the pointers relating to sparse (set the real and imaginary data later)*/ // #ifndef SAFEMODE // // /* Hack Method */ // ((mxArrayHack*)*p_mxInput)->data.number_array.reserved5 = ir; // ((mxArrayHack*)*p_mxInput)->data.number_array.reserved6[0] = (size_t)jc; // ((mxArrayHack*)*p_mxInput)->data.number_array.reserved6[1] = (size_t)(hdr->nzmax); // // /* dont do this as it makes a write turn into a copy to local memory */ // /*((mxArrayHack*)*p_mxInput)->reserved3 = 1;*/ /*give it a reference count*/ // // #else // // /* Safe - but takes it out of global memory */ // mxSetIr(*p_mxInput, (mwIndex*) safeCopy(ir,(hdr->nzmax)*sizeof(mwIndex))); // mxSetJc(*p_mxInput, (mwIndex*) safeCopy(jc,(pSize[1]+1)*sizeof(mwIndex))); // // #endif // mxSetNzmax(*p_mxInput,hdr->nzmax); // // } else { /* rebuild constitute the array */ mydebug("shallowrestore: found non-cell, non-sparse"); /* create an empty array */ *p_mxInput = mxCreateNumericMatrix(0,0,hdr->classid,(hdr->isComplex)?mxCOMPLEX:mxREAL); mydebug("%d %d (of total: %d)",pSize[0],pSize[1],hdr->nDims); /* set the size */ if (mxSetDimensions(*p_mxInput, pSize, hdr->nDims)) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:attach", "Unable to resize the array."); // } /* Free the memory it was created with (shouldn't be necessary) */ mxFree(mxGetPr(*p_mxInput)); mxFree(mxGetPi(*p_mxInput)); /* set the real and imaginary data */ if ( ! hdr->isComplex ) { /* Hack Method */ mydebug("pr:0x%llx",pr); /* BUGFIX: this line causes matlab ABORT when shared object is a scalar! */ /* the theory is that scalars are copied not copy on reference hence * the return of the function causes a failure. */ ((mxArrayHack*)(*p_mxInput))->data.number_array.pdata = pr; if ( hdr->isComplex ) ((mxArrayHack*)(*p_mxInput))->data.number_array.pimag_data = pi; } else { /* Safe - but takes it out of global memory */ mxSetData(*p_mxInput, safeCopy(pr, hdr->nzmax*hdr->elemsiz)); if ( hdr->isComplex ) mxSetImagData(*p_mxInput, safeCopy(pi, hdr->nzmax*hdr->elemsiz)); } } return hdr->shmsiz; } /* ------------------------------------------------------------------------- */ /* deepscan */ /* */ /* Recursively descend through Matlab matrix to assess how much space its */ /* serialization will require. */ /* */ /* Arguments: */ /* header to populate. */ /* data container to populate. */ /* mxArray to analyze. */ /* Returns: */ /* size that shared memory segment will need to be. */ /* ------------------------------------------------------------------------- */ size_t deepscan(header_t *hdr, data_t *dat, const mxArray* mxInput) { /* counter */ size_t i; /* for structures */ size_t field_num, count, plussiz; size_t strBytes; /* initialize data info; _possibly_ update these later */ dat->pSize = ( mwSize* )NULL; dat->pr = ( void*)NULL; dat->pi = ( void*)NULL; dat->ir = ( void*)NULL; dat->jc = ( mwIndex*)NULL; dat->child_dat = ( data_t*)NULL; dat->child_hdr = (header_t*)NULL; if ( mxInput==(const mxArray*)NULL || mxIsEmpty(mxInput) ) { /* initialize header info */ hdr->isCell = 0; hdr->isSparse = 0; hdr->isComplex = 0; hdr->isStruct = 0; hdr->classid = mxUNKNOWN_CLASS; hdr->nDims = 0; hdr->elemsiz = 0; hdr->nzmax = 0; hdr->nFields = 0; hdr->shmsiz = sizeof(header_t); return hdr->shmsiz; } /* initialize header info */ hdr->isCell = mxIsCell(mxInput); hdr->isSparse = mxIsSparse(mxInput); hdr->isComplex = mxIsComplex(mxInput); hdr->isStruct = mxIsStruct(mxInput); hdr->classid = mxGetClassID(mxInput); hdr->nDims = mxGetNumberOfDimensions(mxInput); hdr->elemsiz = mxGetElementSize(mxInput); hdr->nzmax = mxGetNumberOfElements(mxInput); /* update this later (if sparse) */ hdr->nFields = 0; /* update this later */ hdr->shmsiz = sizeof(header_t); /* update this later */ /* copy the size */ dat->pSize = (mwSize*)mxGetDimensions(mxInput); /* some abuse of const for now, fix on deep copy*/ /* Add space for the dimensions */ hdr->shmsiz += pad_to_align(hdr->nDims * sizeof(mwSize)); if ( hdr->isStruct ) { /* struct case */ mydebug("deepscan: found structure"); /* How many fields to work with? */ hdr->nFields = mxGetNumberOfFields(mxInput); /* Find the size required to store the field names */ strBytes = FieldNamesSize(mxInput); /* always a multiple of alignment size */ hdr->shmsiz += strBytes; /* Add space for the field string */ /* use mxCalloc so mem is freed on error via garbage collection */ dat->child_hdr = (header_t*)mxCalloc(hdr->nzmax * hdr->nFields * (sizeof(header_t) + sizeof(data_t)) + strBytes, 1); /* extra space for the field string */ dat->child_dat = (data_t*)&dat->child_hdr[hdr->nFields * hdr->nzmax]; dat->ir = (void*)&dat->child_dat[hdr->nFields * hdr->nzmax]; /* make a record of the field names */ CopyFieldNames(mxInput, (char*)(dat->ir)); /* go through each recursively */ count = 0; for ( i=0; inzmax; i++ ) { /* each element */ for (field_num = 0; field_num < hdr->nFields; field_num++) { /* each field */ /* call recursivley */ plussiz = deepscan(&(dat->child_hdr[count]), &(dat->child_dat[count]), mxGetFieldByNumber(mxInput,i,field_num) ); hdr->shmsiz += plussiz; count++; /* progress */ mydebug("deepscan: finished element %d field %d (%12u %12u)",i,field_num,plussiz,hdr->shmsiz); } } } else if ( hdr->isCell ) { /* cell case */ mydebug("deepscan: found cell"); /* use mxCalloc so mem is freed on error via garbage collection */ dat->child_hdr = (header_t*)mxCalloc(hdr->nzmax,sizeof(header_t) + sizeof(data_t)); dat->child_dat = (data_t*)&dat->child_hdr[hdr->nzmax]; /* go through each recursively */ for ( i=0;inzmax;i++ ) { plussiz = deepscan( &(dat->child_hdr[i]), &(dat->child_dat[i]), mxGetCell(mxInput,i)); hdr->shmsiz += plussiz; mydebug("deepscan: finished %d (%12u %12u)",i,plussiz,hdr->shmsiz); } /* if its a cell it has to have at least one mom-empty element */ if ( hdr->shmsiz==(1+hdr->nzmax)*sizeof(header_t) ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone", "Required third argument (variable) must contain at " "least one non-empty item (at all levels)."); } else if ( mxIsNumeric(mxInput) || mxIsLogical(mxInput) || mxIsChar(mxInput)) { /* a matrix containing data */ /* matrix case */ if ( hdr->isSparse ) { /* len(pr)=nzmax, len(ir)=nzmax, len(jc)=colc+1 */ hdr->nzmax = mxGetNzmax(mxInput);/* make sure to do this because its sparse */ dat->ir = mxGetIr(mxInput); dat->jc = mxGetJc(mxInput); /* ensure both pointers are aligned individually */ hdr->shmsiz += pad_to_align(sizeof(mwIndex)*(hdr->nzmax)); /* ir */ hdr->shmsiz += pad_to_align(sizeof(mwIndex)*(dat->pSize[1]+1)); /* jc */ } dat->pr = mxGetData(mxInput); dat->pi = mxGetImagData(mxInput); /* ensure both pointers are aligned individually */ hdr->shmsiz += pad_to_align(hdr->elemsiz*hdr->nzmax); /* pr */ if (hdr->isComplex) hdr->shmsiz += pad_to_align(hdr->elemsiz*hdr->nzmax); /* pi */ } else { /* error case */ mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone", "Unknown class found: %s.", mxGetClassName(mxInput)); } return hdr->shmsiz; } /* ------------------------------------------------------------------------- */ /* deepcopy */ /* */ /* Descend through header and data structure and copy relevent data to */ /* shared memory. */ /* */ /* Arguments: */ /* header to serialize. */ /* data container of pointers to data to serialize. */ /* pointer to shared memory segment. */ /* Returns: */ /* void */ /* ------------------------------------------------------------------------- */ void deepcopy(header_t *hdr, data_t *dat, char *shm, bool allocate_only) { /* declarations */ size_t i,offset; mwSize *pSize; /* points to the size data */ size_t nDims=hdr->nDims; /* for structures */ size_t nFields; int ret; /* copy the header (NOALIGN) */ offset = sizeof(header_t); memcpy(shm,hdr,offset); shm+=offset; /* keep for later */ pSize = (mwSize*)shm; /* copy the dimensions (ALIGN) */ offset = nDims * sizeof(mwSize); memcpy(shm,dat->pSize,offset); shm += pad_to_align(offset); if (hdr->isStruct) { /* struct case */ mydebug("deepcopy: found structure"); /* place the field names next in shared memory */ /* note: NumFieldsFromString() automatically pads the offset */ ret = NumFieldsFromString((char*)(dat->ir), &nFields, &offset); /* check the recovery */ if ( ret || nFields!=hdr->nFields ) mexErrMsgIdAndTxt("MATLAB:sharedmatrix:clone", "Structure fields have not been recovered properly."); /* copy the field string (ALIGN) */ memcpy(shm,dat->ir,offset); shm += offset; /* aligned already! in NumFieldsFromString */ /* copy children recursively (NOALIGN) */ for ( i=0; inzmax*hdr->nFields; i++ ) { deepcopy( &(dat->child_hdr[i]),&(dat->child_dat[i]), shm, allocate_only ); shm += (dat->child_hdr[i]).shmsiz; } } else if ( hdr->isCell ) { /* cell case */ mydebug("deepcopy: found cell"); /* copy children recursively (NOALIGN) */ for( i=0; inzmax; i++ ) { deepcopy(&(dat->child_hdr[i]),&(dat->child_dat[i]),shm, allocate_only ); shm+=(dat->child_hdr[i]).shmsiz; } } else { /* matrix case */ /* copy real data (ALIGN) */ offset = (hdr->nzmax)*(hdr->elemsiz); if (!allocate_only) memcpy(shm,dat->pr,offset); shm += pad_to_align(offset); /* copy complex data (ALIGN) */ if ( hdr->isComplex ) { offset = (hdr->nzmax)*(hdr->elemsiz); if (!allocate_only) memcpy(shm,dat->pi,offset); shm += pad_to_align(offset); } /* indices of sparse (ALIGN) */ if ( hdr->isSparse ) { offset = hdr->nzmax*sizeof(mwIndex); memcpy(shm,dat->ir,offset); shm += pad_to_align(offset); offset = (pSize[1]+1)*sizeof(mwIndex); memcpy(shm,dat->jc,offset); shm += pad_to_align(offset); } } } /* ------------------------------------------------------------------------- */ /* deepfree */ /* */ /* Descend through header and data structure and free the memory. */ /* */ /* Arguments: */ /* data container */ /* Returns: */ /* void */ /* ------------------------------------------------------------------------- */ void deepfree(data_t *dat) { /* recurse to the bottom */ if ( dat->child_dat!=(data_t*)NULL ) deepfree(dat->child_dat); /* free on the way back up */ mxFree(dat->child_hdr); dat->child_hdr = (header_t*)NULL; dat->child_dat = (data_t*)NULL; dat->ir = (void*)NULL; /* could have been used for fieldNames */ } /* ------------------------------------------------------------------------- */ /* */ /* Andrew Smith Code for structs. */ /* */ /* ------------------------------------------------------------------------- */ /* Function to find the number of bytes required to store all of the */ /* field names of a structure */ int FieldNamesSize(const mxArray * mxStruct) { const char* pFieldName; int nFields; int i,j; /* counters */ int Bytes = 0; /* How many fields? */ nFields = mxGetNumberOfFields(mxStruct); /* Go through them */ for (i = 0; i < nFields; i++) { /* This field */ pFieldName = mxGetFieldNameByNumber(mxStruct,i); j = 0; while (pFieldName[j]) { j++; } j++; /* for the null termination */ if (i == (nFields - 1)) j++; /* add this at the end for an end of string sequence since we use 0 elsewhere (term_char). */ /* Pad it out to 8 bytes */ j = pad_to_align(j); /* keep the running tally */ Bytes += j; } /* Add an extra alignment size to store the length of the string (in Bytes) */ Bytes += align_size; return Bytes; } /* Function to copy all of the field names to a character array */ /* Use FieldNamesSize() to allocate the required size of the array */ /* returns the number of bytes used in pList */ int CopyFieldNames(const mxArray * mxStruct, char* pList) { const char* pFieldName; /* name of the field to add to the list */ int nFields; /* the number of fields */ int i,j; /* counters */ int Bytes = 0; /* number of bytes copied */ /* How many fields? */ nFields = mxGetNumberOfFields(mxStruct); /* Go through them */ for (i = 0; i < nFields; i++) { /* This field */ pFieldName = mxGetFieldNameByNumber(mxStruct,i); j = 0; while (pFieldName[j]) { pList[Bytes++]=pFieldName[j++]; } pList[Bytes++] = 0; /* add the null termination */ /* if this is last entry indicate the end of the string */ if (i == (nFields - 1)) { pList[Bytes++] = term_char; pList[Bytes++] = 0; /* another null termination just to be safe */ } /* Pad it out to 8 bytes */ while (Bytes % align_size) { pList[Bytes++] = 0; } } /* Add an extra alignment size to store the length of the string (in Bytes) */ *(unsigned int*)&pList[Bytes] = (unsigned int)(Bytes + align_size); Bytes += align_size; return Bytes; } /*Function to take point a each element of the char** array at a list of names contained in string */ /*ppCharArray must be allocated to length num_names */ /*names are seperated by null termination characters */ /*each name must start on an aligned address (see CopyFieldNames()) */ /*e.g. pCharArray[0] = &name_1, pCharArray[1] = &name_2 ... */ /*returns 0 if successful */ int PointCharArrayAtString(char ** pCharArray, char* pString, int nFields) { int i = 0; /* the index in pString we are up to */ int field_num = 0; /* the field we are up to */ /* and recover them */ while (field_num < nFields) { /* scan past null termination chars */ while (!pString[i]) i++; /* Check the address is aligned (assume every forth bytes is aligned) */ if (i % align_size) return -1; /* grab the address */ pCharArray[field_num] = &pString[i]; field_num++; /* continue until a null termination char */ while (pString[i]) i++; } return 0; } /* This function finds the number of fields contained within in a string */ /* the string is terminated by term_char, a character that can't be in a field name */ /* returns the number of field names found */ /* returns -1 if unaligned field names are found */ int NumFieldsFromString(const char* pString, size_t *pFields, size_t* pBytes) { unsigned int stored_length; /* the recorded length of the string */ bool term_found = false; /* has the termination character been found? */ int i = 0; /* counter */ pFields[0] = 0; /* the number of fields in the string */ pBytes[0] = 0; /* and recover them */ while (!term_found) { /* scan past null termination chars */ while (!pString[i]) { i++; } /* is this the special termination character? */ term_found = pString[i] == term_char; if (!term_found) { /* Check the address is aligned (assume every forth bytes is aligned) */ if (i % align_size) { return -1; } /* a new field */ pFields[0]++; /* continue until a null termination char */ while (pString[i] && (pString[i] != term_char)) { i++; } /* check there wasn't the terminal character immediately after the field */ if (pString[i] == term_char) { return -2; } } } pBytes[0] = i; /* return the aligned size */ pBytes[0] = pad_to_align(pBytes[0]); /* Check what's recovered matches the stored length */ stored_length = *(unsigned int*)&pString[pBytes[0]] ; /* the recorded length of the string */ pBytes[0] += align_size; /* add the extra space for the record */ /* Check on it */ if (stored_length != pBytes[0]) return -3; return 0; } /* Function to find the bytes in the string starting from the end of the string (i.e. the last element is pString[-1])*/ /* returns < 0 on error */ int BytesFromStringEnd(const char* pString, size_t* pBytes) { int offset = align_size; /* start from the end of the string */ pBytes[0] = 0; /* default */ /* Grab it directly from the string */ pBytes[0] = (size_t)(*(unsigned int*)&pString[-offset]); /* scan for the termination character */ while ((offset < 2*align_size) && (pString[-offset] != term_char)) { offset++;} if (offset == align_size) { return -1; }/* failure to find the control character */ else { return 0; }/* happy */ }