TabIndex.cpp
上传用户:woshihumen
上传日期:2013-07-18
资源大小:484k
文件大小:21k
源码类别:

Email服务器

开发平台:

Visual C++

  1. /*
  2.  *  XMail by Davide Libenzi ( Intranet and Internet mail server )
  3.  *  Copyright (C) 1999,..,2004  Davide Libenzi
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  *
  19.  *  Davide Libenzi <davidel@xmailserver.org>
  20.  *
  21.  */
  22. #include "SysInclude.h"
  23. #include "SysDep.h"
  24. #include "SvrDefines.h"
  25. #include "ShBlocks.h"
  26. #include "StrUtils.h"
  27. #include "SList.h"
  28. #include "BuffSock.h"
  29. #include "MiscUtils.h"
  30. #include "TabIndex.h"
  31. ///////////////////////////////////////////////////////////////////////////////
  32. //  The index version MUST be incremented at every file format change
  33. ///////////////////////////////////////////////////////////////////////////////
  34. #define TAB_INDEX_CURR_VERSION      1
  35. #define TAB_SAMPLE_LINES            32
  36. #define TAB_MIN_HASH_SIZE           17
  37. #define TAB_INDEX_DIR               "tabindex"
  38. #define TAB_INDEX_MAGIC             (*(SYS_UINT32 *) "ABDL")
  39. #define KEY_BUFFER_SIZE             1024
  40. #define TAB_RECORD_BUFFER_SIZE      2048
  41. #define TOKEN_SEP_STR               "t"
  42. struct HashLink {
  43. SysListHead LLink;
  44. SYS_UINT32 uOffset;
  45. };
  46. struct HashNode {
  47. SysListHead NodeList;
  48. SYS_UINT32 uCount;
  49. };
  50. struct HashFileHeader {
  51. SYS_UINT32 uMagic;
  52. SYS_UINT32 uVersion;
  53. SYS_UINT32 uHashSize;
  54. };
  55. struct TabHashIndex {
  56. HashFileHeader HFH;
  57. FILE *pIndexFile;
  58. };
  59. struct IndexLookupData {
  60. FILE *pTabFile;
  61. SYS_UINT32 *pHashTable;
  62. };
  63. static int TbixCalcHashSize(FILE * pTabFile, char *pszLineBuffer, int iBufferSize);
  64. static int TbixFreeHash(HashNode * pHash, int iHashSize);
  65. static int TbixBuildKey(char *pszKey, va_list Args, bool bCaseSens);
  66. static int TbixBuildKey(char *pszKey, char const *const *ppszTabTokens,
  67. int const *piFieldsIdx, bool bCaseSens);
  68. static int TbixOpenIndex(char const *pszIndexFile, TabHashIndex & THI);
  69. static int TbixCloseIndex(TabHashIndex & THI);
  70. static int TbixCheckIndex(char const *pszIndexFile);
  71. static SYS_UINT32 *TbixReadTable(TabHashIndex & THI, SYS_UINT32 uHashVal);
  72. static char **TbixLoadRecord(FILE * pTabFile, SYS_UINT32 uOffset);
  73. static int TbixCalcHashSize(FILE * pTabFile, char *pszLineBuffer, int iBufferSize)
  74. {
  75. int iSampleLines = 0;
  76. unsigned long ulOrigOffset = (unsigned long) ftell(pTabFile);
  77. unsigned long ulCurrOffset = 0;
  78. unsigned long ulLineSize = 0;
  79. rewind(pTabFile);
  80. while (iSampleLines < TAB_SAMPLE_LINES) {
  81. if (MscGetString(pTabFile, pszLineBuffer, iBufferSize - 1) == NULL)
  82. break;
  83. unsigned long ulOffset = (unsigned long) ftell(pTabFile);
  84. if (!IsEmptyString(pszLineBuffer) && (pszLineBuffer[0] != TAB_COMMENT_CHAR)) {
  85. ulLineSize += ulOffset - ulCurrOffset;
  86. ++iSampleLines;
  87. }
  88. ulCurrOffset = ulOffset;
  89. }
  90. if (iSampleLines == 0) {
  91. fseek(pTabFile, ulOrigOffset, SEEK_SET);
  92. return (TAB_MIN_HASH_SIZE);
  93. }
  94. ulLineSize /= iSampleLines;
  95. fseek(pTabFile, 0, SEEK_END);
  96. unsigned long ulFileSize = (unsigned long) ftell(pTabFile);
  97. fseek(pTabFile, ulOrigOffset, SEEK_SET);
  98. int iHashSize = (int) (ulFileSize / ulLineSize) + TAB_MIN_HASH_SIZE;
  99. while (!IsPrimeNumber(iHashSize))
  100. ++iHashSize;
  101. return (iHashSize);
  102. }
  103. char *TbixGetIndexFile(char const *pszTabFilePath, int const *piFieldsIdx, char *pszIndexFile)
  104. {
  105. char szFileDir[SYS_MAX_PATH] = "";
  106. char szFileName[SYS_MAX_PATH] = "";
  107. MscSplitPath(pszTabFilePath, szFileDir, szFileName, NULL);
  108. sprintf(pszIndexFile, "%s%s%s%s-", szFileDir, TAB_INDEX_DIR, SYS_SLASH_STR, szFileName);
  109. for (int ii = 0; piFieldsIdx[ii] != INDEX_SEQUENCE_TERMINATOR; ii++) {
  110. char szIndex[64] = "";
  111. sprintf(szIndex, "%02d", piFieldsIdx[ii]);
  112. strcat(pszIndexFile, szIndex);
  113. }
  114. strcat(pszIndexFile, ".hdx");
  115. return (pszIndexFile);
  116. }
  117. static int TbixFreeHash(HashNode * pHash, int iHashSize)
  118. {
  119. for (int ii = 0; ii < iHashSize; ii++) {
  120. SysListHead *pHead = &pHash[ii].NodeList;
  121. SysListHead *pLLink;
  122. while ((pLLink = SYS_LIST_FIRST(pHead)) != NULL) {
  123. HashLink *pHL = SYS_LIST_ENTRY(pLLink, HashLink, LLink);
  124. SYS_LIST_DEL(&pHL->LLink);
  125. SysFree(pHL);
  126. }
  127. }
  128. SysFree(pHash);
  129. return (0);
  130. }
  131. int TbixCreateIndex(char const *pszTabFilePath, int const *piFieldsIdx, bool bCaseSens,
  132.     int (*pHashFunc) (char const *const *, int const *, SYS_UINT32 *, bool))
  133. {
  134. ///////////////////////////////////////////////////////////////////////////////
  135. //  Adjust hash function
  136. ///////////////////////////////////////////////////////////////////////////////
  137. if (pHashFunc == NULL)
  138. pHashFunc = TbixCalculateHash;
  139. ///////////////////////////////////////////////////////////////////////////////
  140. //  Build index file name
  141. ///////////////////////////////////////////////////////////////////////////////
  142. char szIndexFile[SYS_MAX_PATH] = "";
  143. if (TbixGetIndexFile(pszTabFilePath, piFieldsIdx, szIndexFile) < 0)
  144. return (ErrGetErrorCode());
  145. FILE *pTabFile = fopen(pszTabFilePath, "rb");
  146. if (pTabFile == NULL) {
  147. ErrSetErrorCode(ERR_FILE_OPEN, pszTabFilePath);
  148. return (ERR_FILE_OPEN);
  149. }
  150. ///////////////////////////////////////////////////////////////////////////////
  151. //  Calculate file lookup hash size
  152. ///////////////////////////////////////////////////////////////////////////////
  153. char szLineBuffer[TAB_RECORD_BUFFER_SIZE] = "";
  154. int iHashSize = TbixCalcHashSize(pTabFile, szLineBuffer, sizeof(szLineBuffer));
  155. ///////////////////////////////////////////////////////////////////////////////
  156. //  Alloc and init hash records
  157. ///////////////////////////////////////////////////////////////////////////////
  158. HashNode *pHash = (HashNode *) SysAlloc(iHashSize * sizeof(HashNode));
  159. if (pHash == NULL) {
  160. fclose(pTabFile);
  161. return (ErrGetErrorCode());
  162. }
  163. int ii;
  164. for (ii = 0; ii < iHashSize; ii++) {
  165. SYS_INIT_LIST_HEAD(&pHash[ii].NodeList);
  166. pHash[ii].uCount = 0;
  167. }
  168. ///////////////////////////////////////////////////////////////////////////////
  169. //  Setup indexes records
  170. ///////////////////////////////////////////////////////////////////////////////
  171. for (;;) {
  172. ///////////////////////////////////////////////////////////////////////////////
  173. //  Get current offset
  174. ///////////////////////////////////////////////////////////////////////////////
  175. SYS_UINT32 uFileOffset = (SYS_UINT32) ftell(pTabFile);
  176. if (MscGetString(pTabFile, szLineBuffer, sizeof(szLineBuffer) - 1) == NULL)
  177. break;
  178. if (szLineBuffer[0] == TAB_COMMENT_CHAR)
  179. continue;
  180. char **ppszTabTokens = StrGetTabLineStrings(szLineBuffer);
  181. if (ppszTabTokens == NULL)
  182. continue;
  183. ///////////////////////////////////////////////////////////////////////////////
  184. //  Calculate hash value
  185. ///////////////////////////////////////////////////////////////////////////////
  186. SYS_UINT32 uHashVal = 0;
  187. if (pHashFunc(ppszTabTokens, piFieldsIdx, &uHashVal, bCaseSens) == 0) {
  188. int iHashIndex = (int) (uHashVal % (SYS_UINT32) iHashSize);
  189. HashLink *pHL = (HashLink *) SysAlloc(sizeof(HashLink));
  190. if (pHL == NULL) {
  191. TbixFreeHash(pHash, iHashSize);
  192. fclose(pTabFile);
  193. return (ErrGetErrorCode());
  194. }
  195. pHL->uOffset = uFileOffset;
  196. SYS_LIST_ADDT(&pHL->LLink, &pHash[iHashIndex].NodeList);
  197. ++pHash[iHashIndex].uCount;
  198. }
  199. StrFreeStrings(ppszTabTokens);
  200. }
  201. fclose(pTabFile);
  202. ///////////////////////////////////////////////////////////////////////////////
  203. //  Write index file
  204. ///////////////////////////////////////////////////////////////////////////////
  205. FILE *pIndexFile = fopen(szIndexFile, "wb");
  206. if (pIndexFile == NULL) {
  207. TbixFreeHash(pHash, iHashSize);
  208. ErrSetErrorCode(ERR_FILE_CREATE, szIndexFile);
  209. return (ERR_FILE_CREATE);
  210. }
  211. ///////////////////////////////////////////////////////////////////////////////
  212. //  Write file header
  213. ///////////////////////////////////////////////////////////////////////////////
  214. HashFileHeader HFH;
  215. ZeroData(HFH);
  216. HFH.uMagic = TAB_INDEX_MAGIC;
  217. HFH.uVersion = TAB_INDEX_CURR_VERSION;
  218. HFH.uHashSize = (SYS_UINT32) iHashSize;
  219. if (!fwrite(&HFH, sizeof(HFH), 1, pIndexFile)) {
  220. fclose(pIndexFile);
  221. SysRemove(szIndexFile);
  222. TbixFreeHash(pHash, iHashSize);
  223. ErrSetErrorCode(ERR_FILE_WRITE);
  224. return (ERR_FILE_WRITE);
  225. }
  226. ///////////////////////////////////////////////////////////////////////////////
  227. //  Dump main table
  228. ///////////////////////////////////////////////////////////////////////////////
  229. SYS_UINT32 uCurrOffset = sizeof(HFH) + iHashSize * sizeof(SYS_UINT32);
  230. for (ii = 0; ii < iHashSize; ii++) {
  231. SYS_UINT32 uTableOffset = 0;
  232. if (pHash[ii].uCount != 0) {
  233. uTableOffset = uCurrOffset;
  234. uCurrOffset += (pHash[ii].uCount + 1) * sizeof(SYS_UINT32);
  235. }
  236. if (!fwrite(&uTableOffset, sizeof(uTableOffset), 1, pIndexFile)) {
  237. fclose(pIndexFile);
  238. SysRemove(szIndexFile);
  239. TbixFreeHash(pHash, iHashSize);
  240. ErrSetErrorCode(ERR_FILE_WRITE);
  241. return (ERR_FILE_WRITE);
  242. }
  243. }
  244. ///////////////////////////////////////////////////////////////////////////////
  245. //  Dump hash tables
  246. ///////////////////////////////////////////////////////////////////////////////
  247. for (ii = 0; ii < iHashSize; ii++) {
  248. SYS_UINT32 uRecCount = pHash[ii].uCount;
  249. if (uRecCount != 0) {
  250. if (!fwrite(&uRecCount, sizeof(uRecCount), 1, pIndexFile)) {
  251. fclose(pIndexFile);
  252. SysRemove(szIndexFile);
  253. TbixFreeHash(pHash, iHashSize);
  254. ErrSetErrorCode(ERR_FILE_WRITE);
  255. return (ERR_FILE_WRITE);
  256. }
  257. SysListHead *pHead = &pHash[ii].NodeList;
  258. SysListHead *pLLink;
  259. SYS_LIST_FOR_EACH(pLLink, pHead) {
  260. HashLink *pHL = SYS_LIST_ENTRY(pLLink, HashLink, LLink);
  261. SYS_UINT32 uRecordOffset = pHL->uOffset;
  262. if (!fwrite(&uRecordOffset, sizeof(uRecordOffset), 1, pIndexFile)) {
  263. fclose(pIndexFile);
  264. SysRemove(szIndexFile);
  265. TbixFreeHash(pHash, iHashSize);
  266. ErrSetErrorCode(ERR_FILE_WRITE);
  267. return (ERR_FILE_WRITE);
  268. }
  269. }
  270. }
  271. }
  272. fclose(pIndexFile);
  273. TbixFreeHash(pHash, iHashSize);
  274. return (0);
  275. }
  276. static int TbixBuildKey(char *pszKey, va_list Args, bool bCaseSens)
  277. {
  278. SetEmptyString(pszKey);
  279. char const *pszToken;
  280. for (int ii = 0; (pszToken = va_arg(Args, char *)) != NULL; ii++) {
  281. if (ii > 0)
  282. strcat(pszKey, TOKEN_SEP_STR);
  283. strcat(pszKey, pszToken);
  284. }
  285. if (!bCaseSens)
  286. StrLower(pszKey);
  287. return (0);
  288. }
  289. static int TbixBuildKey(char *pszKey, char const *const *ppszTabTokens,
  290. int const *piFieldsIdx, bool bCaseSens)
  291. {
  292. SetEmptyString(pszKey);
  293. int iFieldsCount = StrStringsCount(ppszTabTokens);
  294. for (int ii = 0; piFieldsIdx[ii] != INDEX_SEQUENCE_TERMINATOR; ii++) {
  295. if ((piFieldsIdx[ii] < 0) || (piFieldsIdx[ii] >= iFieldsCount)) {
  296. ErrSetErrorCode(ERR_BAD_TAB_INDEX_FIELD);
  297. return (ERR_BAD_TAB_INDEX_FIELD);
  298. }
  299. if (ii > 0)
  300. strcat(pszKey, TOKEN_SEP_STR);
  301. strcat(pszKey, ppszTabTokens[piFieldsIdx[ii]]);
  302. }
  303. if (!bCaseSens)
  304. StrLower(pszKey);
  305. return (0);
  306. }
  307. int TbixCalculateHash(char const *const *ppszTabTokens, int const *piFieldsIdx,
  308.       SYS_UINT32 * puHashVal, bool bCaseSens)
  309. {
  310. char szKey[KEY_BUFFER_SIZE] = "";
  311. if (TbixBuildKey(szKey, ppszTabTokens, piFieldsIdx, bCaseSens) < 0)
  312. return (ErrGetErrorCode());
  313. *puHashVal = MscHashString(szKey, strlen(szKey));
  314. return (0);
  315. }
  316. static int TbixOpenIndex(char const *pszIndexFile, TabHashIndex & THI)
  317. {
  318. FILE *pIndexFile = fopen(pszIndexFile, "rb");
  319. if (pIndexFile == NULL) {
  320. ErrSetErrorCode(ERR_FILE_OPEN, pszIndexFile);
  321. return (ERR_FILE_OPEN);
  322. }
  323. ///////////////////////////////////////////////////////////////////////////////
  324. //  Read header and check signature
  325. ///////////////////////////////////////////////////////////////////////////////
  326. ZeroData(THI);
  327. if (!fread(&THI.HFH, sizeof(THI.HFH), 1, pIndexFile)) {
  328. fclose(pIndexFile);
  329. ErrSetErrorCode(ERR_FILE_READ, pszIndexFile);
  330. return (ERR_FILE_READ);
  331. }
  332. if ((THI.HFH.uMagic != TAB_INDEX_MAGIC) || (THI.HFH.uVersion != TAB_INDEX_CURR_VERSION)) {
  333. fclose(pIndexFile);
  334. ErrSetErrorCode(ERR_BAD_INDEX_FILE, pszIndexFile);
  335. return (ERR_BAD_INDEX_FILE);
  336. }
  337. THI.pIndexFile = pIndexFile;
  338. return (0);
  339. }
  340. static int TbixCloseIndex(TabHashIndex & THI)
  341. {
  342. fclose(THI.pIndexFile);
  343. ZeroData(THI);
  344. return (0);
  345. }
  346. static int TbixCheckIndex(char const *pszIndexFile)
  347. {
  348. TabHashIndex THI;
  349. if (TbixOpenIndex(pszIndexFile, THI) < 0)
  350. return (ErrGetErrorCode());
  351. TbixCloseIndex(THI);
  352. return (0);
  353. }
  354. static SYS_UINT32 *TbixReadTable(TabHashIndex & THI, SYS_UINT32 uHashVal)
  355. {
  356. SYS_UINT32 uHashIndex = uHashVal % THI.HFH.uHashSize;
  357. unsigned long ulTableOffset = sizeof(HashFileHeader) + uHashIndex * sizeof(SYS_UINT32);
  358. if (fseek(THI.pIndexFile, ulTableOffset, SEEK_SET) != 0) {
  359. ErrSetErrorCode(ERR_BAD_INDEX_FILE);
  360. return (NULL);
  361. }
  362. SYS_UINT32 uTableOffset;
  363. if (!fread(&uTableOffset, sizeof(uTableOffset), 1, THI.pIndexFile)) {
  364. ErrSetErrorCode(ERR_FILE_READ);
  365. return (NULL);
  366. }
  367. if (uTableOffset == 0) {
  368. ErrSetErrorCode(ERR_RECORD_NOT_FOUND);
  369. return (NULL);
  370. }
  371. if (fseek(THI.pIndexFile, uTableOffset, SEEK_SET) != 0) {
  372. ErrSetErrorCode(ERR_BAD_INDEX_FILE);
  373. return (NULL);
  374. }
  375. SYS_UINT32 uTableSize;
  376. if (!fread(&uTableSize, sizeof(uTableSize), 1, THI.pIndexFile)) {
  377. ErrSetErrorCode(ERR_FILE_READ);
  378. return (NULL);
  379. }
  380. SYS_UINT32 *pOffTable = (SYS_UINT32 *) SysAlloc((uTableSize + 1) * sizeof(SYS_UINT32));
  381. if (pOffTable == NULL)
  382. return (NULL);
  383. pOffTable[0] = uTableSize;
  384. if (!fread(&pOffTable[1], uTableSize * sizeof(SYS_UINT32), 1, THI.pIndexFile)) {
  385. SysFree(pOffTable);
  386. ErrSetErrorCode(ERR_FILE_READ);
  387. return (NULL);
  388. }
  389. return (pOffTable);
  390. }
  391. char **TbixLookup(char const *pszTabFilePath, int const *piFieldsIdx, bool bCaseSens, ...)
  392. {
  393. ///////////////////////////////////////////////////////////////////////////////
  394. //  Build index file name
  395. ///////////////////////////////////////////////////////////////////////////////
  396. char szIndexFile[SYS_MAX_PATH] = "";
  397. if (TbixGetIndexFile(pszTabFilePath, piFieldsIdx, szIndexFile) < 0)
  398. return (NULL);
  399. ///////////////////////////////////////////////////////////////////////////////
  400. //  Calculate key & hash
  401. ///////////////////////////////////////////////////////////////////////////////
  402. va_list Args;
  403. va_start(Args, bCaseSens);
  404. char szRefKey[KEY_BUFFER_SIZE] = "";
  405. if (TbixBuildKey(szRefKey, Args, bCaseSens) < 0) {
  406. va_end(Args);
  407. return (NULL);
  408. }
  409. va_end(Args);
  410. SYS_UINT32 uHashVal = MscHashString(szRefKey, strlen(szRefKey));
  411. ///////////////////////////////////////////////////////////////////////////////
  412. //  Open index
  413. ///////////////////////////////////////////////////////////////////////////////
  414. TabHashIndex THI;
  415. if (TbixOpenIndex(szIndexFile, THI) < 0)
  416. return (NULL);
  417. ///////////////////////////////////////////////////////////////////////////////
  418. //  Try to lookup records
  419. ///////////////////////////////////////////////////////////////////////////////
  420. SYS_UINT32 *pHashTable = TbixReadTable(THI, uHashVal);
  421. TbixCloseIndex(THI);
  422. if (pHashTable == NULL)
  423. return (NULL);
  424. ///////////////////////////////////////////////////////////////////////////////
  425. //  Search for the matched one
  426. ///////////////////////////////////////////////////////////////////////////////
  427. FILE *pTabFile = fopen(pszTabFilePath, "rb");
  428. if (pTabFile == NULL) {
  429. SysFree(pHashTable);
  430. ErrSetErrorCode(ERR_FILE_OPEN, pszTabFilePath);
  431. return (NULL);
  432. }
  433. int iHashNodes = (int) pHashTable[0];
  434. for (int ii = 0; ii < iHashNodes; ii++) {
  435. char **ppszTabTokens = TbixLoadRecord(pTabFile, pHashTable[ii + 1]);
  436. if (ppszTabTokens != NULL) {
  437. char szKey[KEY_BUFFER_SIZE] = "";
  438. if (TbixBuildKey(szKey, ppszTabTokens, piFieldsIdx, bCaseSens) == 0) {
  439. if (bCaseSens) {
  440. if (strcmp(szKey, szRefKey) == 0) {
  441. fclose(pTabFile);
  442. SysFree(pHashTable);
  443. return (ppszTabTokens);
  444. }
  445. } else {
  446. if (stricmp(szKey, szRefKey) == 0) {
  447. fclose(pTabFile);
  448. SysFree(pHashTable);
  449. return (ppszTabTokens);
  450. }
  451. }
  452. }
  453. StrFreeStrings(ppszTabTokens);
  454. }
  455. }
  456. fclose(pTabFile);
  457. SysFree(pHashTable);
  458. ErrSetErrorCode(ERR_RECORD_NOT_FOUND);
  459. return (NULL);
  460. }
  461. static char **TbixLoadRecord(FILE * pTabFile, SYS_UINT32 uOffset)
  462. {
  463. if (fseek(pTabFile, uOffset, SEEK_SET) != 0) {
  464. ErrSetErrorCode(ERR_BAD_INDEX_FILE);
  465. return (NULL);
  466. }
  467. char szLineBuffer[TAB_RECORD_BUFFER_SIZE] = "";
  468. if (MscGetString(pTabFile, szLineBuffer, sizeof(szLineBuffer) - 1) == NULL) {
  469. ErrSetErrorCode(ERR_FILE_READ);
  470. return (NULL);
  471. }
  472. return (StrGetTabLineStrings(szLineBuffer));
  473. }
  474. int TbixCheckIndex(char const *pszTabFilePath, int const *piFieldsIdx, bool bCaseSens,
  475.    int (*pHashFunc) (char const *const *, int const *, SYS_UINT32 *, bool))
  476. {
  477. SYS_FILE_INFO FI_Tab;
  478. if (SysGetFileInfo(pszTabFilePath, FI_Tab) < 0)
  479. return (ErrGetErrorCode());
  480. ///////////////////////////////////////////////////////////////////////////////
  481. //  Build index file name
  482. ///////////////////////////////////////////////////////////////////////////////
  483. char szIndexFile[SYS_MAX_PATH] = "";
  484. if (TbixGetIndexFile(pszTabFilePath, piFieldsIdx, szIndexFile) < 0)
  485. return (ErrGetErrorCode());
  486. ///////////////////////////////////////////////////////////////////////////////
  487. //  Compare TAB <-> Index dates
  488. ///////////////////////////////////////////////////////////////////////////////
  489. SYS_FILE_INFO FI_Index;
  490. if ((SysGetFileInfo(szIndexFile, FI_Index) < 0) || (FI_Tab.tMod > FI_Index.tMod) ||
  491.     (TbixCheckIndex(szIndexFile) < 0)) {
  492. ///////////////////////////////////////////////////////////////////////////////
  493. //  Rebuild the index
  494. ///////////////////////////////////////////////////////////////////////////////
  495. if (TbixCreateIndex(pszTabFilePath, piFieldsIdx, bCaseSens, pHashFunc) < 0)
  496. return (ErrGetErrorCode());
  497. }
  498. return (0);
  499. }
  500. INDEX_HANDLE TbixOpenHandle(char const *pszTabFilePath, int const *piFieldsIdx,
  501.     SYS_UINT32 uHashVal)
  502. {
  503. ///////////////////////////////////////////////////////////////////////////////
  504. //  Build index file name
  505. ///////////////////////////////////////////////////////////////////////////////
  506. char szIndexFile[SYS_MAX_PATH] = "";
  507. if (TbixGetIndexFile(pszTabFilePath, piFieldsIdx, szIndexFile) < 0)
  508. return (INVALID_INDEX_HANDLE);
  509. ///////////////////////////////////////////////////////////////////////////////
  510. //  Open index
  511. ///////////////////////////////////////////////////////////////////////////////
  512. TabHashIndex THI;
  513. if (TbixOpenIndex(szIndexFile, THI) < 0)
  514. return (INVALID_INDEX_HANDLE);
  515. ///////////////////////////////////////////////////////////////////////////////
  516. //  Try to lookup records
  517. ///////////////////////////////////////////////////////////////////////////////
  518. SYS_UINT32 *pHashTable = TbixReadTable(THI, uHashVal);
  519. TbixCloseIndex(THI);
  520. if (pHashTable == NULL)
  521. return (INVALID_INDEX_HANDLE);
  522. ///////////////////////////////////////////////////////////////////////////////
  523. //  Open tab file
  524. ///////////////////////////////////////////////////////////////////////////////
  525. FILE *pTabFile = fopen(pszTabFilePath, "rb");
  526. if (pTabFile == NULL) {
  527. SysFree(pHashTable);
  528. ErrSetErrorCode(ERR_FILE_OPEN, pszTabFilePath);
  529. return (INVALID_INDEX_HANDLE);
  530. }
  531. ///////////////////////////////////////////////////////////////////////////////
  532. //  Setup lookup struct
  533. ///////////////////////////////////////////////////////////////////////////////
  534. IndexLookupData *pILD = (IndexLookupData *) SysAlloc(sizeof(IndexLookupData));
  535. if (pILD == NULL) {
  536. fclose(pTabFile);
  537. SysFree(pHashTable);
  538. return (INVALID_INDEX_HANDLE);
  539. }
  540. pILD->pTabFile = pTabFile;
  541. pILD->pHashTable = pHashTable;
  542. return ((INDEX_HANDLE) pILD);
  543. }
  544. int TbixCloseHandle(INDEX_HANDLE hIndexLookup)
  545. {
  546. IndexLookupData *pILD = (IndexLookupData *) hIndexLookup;
  547. fclose(pILD->pTabFile);
  548. SysFree(pILD->pHashTable);
  549. SysFree(pILD);
  550. return (0);
  551. }
  552. int TbixLookedUpRecords(INDEX_HANDLE hIndexLookup)
  553. {
  554. IndexLookupData *pILD = (IndexLookupData *) hIndexLookup;
  555. return ((int) pILD->pHashTable[0]);
  556. }
  557. char **TbixGetRecord(INDEX_HANDLE hIndexLookup, int iRecord)
  558. {
  559. IndexLookupData *pILD = (IndexLookupData *) hIndexLookup;
  560. if ((iRecord < 0) || (iRecord >= (int) pILD->pHashTable[0])) {
  561. ErrSetErrorCode(ERR_RECORD_NOT_FOUND);
  562. return (NULL);
  563. }
  564. return (TbixLoadRecord(pILD->pTabFile, pILD->pHashTable[iRecord + 1]));
  565. }