]> git.ipfire.org Git - thirdparty/HylaFAX.git/commitdiff
mkhash: Berstien hash, collision free
authorAidan Van Dyk <aidan@ifax.com>
Mon, 15 Sep 2008 16:50:04 +0000 (16:50 +0000)
committerAidan Van Dyk <aidan@ifax.com>
Mon, 15 Sep 2008 16:50:04 +0000 (16:50 +0000)
Ah,  the simplicity of FaxRequest::readQFile() returns...

This hash implentation purposly skipps the '!' in the:
        [!]<type>:....
of the pdf/tiff/ps and !pdf/!tiff/!ps document handling.

faxd/FaxRequest.c++
faxd/mkhash.c

index 6baba2324b760bf6490438784bff487423d6b747..9a33542d2f437a6a95cbc977057a2c8b4eccaaef 100644 (file)
@@ -249,15 +249,19 @@ FaxRequest::readQFile(bool& rejectJob)
         * process only writes valid entries in the file.
         */
        const char* cmd = bp;
-       u_int hash = 0;
+       HASH_DECLARE(hash);
        for (; *bp != ':' && *bp != '\n'; bp++)
-           hash += hash ^ *bp;
+       {
+           HASH_ITERATE(hash, *bp);
+       }
        if (*bp != ':') {                       // invalid, skip line
            error("Syntax error, missing ':' on line %u", (u_int) lineno);
            while (*bp++ != '\n')
                ;
            continue;
        }
+       HASH_FINISH(hash);
+
        *bp++ = '\0';                           // null-terminate cmd
        /*
         * Collect the parameter value.
@@ -268,7 +272,8 @@ FaxRequest::readQFile(bool& rejectJob)
        while (*bp != '\n')
            bp++;
        *bp++ = '\0';                           // null-terminate tag
-       switch (HASH(hash)) {
+       // logError("%s[%u]: %s", cmd, hash, tag);
+       switch (hash) {
        case H_EXTERNAL:        external = tag; break;
        case H_NUMBER:          number = tag; break;
        case H_MAILADDR:        mailaddr = tag; break;
@@ -279,12 +284,8 @@ FaxRequest::readQFile(bool& rejectJob)
        case H_PAGEHANDLING:    pagehandling = tag; break;
        case H_MODEM:           modem = tag; break;
        case H_FAXNUMBER:       faxnumber = tag; break;
-       case H_TSI:                     // NB: tsi csi collide
-           if (cmd[0] == 't')
-               tsi = tag;
-           else
-               csi = tag;
-           break;
+       case H_TSI:             tsi = tag; break;
+       case H_CSI:             csi = tag; break;
        case H_RECEIVER:        receiver = tag; break;
        case H_COMPANY:         company = tag; break;
        case H_LOCATION:        location = tag; break;
@@ -299,33 +300,17 @@ FaxRequest::readQFile(bool& rejectJob)
        case H_SIGNALRATE:      sigrate = tag; break;
        case H_DATAFORMAT:      df = tag; break;
        case H_JOBTYPE:         jobtype = tag; break;
-       case H_TAGLINE:                 // NB: tottries collides
-           if (cmd[1] == 'a')
-               tagline = tag;
-           else
-               tottries = atoi(tag);
-           break;
+       case H_TAGLINE:         tagline = tag; break;
+       case H_TOTTRIES:        tottries = atoi(tag); break;
        case H_SUBADDR:         subaddr = tag; break;
        case H_PASSWD:          passwd = tag; break;
-       case H_STATE:                   // NB: comments collides
-           if (cmd[0] == 's')
-               state = tag[0] - '0';
-           else
-               comments = tag;
-           break;
-       case H_NPAGES:
-           if (cmd[0] == 'n')
-               npages = atoi(tag);
-           else
-               fromcompany = tag;
-           break;
+       case H_STATE:           state = tag[0] - '0'; break;
+       case H_COMMENTS:        comments = tag; break;
+       case H_NPAGES:          npages = atoi(tag); break;
+       case H_FROMCOMPANY:     fromcompany = tag; break;
        case H_TOTPAGES:        totpages = atoi(tag); break;
-       case H_NTRIES:                  // NB: maxtries collides
-           if (cmd[0] == 'n')
-               ntries = atoi(tag);
-           else
-               maxtries = atoi(tag);
-           break;
+       case H_NTRIES:          ntries = atoi(tag); break;
+       case H_MAXTRIES:        maxtries = atoi(tag); break;
        case H_NDIALS:          ndials = atoi(tag); break;
        case H_TOTDIALS:        totdials = atoi(tag); break;
        case H_MAXDIALS:        maxdials = atoi(tag); break;
@@ -341,11 +326,7 @@ FaxRequest::readQFile(bool& rejectJob)
        case H_DESIREDTL:       desiredtl = tag[0] - '0'; break;
        case H_USECCOVER:       useccover = tag[0] - '0'; break;
        case H_USEXVRES:        usexvres = tag[0] - '0'; break;
-       case H_TTS:
-           tts = atoi(tag);
-           if (tts == 0)       // distinguish ``now'' from unset
-               tts = Sys::now();
-           break;
+       case H_TTS:             tts = atoi(tag); break;
        case H_KILLTIME:        killtime = atoi(tag); break;
        case H_RETRYTIME:       retrytime = atoi(tag); break;
        case H_NOTIFY:          checkNotifyValue(tag); break;
@@ -354,6 +335,9 @@ FaxRequest::readQFile(bool& rejectJob)
        case H_NSF:             nsf = tag; break;
        case H_STATUSCODE:      statuscode = atoi(tag); break;
        case H_DONEOP:          doneop = tag; break;
+       case H_RETURNED:        status = (FaxSendStatus) atoi(tag); break;
+       case H_MINBR:           minbr = atoi(tag); break;
+
        case H_STATUS:
            /*
             * Check for multi-line status strings.
@@ -370,12 +354,8 @@ FaxRequest::readQFile(bool& rejectJob)
            statusstring = tag;
            break;
 
-       case H_RETURNED:        status = (FaxSendStatus) atoi(tag); break;
-       case H_POLL:            // H_MINBR collides
-           if (cmd[0] == 'm')
-               minbr = atoi(tag);
-           else
-               addItem(send_poll, tag); break;
+
+       case H_POLL:            addItem(send_poll, tag); break;
        case H_FAX:             addItem(send_fax, tag); break;
        case H_PDF:
            if (cmd[0] == '!')
@@ -390,17 +370,10 @@ FaxRequest::readQFile(bool& rejectJob)
                addItem(send_tiff, tag, rejectJob);
            break;
        case H_POSTSCRIPT:
-           // collides with H_PDF
            if (cmd[0] == '!')
-               if (cmd[2] == 'o')
-                   addItem(send_postscript_saved, tag);
-               else
-                   addItem(send_pdf_saved, tag);
+               addItem(send_postscript_saved, tag);
            else
-               if (cmd[1] == 'o')
-                   addItem(send_postscript, tag, rejectJob);
-               else
-                   addItem(send_pdf, tag, rejectJob);
+               addItem(send_postscript, tag, rejectJob);
            break;
        case H_PCL:
            if (cmd[0] == '!')
@@ -420,10 +393,14 @@ FaxRequest::readQFile(bool& rejectJob)
            else
                addItem(send_page, tag);
            break;
+       default:
+           error("Unknown field %s[%u]: %s", cmd, hash, tag);
        }
     } while (bp < ep);
     if (pri == (u_short) -1)
        pri = usrpri;
+    if (tts == 0)      // distinguish ``now'' from unset
+       tts = Sys::now();
     /*
      * Validate certain items that are assumed to have
      * ``suitable values'' by higher-level code (i.e.
index c4a6cb68a39250f2eeb9d3d0263135b6e4fadfc5..fd793e9c4cf4ba593bcc10198c86fa0815a46101 100644 (file)
 #include <stdio.h>
 #include <string.h>
 
-int    bits[16];
-int    bound;
-int    collisions;
+#define HASH_DECLARE(h)                unsigned int h = 0;
+#define HASH_ITERATE(h,c)      do { unsigned char cc = (c); if (cc != '!') h = 33*h + cc;} while (0)
+#define HASH_FINISH(h)         do {} while (0);
+
+#define PRINT_HASH()                                           \
+       printf("%s\n%s\n%s\n",                                  \
+       "#define HASH_DECLARE(h)        unsigned int h = 0 ",   \
+       "#define HASH_ITERATE(h,c)      do { unsigned char cc = (c); if (cc != '!') h = 33*h + cc;} while (0)", \
+       "#define HASH_FINISH(h)         do {} while (0);");
+
 
 void
 hash(const char* cp)
 {
     char name[80];
     char* xp = name;
-    unsigned int h = 0;
+
+    HASH_DECLARE(nh);
+
     while (*cp) {
-       if (*cp == '!')
+       char c = *cp++;
+       if (c == '!')
            *xp++ = '_';
        else
-           *xp++ = toupper(*cp);
-       h += h^*cp++;
+           *xp++ = toupper(c);
+       HASH_ITERATE(nh, c);
     }
     *xp = '\0';
-    h %= bound;
-    printf("#define    H_%s    %u", name, h);
-    if (bits[h/32] & (1<<(h%32))) {
-       collisions++;
-       printf("        /* collision */");
-    }
-    putchar('\n');
-    bits[h/32] |= 1<<(h%32);
+    HASH_FINISH(nh);
+
+    printf("#define    H_%s    %uU\n", name, nh);
 }
 
 int
 main()
 {
-    bound = 226;
-    memset(bits, 0, sizeof (bits));
-    collisions = 0;
     printf("/* THIS FILE WAS AUTOMATICALLY GENERATED, DO NOT EDIT */\n");
-    printf("#define    HASH(x) ((x) %% %u)\n", bound);
+    PRINT_HASH();
     hash("external");
     hash("number");
     hash("mailaddr");
@@ -148,6 +150,5 @@ main()
     hash("returned");
     hash("doneop");
     hash("commid");
-    printf("/* %u total collisions */\n", collisions);
     return (0);
 }