diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 82b9a921e..2dbd9c261 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -39,6 +39,10 @@ of the counts from all registered server layers. A preprocessor macro `HAS_DBSERVER_STATS` macro is defined in the `dbServer.h` header file to simplify code that needs to support older versions of Base as well. +### Other + +- `dbgrep` now takes an optional second argument of field names e.g. `dbgrep("*PRESSURE*","VAL DESC")` + ----- ## EPICS Release 7.0.9 diff --git a/modules/database/src/ioc/db/dbIocRegister.c b/modules/database/src/ioc/db/dbIocRegister.c index 9b5085ea0..ac37dc731 100644 --- a/modules/database/src/ioc/db/dbIocRegister.c +++ b/modules/database/src/ioc/db/dbIocRegister.c @@ -235,14 +235,16 @@ static void dblaCallFunc(const iocshArgBuf *args) { iocshSetError(dbla(args[0].s /* dbgrep */ static const iocshArg dbgrepArg0 = { "pattern",iocshArgStringRecord}; -static const iocshArg * const dbgrepArgs[1] = {&dbgrepArg0}; -static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs, - "List record names matching pattern.\n" +static const iocshArg dbgrepArg1 = { "fields",iocshArgString}; +static const iocshArg * const dbgrepArgs[2] = {&dbgrepArg0,&dbgrepArg1}; +static const iocshFuncDef dbgrepFuncDef = {"dbgrep",2,dbgrepArgs, + "List record names matching pattern and optionally print field values. \n" "The pattern can contain any characters that are legal in record names as well as:\n" " - \"?\", which matches 0 or one characters.\n" " - \"*\", which matches 0 or more characters.\n\n" - "Example: dbgrep(\"*gpibAi*\")\n"}; -static void dbgrepCallFunc(const iocshArgBuf *args) { iocshSetError(dbgrep(args[0].sval));} + "Example: dbgrep(\"*gpibAi*\")\n" + " dbgrep(\"*gpibAi*\",\"VAL DESC\")\n"}; +static void dbgrepCallFunc(const iocshArgBuf *args) { iocshSetError(dbgrep(args[0].sval,args[1].sval));} /* dbgf */ static const iocshArg dbgfArg0 = { "record name",iocshArgStringRecord}; diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index 583eb9af3..9d99e7d01 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -100,13 +100,59 @@ long dba(const char*pname) return 0; } +/* split a space separated list of field names and return the number of + fields with each field an element of papfields. These elements + point to within the fieldnames variable which is modified + by the function. memory is allocated for *ppapfields and needs + to be freed later by the calling routine */ +static int splitFieldsList(char *fieldnames, char ***ppapfields) +{ + char *pnext = fieldnames; + int nfields = 0, maxfields = 1; + char* saveptr = NULL; + /* this may overcount real fields e.g. " VAL " hence maxfields */ + while (*pnext && (pnext = strchr(pnext, ' '))) { + maxfields++; + while (*pnext == ' ') pnext++; + } + *ppapfields = dbCalloc(maxfields, sizeof(char *)); + pnext = epicsStrtok_r(fieldnames, " ", &saveptr); + while(pnext != NULL) { + (*ppapfields)[nfields++] = pnext; + pnext = epicsStrtok_r(NULL, " ", &saveptr); + } + return nfields; +} + +static void printFieldsList(DBENTRY *pdbentry, char** papfields, int nfields) +{ + int ifield; + for (ifield = 0; ifield < nfields; ifield++) { + char *pvalue; + long status = dbFindField(pdbentry, papfields[ifield]); + if (status) { + if (!strcmp(papfields[ifield], "recordType")) { + pvalue = dbGetRecordTypeName(pdbentry); + } + else { + printf(", "); + continue; + } + } + else { + pvalue = dbGetString(pdbentry); + } + printf(", \"%s\"", (pvalue ? pvalue : "")); + } + printf("\n"); +} + long dbl(const char *precordTypename, const char *fields) { DBENTRY dbentry; DBENTRY *pdbentry=&dbentry; long status; int nfields = 0; - int ifield; char *fieldnames = 0; char **papfields = 0; @@ -121,25 +167,8 @@ long dbl(const char *precordTypename, const char *fields) if (fields && (*fields == '\0')) fields = NULL; if (fields) { - char *pnext; - fieldnames = epicsStrDup(fields); - nfields = 1; - pnext = fieldnames; - while (*pnext && (pnext = strchr(pnext,' '))) { - nfields++; - while (*pnext == ' ') pnext++; - } - papfields = dbCalloc(nfields,sizeof(char *)); - pnext = fieldnames; - for (ifield = 0; ifield < nfields; ifield++) { - papfields[ifield] = pnext; - if (ifield < nfields - 1) { - pnext = strchr(pnext, ' '); - *pnext++ = 0; - while (*pnext == ' ') pnext++; - } - } + nfields = splitFieldsList(fieldnames, &papfields); } dbInitEntry(pdbbase, pdbentry); if (!precordTypename) @@ -154,24 +183,7 @@ long dbl(const char *precordTypename, const char *fields) status = dbFirstRecord(pdbentry); while (!status) { printf("%s", dbGetRecordName(pdbentry)); - for (ifield = 0; ifield < nfields; ifield++) { - char *pvalue; - status = dbFindField(pdbentry, papfields[ifield]); - if (status) { - if (!strcmp(papfields[ifield], "recordType")) { - pvalue = dbGetRecordTypeName(pdbentry); - } - else { - printf(", "); - continue; - } - } - else { - pvalue = dbGetString(pdbentry); - } - printf(", \"%s\"", pvalue ? pvalue : ""); - } - printf("\n"); + printFieldsList(pdbentry, papfields, nfields); status = dbNextRecord(pdbentry); } if (precordTypename) @@ -283,14 +295,17 @@ long dbli(const char *pattern) return 0; } -long dbgrep(const char *pmask) +long dbgrep(const char *pmask,const char *fields) { DBENTRY dbentry; DBENTRY *pdbentry = &dbentry; long status; + int nfields = 0; + char *fieldnames = 0; + char **papfields = 0; if (!pmask || !*pmask) { - printf("Usage: dbgrep \"pattern\"\n"); + printf("Usage: dbgrep \"pattern\" \"fields\"\n"); return 1; } @@ -298,20 +313,30 @@ long dbgrep(const char *pmask) printf("No database loaded\n"); return 0; } - + if (fields && (*fields == '\0')) + fields = NULL; + if (fields) { + fieldnames = epicsStrDup(fields); + nfields = splitFieldsList(fieldnames, &papfields); + } dbInitEntry(pdbbase, pdbentry); status = dbFirstRecordType(pdbentry); while (!status) { status = dbFirstRecord(pdbentry); while (!status) { char *pname = dbGetRecordName(pdbentry); - if (epicsStrGlobMatch(pname, pmask)) - puts(pname); + if (epicsStrGlobMatch(pname, pmask)) { + printf("%s", pname); + printFieldsList(pdbentry, papfields, nfields); + } status = dbNextRecord(pdbentry); } status = dbNextRecordType(pdbentry); } - + if (nfields > 0) { + free((void *)papfields); + free((void *)fieldnames); + } dbFinishEntry(pdbentry); return 0; } diff --git a/modules/database/src/ioc/db/dbTest.h b/modules/database/src/ioc/db/dbTest.h index f774b1751..dd6b1dd49 100644 --- a/modules/database/src/ioc/db/dbTest.h +++ b/modules/database/src/ioc/db/dbTest.h @@ -29,7 +29,7 @@ DBCORE_API long dbla(const char *pmask); /* list infos */ DBCORE_API long dbli(const char *patern); /*list records with mask*/ -DBCORE_API long dbgrep(const char *pmask); +DBCORE_API long dbgrep(const char *pmask,const char *fields); /*get field value*/ DBCORE_API long dbgf(const char *pname); /*put field value*/