From 055d7f7f593d2d6b8284a8ef5a04333dc7b567eb Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Sat, 7 Mar 2026 17:45:48 +0300 Subject: [PATCH] fixed, tested --- stringHash4MCU_/hashgen.c | 120 ++++++++++++++++++++----------- stringHash4MCU_/hashtest.c | 117 ------------------------------ stringHash4MCU_/{run => runtest} | 4 ++ stringHash4MCU_/test.c | 16 ++--- stringHash4MCU_/testdic | 14 ++-- 5 files changed, 99 insertions(+), 172 deletions(-) delete mode 100644 stringHash4MCU_/hashtest.c rename stringHash4MCU_/{run => runtest} (82%) diff --git a/stringHash4MCU_/hashgen.c b/stringHash4MCU_/hashgen.c index 88350ec..f94fc30 100644 --- a/stringHash4MCU_/hashgen.c +++ b/stringHash4MCU_/hashgen.c @@ -20,6 +20,8 @@ #include #include +// maximal string length (n*4) without terminating '\0' - for buffers +#define MAXCMDLEN (128) #define ALLOCSZ (5000) typedef struct{ @@ -51,15 +53,25 @@ static void parse_args(int argc, char **argv){ } } -#define HASHFNO (3) +#define HASHFNO (4) +static uint32_t my(const char *str){ + char buf[MAXCMDLEN+1]; + uint32_t hash = 0, *c = (uint32_t*)buf; + bzero(buf, sizeof(buf)); + int len = strlen(str); + memcpy(buf, str, len); + len = (len + 3) / 4; + for(int i = 0; i < len; ++i) + hash = (hash << 7) | c[i]; + DBG("Hash for '%s' is %u", str, hash); + return hash; +} // djb2 & sdbm: http://www.cse.yorku.ca/~oz/hash.html static uint32_t djb2(const char *str){ uint32_t hash = 5381; uint32_t c; while((c = (uint32_t)*str++)) hash = ((hash << 7) + hash) + c; - //hash = hash * 31 + c; - //hash = hash * 33 + c; return hash; } static uint32_t sdbm(const char *str){ @@ -84,6 +96,17 @@ static uint32_t jenkins(const char *str){ } static const char *hashsources[HASHFNO] = { +"static uint32_t hashf(const char *str){\n\ + char buf[CMD_MAXLEN+1];\n\ + uint32_t hash = 0, *c = (uint32_t*)buf;\n\ + bzero(buf, sizeof(buf));\n\ + int len = strlen(str);\n\ + memcpy(buf, str, len);\n\ + len = (len + 3) / 4;\n\ + for(int i = 0; i < len; ++i)\n\ + hash = (hash << 7) | c[i];\n\ + return hash;\n\ +}\n", "static uint32_t hashf(const char *str){\n\ uint32_t hash = 5381;\n\ uint32_t c;\n\ @@ -112,13 +135,14 @@ static const char *hashsources[HASHFNO] = { }\n" }; -static uint32_t (*hash[HASHFNO])(const char *str) = {djb2, sdbm, jenkins}; -static const char *hashnames[HASHFNO] = {"DJB2", "SDBM", "Jenkins"}; +static uint32_t (*hash[HASHFNO])(const char *str) = {my, djb2, sdbm, jenkins}; +static const char *hashnames[HASHFNO] = {"My", "DJB2", "SDBM", "Jenkins"}; typedef struct{ - char str[32]; // string command - char fname[32]; // function namee - uint32_t hash; // command hash + char str[MAXCMDLEN+1]; // string command define (capital letters) + char fname[MAXCMDLEN+1]; // function name + char macroname[MAXCMDLEN+1];// macro name + uint32_t hash; // command hash } strhash; static int sorthashesH(const void *a, const void *b){ // sort by hash @@ -143,11 +167,11 @@ static FILE *openoutp(const char *name){ } static char *macroname(const char *cmd){ - static char macro[32]; + static char macro[MAXCMDLEN+1]; int i = 0; - while(i < 31 && *cmd){ + while(i < MAXCMDLEN && *cmd){ char c = *cmd++; - if(!isalnum(c)) c = '_'; + if(!isalpha(c)) c = '_'; if(islower(c)) c = toupper(c); macro[i++] = c; } @@ -156,9 +180,9 @@ static char *macroname(const char *cmd){ } static char *fnname(const char *cmd){ - static char fn[32]; + static char fn[MAXCMDLEN+1]; int i = 0; - while(i < 31 && *cmd){ + while(i < MAXCMDLEN && *cmd){ char c = *cmd++; if(!isalpha(c)) c = '_'; if(isupper(c)) c = tolower(c); @@ -170,14 +194,14 @@ static char *fnname(const char *cmd){ static const char *fhdr = "int parsecmd(const char *str){\n\ - if(!str || !*str) return RET_CMDNOTFOUND;\n\ - int i = 0;\n\ - while(*str > '@' && i < CMD_MAXLEN){ lastcmd[i++] = *str++; }\n\ - lastcmd[i] = 0;\n\ - while(*str && *str <= ' ') ++str;\n\ - char *args = (char*) str;\n\ - uint32_t h = hashf(lastcmd);\n\ - switch(h){\n\n" + if(!str || !*str) return RET_CMDNOTFOUND;\n\ + bzero(lastcmd, sizeof(lastcmd));\n\ + int i = 0;\n\ + while(*str > '@' && i < CMD_MAXLEN){ lastcmd[i++] = *str++; }\n\ + while(*str && *str <= ' ') ++str;\n\ + char *args = (char*) str;\n\ + uint32_t h = hashf(lastcmd);\n\ + switch(h){\n" ; static const char *ffooter = " default: break;\n\ @@ -186,7 +210,10 @@ static const char *ffooter = }\n\n" ; static const char *fns = -"int fn_%s(uint32_t _U_ hash, char _U_ *args) WAL; // \"%s\" (%u)\n\n" + "int fn_%s(uint32_t _U_ hash, char _U_ *args) WAL; // \"%s\" (%u)\n" +; +static const char *fnsh = + "int fn_%s(uint32_t, char*); // \"%s\" (%u)\n" ; static const char *headercontent = "// Generated by HASHGEN (https://github.com/eddyem/eddys_snippets/tree/master/stringHash4MCU_)\n\ @@ -195,7 +222,7 @@ static const char *headercontent = #ifndef _U_\n\ #define _U_ __attribute__((__unused__))\n\ #endif\n\n\ -#define CMD_MAXLEN (32)\n\n\ +#define CMD_MAXLEN (%d)\n\n\ enum{\n\ RET_HELP = -3,\n\ RET_CMDNOTFOUND = -2,\n\ @@ -215,10 +242,11 @@ static const char *srchdr = // Licensed by GPLv3\n\ #include \n\ #include \n\ +#include \n\ #include \"%s\"\n\n\ #ifndef WAL\n\ #define WAL __attribute__ ((weak, alias (\"__f1\")))\n\ -#endif\n\nstatic int __f1(uint32_t _U_ h, char _U_ *a){return 1;}\n\n\ +#endif\n\nstatic int __f1(uint32_t _U_ h, char _U_ *a){return RET_BAD;}\n\n\ char lastcmd[CMD_MAXLEN + 1];\n\n" ; @@ -226,13 +254,14 @@ static void build(strhash *H, int hno, int hlen){ green("Generate files for hash function '%s'\n", hashnames[hno]); int lmax = 1; for(int i = 0; i < hlen; ++i){ + strcpy(H[i].macroname, macroname(H[i].str)); int l = strlen(H[i].str); if(l > lmax){ lmax = l; } } lmax = (lmax + 3)/4; - lmax *= 4; + lmax *= 4; // round by 4 bytes // resort H by strings qsort(H, hlen, sizeof(strhash), sorthashesS); FILE *source = openoutp(G.sourcefile), *header = openoutp(G.headerfile); @@ -242,22 +271,26 @@ static void build(strhash *H, int hno, int hlen){ fprintf(source, fns, H[i].fname, H[i].str, H[i].hash); } } - fprintf(header, "%s", headercontent); - fprintf(source, "%s\n", hashsources[hno]); + fprintf(header, headercontent, lmax); + fprintf(source, "\n%s\n", hashsources[hno]); fprintf(source, "%s", fhdr); for(int i = 0; i < hlen; ++i){ - char *m = macroname(H[i].str); - fprintf(source, sw, m, H[i].fname); - fprintf(header, "#define CMD_%-*s (%u)\n", lmax, m, H[i].hash); + fprintf(source, sw, H[i].macroname, H[i].fname); + fprintf(header, "#define CMD_%-*s (%u)\n", lmax, H[i].macroname, H[i].hash); } fprintf(source, "%s", ffooter); fclose(source); - fprintf(header, "\n\n"); + fprintf(header, "\n"); for(int i = 0; i < hlen; ++i){ - char *m = macroname(H[i].str); - fprintf(header, "#define STR_%-*s \"%s\"\n", lmax, m, H[i].str); + fprintf(header, "#define STR_%-*s \"%s\"\n", lmax, H[i].macroname, H[i].str); } - + if(G.genfunc){ + fprintf(header, "\n"); + for(int i = 0; i < hlen; ++i){ + fprintf(header, fnsh, H[i].fname, H[i].str, H[i].hash); + } + } + fclose(header); } @@ -280,19 +313,26 @@ int main(int argc, char **argv){ } while(*word && *word < 33) ++word; if(!*word) break; - char *nxt = strchr(word, '\n'); + char *eol = strchr(word, '\n'); + char *sp = strchr(word, ' '); + char *nxt = eol; + if(sp){ // got space after command - truncate + if(eol){ + if(eol > sp) nxt = sp; // space before strend + }else nxt = sp; // no strend, but have space + }; if(nxt){ int len = nxt - word; - if(len > 31) len = 31; + if(len > MAXCMDLEN) len = MAXCMDLEN; strncpy(H[idx].str, word, len); H[idx].str[len] = 0; }else{ - snprintf(H[idx].str, 31, "%s", word); + snprintf(H[idx].str, MAXCMDLEN, "%s", word); } - snprintf(H[idx].fname, 31, "%s", fnname(H[idx].str)); + snprintf(H[idx].fname, MAXCMDLEN, "%s", fnname(H[idx].str)); ++idx; - if(!nxt) break; - word = nxt + 1; + if(!eol) break; + word = eol + 1; } // test fname matches qsort(H, idx, sizeof(strhash), sorthashesF); diff --git a/stringHash4MCU_/hashtest.c b/stringHash4MCU_/hashtest.c deleted file mode 100644 index be70fd0..0000000 --- a/stringHash4MCU_/hashtest.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2022 Edward V. Emelianov . - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#define ALLOCSZ (5000) -#define DJB2 - -#if defined DJB2 -// djb2 http://www.cse.yorku.ca/~oz/hash.html -static uint32_t hash(const char *str){ - uint32_t hash = 5381; - uint32_t c; - while((c = (uint32_t)*str++)) - hash = ((hash << 5) + hash) + c; - //hash = hash * 31 + c; - //hash = hash * 33 + c; - return hash; -} -#elif defined SDBM -static uint32_t hash(const char *str){ // sdbm - uint32_t hash = 5381; - uint32_t c; - while((c = (uint32_t)*str++)) - hash = c + (hash << 6) + (hash << 16) - hash; - return hash; -} -#elif defined JENKINS -uint32_t hash(const char *str){ - uint32_t hash = 0, c; - while((c = (uint32_t)*str++)){ - hash += c; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; -} -#endif - - -typedef struct{ - char str[32]; - uint32_t hash; -} strhash; - -static int sorthashes(const void *a, const void *b){ - register uint32_t h1 = ((strhash*)a)->hash, h2 = ((strhash*)b)->hash; - if(h2 > h1) return h2 - h1; - else return -((h1 - h2)); -} - -int main(int argc, char **argv){ - //char buf[32]; - initial_setup(); - if(argc != 2) ERRX("Usage: %s dictionary_file", argv[0]); - mmapbuf *b = My_mmap(argv[1]); - if(!b) ERRX("Can't open %s", argv[1]); - char *word = b->data; - strhash *H = MALLOC(strhash, ALLOCSZ); - int l = ALLOCSZ, idx = 0; - while(*word){ - if(idx >= l){ - l += ALLOCSZ; - H = realloc(H, sizeof(strhash) * l); - if(!H) ERR("realloc()"); - } - char *nxt = strchr(word, '\n'); - if(nxt){ - int len = nxt - word; - if(len > 31) len = 31; - strncpy(H[idx].str, word, len); - H[idx].str[len] = 0; - //strncpy(buf, word, len); - //buf[len] = 0; - }else{ - //snprintf(buf, 31, "%s", word); - snprintf(H[idx].str, 31, "%s", word); - } - H[idx].hash = hash(H[idx].str); - //printf("word: %s\n", buf); - //printf("%u\t%s\n", hash(buf), buf); - //printf("%u\t%s\n", H[idx].hash, H[idx].str); - ++idx; - if(!nxt) break; - word = nxt + 1; - } - qsort(H, idx, sizeof(strhash), sorthashes); - --idx; - strhash *p = H; - for(int i = 0; i < idx; ++i, ++p){ - if(p->hash == p[1].hash){ - printf("Words '%s' and '%s' have same hashes: %u\n", p->str, p[1].str, p->hash); - } - } - FREE(H); - My_munmap(b); - return 0; -} diff --git a/stringHash4MCU_/run b/stringHash4MCU_/runtest similarity index 82% rename from stringHash4MCU_/run rename to stringHash4MCU_/runtest index e79297c..1f35e66 100755 --- a/stringHash4MCU_/run +++ b/stringHash4MCU_/runtest @@ -3,8 +3,12 @@ gcc hashgen.c -o hashgen -lusefull_macros ./hashgen -d testdic -H hdr.h -S hdr.c -F gcc hdr.c test.c strfunc.c -o test +./test "wrongarg" +./test "Wrong Arg" ./test "time 54 = some" ./test "voltage12 more" ./test "esw45 = some text" ./test "goto 55 = " ./test "stop 3256" +./test "mcut" + diff --git a/stringHash4MCU_/test.c b/stringHash4MCU_/test.c index 3dc0dda..7ea924c 100644 --- a/stringHash4MCU_/test.c +++ b/stringHash4MCU_/test.c @@ -7,12 +7,12 @@ static int noargs(uint32_t hash){ switch(hash){ - case CMD_REBOOT: printf("REBOOT\n"); break; + case CMD_RESET: printf("REBOOT\n"); break; case CMD_TIME: printf("TIME!\n"); break; - case CMD_TEMP: printf("Temp\n"); break; - default: printf("Unknown hash 0x%x\n", hash); return 0; + case CMD_MCUT: printf("Temp\n"); break; + default: printf("Unknown hash 0x%x\n", hash); return RET_BAD; } - return 1; + return RET_GOOD; } static int withparno(uint32_t hash, char *args){ uint32_t N; @@ -30,7 +30,7 @@ static int withparno(uint32_t hash, char *args){ switch(hash){ case CMD_ESW: fname = "ESW"; break; case CMD_GOTO: fname = "GOTO"; break; - case CMD_POS: fname = "POS"; break; + case CMD_ABSPOS: fname = "ABSPOS"; break; case CMD_STOP: fname = "STOP"; break; default: fname = "unknown"; } @@ -42,12 +42,12 @@ static int withparno(uint32_t hash, char *args){ // these functions should be global to substitute weak aliases int fn_esw(uint32_t hash, char *args){return withparno(hash, args);} int fn_goto(uint32_t hash, char *args){return withparno(hash, args);} -int fn_pos(uint32_t hash, char *args){return withparno(hash, args);} +int fn_abspos(uint32_t hash, char *args){return withparno(hash, args);} int fn_stop(uint32_t hash, char *args){return withparno(hash, args);} int fn_voltage(uint32_t hash, char *args){return withparno(hash, args);} -int fn_reboot(uint32_t hash, _U_ char *args){return noargs(hash);} +int fn_reset(uint32_t hash, _U_ char *args){return noargs(hash);} int fn_time(uint32_t hash, _U_ char *args){return noargs(hash);} -int fn_temp(uint32_t hash, _U_ char *args){return noargs(hash);} +int fn_mcut(uint32_t hash, _U_ char *args){return noargs(hash);} int main(int argc, char **argv){ if(argc != 2) return 1; diff --git a/stringHash4MCU_/testdic b/stringHash4MCU_/testdic index bb2b5b1..bcc64d4 100644 --- a/stringHash4MCU_/testdic +++ b/stringHash4MCU_/testdic @@ -1,8 +1,8 @@ -pos -temp -voltage -time -reboot -stop -goto +abspos esw +goto +stop +voltage +reset +time +mcut