You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1504 lines
48 KiB

  1. /************* TabMul C++ Program Source Code File (.CPP) **************/
  2. /* PROGRAM NAME: TABMUL */
  3. /* ------------- */
  4. /* Version 1.7 */
  5. /* */
  6. /* COPYRIGHT: */
  7. /* ---------- */
  8. /* (C) Copyright to PlugDB Software Development 2003 - 2012 */
  9. /* Author: Olivier BERTRAND */
  10. /* */
  11. /* WHAT THIS PROGRAM DOES: */
  12. /* ----------------------- */
  13. /* This program are the TDBMUL class DB routines. */
  14. /* */
  15. /* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
  16. /* -------------------------------------- */
  17. /* */
  18. /* REQUIRED FILES: */
  19. /* --------------- */
  20. /* TABMUL.CPP - Source code */
  21. /* PLGDBSEM.H - DB application declaration file */
  22. /* TABDOS.H - TABDOS classes declaration file */
  23. /* TABMUL.H - TABFIX classes declaration file */
  24. /* GLOBAL.H - Global declaration file */
  25. /* */
  26. /* REQUIRED LIBRARIES: */
  27. /* ------------------- */
  28. /* Large model C library */
  29. /* */
  30. /* REQUIRED PROGRAMS: */
  31. /* ------------------ */
  32. /* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
  33. /* */
  34. /***********************************************************************/
  35. /***********************************************************************/
  36. /* Include relevant section of system dependant header files. */
  37. /***********************************************************************/
  38. #include "my_global.h"
  39. #if defined(WIN32)
  40. #include <stdlib.h>
  41. #include <stdio.h>
  42. #if defined(__BORLANDC__)
  43. #define __MFC_COMPAT__ // To define min/max as macro
  44. #endif
  45. //#include <windows.h>
  46. #else
  47. #if defined(UNIX)
  48. #include <fnmatch.h>
  49. #include <errno.h>
  50. #include <stdlib.h>
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include "osutil.h"
  54. #else
  55. //#include <io.h>
  56. #endif
  57. //#include <fcntl.h>
  58. #endif
  59. /***********************************************************************/
  60. /* Include application header files: */
  61. /***********************************************************************/
  62. #include "global.h" // global declarations
  63. #include "plgdbsem.h" // DB application declarations
  64. #include "reldef.h" // DB definition declares
  65. #include "filamtxt.h"
  66. #include "tabdos.h" // TDBDOS and DOSCOL class dcls
  67. #include "tabmul.h" // TDBMUL and MULCOL classes dcls
  68. extern "C" int trace;
  69. /* ------------------------- Class TDBMUL ---------------------------- */
  70. /***********************************************************************/
  71. /* TABMUL constructors. */
  72. /***********************************************************************/
  73. TDBMUL::TDBMUL(PTDBASE tdbp) : TDBASE(tdbp->GetDef())
  74. {
  75. Tdbp = tdbp;
  76. Filenames = NULL;
  77. Rows = 0;
  78. Mul = tdbp->GetDef()->GetMultiple();
  79. NumFiles = 0;
  80. iFile = 0;
  81. } // end of TDBMUL standard constructor
  82. TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp)
  83. {
  84. Tdbp = tdbp->Tdbp;
  85. Filenames = tdbp->Filenames;
  86. Rows = tdbp->Rows;
  87. Mul = tdbp->Mul;
  88. NumFiles = tdbp->NumFiles;
  89. iFile = tdbp->iFile;
  90. } // end of TDBMUL copy constructor
  91. // Method
  92. PTDB TDBMUL::CopyOne(PTABS t)
  93. {
  94. PTDBMUL tp;
  95. PGLOBAL g = t->G; // Is this really useful ???
  96. tp = new(g) TDBMUL(this);
  97. tp->Tdbp = (PTDBASE)Tdbp->CopyOne(t);
  98. tp->Columns = tp->Tdbp->GetColumns();
  99. return tp;
  100. } // end of CopyOne
  101. PTDB TDBMUL::Duplicate(PGLOBAL g)
  102. {
  103. PTDBMUL tmup = new(g) TDBMUL(this);
  104. tmup->Tdbp = (PTDBASE)Tdbp->Duplicate(g);
  105. return tmup;
  106. } // end of Duplicate
  107. /***********************************************************************/
  108. /* Initializes the table filename list. */
  109. /* Note: tables created by concatenating the file components without */
  110. /* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
  111. /* have a LRECL that is the sum of the lengths of all components. */
  112. /* This is why we use a big filename array to take care of that. */
  113. /***********************************************************************/
  114. bool TDBMUL::InitFileNames(PGLOBAL g)
  115. {
  116. #define PFNZ 4096
  117. #define FNSZ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT
  118. char *pfn[PFNZ];
  119. char *filename;
  120. int rc, n = 0;
  121. if (trace)
  122. htrc("in InitFileName: fn[]=%d\n", FNSZ);
  123. filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
  124. // The sub table may need to refer to the Table original block
  125. Tdbp->SetTable(To_Table); // Was not set at construction
  126. PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
  127. if (trace)
  128. htrc("InitFileName: fn='%s'\n", filename);
  129. if (Mul == 1) {
  130. /*******************************************************************/
  131. /* To_File is a multiple name with special characters */
  132. /*******************************************************************/
  133. #if defined(WIN32)
  134. char drive[_MAX_DRIVE], direc[_MAX_DIR];
  135. WIN32_FIND_DATA FileData;
  136. HANDLE hSearch;
  137. _splitpath(filename, drive, direc, NULL, NULL);
  138. // Start searching files in the target directory.
  139. hSearch = FindFirstFile(filename, &FileData);
  140. if (hSearch == INVALID_HANDLE_VALUE) {
  141. rc = GetLastError();
  142. if (rc != ERROR_FILE_NOT_FOUND) {
  143. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  144. FORMAT_MESSAGE_IGNORE_INSERTS,
  145. NULL, GetLastError(), 0,
  146. (LPTSTR)&filename, sizeof(filename), NULL);
  147. sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
  148. return true;
  149. } // endif rc
  150. goto suite;
  151. } // endif hSearch
  152. while (n < PFNZ) {
  153. strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName);
  154. pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
  155. strcpy(pfn[n++], filename);
  156. if (!FindNextFile(hSearch, &FileData)) {
  157. rc = GetLastError();
  158. if (rc != ERROR_NO_MORE_FILES) {
  159. sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
  160. FindClose(hSearch);
  161. return true;
  162. } // endif rc
  163. break;
  164. } // endif FindNextFile
  165. } // endwhile n
  166. // Close the search handle.
  167. if (!FindClose(hSearch)) {
  168. strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
  169. return true;
  170. } // endif FindClose
  171. #else // !WIN32
  172. struct stat fileinfo;
  173. char fn[PATH_MAX], direc[PATH_MAX], pattern[256], ftype[8];
  174. DIR *dir;
  175. struct dirent *entry;
  176. _splitpath(filename, NULL, direc, pattern, ftype);
  177. strcat(pattern, ftype);
  178. if (trace)
  179. htrc("direc=%s pattern=%s ftype=%s\n", direc, pattern, ftype);
  180. // Start searching files in the target directory.
  181. if (!(dir = opendir(direc))) {
  182. sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno));
  183. if (trace)
  184. htrc("%s\n", g->Message);
  185. return true;
  186. } // endif dir
  187. if (trace)
  188. htrc("dir opened: reading files\n");
  189. while ((entry = readdir(dir)) && n < PFNZ) {
  190. strcat(strcpy(fn, direc), entry->d_name);
  191. if (trace)
  192. htrc("%s read\n", fn);
  193. if (lstat(fn, &fileinfo) < 0) {
  194. sprintf(g->Message, "%s: %s", fn, strerror(errno));
  195. return true;
  196. } else if (!S_ISREG(fileinfo.st_mode))
  197. continue; // Not a regular file (should test for links)
  198. /*******************************************************************/
  199. /* Test whether the file name matches the table name filter. */
  200. /*******************************************************************/
  201. if (fnmatch(pattern, entry->d_name, 0))
  202. continue; // Not a match
  203. strcat(strcpy(filename, direc), entry->d_name);
  204. pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
  205. strcpy(pfn[n++], filename);
  206. if (trace)
  207. htrc("Adding pfn[%d] %s\n", n, filename);
  208. } // endwhile readdir
  209. // Close the dir handle.
  210. closedir(dir);
  211. #endif // !WIN32
  212. } else {
  213. /*******************************************************************/
  214. /* To_File is the name of a file containing the file name list */
  215. /*******************************************************************/
  216. char *p;
  217. FILE *stream;
  218. if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r")))
  219. return true;
  220. while (n < PFNZ) {
  221. if (!fgets(filename, FNSZ, stream)) {
  222. fclose(stream);
  223. break;
  224. } // endif fgets
  225. p = filename + strlen(filename) - 1;
  226. #if defined(UNIX)
  227. // Data files can be imported from Windows (having CRLF)
  228. if (*p == '\n' || *p == '\r') {
  229. // is this enough for Unix ???
  230. *p--; // Eliminate ending CR or LF character
  231. if (p >= filename)
  232. // is this enough for Unix ???
  233. if (*p == '\n' || *p == '\r')
  234. *p--; // Eliminate ending CR or LF character
  235. } // endif p
  236. #else
  237. if (*p == '\n')
  238. p--; // Eliminate ending new-line character
  239. #endif
  240. // Trim rightmost blanks
  241. for (; p >= filename && *p == ' '; p--) ;
  242. *(++p) = '\0';
  243. // Suballocate the file name
  244. pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
  245. strcpy(pfn[n++], filename);
  246. } // endfor n
  247. } // endif Mul
  248. #if defined(WIN32)
  249. suite:
  250. #endif
  251. if (n) {
  252. Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
  253. for (int i = 0; i < n; i++)
  254. Filenames[i] = pfn[i];
  255. } else {
  256. Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
  257. Filenames[0] = NULL;
  258. } // endif n
  259. NumFiles = n;
  260. return false;
  261. } // end of InitFileNames
  262. /***********************************************************************/
  263. /* The table column list is the sub-table column list. */
  264. /***********************************************************************/
  265. PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num)
  266. {
  267. PCOL cp;
  268. /*********************************************************************/
  269. /* Because special columns are directly added to the MUL block, */
  270. /* make sure that the sub-table has the same column list, before */
  271. /* and after the call to the ColDB function. */
  272. /*********************************************************************/
  273. Tdbp->SetColumns(Columns);
  274. cp = Tdbp->ColDB(g, name, num);
  275. Columns = Tdbp->GetColumns();
  276. return cp;
  277. } // end of ColDB
  278. /***********************************************************************/
  279. /* MUL GetProgMax: get the max value for progress information. */
  280. /***********************************************************************/
  281. int TDBMUL::GetProgMax(PGLOBAL g)
  282. {
  283. if (!Filenames && InitFileNames(g))
  284. return -1;
  285. return NumFiles; // This is a temporary setting
  286. } // end of GetProgMax
  287. /***********************************************************************/
  288. /* MUL GetProgCur: get the current value for progress information. */
  289. /***********************************************************************/
  290. int TDBMUL::GetProgCur(void)
  291. {
  292. return iFile; // This is a temporary setting
  293. } // end of GetProgMax
  294. /***********************************************************************/
  295. /* MUL Cardinality: returns table cardinality in number of rows. */
  296. /* This function can be called with a null argument to test the */
  297. /* availability of Cardinality implementation (1 yes, 0 no). */
  298. /* Can be used on Multiple FIX table only. */
  299. /***********************************************************************/
  300. int TDBMUL::Cardinality(PGLOBAL g)
  301. {
  302. if (!g)
  303. return Tdbp->Cardinality(g);
  304. if (!Filenames && InitFileNames(g))
  305. return -1;
  306. int n, card = 0;
  307. for (int i = 0; i < NumFiles; i++) {
  308. Tdbp->SetFile(g, Filenames[i]);
  309. Tdbp->ResetSize();
  310. if ((n = Tdbp->Cardinality(g)) < 0) {
  311. // strcpy(g->Message, MSG(BAD_CARDINALITY));
  312. return -1;
  313. } // endif n
  314. card += n;
  315. } // endfor i
  316. return card;
  317. } // end of Cardinality
  318. /***********************************************************************/
  319. /* Sum up the sizes of all sub-tables. */
  320. /***********************************************************************/
  321. int TDBMUL::GetMaxSize(PGLOBAL g)
  322. {
  323. if (MaxSize < 0) {
  324. int i;
  325. int mxsz;
  326. if (trace)
  327. htrc("TDBMUL::GetMaxSize: Filenames=%p\n", Filenames);
  328. if (!Filenames && InitFileNames(g))
  329. return -1;
  330. if (Use == USE_OPEN) {
  331. strcpy(g->Message, MSG(MAXSIZE_ERROR));
  332. return -1;
  333. } else
  334. MaxSize = 0;
  335. for (i = 0; i < NumFiles; i++) {
  336. Tdbp->SetFile(g, Filenames[i]);
  337. Tdbp->ResetSize();
  338. if ((mxsz = Tdbp->GetMaxSize(g)) < 0) {
  339. MaxSize = -1;
  340. return mxsz;
  341. } // endif mxsz
  342. MaxSize += mxsz;
  343. } // endfor i
  344. } // endif MaxSize
  345. return MaxSize;
  346. } // end of GetMaxSize
  347. /***********************************************************************/
  348. /* Reset read/write position values. */
  349. /***********************************************************************/
  350. void TDBMUL::ResetDB(void)
  351. {
  352. for (PCOL colp = Columns; colp; colp = colp->GetNext())
  353. if (colp->GetAmType() == TYPE_AM_FILID)
  354. colp->COLBLK::Reset();
  355. Tdbp->ResetDB();
  356. } // end of ResetDB
  357. /***********************************************************************/
  358. /* Returns RowId if b is false or Rownum if b is true. */
  359. /***********************************************************************/
  360. int TDBMUL::RowNumber(PGLOBAL g, bool b)
  361. {
  362. return ((b) ? 0 : Rows)
  363. + ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1);
  364. } // end of RowNumber
  365. /***********************************************************************/
  366. /* MUL Access Method opening routine. */
  367. /* Open first file, other will be opened sequencially when reading. */
  368. /***********************************************************************/
  369. bool TDBMUL::OpenDB(PGLOBAL g)
  370. {
  371. if (trace)
  372. htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
  373. this, Tdb_No, Use, To_Key_Col, Mode);
  374. if (Use == USE_OPEN) {
  375. /*******************************************************************/
  376. /* Table already open, replace it at its beginning. */
  377. /*******************************************************************/
  378. if (Filenames[iFile = 0]) {
  379. Tdbp->CloseDB(g);
  380. Tdbp->SetUse(USE_READY);
  381. Tdbp->SetFile(g, Filenames[iFile = 0]);
  382. Tdbp->ResetSize();
  383. Rows = 0;
  384. ResetDB();
  385. return Tdbp->OpenDB(g); // Re-open with new file name
  386. } else
  387. return false;
  388. } // endif use
  389. /*********************************************************************/
  390. /* We need to calculate MaxSize before opening the query. */
  391. /*********************************************************************/
  392. if (GetMaxSize(g) < 0)
  393. return true;
  394. /*********************************************************************/
  395. /* Open the first table file of the list. */
  396. /*********************************************************************/
  397. //if (!Filenames && InitFileNames(g)) // was done in GetMaxSize
  398. // return true;
  399. if (Filenames[iFile = 0]) {
  400. Tdbp->SetFile(g, Filenames[0]);
  401. Tdbp->SetMode(Mode);
  402. Tdbp->ResetDB();
  403. Tdbp->ResetSize();
  404. if (Tdbp->OpenDB(g))
  405. return true;
  406. } // endif *Filenames
  407. Use = USE_OPEN;
  408. return false;
  409. } // end of OpenDB
  410. /***********************************************************************/
  411. /* ReadDB: Data Base read routine for MUL access method. */
  412. /***********************************************************************/
  413. int TDBMUL::ReadDB(PGLOBAL g)
  414. {
  415. int rc;
  416. if (NumFiles == 0)
  417. return RC_EF;
  418. else if (To_Kindex) {
  419. /*******************************************************************/
  420. /* Reading is by an index table. */
  421. /*******************************************************************/
  422. strcpy(g->Message, MSG(NO_INDEX_READ));
  423. rc = RC_FX;
  424. } else {
  425. /*******************************************************************/
  426. /* Now start the reading process. */
  427. /*******************************************************************/
  428. retry:
  429. rc = Tdbp->ReadDB(g);
  430. if (rc == RC_EF) {
  431. if (Tdbp->GetDef()->GetPseudo() & 1)
  432. // Total number of rows met so far
  433. Rows += Tdbp->RowNumber(g) - 1;
  434. if (++iFile < NumFiles) {
  435. /***************************************************************/
  436. /* Continue reading from next table file. */
  437. /***************************************************************/
  438. Tdbp->CloseDB(g);
  439. Tdbp->SetUse(USE_READY);
  440. Tdbp->SetFile(g, Filenames[iFile]);
  441. Tdbp->ResetSize();
  442. ResetDB();
  443. if (Tdbp->OpenDB(g)) // Re-open with new file name
  444. return RC_FX;
  445. goto retry;
  446. } // endif iFile
  447. } else if (rc == RC_FX)
  448. strcat(strcat(strcat(g->Message, " ("), Tdbp->GetFile(g)), ")");
  449. } // endif To_Kindex
  450. return rc;
  451. } // end of ReadDB
  452. /***********************************************************************/
  453. /* Data Base write routine for MUL access method. */
  454. /***********************************************************************/
  455. int TDBMUL::WriteDB(PGLOBAL g)
  456. {
  457. return Tdbp->WriteDB(g);
  458. // strcpy(g->Message, MSG(TABMUL_READONLY));
  459. // return RC_FX; // NIY
  460. } // end of WriteDB
  461. /***********************************************************************/
  462. /* Data Base delete line routine for MUL access method. */
  463. /***********************************************************************/
  464. int TDBMUL::DeleteDB(PGLOBAL g, int irc)
  465. {
  466. // When implementing DELETE_MODE InitFileNames must be updated to
  467. // eliminate CRLF under Windows if the file is read in binary.
  468. strcpy(g->Message, MSG(TABMUL_READONLY));
  469. return RC_FX; // NIY
  470. } // end of DeleteDB
  471. /***********************************************************************/
  472. /* Data Base close routine for MUL access method. */
  473. /***********************************************************************/
  474. void TDBMUL::CloseDB(PGLOBAL g)
  475. {
  476. if (NumFiles > 0) {
  477. Tdbp->CloseDB(g);
  478. iFile = NumFiles;
  479. } // endif NumFiles
  480. } // end of CloseDB
  481. /* --------------------------- Class DIRDEF -------------------------- */
  482. /***********************************************************************/
  483. /* DefineAM: define specific AM block values from XDB file. */
  484. /***********************************************************************/
  485. bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
  486. {
  487. Desc = Fn = GetStringCatInfo(g, "Filename", NULL);
  488. Incl = (GetIntCatInfo("Subdir", 0) != 0);
  489. Huge = (GetIntCatInfo("Huge", 0) != 0);
  490. return false;
  491. } // end of DefineAM
  492. /***********************************************************************/
  493. /* GetTable: makes a new Table Description Block. */
  494. /***********************************************************************/
  495. PTDB DIRDEF::GetTable(PGLOBAL g, MODE m)
  496. {
  497. #if 0
  498. if (Huge)
  499. return new(g) TDBDHR(this); // Not implemented yet
  500. else
  501. #endif
  502. if (Incl)
  503. return new(g) TDBSDR(this); // Including sub-directory files
  504. else
  505. return new(g) TDBDIR(this); // Not Including sub-directory files
  506. } // end of GetTable
  507. /* ------------------------- Class TDBDIR ---------------------------- */
  508. /***********************************************************************/
  509. /* TABDIR constructors. */
  510. /***********************************************************************/
  511. TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
  512. {
  513. To_File = tdp->Fn;
  514. iFile = 0;
  515. #if defined(WIN32)
  516. memset(&FileData, 0, sizeof(_finddata_t));
  517. Hsearch = -1;
  518. *Drive = '\0';
  519. #else // !WIN32
  520. memset(&Fileinfo, 0, sizeof(struct stat));
  521. Entry = NULL;
  522. Dir = NULL;
  523. Done = false;
  524. *Pattern = '\0';
  525. #endif // !WIN32
  526. *Fpath = '\0';
  527. *Direc = '\0';
  528. *Fname = '\0';
  529. *Ftype = '\0';
  530. } // end of TDBDIR standard constructor
  531. TDBDIR::TDBDIR(PTDBDIR tdbp) : TDBASE(tdbp)
  532. {
  533. To_File = tdbp->To_File;
  534. iFile = tdbp->iFile;
  535. #if defined(WIN32)
  536. FileData = tdbp->FileData;
  537. Hsearch = tdbp->Hsearch;
  538. strcpy(Drive, tdbp->Drive);
  539. #else // !WIN32
  540. Fileinfo = tdbp->Fileinfo;
  541. Entry = tdbp->Entry;
  542. Dir = tdbp->Dir;
  543. Done = tdbp->Done;
  544. strcpy(Pattern, tdbp->Pattern);
  545. #endif // !WIN32
  546. strcpy(Direc, tdbp->Direc);
  547. strcpy(Fname, tdbp->Fname);
  548. strcpy(Ftype, tdbp->Ftype);
  549. } // end of TDBDIR copy constructor
  550. // Method
  551. PTDB TDBDIR::CopyOne(PTABS t)
  552. {
  553. PTDB tp;
  554. PGLOBAL g = t->G; // Is this really useful ???
  555. tp = new(g) TDBDIR(this);
  556. tp->SetColumns(Columns);
  557. return tp;
  558. } // end of CopyOne
  559. /***********************************************************************/
  560. /* Initialize/get the components of the search file pattern. */
  561. /***********************************************************************/
  562. char* TDBDIR::Path(PGLOBAL g)
  563. {
  564. PCATLG cat = PlgGetCatalog(g);
  565. #if defined(WIN32)
  566. if (!*Drive) {
  567. PlugSetPath(Fpath, To_File, cat->GetDataPath());
  568. _splitpath(Fpath, Drive, Direc, Fname, Ftype);
  569. } else
  570. _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull ???
  571. return Fpath;
  572. #else // !WIN32
  573. if (!Done) {
  574. PlugSetPath(Fpath, To_File, cat->GetDataPath());
  575. _splitpath(Fpath, NULL, Direc, Fname, Ftype);
  576. strcat(strcpy(Pattern, Fname), Ftype);
  577. Done = true;
  578. } // endif Done
  579. return Pattern;
  580. #endif // !WIN32
  581. } // end of Path
  582. /***********************************************************************/
  583. /* Allocate DIR column description block. */
  584. /***********************************************************************/
  585. PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
  586. {
  587. return new(g) DIRCOL(cdp, this, cprec, n);
  588. } // end of MakeCol
  589. /***********************************************************************/
  590. /* DIR GetMaxSize: returns the number of retrieved files. */
  591. /***********************************************************************/
  592. int TDBDIR::GetMaxSize(PGLOBAL g)
  593. {
  594. if (MaxSize < 0) {
  595. int n = -1;
  596. #if defined(WIN32)
  597. int h;
  598. // Start searching files in the target directory.
  599. h = _findfirst(Path(g), &FileData);
  600. if (h != -1) {
  601. for (n = 1;; n++)
  602. if (_findnext(h, &FileData))
  603. break;
  604. // Close the search handle.
  605. _findclose(h);
  606. } else
  607. n = 0;
  608. #else // !WIN32
  609. Path(g);
  610. // Start searching files in the target directory.
  611. if (!(Dir = opendir(Direc))) {
  612. sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
  613. return -1;
  614. } // endif dir
  615. while ((Entry = readdir(Dir))) {
  616. strcat(strcpy(Fpath, Direc), Entry->d_name);
  617. if (lstat(Fpath, &Fileinfo) < 0) {
  618. sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
  619. return -1;
  620. } else if (S_ISREG(Fileinfo.st_mode))
  621. // Test whether the file name matches the table name filter
  622. if (!fnmatch(Pattern, Entry->d_name, 0))
  623. n++; // We have a match
  624. } // endwhile Entry
  625. // Close the DIR handle.
  626. closedir(Dir);
  627. #endif // !WIN32
  628. MaxSize = n;
  629. } // endif MaxSize
  630. return MaxSize;
  631. } // end of GetMaxSize
  632. /***********************************************************************/
  633. /* DIR Access Method opening routine. */
  634. /* Open first file, other will be opened sequencially when reading. */
  635. /***********************************************************************/
  636. bool TDBDIR::OpenDB(PGLOBAL g)
  637. {
  638. if (trace)
  639. htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
  640. this, Tdb_No, Use, Mode);
  641. if (Use == USE_OPEN) {
  642. /*******************************************************************/
  643. /* Table already open, reopen it. */
  644. /*******************************************************************/
  645. CloseDB(g);
  646. SetUse(USE_READY);
  647. } // endif use
  648. Use = USE_OPEN;
  649. #if !defined(WIN32)
  650. Path(g); // Be sure it is done
  651. Dir = NULL; // For ReadDB
  652. #endif // !WIN32
  653. return false;
  654. } // end of OpenDB
  655. /***********************************************************************/
  656. /* Data Base read routine for DIR access method. */
  657. /***********************************************************************/
  658. int TDBDIR::ReadDB(PGLOBAL g)
  659. {
  660. int rc = RC_OK;
  661. #if defined(WIN32)
  662. if (Hsearch == -1) {
  663. /*******************************************************************/
  664. /* Start searching files in the target directory. The use of the */
  665. /* Path function is required when called from TDBSDR. */
  666. /*******************************************************************/
  667. Hsearch = _findfirst(Path(g), &FileData);
  668. if (Hsearch == -1)
  669. rc = RC_EF;
  670. else
  671. iFile++;
  672. } else {
  673. if (_findnext(Hsearch, &FileData)) {
  674. // Restore file name and type pattern
  675. _splitpath(To_File, NULL, NULL, Fname, Ftype);
  676. rc = RC_EF;
  677. } else
  678. iFile++;
  679. } // endif Hsearch
  680. if (rc == RC_OK)
  681. _splitpath(FileData.name, NULL, NULL, Fname, Ftype);
  682. #else // !Win32
  683. rc = RC_NF;
  684. if (!Dir)
  685. // Start searching files in the target directory.
  686. if (!(Dir = opendir(Direc))) {
  687. sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
  688. rc = RC_FX;
  689. } // endif dir
  690. while (rc == RC_NF)
  691. if ((Entry = readdir(Dir))) {
  692. // We need the Fileinfo structure to get info about the file
  693. strcat(strcpy(Fpath, Direc), Entry->d_name);
  694. if (lstat(Fpath, &Fileinfo) < 0) {
  695. sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
  696. rc = RC_FX;
  697. } else if (S_ISREG(Fileinfo.st_mode))
  698. // Test whether the file name matches the table name filter
  699. if (!fnmatch(Pattern, Entry->d_name, 0)) {
  700. iFile++; // We have a match
  701. _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
  702. rc = RC_OK;
  703. } // endif fnmatch
  704. } else {
  705. // Restore file name and type pattern
  706. _splitpath(To_File, NULL, NULL, Fname, Ftype);
  707. rc = RC_EF;
  708. } // endif Entry
  709. #endif // !WIN32
  710. return rc;
  711. } // end of ReadDB
  712. /***********************************************************************/
  713. /* Data Base write routine for DIR access method. */
  714. /***********************************************************************/
  715. int TDBDIR::WriteDB(PGLOBAL g)
  716. {
  717. strcpy(g->Message, MSG(TABDIR_READONLY));
  718. return RC_FX; // NIY
  719. } // end of WriteDB
  720. /***********************************************************************/
  721. /* Data Base delete line routine for DIR access method. */
  722. /***********************************************************************/
  723. int TDBDIR::DeleteDB(PGLOBAL g, int irc)
  724. {
  725. strcpy(g->Message, MSG(TABDIR_READONLY));
  726. return RC_FX; // NIY
  727. } // end of DeleteDB
  728. /***********************************************************************/
  729. /* Data Base close routine for MUL access method. */
  730. /***********************************************************************/
  731. void TDBDIR::CloseDB(PGLOBAL g)
  732. {
  733. #if defined(WIN32)
  734. // Close the search handle.
  735. _findclose(Hsearch);
  736. Hsearch = -1;
  737. #else // !WIN32
  738. // Close the DIR handle
  739. if (Dir) {
  740. closedir(Dir);
  741. Dir = NULL;
  742. } // endif dir
  743. #endif // !WIN32
  744. iFile = 0;
  745. } // end of CloseDB
  746. // ------------------------ DIRCOL functions ----------------------------
  747. /***********************************************************************/
  748. /* DIRCOL public constructor. */
  749. /***********************************************************************/
  750. DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
  751. : COLBLK(cdp, tdbp, i)
  752. {
  753. if (cprec) {
  754. Next = cprec->GetNext();
  755. cprec->SetNext(this);
  756. } else {
  757. Next = tdbp->GetColumns();
  758. tdbp->SetColumns(this);
  759. } // endif cprec
  760. // Set additional DIR access method information for column.
  761. N = cdp->GetOffset();
  762. } // end of DIRCOL constructor
  763. /***********************************************************************/
  764. /* DIRCOL constructor used for copying columns. */
  765. /* tdbp is the pointer to the new table descriptor. */
  766. /***********************************************************************/
  767. DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
  768. {
  769. N = col1->N;
  770. } // end of DIRCOL copy constructor
  771. /***********************************************************************/
  772. /* ReadColumn: what this routine does is to access the information */
  773. /* corresponding to this column and convert it to buffer type. */
  774. /***********************************************************************/
  775. void DIRCOL::ReadColumn(PGLOBAL g)
  776. {
  777. PTDBDIR tdbp = (PTDBDIR)To_Tdb;
  778. if (trace)
  779. htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
  780. Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
  781. /*********************************************************************/
  782. /* Retrieve the information corresponding to the column number. */
  783. /*********************************************************************/
  784. switch (N) {
  785. #if defined(WIN32)
  786. case 0: Value->SetValue_psz(tdbp->Drive); break;
  787. #endif // WIN32
  788. case 1: Value->SetValue_psz(tdbp->Direc); break;
  789. case 2: Value->SetValue_psz(tdbp->Fname); break;
  790. case 3: Value->SetValue_psz(tdbp->Ftype); break;
  791. #if defined(WIN32)
  792. case 4: Value->SetValue((int)tdbp->FileData.attrib); break;
  793. case 5: Value->SetValue((int)tdbp->FileData.size); break;
  794. case 6: Value->SetValue((int)tdbp->FileData.time_write); break;
  795. case 7: Value->SetValue((int)tdbp->FileData.time_create); break;
  796. case 8: Value->SetValue((int)tdbp->FileData.time_access); break;
  797. #else // !WIN32
  798. case 4: Value->SetValue((int)tdbp->Fileinfo.st_mode); break;
  799. case 5: Value->SetValue((int)tdbp->Fileinfo.st_size); break;
  800. case 6: Value->SetValue((int)tdbp->Fileinfo.st_mtime); break;
  801. case 7: Value->SetValue((int)tdbp->Fileinfo.st_ctime); break;
  802. case 8: Value->SetValue((int)tdbp->Fileinfo.st_atime); break;
  803. case 9: Value->SetValue((int)tdbp->Fileinfo.st_uid); break;
  804. case 10: Value->SetValue((int)tdbp->Fileinfo.st_gid); break;
  805. #endif // !WIN32
  806. default:
  807. sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
  808. longjmp(g->jumper[g->jump_level], GetAmType());
  809. } // endswitch N
  810. } // end of ReadColumn
  811. /* ------------------------- Class TDBSDR ---------------------------- */
  812. /***********************************************************************/
  813. /* TABSDR copy constructors. */
  814. /***********************************************************************/
  815. TDBSDR::TDBSDR(PTDBSDR tdbp) : TDBDIR(tdbp)
  816. {
  817. Sub = tdbp->Sub;
  818. } // end of TDBSDR copy constructor
  819. // Method
  820. PTDB TDBSDR::CopyOne(PTABS t)
  821. {
  822. PTDB tp;
  823. PGLOBAL g = t->G; // Is this really useful ???
  824. tp = new(g) TDBSDR(this);
  825. tp->SetColumns(Columns);
  826. return tp;
  827. } // end of CopyOne
  828. /***********************************************************************/
  829. /* SDR GetMaxSize: returns the number of retrieved files. */
  830. /***********************************************************************/
  831. int TDBSDR::GetMaxSize(PGLOBAL g)
  832. {
  833. if (MaxSize < 0) {
  834. Path(g);
  835. MaxSize = FindInDir(g);
  836. } // endif MaxSize
  837. return MaxSize;
  838. } // end of GetMaxSize
  839. /***********************************************************************/
  840. /* SDR GetMaxSize: returns the number of retrieved files. */
  841. /***********************************************************************/
  842. int TDBSDR::FindInDir(PGLOBAL g)
  843. {
  844. int n = 0;
  845. size_t m = strlen(Direc);
  846. // Start searching files in the target directory.
  847. #if defined(WIN32)
  848. int h = _findfirst(Path(g), &FileData);
  849. if (h != -1) {
  850. for (n = 1;; n++)
  851. if (_findnext(h, &FileData))
  852. break;
  853. // Close the search handle.
  854. _findclose(h);
  855. } // endif h
  856. // Now search files in sub-directories.
  857. _makepath(Fpath, Drive, Direc, "*", "");
  858. h = _findfirst(Fpath, &FileData);
  859. if (h != -1) {
  860. while (true) {
  861. if (FileData.attrib & _A_SUBDIR && *FileData.name != '.') {
  862. // Look in the name sub-directory
  863. strcat(strcat(Direc, FileData.name), "\\");
  864. n += FindInDir(g);
  865. Direc[m] = '\0'; // Restore path
  866. } // endif SUBDIR
  867. if (_findnext(h, &FileData))
  868. break;
  869. } // endwhile
  870. // Close the search handle.
  871. _findclose(h);
  872. } // endif h
  873. #else // !WIN32
  874. int k;
  875. DIR *dir = opendir(Direc);
  876. if (!dir) {
  877. sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
  878. return -1;
  879. } // endif dir
  880. while ((Entry = readdir(dir))) {
  881. strcat(strcpy(Fpath, Direc), Entry->d_name);
  882. if (lstat(Fpath, &Fileinfo) < 0) {
  883. sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
  884. return -1;
  885. } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
  886. // Look in the name sub-directory
  887. strcat(strcat(Direc, Entry->d_name), "/");
  888. if ((k = FindInDir(g)) < 0)
  889. return k;
  890. else
  891. n += k;
  892. Direc[m] = '\0'; // Restore path
  893. } else if (S_ISREG(Fileinfo.st_mode))
  894. // Test whether the file name matches the table name filter
  895. if (!fnmatch(Pattern, Entry->d_name, 0))
  896. n++; // We have a match
  897. } // endwhile readdir
  898. // Close the DIR handle.
  899. closedir(dir);
  900. #endif // !WIN32
  901. return n;
  902. } // end of FindInDir
  903. /***********************************************************************/
  904. /* DIR Access Method opening routine. */
  905. /* Open first file, other will be opened sequencially when reading. */
  906. /***********************************************************************/
  907. bool TDBSDR::OpenDB(PGLOBAL g)
  908. {
  909. if (!Sub) {
  910. Path(g);
  911. Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
  912. Sub->Next = NULL;
  913. Sub->Prev = NULL;
  914. #if defined(WIN32)
  915. Sub->H = -1;
  916. Sub->Len = strlen(Direc);
  917. #else // !WIN32
  918. Sub->D = NULL;
  919. Sub->Len = 0;
  920. #endif // !WIN32
  921. } // endif To_Sub
  922. return TDBDIR::OpenDB(g);
  923. } // end of OpenDB
  924. /***********************************************************************/
  925. /* Data Base read routine for SDR access method. */
  926. /***********************************************************************/
  927. int TDBSDR::ReadDB(PGLOBAL g)
  928. {
  929. int rc;
  930. #if defined(WIN32)
  931. again:
  932. rc = TDBDIR::ReadDB(g);
  933. if (rc == RC_EF) {
  934. // Are there more files in sub-directories
  935. retry:
  936. do {
  937. if (Sub->H == -1) {
  938. _makepath(Fpath, Drive, Direc, "*", "");
  939. Sub->H = _findfirst(Fpath, &FileData);
  940. } else if (_findnext(Sub->H, &FileData)) {
  941. _findclose(Sub->H);
  942. Sub->H = -1;
  943. *FileData.name = '\0';
  944. } // endif findnext
  945. } while(*FileData.name == '.');
  946. if (Sub->H == -1) {
  947. // No more sub-directories. Are we in a sub-directory?
  948. if (!Sub->Prev)
  949. return rc; // No, all is finished
  950. // here we must continue in the parent directory
  951. Sub = Sub->Prev;
  952. goto retry;
  953. } else {
  954. // Search next sub-directory
  955. Direc[Sub->Len] = '\0';
  956. if (!Sub->Next) {
  957. PSUBDIR sup;
  958. sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
  959. sup->Next = NULL;
  960. sup->Prev = Sub;
  961. sup->H = -1;
  962. Sub->Next = sup;
  963. } // endif Next
  964. Sub = Sub->Next;
  965. strcat(strcat(Direc, FileData.name), "\\");
  966. Sub->Len = strlen(Direc);
  967. // Reset Hsearch used by TDBDIR::ReadDB
  968. _findclose(Hsearch);
  969. Hsearch = -1;
  970. goto again;
  971. } // endif H
  972. } // endif rc
  973. #else // !WIN32
  974. rc = RC_NF;
  975. again:
  976. if (!Sub->D)
  977. // Start searching files in the target directory.
  978. if (!(Sub->D = opendir(Direc))) {
  979. sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
  980. rc = RC_FX;
  981. } // endif dir
  982. while (rc == RC_NF)
  983. if ((Entry = readdir(Sub->D))) {
  984. // We need the Fileinfo structure to get info about the file
  985. strcat(strcpy(Fpath, Direc), Entry->d_name);
  986. if (lstat(Fpath, &Fileinfo) < 0) {
  987. sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
  988. rc = RC_FX;
  989. } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
  990. // Look in the name sub-directory
  991. if (!Sub->Next) {
  992. PSUBDIR sup;
  993. sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
  994. sup->Next = NULL;
  995. sup->Prev = Sub;
  996. Sub->Next = sup;
  997. } // endif Next
  998. Sub = Sub->Next;
  999. Sub->D = NULL;
  1000. Sub->Len = strlen(Direc);
  1001. strcat(strcat(Direc, Entry->d_name), "/");
  1002. goto again;
  1003. } else if (S_ISREG(Fileinfo.st_mode))
  1004. // Test whether the file name matches the table name filter
  1005. if (!fnmatch(Pattern, Entry->d_name, 0)) {
  1006. iFile++; // We have a match
  1007. _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
  1008. rc = RC_OK;
  1009. } // endif fnmatch
  1010. } else {
  1011. // No more files. Close the DIR handle.
  1012. closedir(Sub->D);
  1013. // Are we in a sub-directory?
  1014. if (Sub->Prev) {
  1015. // Yes, we must continue in the parent directory
  1016. Direc[Sub->Len] = '\0';
  1017. Sub = Sub->Prev;
  1018. } else
  1019. rc = RC_EF; // No, all is finished
  1020. } // endif Entry
  1021. #endif // !WIN32
  1022. return rc;
  1023. } // end of ReadDB
  1024. #if 0
  1025. /* ------------------------- Class TDBDHR ---------------------------- */
  1026. /***********************************************************************/
  1027. /* TABDHR constructors. */
  1028. /***********************************************************************/
  1029. TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
  1030. {
  1031. memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
  1032. Hsearch = INVALID_HANDLE_VALUE;
  1033. iFile = 0;
  1034. *Drive = '\0';
  1035. *Direc = '\0';
  1036. *Fname = '\0';
  1037. *Ftype = '\0';
  1038. } // end of TDBDHR standard constructor
  1039. TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
  1040. {
  1041. FileData = tdbp->FileData;
  1042. Hsearch = tdbp->Hsearch;
  1043. iFile = tdbp->iFile;
  1044. strcpy(Drive, tdbp->Drive);
  1045. strcpy(Direc, tdbp->Direc);
  1046. strcpy(Fname, tdbp->Fname);
  1047. strcpy(Ftype, tdbp->Ftype);
  1048. } // end of TDBDHR copy constructor
  1049. // Method
  1050. PTDB TDBDHR::CopyOne(PTABS t)
  1051. {
  1052. PTDB tp;
  1053. PGLOBAL g = t->G; // Is this really useful ???
  1054. tp = new(g) TDBDHR(this);
  1055. tp->Columns = Columns;
  1056. return tp;
  1057. } // end of CopyOne
  1058. /***********************************************************************/
  1059. /* Allocate DHR column description block. */
  1060. /***********************************************************************/
  1061. PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
  1062. {
  1063. return new(g) DHRCOL(cdp, this, cprec, n);
  1064. } // end of MakeCol
  1065. /***********************************************************************/
  1066. /* DHR GetMaxSize: returns the number of retrieved files. */
  1067. /***********************************************************************/
  1068. int TDBDHR::GetMaxSize(PGLOBAL g)
  1069. {
  1070. if (MaxSize < 0) {
  1071. char filename[_MAX_PATH];
  1072. int i, rc;
  1073. int n = -1;
  1074. HANDLE h;
  1075. PDBUSER dup = PlgGetUser(g);
  1076. PlugSetPath(filename, To_File, dup->Path);
  1077. // Start searching files in the target directory.
  1078. h = FindFirstFile(filename, &FileData);
  1079. if (h == INVALID_HANDLE_VALUE) {
  1080. switch (rc = GetLastError()) {
  1081. case ERROR_NO_MORE_FILES:
  1082. case ERROR_FILE_NOT_FOUND:
  1083. n = 0;
  1084. break;
  1085. default:
  1086. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  1087. FORMAT_MESSAGE_IGNORE_INSERTS,
  1088. NULL, rc, 0,
  1089. (LPTSTR)&filename, sizeof(filename), NULL);
  1090. sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
  1091. } // endswitch rc
  1092. } else {
  1093. for (n = 1;; n++)
  1094. if (!FindNextFile(h, &FileData)) {
  1095. rc = GetLastError();
  1096. if (rc != ERROR_NO_MORE_FILES) {
  1097. sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
  1098. n = -1;
  1099. } // endif rc
  1100. break;
  1101. } // endif FindNextFile
  1102. // Close the search handle.
  1103. if (!FindClose(h) && n != -1)
  1104. strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
  1105. } // endif Hsearch
  1106. MaxSize = n;
  1107. } // endif MaxSize
  1108. return MaxSize;
  1109. } // end of GetMaxSize
  1110. /***********************************************************************/
  1111. /* DHR Access Method opening routine. */
  1112. /* Open first file, other will be opened sequencially when reading. */
  1113. /***********************************************************************/
  1114. bool TDBDHR::OpenDB(PGLOBAL g)
  1115. {
  1116. if (trace)
  1117. htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
  1118. this, Tdb_No, Use, Mode);
  1119. if (Use == USE_OPEN) {
  1120. /*******************************************************************/
  1121. /* Table already open, reopen it. */
  1122. /*******************************************************************/
  1123. CloseDB(g);
  1124. SetUse(USE_READY);
  1125. } // endif use
  1126. /*********************************************************************/
  1127. /* Direct access needed for join or sorting. */
  1128. /*********************************************************************/
  1129. if (NeedIndexing(g)) {
  1130. // Direct access of DHR tables is not implemented yet
  1131. sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
  1132. return true;
  1133. } // endif NeedIndexing
  1134. Use = USE_OPEN;
  1135. return false;
  1136. } // end of OpenDB
  1137. /***********************************************************************/
  1138. /* Data Base read routine for DHR access method. */
  1139. /***********************************************************************/
  1140. int TDBDHR::ReadDB(PGLOBAL g)
  1141. {
  1142. int rc = RC_OK;
  1143. DWORD erc;
  1144. if (Hsearch == INVALID_HANDLE_VALUE) {
  1145. char *filename[_MAX_PATH];
  1146. PDBUSER dup = PlgGetUser(g);
  1147. PlugSetPath(filename, To_File, dup->Path);
  1148. _splitpath(filename, Drive, Direc, NULL, NULL);
  1149. /*******************************************************************/
  1150. /* Start searching files in the target directory. */
  1151. /*******************************************************************/
  1152. Hsearch = FindFirstFile(filename, &FileData);
  1153. if (Hsearch != INVALID_HANDLE_VALUE)
  1154. iFile = 1;
  1155. else switch (erc = GetLastError()) {
  1156. case ERROR_NO_MORE_FILES:
  1157. case ERROR_FILE_NOT_FOUND:
  1158. // case ERROR_PATH_NOT_FOUND: ???????
  1159. rc = RC_EF;
  1160. break;
  1161. default:
  1162. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  1163. FORMAT_MESSAGE_IGNORE_INSERTS,
  1164. NULL, erc, 0,
  1165. (LPTSTR)&filename, sizeof(filename), NULL);
  1166. sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
  1167. rc = RC_FX;
  1168. } // endswitch erc
  1169. } else {
  1170. if (!FindNextFile(Hsearch, &FileData)) {
  1171. DWORD erc = GetLastError();
  1172. if (erc != ERROR_NO_MORE_FILES) {
  1173. sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
  1174. FindClose(Hsearch);
  1175. rc = RC_FX;
  1176. } else
  1177. rc = RC_EF;
  1178. } else
  1179. iFile++;
  1180. } // endif Hsearch
  1181. if (rc == RC_OK)
  1182. _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
  1183. return rc;
  1184. } // end of ReadDB
  1185. /***********************************************************************/
  1186. /* Data Base close routine for MUL access method. */
  1187. /***********************************************************************/
  1188. void TDBDHR::CloseDB(PGLOBAL g)
  1189. {
  1190. // Close the search handle.
  1191. if (!FindClose(Hsearch)) {
  1192. strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
  1193. longjmp(g->jumper[g->jump_level], GetAmType());
  1194. } // endif FindClose
  1195. iFile = 0;
  1196. Hsearch = INVALID_HANDLE_VALUE;
  1197. } // end of CloseDB
  1198. // ------------------------ DHRCOL functions ----------------------------
  1199. /***********************************************************************/
  1200. /* DHRCOL public constructor. */
  1201. /***********************************************************************/
  1202. DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
  1203. : COLBLK(cdp, tdbp, i)
  1204. {
  1205. if (cprec) {
  1206. Next = cprec->GetNext();
  1207. cprec->SetNext(this);
  1208. } else {
  1209. Next = tdbp->GetColumns();
  1210. tdbp->SetColumns(this);
  1211. } // endif cprec
  1212. // Set additional DHR access method information for column.
  1213. N = cdp->GetOffset();
  1214. } // end of DOSCOL constructor
  1215. /***********************************************************************/
  1216. /* DHRCOL constructor used for copying columns. */
  1217. /* tdbp is the pointer to the new table descriptor. */
  1218. /***********************************************************************/
  1219. DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
  1220. {
  1221. N = col1->N;
  1222. } // end of DHRCOL copy constructor
  1223. /***********************************************************************/
  1224. /* ReadColumn: what this routine does is to access the information */
  1225. /* corresponding to this column and convert it to buffer type. */
  1226. /***********************************************************************/
  1227. void DHRCOL::ReadColumn(PGLOBAL g)
  1228. {
  1229. int rc;
  1230. PTDBDHR tdbp = (PTDBDHR)To_Tdb;
  1231. if (trace)
  1232. htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
  1233. Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
  1234. /*********************************************************************/
  1235. /* Retrieve the information corresponding to the column number. */
  1236. /*********************************************************************/
  1237. switch (N) {
  1238. case 0: // Drive
  1239. Value->SetValue(Drive, _MAX_DRIVE);
  1240. break;
  1241. case 1: // Path
  1242. Value->SetValue(Direc, _MAX_DHR);
  1243. break;
  1244. case 2: // Name
  1245. Value->SetValue(Fname, _MAX_FNAME);
  1246. break;
  1247. case 3: // Extention
  1248. Value->SetValue(Ftype, _MAX_EXT);
  1249. break;
  1250. case 4: // Extention
  1251. Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
  1252. break;
  1253. case 5:
  1254. Value->SetValue(tdbp->FileData.dwFileAttributes);
  1255. break;
  1256. case 6:
  1257. Value->SetValue(..................
  1258. } // end of ReadColumn
  1259. #endif // 0