MATLAB: Recursive MEX function, structures within structure

mexstructures

I'm trying to make a MEX function that takes a structure (STRUCT0) and a number of strings (STRING1, STRING2, …) as input arguments. The function should test whether STRUCT0.STRING1.STRING2 is a valid field. The function "checkForFields" below will verify that STRUCT0 is a structure, that STRING1 is a valid field and that STRUCT0.STRING1 is itself a structure. It should then recursively call itself, to check whether STRING2 is a field of STRUCT0.STRING1. However, that's where it goes wrong. When the function recursively calls itself, STRUCT0.STRING1 is no longer recognised as a structure. How should I define the input arguments for the recursive function call?
Many thanks, Dries
#include "mex.h"
#include "matrix.h"
void checkForFields(mxArray *output[], int nInputArguments, const mxArray *inputArguments[]);
void mexFunction(
int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]) {
// define a boolean output argument, initialised to false
plhs[0] = mxCreateLogicalScalar(0);
// check number of input arguments:
if(nrhs<2) {
mexErrMsgIdAndTxt("driesMex:fieldExists:nrhs1",
"Function requires a structure and at least one field.");
}
// check number of output arguments:
if(nlhs>1) {
mexErrMsgIdAndTxt("driesMex:fieldExists:nlhs",
"Function supports maximum one output.");
}
// if first argument is a struct
if (mxIsStruct(prhs[0])) {
// call a subroutine that will recursively call itself
checkForFields(plhs, nrhs, prhs);
} else {
// first argument is not a struct, issue a warning:
mexWarnMsgIdAndTxt("driesMex:fieldExists:firstArg", "First argument is not a structure.");
}
}
void checkForFields(mxArray *output[], int nInputArguments, const mxArray *inputArguments[]){
// *output[]: pointer to output mxArray
// nInputArguments: number of input arguments
// *inputArguments: pointer to input mxArray,
// first argument must be struct, rest are fields to be tested
// initialise output to false
output[0] = mxCreateLogicalScalar(0);
// if first argument is not a struct
if (!mxIsStruct(inputArguments[0])) {
// issue a warning:
mexWarnMsgIdAndTxt("driesMex:fieldExists:checkForFields:firstArg", "CheckForFields: First argument is not a structure.");
}
// if second argument is a string
if (mxIsChar(inputArguments[1])) {
// if second argument is a field
if (mxGetFieldNumber(inputArguments[0], mxArrayToString(inputArguments[1]))+1) {
// output argument should be set to true
output[0] = mxCreateLogicalScalar(1);
// check if there are more than 2 input arguments
if (nInputArguments>2) {
// check if second argument is also struct
if (mxIsStruct(mxGetField(inputArguments[0], 0, mxArrayToString(inputArguments[1])))){
// recursively call this subroutine
checkForFields(output, nInputArguments-1, &inputArguments[1]);
// output argument may be overwritten if subsequent field was not a field
}
}
}
// else second argument is not a field
// output argument was already initialised to false
} else {
// second argument is not a string, throw error
mexErrMsgIdAndTxt("driesMex:fieldExists:nrhs2",
"Function requires field argument(s) to be a string.");
}
}

Best Answer

  • I would not use a recursion at all.
    #include "mex.h" // Includes matrix.h already
    void mexFunction(
    int nlhs, mxArray *plhs[],
    int nrhs, const mxArray *prhs[])
    {
    mwSize i;
    char Field[mxMAXNAM];
    S = prhs[0];
    if (!mxIsStruct(S)) {
    mexErrMsgIdAndTxt(...);
    }
    for (i = 1; i < nrhs; i++) {
    // mxGetString replies 1 if the input is not a string
    // or too long:
    if (mxGetString(prhs[i], Field, mxMAXNAM)) {
    // Check for: prhs[i] is not a string, or too long
    mexErrMsgIdAndTxt(...);
    }
    // mxGetFields replies NULL, if S is not a struct or doe not
    // have the wanted field:
    S = mxGetField(S, 0, Field);
    if (S == NULL) { // Field not found:
    plhs[0] = mxCreateLogicalScalar(0);
    return;
    }
    }
    // All subfields have been found:
    plhs[0] = mxCreateLogicalScalar(1);
    return;
    }