/* varnames_in_sel Apr 09 */ /* varnames_in_sel takes a jgofs selection string, */ /* returns the number of different jgofs variables in it, and */ /* updates a list of jgofs variables with any newly found variables */ /* that are not already in the list */ /* */ /* Returns count of elements added to list (see Arg 1) */ /* Arg */ /* 1 Pointer to list to be updated. If NULL, a list will */ /* be created. If not NULL, last element of */ /* list must be NULL. The last element of the returned */ /* list will be NULL. */ /* The list must be dynamically */ /* allocated so it can be dynamically extended if needed. */ /* Each list element is a pointer to a jgofs varname. */ /* (Each jgofs varname is a null-terminated char string) */ /* List elements returned by this program are dynamically */ /* allocated */ /* 2 Pointer to null-terminated char string holding the */ /* selection */ /* The next 3 args are normally specified as NULL. */ /* They are pointers to functions to be called in case */ /* of various parsing errors. If specified as NULL, the */ /* calling program will exit with error information ultimately */ /* handled according to the program's "err" function. If the */ /* calling program does not already have an "err" function, */ /* the jgofs distribution contains err_stub* routines. Please */ /* see readme.libupd in src/lib */ /* Non-NULL pointers are needed only if the caller does */ /* NOT want to exit after a parsing error occurs. */ /* If such control is of interest, 2 other sources */ /* of information will be needed. First, the type and */ /* calling sequence for each function can be determined by */ /* looking at the default functions (below). Second, the */ /* source code of jgofs_selection_parser (src/lib/parse.c) */ /* will need to be consulted if the particulars of an error */ /* are of interest */ /* 3 Defaults to (*err)() (application-dependent) */ /* 4 Defaults to (*errn)() (src/lib/utils.c - will call err */ /* NB: this err is NOT arg 3 above) */ /* 5 Defaults to (*malloc_err_stub)() (below) */ #define VARNAMES_IN_SEL_VERSION "varnames_in_sel v 1.0 12 Jun 2009" /************************************************************************/ #include "parse.h" /* Next 3 are global only to communicate between */ /* add_varnames_from_selection & varnames_in_sel in this */ /* module */ char **selection_varnames_list; int n_selection_varnames; int size_selection_varnames_list; /* functions from utils (in jgofs.a library) */ void errn(); char *strdupl(); /* function from parse (in jgofs.a library) */ void jgofs_selection_parser(); /* function from "somewhere". jgofs.a library requires an err */ /* function. If not in user program, we've provided err_stub* */ /* files - see src/lib/readme.libupd */ void err(); /********** */ char *varnames_in_sel_return_vers() /* Dummy routine. Exists only to force .h file version string into */ /* this module. Note string must not be global or we'll have con- */ /* flicts if another routine similarly includes the version string */ { static char version[] = VARNAMES_IN_SEL_VERSION"/"FULL_PARSEH_VERSION; return version; } /* Code below stolen from outer's malloc_err routine. */ void malloc_err_stub(s,n) char *s; int n; { /* Don't want to malloc an error buffer if we're having trouble */ /* malloc'ing in the first place */ /* Tried putting malloc in here, too, returning ptr when OK, but */ /* ran into BUSERR alignment problems. Don't know why... */ #define STUB_MAX_S 50 char idbuf[32 + STUB_MAX_S + 9 + 1] = "parse could not get memory for "; int len; if ( (len = strlen(s)) > STUB_MAX_S ) len = STUB_MAX_S; strncat(idbuf,s,len); strcat(idbuf,". nbytes "); errn(idbuf,n); return; } /* parse will want to know what level a variable is on. Tell it 0 */ int dummy_iovarlevel(vn) int *vn; { return 0; } /* Next function is the heart of the trick. When parse finds a */ /* token that is syntactically a varname, it wants to associate the */ /* varname w/a varnum, so it calls a lookup routine. We replace */ /* that call w/a call to add_varname. We assume that the token */ /* is a legit varname, and return bogus info. The bogus info is OK */ /* as long as the results of the parse are not used. A dicier */ /* problem is that of correctly diagnosing errors, particularly */ /* those relating to illegal varnames and bad levels. Punt! */ int add_varnames_from_selection(s) char *s; { int index,nbytes; /* parse can't tell a "not" from a varname w/o following return */ if (strcmp(s,"not") == 0) return ILLEGAL_VARNUM; if (selection_varnames_list == NULL) err("varnames_in_sel: internal error: NULL selection_varnames_list", ""); /* Doing logic w/indices rather than pointer avoids issues due to */ /* realloc */ index = 0; while (selection_varnames_list[index] != NULL) { if (strcmp(s,selection_varnames_list[index]) == 0) break; index++; } if (selection_varnames_list[index] == NULL) { n_selection_varnames++; strdupl (&selection_varnames_list[index++],s, "varnames_from_selection: adding name"); nbytes = (index + 1) * (sizeof(char **)); selection_varnames_list = (char **)realloc(selection_varnames_list,nbytes); if (selection_varnames_list == NULL) errn("varnames_in_sel: mem alloc failure. Bytes wanted: ",nbytes); selection_varnames_list[index] = NULL; } return index; /* This return is to parse - nothing to do w/us - but */ /* might as well make it "real" in some sense */ } int varnames_in_sel (var_array_ptr,selection,user_err,user_errn,user_malloc_err) char ***var_array_ptr; char *selection; void (*user_err)(); void (*user_errn)(); void (*user_malloc_err)(); { struct parse_functions parse_functions; struct parse_data parse_data; /* Set up for parsing */ parse_data.tstcnt = 0; parse_data.tstproccnt = 0; parse_functions.varname_lookup = &add_varnames_from_selection; parse_functions.iovarlevel = &dummy_iovarlevel; parse_functions.err = (user_err == NULL) ? &err : user_err; parse_functions.errn = (user_errn == NULL) ? &errn : user_errn; parse_functions.malloc_err = (user_malloc_err == NULL) ? &malloc_err_stub : user_malloc_err; selection_varnames_list = *var_array_ptr; if (selection_varnames_list == NULL) { selection_varnames_list = (char **)malloc(sizeof (char **)); if (selection_varnames_list == NULL) err("varnames_in_sel: could not allocate 1 (char **) pointer",""); *selection_varnames_list = NULL; } n_selection_varnames = 0; /* Next line causes a list of vars used in selection to be */ /* placed in selection_varnames_list. See comments before */ /* add_varnames_from_selection (above). Apologies for the */ /* indirectness of this action */ jgofs_selection_parser (selection,&parse_data,&parse_functions); *var_array_ptr = selection_varnames_list; return n_selection_varnames; }