From 04fca92bf02d6d085f7f3679e791a4eb79f6b5fd Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 19 Apr 2021 10:08:58 -0400 Subject: [PATCH] Finally got around to modifying the "cellname [list] top" command so that it returns cellnames in "natural sort" alphabetical order instead of the random order produced by scanning the hash table of cell names. Since this command is used by the "cell manager" window code, which was also not doing any sorting, then this fixes the same issue in the "cell manager". --- VERSION | 2 +- database/DBcellname.c | 134 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 111 insertions(+), 25 deletions(-) diff --git a/VERSION b/VERSION index cb339f4e..f9ae0443 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.153 +8.3.154 diff --git a/database/DBcellname.c b/database/DBcellname.c index dbfc32f0..b19ad2fc 100644 --- a/database/DBcellname.c +++ b/database/DBcellname.c @@ -21,7 +21,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #endif /* not lint */ #include +#include /* for qsort() */ #include +#include #include "tcltk/tclmagic.h" #include "utils/magic.h" @@ -598,6 +600,67 @@ DBTopPrint(mw, dolist) } } +/* + * ---------------------------------------------------------------------------- + * Simple natural sort routine + * https://stackoverflow.com/questions/34518/natural-sorting-algorithm + * By Norman Ramsey, edited for style. + * ---------------------------------------------------------------------------- + */ + +int strcmpbynum(const char *s1, const char *s2) +{ + /* Like strcmp() but compare sequences of digits numerically */ + for (;;) + { + if (*s2 == '\0') + return *s1 != '\0'; + else if (*s1 == '\0') + return 1; + else if (!(isdigit(*s1) && isdigit(*s2))) + { + if (*s1 != *s2) + return (int)*s1 - (int)*s2; + else + { + ++s1; + ++s2; + } + } + else + { + char *lim1, *lim2; + unsigned long n1 = strtoul(s1, &lim1, 10); + unsigned long n2 = strtoul(s2, &lim2, 10); + if (n1 > n2) + return 1; + else if (n1 < n2) + return -1; + s1 = lim1; + s2 = lim2; + } + } +} + +/* + * ---------------------------------------------------------------------------- + * Sort routine for qsort() to be used by DBCellPrint(). Sorts in alphabetical + * order using the natural sort routine above. List is reverse sorted since + * the code below prints from the end to the beginning of the list. + * ---------------------------------------------------------------------------- + */ + +int +qcompare(const void *one, const void *two) +{ + int cval; + + char *s1 = *((char **)one); + char *s2 = *((char **)two); + cval = strcmpbynum(s1, s2); + return -cval; +} + /* * ---------------------------------------------------------------------------- * @@ -625,11 +688,12 @@ DBCellPrint(CellName, who, dolist) int who; bool dolist; { - int found; + int found, numcells; HashSearch hs; HashEntry *entry; CellDef *celldef; CellUse *celluse; + char **celllist; if (!dolist) { @@ -657,6 +721,11 @@ DBCellPrint(CellName, who, dolist) * CDMODIFIED flag set. */ + numcells = dbCellDefTable.ht_nEntries; + if (numcells == 0) numcells = 1; + celllist = (char **)mallocMagic(numcells * sizeof(char *)); + numcells = 0; + HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { @@ -666,28 +735,39 @@ DBCellPrint(CellName, who, dolist) if (((celldef->cd_flags & CDINTERNAL) != CDINTERNAL) && ((who != MODIFIED) || (celldef->cd_flags & CDMODIFIED))) - { if (celldef->cd_name != NULL) - { - if (dolist) -#ifdef MAGIC_WRAPPER - Tcl_AppendElement(magicinterp, celldef->cd_name); -#else - TxPrintf("%s ", celldef->cd_name); -#endif - else - TxPrintf(" %s\n", celldef->cd_name); - } - } + celllist[numcells++] = celldef->cd_name; + } } + + qsort(celllist, numcells, sizeof(char *), qcompare); + + while (--numcells >= 0) + { + if (dolist) +#ifdef MAGIC_WRAPPER + Tcl_AppendElement(magicinterp, celllist[numcells]); +#else + TxPrintf("%s ", celllist[numcells]); +#endif + else + TxPrintf(" %s\n", celllist[numcells]); + } + + freeMagic(celllist); break; case TOPCELLS: /* - * Print the name of all the 'top' cells. + * Print the name of all the 'top' cells. Sort alphabetically. */ + numcells = dbCellDefTable.ht_nEntries; + if (numcells == 0) numcells = 1; + celllist = (char **)mallocMagic(numcells * sizeof(char *)); + numcells = 0; + HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { @@ -712,19 +792,25 @@ DBCellPrint(CellName, who, dolist) } } if ( (found == 0) && (celldef->cd_name != NULL) ) - { - if (dolist) -#ifdef MAGIC_WRAPPER - Tcl_AppendElement(magicinterp, celldef->cd_name); -#else - TxPrintf("%s ", celldef->cd_name); -#endif - else - TxPrintf(" %s\n", celldef->cd_name); - } + celllist[numcells++] = celldef->cd_name; } } } + + qsort(celllist, numcells, sizeof(char *), qcompare); + + while (--numcells >= 0) + { + if (dolist) +#ifdef MAGIC_WRAPPER + Tcl_AppendElement(magicinterp, celllist[numcells]); +#else + TxPrintf("%s ", celllist[numcells]); +#endif + else + TxPrintf(" %s\n", celllist[numcells]); + } + freeMagic(celllist); break; default: