/* $Id: nt_fullpath_cached.c 2849 2016-08-30 14:28:46Z bird $ */ /** @file * fixcase - fixes the case of paths, windows specific. */ /* * Copyright (c) 2004-2010 knut st. osmundsen * * This file is part of kBuild. * * kBuild 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. * * kBuild 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 kBuild. If not, see * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include #include #include "nt_fullpath.h" /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef struct NTFULLPATHENTRY { /** Pointer to the next entry with the same hash table index. */ struct NTFULLPATHENTRY *pNext; /** The input hash. */ unsigned uHash; /** The input length. */ unsigned cchInput; /** Length of the result. */ unsigned cchResult; /** The result string (stored immediately after this structure). */ const char *pszResult; /** The input string (variable length). */ char szInput[1]; } NTFULLPATHENTRY; typedef NTFULLPATHENTRY *PNTFULLPATHENTRY; /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** Number of result in the nt_fullpath cache. */ size_t g_cNtFullPathHashEntries = 0; /** Number of bytes used for nt_fullpath cache result entries. */ size_t g_cbNtFullPathHashEntries = 0; /** Number of hash table collsioins in the nt_fullpath cache. */ size_t g_cNtFullPathHashCollisions = 0; /** Hash table. */ PNTFULLPATHENTRY g_apNtFullPathHashTab[16381]; /** * A nt_fullpath frontend which caches the result of previous calls. */ void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cchFull) { PNTFULLPATHENTRY pEntry; unsigned cchInput; unsigned idx; unsigned cchResult; /* We use the sdbm hash algorithm here (see kDep.c for full details). */ unsigned const char *puch = (unsigned const char *)pszPath; unsigned uHash = 0; unsigned uChar; while ((uChar = *puch++) != 0) uHash = uChar + (uHash << 6) + (uHash << 16) - uHash; cchInput = (unsigned)((uintptr_t)&puch[-1] - (uintptr_t)pszPath); /* Do the cache lookup. */ idx = uHash % (sizeof(g_apNtFullPathHashTab) / sizeof(g_apNtFullPathHashTab[0])); for (pEntry = g_apNtFullPathHashTab[idx]; pEntry != NULL; pEntry = pEntry->pNext) if ( pEntry->uHash == uHash && pEntry->cchInput == cchInput && memcmp(pEntry->szInput, pszPath, cchInput) == 0) { if (cchFull > pEntry->cchResult) memcpy(pszFull, pEntry->pszResult, pEntry->cchResult + 1); else { assert(0); memcpy(pszFull, pEntry->pszResult, cchFull); pszFull[cchFull - 1] = '\0'; } return; } /* Make the call... */ nt_fullpath(pszPath, pszFull, cchFull); /* ... and cache the result. */ cchResult = (unsigned)strlen(pszFull); pEntry = malloc(sizeof(*pEntry) + cchInput + cchResult + 1); if (pEntry) { g_cbNtFullPathHashEntries += sizeof(*pEntry) + cchInput + cchResult + 1; pEntry->cchInput = cchInput; pEntry->cchResult = cchResult; pEntry->pszResult = &pEntry->szInput[cchInput + 1]; pEntry->uHash = uHash; memcpy(pEntry->szInput, pszPath, cchInput + 1); memcpy((char *)pEntry->pszResult, pszFull, cchResult + 1); pEntry->pNext = g_apNtFullPathHashTab[idx]; if (pEntry->pNext) g_cNtFullPathHashCollisions++; g_apNtFullPathHashTab[idx] = pEntry; g_cNtFullPathHashEntries++; } }