#define GNU_SOURCE #include #include #include #define HASH_KEY_LENGTH 5 #define BUFFER_LENGTH 50 #define HASH_TABLE_ENTRIES 26 /** * A entry in the hash table. */ typedef struct HASHITEM { /** Pointer to the next item in the hash list. */ struct HASHITEM *pNext; /** Pointer to the previous item in the hash list. */ struct HASHITEM *pPrev; /** Hash key. */ char aKey[HASH_KEY_LENGTH]; /** Pointer to the string data. */ char *pszData; } HASHITEM, *PHASHITEM; /** Hash table. */ PHASHITEM g_aHashTable[HASH_TABLE_ENTRIES]; int calcHashKey(const char *pszHash) { int iHash = 0; /* Dead simple. */ while (*pszHash != '\0') { iHash += *pszHash; pszHash++; } return iHash % HASH_TABLE_ENTRIES; } PHASHITEM getItemFromHash(const char *pszHash) { int iHash = calcHashKey(pszHash); PHASHITEM pCurr = g_aHashTable[iHash]; while ( pCurr && strcmp(pszHash, pCurr->aKey)) { pCurr = pCurr->pNext; } return pCurr; } void execGetHash(const char *pszHash) { PHASHITEM pItem = getItemFromHash(pszHash); if (pItem) { printf("Item with hash '%s':\n", pszHash); printf("%s", pItem->pszData); printf("\n"); } else printf("Could not get item with hash '%s'\n", pszHash); } void execRemoveHash(const char *pszHash) { PHASHITEM pItem = getItemFromHash(pszHash); if (pItem) { PHASHITEM pPrev = pItem->pPrev; PHASHITEM pNext = pItem->pNext; if (pPrev) { pPrev->pNext = pNext; } else { g_aHashTable[calcHashKey(pszHash)] = pNext; } if (pNext) { pNext->pPrev = pPrev; } free(pItem->pszData); free(pItem); } else { printf("Could not get item with hash '%s'\n", pszHash); } } void execInsertHash(const char *pszHash, char *pszData) { PHASHITEM pItem = getItemFromHash(pszHash); if (pItem) { printf("Item with hash '%s' exists already\n", pszHash); } else { unsigned i = 0; PHASHITEM pItem = (PHASHITEM)malloc(sizeof(HASHITEM)); PHASHITEM pFirst = g_aHashTable[calcHashKey(pszHash)]; pItem->pNext = pFirst; if (pFirst) pFirst->pPrev = pFirst; g_aHashTable[calcHashKey(pszHash)] = pItem; pItem->pszData = pszData; for (i = 0; i < strlen(pszHash) + 1; i++) pItem->aKey[i] = pszHash[i]; printf("%s %p %p\n", pItem->aKey, pItem->pPrev, pItem->pNext); } } int parseCmd(const char *pszCmdLine) { char aCmd[6 + 1]; char aKey[HASH_KEY_LENGTH + 10]; int iCmdPos = 0; int iKeyPos = 0; while ( *pszCmdLine != ' ' && *pszCmdLine != '\0' && iCmdPos < sizeof(aCmd) - 1) { aCmd[iCmdPos] = *pszCmdLine; iCmdPos++; pszCmdLine++; } aCmd[iCmdPos] = '\0'; if (!strcmp(aCmd, "quit")) { return -1; } else { /* Skip ' ' */ pszCmdLine++; /* All other commands require at least the hash. */ while ( *pszCmdLine != ' ' && *pszCmdLine != '\0' && iKeyPos < sizeof(aKey) - 1) { aKey[iKeyPos] = *pszCmdLine; iKeyPos++; pszCmdLine++; } aKey[iKeyPos] = '\0'; if (!strcmp(aCmd, "insert")) { char *pszData = NULL; char *pszCurr = NULL; size_t cbHashLen = 0; /* Skip ' ' */ pszCmdLine++; cbHashLen = strlen(pszCmdLine); pszData = (char *)calloc(cbHashLen+1, 1); pszCurr = pszData; while (*pszCmdLine != '\0') { *pszCurr = *pszCmdLine; pszCmdLine++; pszCurr++; } execInsertHash(aKey, pszData); } else if (!strcmp(aCmd, "get")) { execGetHash(aKey); } else if (!strcmp(aCmd, "remove")) { execRemoveHash(aKey); } else printf("Command %s is not known\n", aCmd); } return 0; } char *readLine(size_t *pcbRead) { char *pszDst = NULL; char *pCurr = NULL; size_t cbBuffer = BUFFER_LENGTH; /* Set initial buffer. This will grow if needed. */ pszDst = (char *)malloc(cbBuffer); pCurr = pszDst; *pcbRead = 0; for (;;) { *pCurr = fgetc(stdin); *pcbRead++; if (*pCurr == '\n') break; pCurr++; if (*pcbRead == cbBuffer) { /* Buffer is full. Expand */ cbBuffer += BUFFER_LENGTH; char *pszNew = realloc(pszDst, cbBuffer); if (!pszNew) { unsigned i; pszNew = malloc(cbBuffer); for (i = 0; i < *pcbRead; i++) pszNew[i] = pszDst[i]; free(pszDst); } pszDst = pszNew; pCurr = pszDst + *pcbRead; } } return pszDst; } int main(void) { unsigned fRunning = 1; memset(g_aHashTable, 0, sizeof(g_aHashTable)); while (fRunning) { char *pszCmdLine; ssize_t cbRead; size_t cbCmdLen; printf("#: "); pszCmdLine = readLine(&cbRead); /* Remove \n */ pszCmdLine[cbRead - 1] = '\0'; int rc = parseCmd(pszCmdLine); if (rc == -1) { fRunning = 0; } free(pszCmdLine); } return 0; }