From a781896e283dd8e6d3de35747ded2641eec53833 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 25 Jul 2025 11:39:44 +0200 Subject: [PATCH] map for fields and more --- .../database/src/ioc/dbStatic/dbLexRoutines.c | 115 ++++++++++++++++-- 1 file changed, 104 insertions(+), 11 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 117f214ab..b96aa17fd 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1190,6 +1190,17 @@ static void dbRecordHead(char *recordType, char *name, int visible) dbVisibleRecord(pdbentry); } +static const char* dbFieldConfusionMap [] = { + "INP","OUT", + "DOL","INP", + "ZNAM","ZRST", + "ONAM","ONST", + "INPA-J","DOL0-9", + "INPK-P","DOLA-F", + "INP0-9","INPA-J", + NULL +}; + static void dbRecordField(char *name,char *value) { DBENTRY *pdbentry; @@ -1208,24 +1219,106 @@ static void dbRecordField(char *name,char *value) DBENTRY temp; double bestSim = -1.0; const dbFldDes *bestFld = NULL; + int i; + const char* fld; dbCopyEntryContents(pdbentry, &temp); - const char* guess = - strcmp(name, "OUT") == 0 ? "INP" : - strcmp(name, "INP") == 0 ? "OUT" : - NULL; - for(status = dbFirstField(&temp, 0); !status; status = dbNextField(&temp, 0)) { - if (guess && strcmp(temp.pflddes->name, guess) == 0) { + for(i = 0; (fld = dbFieldConfusionMap[i]) != NULL; i++) { + char buf[10]; + const char* guess = NULL; + size_t l = strlen(fld); + if (l >= 3 && fld[l-2] == '-' && + strncmp(name, fld, l-3) == 0 && + name[l-3] >= fld[l-3] && + name[l-3] <= fld[l-1]) + { + /* range map */ + size_t l2 = strlen(dbFieldConfusionMap[i^1]); + memset(buf, 0, sizeof(buf)); + strncpy(buf, dbFieldConfusionMap[i^1], sizeof(buf)-1); + buf[l2-3] += name[l-3] - fld[l-3]; + buf[l2-2] = 0; + guess = buf; + } else if (strcmp(name, fld) == 0) { + /* simple map */ + guess = dbFieldConfusionMap[i^1]; + } + if (guess && dbFindFieldPart(&temp, &guess) == 0) { + /* guessed field exists */ bestFld = temp.pflddes; break; } - double sim = epicsStrSimilarity(name, temp.pflddes->name); - if(!bestFld || sim > bestSim) { - bestSim = sim; - bestFld = temp.pflddes; + } + if (!bestFld) { + /* no map found, use weighted lexical similarity */ + char quote = 0; + if (*value == '"' || *value == '\'') { + quote = *value++; + } + for (status = dbFirstField(&temp, 0); !status; status = dbNextField(&temp, 0)) { + if (temp.pflddes->special == SPC_NOMOD || + temp.pflddes->special == SPC_DBADDR) /* cannot be configured */ + continue; + double sim = epicsStrSimilarity(name, temp.pflddes->name); + if (!temp.pflddes->promptgroup) + sim *= 0.5; /* no prompt: unlikely */ + if (temp.pflddes->interest) + sim *= 1.0 - 0.1 * temp.pflddes->interest; /* 10% less likely per interest level */ + + long status = 0; + char* end = "e; + if (*value != quote) { + /* value given, check match to field type */ + switch (temp.pflddes->field_type) { + epicsAny dummy; + case DBF_CHAR: + status = epicsParseInt8(value, &dummy.int8, 0, &end); + break; + case DBF_UCHAR: + status = epicsParseUInt8(value, &dummy.uInt8, 0, &end); + break; + case DBF_SHORT: + status = epicsParseInt16(value, &dummy.int16, 0, &end); + break; + case DBF_USHORT: + status = epicsParseUInt16(value, &dummy.uInt16, 0, &end); + break; + case DBF_LONG: + status = epicsParseInt32(value, &dummy.int32, 0, &end); + break; + case DBF_ULONG: + status = epicsParseUInt32(value, &dummy.uInt32, 0, &end); + break; + case DBF_INT64: + status = epicsParseInt64(value, &dummy.int64, 0, &end); + break; + case DBF_UINT64: + status = epicsParseUInt64(value, &dummy.uInt64, 0, &end); + break; + case DBF_FLOAT: + status = epicsParseFloat(value, &dummy.float32, &end); + break; + case DBF_DOUBLE: + status = epicsParseDouble(value, &dummy.float64, &end); + break; + case DBF_ENUM: + case DBF_MENU: + case DBF_DEVICE: + /* TODO */ + default: + break; + } + if (status || *end != quote) { + sim *= 0.1; /* value type does not match field type: unlikely */ + } + } + if (sim > bestSim) { + bestSim = sim; + bestFld = temp.pflddes; + } } } dbFinishEntry(&temp); - if(bestSim>0.0) { + if (bestFld) { fprintf(stderr, " Did you mean \"%s\"?", bestFld->name); if(bestFld->prompt) fprintf(stderr, " (%s)", bestFld->prompt);