1/************* TabMul C++ Program Source Code File (.CPP) **************/
2/* PROGRAM NAME: TABMUL */
3/* ------------- */
4/* Version 1.9 */
5/* */
6/* COPYRIGHT: */
7/* ---------- */
8/* (C) Copyright to PlugDB Software Development 2003 - 2017 */
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/***********************************************************************/
37/* Include relevant section of system dependant header files. */
38/***********************************************************************/
39#include "my_global.h"
40#if defined(__WIN__)
41#include <stdlib.h>
42#include <stdio.h>
43#if defined(__BORLANDC__)
44#define __MFC_COMPAT__ // To define min/max as macro
45#endif
46//#include <windows.h>
47#if defined(PATHMATCHSPEC)
48#include "Shlwapi.h"
49//using namespace std;
50#pragma comment(lib,"shlwapi.lib")
51#endif // PATHMATCHSPEC
52#else
53#if defined(UNIX)
54#include <fnmatch.h>
55#include <errno.h>
56#include <stdlib.h>
57#include <stdio.h>
58#include <string.h>
59#include "osutil.h"
60#else
61//#include <io.h>
62#endif
63//#include <fcntl.h>
64#endif
65
66/***********************************************************************/
67/* Include application header files: */
68/***********************************************************************/
69#include "global.h" // global declarations
70#include "plgdbsem.h" // DB application declarations
71#include "reldef.h" // DB definition declares
72#include "filamtxt.h"
73#include "tabdos.h" // TDBDOS and DOSCOL class dcls
74#include "tabmul.h" // TDBMUL and MULCOL classes dcls
75
76/* ------------------------- Class TDBMUL ---------------------------- */
77
78/***********************************************************************/
79/* TABMUL constructors. */
80/***********************************************************************/
81TDBMUL::TDBMUL(PTDB tdbp) : TDBASE(tdbp->GetDef())
82 {
83 Tdbp = tdbp;
84 Filenames = NULL;
85 Rows = 0;
86 Mul = tdbp->GetDef()->GetMultiple();
87 NumFiles = 0;
88 iFile = 0;
89 } // end of TDBMUL standard constructor
90
91TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp)
92 {
93 Tdbp = tdbp->Tdbp;
94 Filenames = tdbp->Filenames;
95 Rows = tdbp->Rows;
96 Mul = tdbp->Mul;
97 NumFiles = tdbp->NumFiles;
98 iFile = tdbp->iFile;
99 } // end of TDBMUL copy constructor
100
101// Method
102PTDB TDBMUL::Clone(PTABS t)
103 {
104 PTDBMUL tp;
105 PGLOBAL g = t->G; // Is this really useful ???
106
107 tp = new(g) TDBMUL(this);
108 tp->Tdbp = Tdbp->Clone(t);
109 tp->Columns = tp->Tdbp->GetColumns();
110 return tp;
111 } // end of Clone
112
113PTDB TDBMUL::Duplicate(PGLOBAL g)
114 {
115 PTDBMUL tmup = new(g) TDBMUL(this);
116
117 tmup->Tdbp = Tdbp->Duplicate(g);
118 return tmup;
119 } // end of Duplicate
120
121/***********************************************************************/
122/* Initializes the table filename list. */
123/* Note: tables created by concatenating the file components without */
124/* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
125/* have a LRECL that is the sum of the lengths of all components. */
126/* This is why we use a big filename array to take care of that. */
127/***********************************************************************/
128bool TDBMUL::InitFileNames(PGLOBAL g)
129 {
130#define PFNZ 4096
131#define FNSZ (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
132 PTDBDIR dirp;
133 PSZ pfn[PFNZ];
134 PSZ filename;
135 int rc, n = 0;
136
137 if (trace(1))
138 htrc("in InitFileName: fn[]=%d\n", FNSZ);
139
140 filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
141
142 // The sub table may need to refer to the Table original block
143 Tdbp->SetTable(To_Table); // Was not set at construction
144
145 PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
146
147 if (trace(1))
148 htrc("InitFileName: fn='%s'\n", filename);
149
150 if (Mul != 2) {
151 /*******************************************************************/
152 /* To_File is a multiple name with special characters */
153 /*******************************************************************/
154 if (Mul == 1)
155 dirp = new(g) TDBDIR(PlugDup(g, filename));
156 else // Mul == 3 (Subdir)
157 dirp = new(g) TDBSDR(PlugDup(g, filename));
158
159 if (dirp->OpenDB(g))
160 return true;
161
162 if (trace(1) && Mul == 3) {
163 int nf = ((PTDBSDR)dirp)->FindInDir(g);
164 htrc("Number of files = %d\n", nf);
165 } // endif trace
166
167 while (true)
168 if ((rc = dirp->ReadDB(g)) == RC_OK) {
169#if defined(__WIN__)
170 strcat(strcpy(filename, dirp->Drive), dirp->Direc);
171#else // !__WIN__
172 strcpy(filename, dirp->Direc);
173#endif // !__WIN__
174 strcat(strcat(filename, dirp->Fname), dirp->Ftype);
175 pfn[n++] = PlugDup(g, filename);
176 } else
177 break;
178
179 dirp->CloseDB(g);
180
181 if (rc == RC_FX)
182 return true;
183
184 } else {
185 /*******************************************************************/
186 /* To_File is the name of a file containing the file name list */
187 /*******************************************************************/
188 char *p;
189 FILE *stream;
190
191 if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r")))
192 return true;
193
194 while (n < PFNZ) {
195 if (!fgets(filename, FNSZ, stream)) {
196 fclose(stream);
197 break;
198 } // endif fgets
199
200 p = filename + strlen(filename) - 1;
201
202#if !defined(__WIN__)
203 // Data files can be imported from Windows (having CRLF)
204 if (*p == '\n' || *p == '\r') {
205 // is this enough for Unix ???
206 p--; // Eliminate ending CR or LF character
207
208 if (p >= filename)
209 // is this enough for Unix ???
210 if (*p == '\n' || *p == '\r')
211 p--; // Eliminate ending CR or LF character
212
213 } // endif p
214
215#else
216 if (*p == '\n')
217 p--; // Eliminate ending new-line character
218#endif
219 // Trim rightmost blanks
220 for (; p >= filename && *p == ' '; p--) ;
221
222 *(++p) = '\0';
223
224 // Suballocate the file name
225 pfn[n++] = PlugDup(g, filename);
226 } // endfor n
227
228 } // endif Mul
229
230 if (n) {
231 Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
232
233 for (int i = 0; i < n; i++)
234 Filenames[i] = pfn[i];
235
236 } else {
237 Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
238 Filenames[0] = NULL;
239 } // endif n
240
241 NumFiles = n;
242 return false;
243 } // end of InitFileNames
244
245/***********************************************************************/
246/* The table column list is the sub-table column list. */
247/***********************************************************************/
248PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num)
249 {
250 PCOL cp;
251
252 /*********************************************************************/
253 /* Because special columns are directly added to the MUL block, */
254 /* make sure that the sub-table has the same column list, before */
255 /* and after the call to the ColDB function. */
256 /*********************************************************************/
257 Tdbp->SetColumns(Columns);
258 cp = Tdbp->ColDB(g, name, num);
259 Columns = Tdbp->GetColumns();
260 return cp;
261} // end of ColDB
262
263/***********************************************************************/
264/* MUL GetProgMax: get the max value for progress information. */
265/***********************************************************************/
266int TDBMUL::GetProgMax(PGLOBAL g)
267 {
268 if (!Filenames && InitFileNames(g))
269 return -1;
270
271 return NumFiles; // This is a temporary setting
272 } // end of GetProgMax
273
274/***********************************************************************/
275/* MUL GetProgCur: get the current value for progress information. */
276/***********************************************************************/
277int TDBMUL::GetProgCur(void)
278 {
279 return iFile; // This is a temporary setting
280 } // end of GetProgMax
281
282/***********************************************************************/
283/* MUL Cardinality: returns table cardinality in number of rows. */
284/* This function can be called with a null argument to test the */
285/* availability of Cardinality implementation (1 yes, 0 no). */
286/* Can be used on Multiple FIX table only. */
287/***********************************************************************/
288int TDBMUL::Cardinality(PGLOBAL g)
289 {
290 if (!g)
291 return Tdbp->Cardinality(g);
292
293 if (!Filenames && InitFileNames(g))
294 return -1;
295
296 int n, card = 0;
297
298 for (int i = 0; i < NumFiles; i++) {
299 Tdbp->SetFile(g, Filenames[i]);
300 Tdbp->ResetSize();
301
302 if ((n = Tdbp->Cardinality(g)) < 0) {
303// strcpy(g->Message, MSG(BAD_CARDINALITY));
304 return -1;
305 } // endif n
306
307 card += n;
308 } // endfor i
309
310 return card;
311 } // end of Cardinality
312
313/***********************************************************************/
314/* Sum up the sizes of all sub-tables. */
315/***********************************************************************/
316int TDBMUL::GetMaxSize(PGLOBAL g)
317 {
318 if (MaxSize < 0) {
319 int i;
320 int mxsz;
321
322 if (trace(1))
323 htrc("TDBMUL::GetMaxSize: Filenames=%p\n", Filenames);
324
325 if (!Filenames && InitFileNames(g))
326 return -1;
327
328 if (Use == USE_OPEN) {
329 strcpy(g->Message, MSG(MAXSIZE_ERROR));
330 return -1;
331 } else
332 MaxSize = 0;
333
334 for (i = 0; i < NumFiles; i++) {
335 Tdbp->SetFile(g, Filenames[i]);
336 Tdbp->ResetSize();
337
338 if ((mxsz = Tdbp->GetMaxSize(g)) < 0) {
339 MaxSize = -1;
340 return mxsz;
341 } // endif mxsz
342
343 MaxSize += mxsz;
344 } // endfor i
345
346 } // endif MaxSize
347
348 return MaxSize;
349 } // end of GetMaxSize
350
351/***********************************************************************/
352/* Reset read/write position values. */
353/***********************************************************************/
354void TDBMUL::ResetDB(void)
355 {
356 for (PCOL colp = Columns; colp; colp = colp->GetNext())
357 if (colp->GetAmType() == TYPE_AM_FILID)
358 colp->COLBLK::Reset();
359
360 Tdbp->ResetDB();
361 } // end of ResetDB
362
363/***********************************************************************/
364/* Returns RowId if b is false or Rownum if b is true. */
365/***********************************************************************/
366int TDBMUL::RowNumber(PGLOBAL g, bool b)
367 {
368 return ((b) ? 0 : Rows)
369 + ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1);
370 } // end of RowNumber
371
372/***********************************************************************/
373/* MUL Access Method opening routine. */
374/* Open first file, other will be opened sequencially when reading. */
375/***********************************************************************/
376bool TDBMUL::OpenDB(PGLOBAL g)
377 {
378 if (trace(1))
379 htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
380 this, Tdb_No, Use, To_Key_Col, Mode);
381
382 if (Use == USE_OPEN) {
383 /*******************************************************************/
384 /* Table already open, replace it at its beginning. */
385 /*******************************************************************/
386 if (Filenames[iFile = 0]) {
387 Tdbp->CloseDB(g);
388 Tdbp->SetUse(USE_READY);
389 Tdbp->SetFile(g, Filenames[iFile = 0]);
390 Tdbp->ResetSize();
391 Rows = 0;
392 ResetDB();
393 return Tdbp->OpenDB(g); // Re-open with new file name
394 } else
395 return false;
396
397 } // endif use
398
399 /*********************************************************************/
400 /* We need to calculate MaxSize before opening the query. */
401 /*********************************************************************/
402 if (GetMaxSize(g) < 0)
403 return true;
404
405 /*********************************************************************/
406 /* Open the first table file of the list. */
407 /*********************************************************************/
408//if (!Filenames && InitFileNames(g)) // was done in GetMaxSize
409// return true;
410
411 if (Filenames[iFile = 0]) {
412 Tdbp->SetFile(g, Filenames[0]);
413 Tdbp->SetMode(Mode);
414 Tdbp->ResetDB();
415 Tdbp->ResetSize();
416
417 if (Tdbp->OpenDB(g))
418 return true;
419
420 } // endif *Filenames
421
422 Use = USE_OPEN;
423 return false;
424 } // end of OpenDB
425
426/***********************************************************************/
427/* ReadDB: Data Base read routine for MUL access method. */
428/***********************************************************************/
429int TDBMUL::ReadDB(PGLOBAL g)
430 {
431 int rc;
432
433 if (NumFiles == 0)
434 return RC_EF;
435 else if (To_Kindex) {
436 /*******************************************************************/
437 /* Reading is by an index table. */
438 /*******************************************************************/
439 strcpy(g->Message, MSG(NO_INDEX_READ));
440 rc = RC_FX;
441 } else {
442 /*******************************************************************/
443 /* Now start the reading process. */
444 /*******************************************************************/
445 retry:
446 rc = Tdbp->ReadDB(g);
447
448 if (rc == RC_EF) {
449 if (Tdbp->GetDef()->GetPseudo() & 1)
450 // Total number of rows met so far
451 Rows += Tdbp->RowNumber(g) - 1;
452
453 if (++iFile < NumFiles) {
454 /***************************************************************/
455 /* Continue reading from next table file. */
456 /***************************************************************/
457 Tdbp->CloseDB(g);
458 Tdbp->SetUse(USE_READY);
459 Tdbp->SetFile(g, Filenames[iFile]);
460 Tdbp->ResetSize();
461 ResetDB();
462
463 if (Tdbp->OpenDB(g)) // Re-open with new file name
464 return RC_FX;
465
466 goto retry;
467 } // endif iFile
468
469 } else if (rc == RC_FX)
470 strcat(strcat(strcat(g->Message, " ("), Tdbp->GetFile(g)), ")");
471
472 } // endif To_Kindex
473
474 return rc;
475 } // end of ReadDB
476
477/***********************************************************************/
478/* Data Base write routine for MUL access method. */
479/***********************************************************************/
480int TDBMUL::WriteDB(PGLOBAL g)
481 {
482 return Tdbp->WriteDB(g);
483// strcpy(g->Message, MSG(TABMUL_READONLY));
484// return RC_FX; // NIY
485 } // end of WriteDB
486
487/***********************************************************************/
488/* Data Base delete line routine for MUL access method. */
489/***********************************************************************/
490int TDBMUL::DeleteDB(PGLOBAL g, int)
491 {
492 // When implementing DELETE_MODE InitFileNames must be updated to
493 // eliminate CRLF under Windows if the file is read in binary.
494 strcpy(g->Message, MSG(TABMUL_READONLY));
495 return RC_FX; // NIY
496 } // end of DeleteDB
497
498/***********************************************************************/
499/* Data Base close routine for MUL access method. */
500/***********************************************************************/
501void TDBMUL::CloseDB(PGLOBAL g)
502 {
503 if (NumFiles > 0) {
504 Tdbp->CloseDB(g);
505 iFile = NumFiles;
506 } // endif NumFiles
507
508 } // end of CloseDB
509
510#if 0
511/* ------------------------- Class TDBMSD ---------------------------- */
512
513 // Method
514PTDB TDBMSD::Clone(PTABS t)
515{
516 PTDBMSD tp;
517 PGLOBAL g = t->G; // Is this really useful ???
518
519 tp = new(g) TDBMSD(this);
520 tp->Tdbp = Tdbp->Clone(t);
521 tp->Columns = tp->Tdbp->GetColumns();
522 return tp;
523} // end of Clone
524
525PTDB TDBMSD::Duplicate(PGLOBAL g)
526{
527 PTDBMSD tmup = new(g) TDBMSD(this);
528
529 tmup->Tdbp = Tdbp->Duplicate(g);
530 return tmup;
531} // end of Duplicate
532
533/***********************************************************************/
534/* Initializes the table filename list. */
535/* Note: tables created by concatenating the file components without */
536/* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
537/* have a LRECL that is the sum of the lengths of all components. */
538/* This is why we use a big filename array to take care of that. */
539/***********************************************************************/
540bool TDBMSD::InitFileNames(PGLOBAL g)
541{
542#define PFNZ 4096
543#define FNSZ (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
544 PTDBSDR dirp;
545 PSZ pfn[PFNZ];
546 PSZ filename;
547 int rc, n = 0;
548
549 if (trace(1))
550 htrc("in InitFileName: fn[]=%d\n", FNSZ);
551
552 filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
553
554 // The sub table may need to refer to the Table original block
555 Tdbp->SetTable(To_Table); // Was not set at construction
556
557 PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
558
559 if (trace(1))
560 htrc("InitFileName: fn='%s'\n", filename);
561
562 dirp = new(g) TDBSDR(filename);
563
564 if (dirp->OpenDB(g))
565 return true;
566
567 while (true)
568 if ((rc = dirp->ReadDB(g)) == RC_OK) {
569#if defined(__WIN__)
570 strcat(strcpy(filename, dirp->Drive), dirp->Direc);
571#else // !__WIN__
572 strcpy(filename, dirp->Direc);
573#endif // !__WIN__
574 strcat(strcat(filename, dirp->Fname), dirp->Ftype);
575 pfn[n++] = PlugDup(g, filename);
576 } else
577 break;
578
579 if (rc == RC_FX)
580 return true;
581
582 if (n) {
583 Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
584
585 for (int i = 0; i < n; i++)
586 Filenames[i] = pfn[i];
587
588 } else {
589 Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
590 Filenames[0] = NULL;
591 } // endif n
592
593 NumFiles = n;
594 return false;
595} // end of InitFileNames
596#endif // 0
597
598 /* --------------------------- Class DIRDEF -------------------------- */
599
600/***********************************************************************/
601/* DefineAM: define specific AM block values from XDB file. */
602/***********************************************************************/
603bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR, int)
604 {
605 Desc = Fn = GetStringCatInfo(g, "Filename", NULL);
606 Incl = GetBoolCatInfo("Subdir", false);
607 Huge = GetBoolCatInfo("Huge", false);
608 Nodir = GetBoolCatInfo("Nodir", true);
609 return false;
610 } // end of DefineAM
611
612/***********************************************************************/
613/* GetTable: makes a new Table Description Block. */
614/***********************************************************************/
615PTDB DIRDEF::GetTable(PGLOBAL g, MODE)
616 {
617#if 0
618 if (Huge)
619 return new(g) TDBDHR(this); // Not implemented yet
620 else
621#endif
622 if (Incl)
623 return new(g) TDBSDR(this); // Including sub-directory files
624 else
625 return new(g) TDBDIR(this); // Not Including sub-directory files
626
627 } // end of GetTable
628
629/* ------------------------- Class TDBDIR ---------------------------- */
630
631/***********************************************************************/
632/* TABDIR constructors. */
633/***********************************************************************/
634void TDBDIR::Init(void)
635{
636 iFile = 0;
637#if defined(__WIN__)
638 Dvalp = NULL;
639 memset(&FileData, 0, sizeof(_finddata_t));
640 hSearch = INVALID_HANDLE_VALUE;
641 *Drive = '\0';
642#else // !__WIN__
643 memset(&Fileinfo, 0, sizeof(struct stat));
644 Entry = NULL;
645 Dir = NULL;
646 Done = false;
647 *Pattern = '\0';
648#endif // !__WIN__
649 *Fpath = '\0';
650 *Direc = '\0';
651 *Fname = '\0';
652 *Ftype = '\0';
653} // end of Init
654
655TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
656{
657 To_File = tdp->Fn;
658 Nodir = tdp->Nodir;
659 Init();
660} // end of TDBDIR standard constructor
661
662TDBDIR::TDBDIR(PSZ fpat) : TDBASE((PTABDEF)NULL)
663{
664 To_File = fpat;
665 Nodir = true;
666 Init();
667} // end of TDBDIR constructor
668
669/***********************************************************************/
670/* Initialize/get the components of the search file pattern. */
671/***********************************************************************/
672char* TDBDIR::Path(PGLOBAL g)
673 {
674 PCATLG cat = PlgGetCatalog(g);
675 PTABDEF defp = (PTABDEF)To_Def;
676
677#if defined(__WIN__)
678 if (!*Drive) {
679 PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
680 _splitpath(Fpath, Drive, Direc, Fname, Ftype);
681 } else
682 _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull for TDBSDR
683
684 return Fpath;
685#else // !__WIN__
686 if (!Done) {
687 PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
688 _splitpath(Fpath, NULL, Direc, Fname, Ftype);
689 strcat(strcpy(Pattern, Fname), Ftype);
690 Done = true;
691 } // endif Done
692
693 return Pattern;
694#endif // !__WIN__
695 } // end of Path
696
697/***********************************************************************/
698/* Allocate DIR column description block. */
699/***********************************************************************/
700PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
701 {
702 return new(g) DIRCOL(cdp, this, cprec, n);
703 } // end of MakeCol
704
705/***********************************************************************/
706/* DIR GetMaxSize: returns the number of retrieved files. */
707/***********************************************************************/
708int TDBDIR::GetMaxSize(PGLOBAL g)
709 {
710 if (MaxSize < 0) {
711 int rc, n = -1;
712#if defined(__WIN__)
713
714 // Start searching files in the target directory.
715 hSearch = FindFirstFile(Path(g), &FileData);
716
717 if (hSearch == INVALID_HANDLE_VALUE) {
718 rc = GetLastError();
719
720 if (rc != ERROR_FILE_NOT_FOUND) {
721 char buf[512];
722
723 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
724 FORMAT_MESSAGE_IGNORE_INSERTS,
725 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
726 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
727 return -1;
728 } // endif rc
729
730 return 0;
731 } // endif hSearch
732
733 while (true) {
734 if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
735 n++;
736
737 if (!FindNextFile(hSearch, &FileData)) {
738 rc = GetLastError();
739
740 if (rc != ERROR_NO_MORE_FILES) {
741 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
742 FindClose(hSearch);
743 return -1;
744 } // endif rc
745
746 break;
747 } // endif Next
748
749 } // endwhile
750
751 // Close the search handle.
752 FindClose(hSearch);
753#else // !__WIN__
754 Path(g);
755
756 // Start searching files in the target directory.
757 if (!(Dir = opendir(Direc))) {
758 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
759 return -1;
760 } // endif dir
761
762 while ((Entry = readdir(Dir))) {
763 strcat(strcpy(Fpath, Direc), Entry->d_name);
764
765 if (lstat(Fpath, &Fileinfo) < 0) {
766 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
767 return -1;
768 } else if (S_ISREG(Fileinfo.st_mode))
769 // Test whether the file name matches the table name filter
770 if (!fnmatch(Pattern, Entry->d_name, 0))
771 n++; // We have a match
772
773 } // endwhile Entry
774
775 // Close the DIR handle.
776 closedir(Dir);
777#endif // !__WIN__
778 MaxSize = n;
779 } // endif MaxSize
780
781 return MaxSize;
782 } // end of GetMaxSize
783
784/***********************************************************************/
785/* DIR Access Method opening routine. */
786/* Open first file, other will be opened sequencially when reading. */
787/***********************************************************************/
788bool TDBDIR::OpenDB(PGLOBAL g)
789 {
790 if (trace(1))
791 htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
792 this, Tdb_No, Use, Mode);
793
794 if (Use == USE_OPEN) {
795 /*******************************************************************/
796 /* Table already open, reopen it. */
797 /*******************************************************************/
798 CloseDB(g);
799 SetUse(USE_READY);
800 } // endif use
801
802 Use = USE_OPEN;
803#if !defined(__WIN__)
804 Path(g); // Be sure it is done
805 Dir = NULL; // For ReadDB
806#endif // !__WIN__
807 return false;
808 } // end of OpenDB
809
810/***********************************************************************/
811/* Data Base read routine for DIR access method. */
812/***********************************************************************/
813int TDBDIR::ReadDB(PGLOBAL g)
814 {
815 int rc = RC_OK;
816
817#if defined(__WIN__)
818 do {
819 if (hSearch == INVALID_HANDLE_VALUE) {
820 /*****************************************************************/
821 /* Start searching files in the target directory. The use of */
822 /* the Path function is required when called from TDBSDR. */
823 /*****************************************************************/
824 hSearch = FindFirstFile(Path(g), &FileData);
825
826 if (hSearch == INVALID_HANDLE_VALUE) {
827 rc = RC_EF;
828 break;
829 } else
830 iFile++;
831
832 } else {
833 if (!FindNextFile(hSearch, &FileData)) {
834 // Restore file name and type pattern
835 _splitpath(To_File, NULL, NULL, Fname, Ftype);
836 rc = RC_EF;
837 break;
838 } else
839 iFile++;
840
841 } // endif hSearch
842
843 } while (Nodir && FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
844
845 if (rc == RC_OK)
846 _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
847
848#else // !Win32
849 rc = RC_NF;
850
851 if (!Dir)
852 // Start searching files in the target directory.
853 if (!(Dir = opendir(Direc))) {
854 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
855 rc = RC_FX;
856 } // endif dir
857
858 while (rc == RC_NF)
859 if ((Entry = readdir(Dir))) {
860 // We need the Fileinfo structure to get info about the file
861 strcat(strcpy(Fpath, Direc), Entry->d_name);
862
863 if (lstat(Fpath, &Fileinfo) < 0) {
864 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
865 rc = RC_FX;
866 } else if (S_ISREG(Fileinfo.st_mode))
867 // Test whether the file name matches the table name filter
868 if (!fnmatch(Pattern, Entry->d_name, 0)) {
869 iFile++; // We have a match
870 _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
871 rc = RC_OK;
872 } // endif fnmatch
873
874 } else {
875 // Restore file name and type pattern
876 _splitpath(To_File, NULL, NULL, Fname, Ftype);
877 rc = RC_EF;
878 } // endif Entry
879
880#endif // !__WIN__
881
882 return rc;
883 } // end of ReadDB
884
885/***********************************************************************/
886/* Data Base write routine for DIR access method. */
887/***********************************************************************/
888int TDBDIR::WriteDB(PGLOBAL g)
889 {
890 strcpy(g->Message, MSG(TABDIR_READONLY));
891 return RC_FX; // NIY
892 } // end of WriteDB
893
894/***********************************************************************/
895/* Data Base delete line routine for DIR access method. */
896/***********************************************************************/
897int TDBDIR::DeleteDB(PGLOBAL g, int)
898 {
899 strcpy(g->Message, MSG(TABDIR_READONLY));
900 return RC_FX; // NIY
901 } // end of DeleteDB
902
903/***********************************************************************/
904/* Data Base close routine for MUL access method. */
905/***********************************************************************/
906void TDBDIR::CloseDB(PGLOBAL)
907 {
908#if defined(__WIN__)
909 // Close the search handle.
910 FindClose(hSearch);
911 hSearch = INVALID_HANDLE_VALUE;
912#else // !__WIN__
913 // Close the DIR handle
914 if (Dir) {
915 closedir(Dir);
916 Dir = NULL;
917 } // endif dir
918#endif // !__WIN__
919 iFile = 0;
920 } // end of CloseDB
921
922// ------------------------ DIRCOL functions ----------------------------
923
924/***********************************************************************/
925/* DIRCOL public constructor. */
926/***********************************************************************/
927DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
928 : COLBLK(cdp, tdbp, i)
929 {
930 if (cprec) {
931 Next = cprec->GetNext();
932 cprec->SetNext(this);
933 } else {
934 Next = tdbp->GetColumns();
935 tdbp->SetColumns(this);
936 } // endif cprec
937
938 // Set additional DIR access method information for column.
939 Tdbp = (PTDBDIR)tdbp;
940 N = cdp->GetOffset();
941 } // end of DIRCOL constructor
942
943/***********************************************************************/
944/* DIRCOL constructor used for copying columns. */
945/* tdbp is the pointer to the new table descriptor. */
946/***********************************************************************/
947DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
948 {
949 Tdbp = (PTDBDIR)tdbp;
950 N = col1->N;
951 } // end of DIRCOL copy constructor
952
953#if defined(__WIN__)
954/***********************************************************************/
955/* Retrieve time information from FileData. */
956/***********************************************************************/
957void DIRCOL::SetTimeValue(PGLOBAL g, FILETIME& ftime)
958{
959 char tsp[24];
960 SYSTEMTIME stp;
961
962 if (FileTimeToSystemTime(&ftime, &stp)) {
963 sprintf(tsp, "%04d-%02d-%02d %02d:%02d:%02d",
964 stp.wYear, stp.wMonth, stp.wDay, stp.wHour, stp.wMinute, stp.wSecond);
965
966 if (Value->GetType() != TYPE_STRING) {
967 if (!Tdbp->Dvalp)
968 Tdbp->Dvalp = AllocateValue(g, TYPE_DATE, 20, 0, false,
969 "YYYY-MM-DD hh:mm:ss");
970
971 Tdbp->Dvalp->SetValue_psz(tsp);
972 Value->SetValue_pval(Tdbp->Dvalp);
973 } else
974 Value->SetValue_psz(tsp);
975
976 } else
977 Value->Reset();
978
979} // end of SetTimeValue
980#endif // __WIN__
981
982/***********************************************************************/
983/* ReadColumn: what this routine does is to access the information */
984/* corresponding to this column and convert it to buffer type. */
985/***********************************************************************/
986void DIRCOL::ReadColumn(PGLOBAL g)
987 {
988 if (trace(1))
989 htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
990 Name, Tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
991
992 /*********************************************************************/
993 /* Retrieve the information corresponding to the column number. */
994 /*********************************************************************/
995 switch (N) {
996#if defined(__WIN__)
997 case 0: Value->SetValue_psz(Tdbp->Drive); break;
998#endif // __WIN__
999 case 1: Value->SetValue_psz(Tdbp->Direc); break;
1000 case 2: Value->SetValue_psz(Tdbp->Fname); break;
1001 case 3: Value->SetValue_psz(Tdbp->Ftype); break;
1002#if defined(__WIN__)
1003 case 4: Value->SetValue((int)Tdbp->FileData.dwFileAttributes); break;
1004 case 5: Value->SetValue((int)Tdbp->FileData.nFileSizeLow); break;
1005 case 6: SetTimeValue(g, Tdbp->FileData.ftLastWriteTime); break;
1006 case 7: SetTimeValue(g, Tdbp->FileData.ftCreationTime); break;
1007 case 8: SetTimeValue(g, Tdbp->FileData.ftLastAccessTime); break;
1008#else // !__WIN__
1009 case 4: Value->SetValue((int)Tdbp->Fileinfo.st_mode); break;
1010 case 5: Value->SetValue((int)Tdbp->Fileinfo.st_size); break;
1011 case 6: Value->SetValue((int)Tdbp->Fileinfo.st_mtime); break;
1012 case 7: Value->SetValue((int)Tdbp->Fileinfo.st_ctime); break;
1013 case 8: Value->SetValue((int)Tdbp->Fileinfo.st_atime); break;
1014 case 9: Value->SetValue((int)Tdbp->Fileinfo.st_uid); break;
1015 case 10: Value->SetValue((int)Tdbp->Fileinfo.st_gid); break;
1016#endif // !__WIN__
1017 default:
1018 sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
1019 throw GetAmType();
1020 } // endswitch N
1021
1022 } // end of ReadColumn
1023
1024/* ------------------------- Class TDBSDR ---------------------------- */
1025
1026/***********************************************************************/
1027/* SDR GetMaxSize: returns the number of retrieved files. */
1028/***********************************************************************/
1029int TDBSDR::GetMaxSize(PGLOBAL g)
1030 {
1031 if (MaxSize < 0) {
1032 Path(g);
1033 MaxSize = FindInDir(g);
1034 } // endif MaxSize
1035
1036 return MaxSize;
1037 } // end of GetMaxSize
1038
1039/***********************************************************************/
1040/* SDR FindInDir: returns the number of retrieved files. */
1041/***********************************************************************/
1042int TDBSDR::FindInDir(PGLOBAL g)
1043 {
1044 int rc, n = 0;
1045 size_t m = strlen(Direc);
1046
1047 // Start searching files in the target directory.
1048#if defined(__WIN__)
1049 HANDLE h;
1050
1051#if defined(PATHMATCHSPEC)
1052 if (!*Drive)
1053 Path(g);
1054
1055 _makepath(Fpath, Drive, Direc, "*", "*");
1056
1057 h = FindFirstFile(Fpath, &FileData);
1058
1059 if (h == INVALID_HANDLE_VALUE) {
1060 rc = GetLastError();
1061
1062 if (rc != ERROR_FILE_NOT_FOUND) {
1063 char buf[512];
1064
1065 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1066 FORMAT_MESSAGE_IGNORE_INSERTS,
1067 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
1068 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
1069 return -1;
1070 } // endif rc
1071
1072 return 0;
1073 } // endif h
1074
1075 while (true) {
1076 if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
1077 *FileData.cFileName != '.') {
1078 // Look in the name sub-directory
1079 strcat(strcat(Direc, FileData.cFileName), "/");
1080 n += FindInDir(g);
1081 Direc[m] = '\0'; // Restore path
1082 } else if (PathMatchSpec(FileData.cFileName, Fpath))
1083 n++;
1084
1085 if (!FindNextFile(h, &FileData)) {
1086 rc = GetLastError();
1087
1088 if (rc != ERROR_NO_MORE_FILES) {
1089 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1090 FindClose(h);
1091 return -1;
1092 } // endif rc
1093
1094 break;
1095 } // endif Next
1096
1097 } // endwhile
1098#else // !PATHMATCHSPEC
1099 h = FindFirstFile(Path(g), &FileData);
1100
1101 if (h == INVALID_HANDLE_VALUE) {
1102 rc = GetLastError();
1103
1104 if (rc != ERROR_FILE_NOT_FOUND) {
1105 char buf[512];
1106
1107 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1108 FORMAT_MESSAGE_IGNORE_INSERTS,
1109 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
1110 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
1111 return -1;
1112 } // endif rc
1113
1114 return 0;
1115 } // endif hSearch
1116
1117 while (true) {
1118 n++;
1119
1120 if (!FindNextFile(h, &FileData)) {
1121 rc = GetLastError();
1122
1123 if (rc != ERROR_NO_MORE_FILES) {
1124 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1125 FindClose(h);
1126 return -1;
1127 } // endif rc
1128
1129 break;
1130 } // endif Next
1131
1132 } // endwhile
1133
1134 // Now search files in sub-directories.
1135 _makepath(Fpath, Drive, Direc, "*", ".");
1136 h = FindFirstFile(Fpath, &FileData);
1137
1138 if (h != INVALID_HANDLE_VALUE) {
1139 while (true) {
1140 if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
1141 *FileData.cFileName != '.') {
1142 // Look in the name sub-directory
1143 strcat(strcat(Direc, FileData.cFileName), "/");
1144 n += FindInDir(g);
1145 Direc[m] = '\0'; // Restore path
1146 } // endif SUBDIR
1147
1148 if (!FindNextFile(h, &FileData))
1149 break;
1150
1151 } // endwhile
1152
1153 } // endif h
1154#endif // !PATHMATCHSPEC
1155
1156 // Close the search handle.
1157 FindClose(h);
1158#else // !__WIN__
1159 int k;
1160 DIR *dir = opendir(Direc);
1161
1162 if (!dir) {
1163 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
1164 return -1;
1165 } // endif dir
1166
1167 while ((Entry = readdir(dir))) {
1168 strcat(strcpy(Fpath, Direc), Entry->d_name);
1169
1170 if (lstat(Fpath, &Fileinfo) < 0) {
1171 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
1172 return -1;
1173 } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
1174 // Look in the name sub-directory
1175 strcat(strcat(Direc, Entry->d_name), "/");
1176
1177 if ((k = FindInDir(g)) < 0)
1178 return k;
1179 else
1180 n += k;
1181
1182 Direc[m] = '\0'; // Restore path
1183 } else if (S_ISREG(Fileinfo.st_mode))
1184 // Test whether the file name matches the table name filter
1185 if (!fnmatch(Pattern, Entry->d_name, 0))
1186 n++; // We have a match
1187
1188 } // endwhile readdir
1189
1190 // Close the DIR handle.
1191 closedir(dir);
1192#endif // !__WIN__
1193
1194 return n;
1195 } // end of FindInDir
1196
1197/***********************************************************************/
1198/* DIR Access Method opening routine. */
1199/* Open first file, other will be opened sequencially when reading. */
1200/***********************************************************************/
1201bool TDBSDR::OpenDB(PGLOBAL g)
1202 {
1203 if (!Sub) {
1204 Path(g);
1205 Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1206 Sub->Next = NULL;
1207 Sub->Prev = NULL;
1208#if defined(__WIN__)
1209 Sub->H = INVALID_HANDLE_VALUE;
1210 Sub->Len = strlen(Direc);
1211#else // !__WIN__
1212 Sub->D = NULL;
1213 Sub->Len = 0;
1214#endif // !__WIN__
1215 } // endif To_Sub
1216
1217 return TDBDIR::OpenDB(g);
1218 } // end of OpenDB
1219
1220/***********************************************************************/
1221/* Data Base read routine for SDR access method. */
1222/***********************************************************************/
1223int TDBSDR::ReadDB(PGLOBAL g)
1224 {
1225 int rc;
1226
1227#if defined(__WIN__)
1228 again:
1229 rc = TDBDIR::ReadDB(g);
1230
1231 if (rc == RC_EF) {
1232 // Are there more files in sub-directories
1233 retry:
1234 do {
1235 if (Sub->H == INVALID_HANDLE_VALUE) {
1236// _makepath(Fpath, Drive, Direc, "*", "."); why was this made?
1237 _makepath(Fpath, Drive, Direc, "*", NULL);
1238 Sub->H = FindFirstFile(Fpath, &FileData);
1239 } else if (!FindNextFile(Sub->H, &FileData)) {
1240 FindClose(Sub->H);
1241 Sub->H = INVALID_HANDLE_VALUE;
1242 *FileData.cFileName= '\0';
1243 break;
1244 } // endif findnext
1245
1246 } while(!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1247 (*FileData.cFileName == '.' &&
1248 (!FileData.cFileName[1] || FileData.cFileName[1] == '.')));
1249
1250 if (Sub->H == INVALID_HANDLE_VALUE) {
1251 // No more sub-directories. Are we in a sub-directory?
1252 if (!Sub->Prev)
1253 return rc; // No, all is finished
1254
1255 // here we must continue in the parent directory
1256 Sub = Sub->Prev;
1257 goto retry;
1258 } else {
1259 // Search next sub-directory
1260 Direc[Sub->Len] = '\0';
1261
1262 if (!Sub->Next) {
1263 PSUBDIR sup;
1264
1265 sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1266 sup->Next = NULL;
1267 sup->Prev = Sub;
1268 sup->H = INVALID_HANDLE_VALUE;
1269 Sub->Next = sup;
1270 } // endif Next
1271
1272 Sub = Sub->Next;
1273 strcat(strcat(Direc, FileData.cFileName), "/");
1274 Sub->Len = strlen(Direc);
1275
1276 // Reset Hsearch used by TDBDIR::ReadDB
1277 FindClose(hSearch);
1278 hSearch = INVALID_HANDLE_VALUE;
1279 goto again;
1280 } // endif H
1281
1282 } // endif rc
1283#else // !__WIN__
1284 rc = RC_NF;
1285
1286 again:
1287 if (!Sub->D)
1288 // Start searching files in the target directory.
1289 if (!(Sub->D = opendir(Direc))) {
1290 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
1291 rc = RC_FX;
1292 } // endif dir
1293
1294 while (rc == RC_NF)
1295 if ((Entry = readdir(Sub->D))) {
1296 // We need the Fileinfo structure to get info about the file
1297 strcat(strcpy(Fpath, Direc), Entry->d_name);
1298
1299 if (lstat(Fpath, &Fileinfo) < 0) {
1300 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
1301 rc = RC_FX;
1302 } else if (S_ISDIR(Fileinfo.st_mode) && strcmp(Entry->d_name, ".")
1303 && strcmp(Entry->d_name, "..")) {
1304 // Look in the name sub-directory
1305 if (!Sub->Next) {
1306 PSUBDIR sup;
1307
1308 sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1309 sup->Next = NULL;
1310 sup->Prev = Sub;
1311 Sub->Next = sup;
1312 } // endif Next
1313
1314 Sub = Sub->Next;
1315 Sub->D = NULL;
1316 Sub->Len = strlen(Direc);
1317 strcat(strcat(Direc, Entry->d_name), "/");
1318 goto again;
1319 } else if (S_ISREG(Fileinfo.st_mode))
1320 // Test whether the file name matches the table name filter
1321 if (!fnmatch(Pattern, Entry->d_name, 0)) {
1322 iFile++; // We have a match
1323 _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
1324 rc = RC_OK;
1325 } // endif fnmatch
1326
1327 } else {
1328 // No more files. Close the DIR handle.
1329 closedir(Sub->D);
1330
1331 // Are we in a sub-directory?
1332 if (Sub->Prev) {
1333 // Yes, we must continue in the parent directory
1334 Direc[Sub->Len] = '\0';
1335 Sub = Sub->Prev;
1336 } else
1337 rc = RC_EF; // No, all is finished
1338
1339 } // endif Entry
1340
1341#endif // !__WIN__
1342
1343 return rc;
1344 } // end of ReadDB
1345
1346#if 0
1347/* ------------------------- Class TDBDHR ---------------------------- */
1348
1349/***********************************************************************/
1350/* TABDHR constructors. */
1351/***********************************************************************/
1352TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
1353 {
1354 memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
1355 Hsearch = INVALID_HANDLE_VALUE;
1356 iFile = 0;
1357 *Drive = '\0';
1358 *Direc = '\0';
1359 *Fname = '\0';
1360 *Ftype = '\0';
1361 } // end of TDBDHR standard constructor
1362
1363TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
1364 {
1365 FileData = tdbp->FileData;
1366 Hsearch = tdbp->Hsearch;
1367 iFile = tdbp->iFile;
1368 strcpy(Drive, tdbp->Drive);
1369 strcpy(Direc, tdbp->Direc);
1370 strcpy(Fname, tdbp->Fname);
1371 strcpy(Ftype, tdbp->Ftype);
1372 } // end of TDBDHR copy constructor
1373
1374// Method
1375PTDB TDBDHR::Clone(PTABS t)
1376 {
1377 PTDB tp;
1378 PGLOBAL g = t->G; // Is this really useful ???
1379
1380 tp = new(g) TDBDHR(this);
1381 tp->Columns = Columns;
1382 return tp;
1383 } // end of Clone
1384
1385/***********************************************************************/
1386/* Allocate DHR column description block. */
1387/***********************************************************************/
1388PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
1389 {
1390 return new(g) DHRCOL(cdp, this, cprec, n);
1391 } // end of MakeCol
1392
1393/***********************************************************************/
1394/* DHR GetMaxSize: returns the number of retrieved files. */
1395/***********************************************************************/
1396int TDBDHR::GetMaxSize(PGLOBAL g)
1397 {
1398 if (MaxSize < 0) {
1399 char filename[_MAX_PATH];
1400 int i, rc;
1401 int n = -1;
1402 HANDLE h;
1403 PDBUSER dup = PlgGetUser(g);
1404
1405 PlugSetPath(filename, To_File, dup->Path);
1406
1407 // Start searching files in the target directory.
1408 h = FindFirstFile(filename, &FileData);
1409
1410 if (h == INVALID_HANDLE_VALUE) {
1411 switch (rc = GetLastError()) {
1412 case ERROR_NO_MORE_FILES:
1413 case ERROR_FILE_NOT_FOUND:
1414 n = 0;
1415 break;
1416 default:
1417 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1418 FORMAT_MESSAGE_IGNORE_INSERTS,
1419 NULL, rc, 0,
1420 (LPTSTR)&filename, sizeof(filename), NULL);
1421 sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
1422 } // endswitch rc
1423
1424 } else {
1425 for (n = 1;; n++)
1426 if (!FindNextFile(h, &FileData)) {
1427 rc = GetLastError();
1428
1429 if (rc != ERROR_NO_MORE_FILES) {
1430 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1431 n = -1;
1432 } // endif rc
1433
1434 break;
1435 } // endif FindNextFile
1436
1437 // Close the search handle.
1438 if (!FindClose(h) && n != -1)
1439 strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
1440
1441 } // endif Hsearch
1442
1443 MaxSize = n;
1444 } // endif MaxSize
1445
1446 return MaxSize;
1447 } // end of GetMaxSize
1448
1449/***********************************************************************/
1450/* DHR Access Method opening routine. */
1451/* Open first file, other will be opened sequencially when reading. */
1452/***********************************************************************/
1453bool TDBDHR::OpenDB(PGLOBAL g)
1454 {
1455 if (trace(1))
1456 htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
1457 this, Tdb_No, Use, Mode);
1458
1459 if (Use == USE_OPEN) {
1460 /*******************************************************************/
1461 /* Table already open, reopen it. */
1462 /*******************************************************************/
1463 CloseDB(g);
1464 SetUse(USE_READY);
1465 } // endif use
1466
1467 /*********************************************************************/
1468 /* Direct access needed for join or sorting. */
1469 /*********************************************************************/
1470 if (NeedIndexing(g)) {
1471 // Direct access of DHR tables is not implemented yet
1472 sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
1473 return true;
1474 } // endif NeedIndexing
1475
1476 Use = USE_OPEN;
1477 return false;
1478 } // end of OpenDB
1479
1480/***********************************************************************/
1481/* Data Base read routine for DHR access method. */
1482/***********************************************************************/
1483int TDBDHR::ReadDB(PGLOBAL g)
1484 {
1485 int rc = RC_OK;
1486 DWORD erc;
1487
1488 if (Hsearch == INVALID_HANDLE_VALUE) {
1489 char *filename[_MAX_PATH];
1490 PDBUSER dup = PlgGetUser(g);
1491
1492 PlugSetPath(filename, To_File, dup->Path);
1493 _splitpath(filename, Drive, Direc, NULL, NULL);
1494
1495 /*******************************************************************/
1496 /* Start searching files in the target directory. */
1497 /*******************************************************************/
1498 Hsearch = FindFirstFile(filename, &FileData);
1499
1500 if (Hsearch != INVALID_HANDLE_VALUE)
1501 iFile = 1;
1502 else switch (erc = GetLastError()) {
1503 case ERROR_NO_MORE_FILES:
1504 case ERROR_FILE_NOT_FOUND:
1505// case ERROR_PATH_NOT_FOUND: ???????
1506 rc = RC_EF;
1507 break;
1508 default:
1509 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1510 FORMAT_MESSAGE_IGNORE_INSERTS,
1511 NULL, erc, 0,
1512 (LPTSTR)&filename, sizeof(filename), NULL);
1513 sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
1514 rc = RC_FX;
1515 } // endswitch erc
1516
1517 } else {
1518 if (!FindNextFile(Hsearch, &FileData)) {
1519 DWORD erc = GetLastError();
1520
1521 if (erc != ERROR_NO_MORE_FILES) {
1522 sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
1523 FindClose(Hsearch);
1524 rc = RC_FX;
1525 } else
1526 rc = RC_EF;
1527
1528 } else
1529 iFile++;
1530
1531 } // endif Hsearch
1532
1533 if (rc == RC_OK)
1534 _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
1535
1536 return rc;
1537 } // end of ReadDB
1538
1539/***********************************************************************/
1540/* Data Base close routine for MUL access method. */
1541/***********************************************************************/
1542void TDBDHR::CloseDB(PGLOBAL g)
1543 {
1544 // Close the search handle.
1545 if (!FindClose(Hsearch)) {
1546 strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
1547 throw GetAmType();
1548 } // endif FindClose
1549
1550 iFile = 0;
1551 Hsearch = INVALID_HANDLE_VALUE;
1552 } // end of CloseDB
1553
1554// ------------------------ DHRCOL functions ----------------------------
1555
1556/***********************************************************************/
1557/* DHRCOL public constructor. */
1558/***********************************************************************/
1559DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
1560 : COLBLK(cdp, tdbp, i)
1561 {
1562 if (cprec) {
1563 Next = cprec->GetNext();
1564 cprec->SetNext(this);
1565 } else {
1566 Next = tdbp->GetColumns();
1567 tdbp->SetColumns(this);
1568 } // endif cprec
1569
1570 // Set additional DHR access method information for column.
1571 N = cdp->GetOffset();
1572 } // end of DOSCOL constructor
1573
1574/***********************************************************************/
1575/* DHRCOL constructor used for copying columns. */
1576/* tdbp is the pointer to the new table descriptor. */
1577/***********************************************************************/
1578DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
1579 {
1580 N = col1->N;
1581 } // end of DHRCOL copy constructor
1582
1583/***********************************************************************/
1584/* ReadColumn: what this routine does is to access the information */
1585/* corresponding to this column and convert it to buffer type. */
1586/***********************************************************************/
1587void DHRCOL::ReadColumn(PGLOBAL g)
1588 {
1589 int rc;
1590 PTDBDHR tdbp = (PTDBDHR)To_Tdb;
1591
1592 if (trace(1))
1593 htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
1594 Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
1595
1596 /*********************************************************************/
1597 /* Retrieve the information corresponding to the column number. */
1598 /*********************************************************************/
1599 switch (N) {
1600 case 0: // Drive
1601 Value->SetValue(Drive, _MAX_DRIVE);
1602 break;
1603 case 1: // Path
1604 Value->SetValue(Direc, _MAX_DHR);
1605 break;
1606 case 2: // Name
1607 Value->SetValue(Fname, _MAX_FNAME);
1608 break;
1609 case 3: // Extention
1610 Value->SetValue(Ftype, _MAX_EXT);
1611 break;
1612 case 4: // Extention
1613 Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
1614 break;
1615 case 5:
1616 Value->SetValue(tdbp->FileData.dwFileAttributes);
1617 break;
1618 case 6:
1619 Value->SetValue(..................
1620 } // end of ReadColumn
1621#endif // 0
1622
1623