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(_WIN32)
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 /***********************************************************************/
TDBMUL(PTDB tdbp)81 TDBMUL::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
TDBMUL(PTDBMUL tdbp)91 TDBMUL::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
Clone(PTABS t)102 PTDB 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
Duplicate(PGLOBAL g)113 PTDB 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 /***********************************************************************/
InitFileNames(PGLOBAL g)128 bool 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(_WIN32)
170 strcat(strcpy(filename, dirp->Drive), dirp->Direc);
171 #else // !_WIN32
172 strcpy(filename, dirp->Direc);
173 #endif // !_WIN32
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(_WIN32)
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 /***********************************************************************/
ColDB(PGLOBAL g,PSZ name,int num)248 PCOL 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 /***********************************************************************/
GetProgMax(PGLOBAL g)266 int 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 /***********************************************************************/
GetProgCur(void)277 int 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 /***********************************************************************/
Cardinality(PGLOBAL g)288 int 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 /***********************************************************************/
GetMaxSize(PGLOBAL g)316 int 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 /***********************************************************************/
ResetDB(void)354 void 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 /***********************************************************************/
RowNumber(PGLOBAL g,bool b)366 int 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 /***********************************************************************/
OpenDB(PGLOBAL g)376 bool 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 /***********************************************************************/
ReadDB(PGLOBAL g)429 int 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 /***********************************************************************/
WriteDB(PGLOBAL g)480 int 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 /***********************************************************************/
DeleteDB(PGLOBAL g,int)490 int 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 /***********************************************************************/
CloseDB(PGLOBAL g)501 void 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
514 PTDB 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
525 PTDB 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 /***********************************************************************/
540 bool 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(_WIN32)
570 strcat(strcpy(filename, dirp->Drive), dirp->Direc);
571 #else // !_WIN32
572 strcpy(filename, dirp->Direc);
573 #endif // !_WIN32
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 /***********************************************************************/
DefineAM(PGLOBAL g,LPCSTR,int)603 bool 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 /***********************************************************************/
GetTable(PGLOBAL g,MODE)615 PTDB 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 /***********************************************************************/
Init(void)634 void TDBDIR::Init(void)
635 {
636 iFile = 0;
637 #if defined(_WIN32)
638 Dvalp = NULL;
639 memset(&FileData, 0, sizeof(_finddata_t));
640 hSearch = INVALID_HANDLE_VALUE;
641 *Drive = '\0';
642 #else // !_WIN32
643 memset(&Fileinfo, 0, sizeof(struct stat));
644 Entry = NULL;
645 Dir = NULL;
646 Done = false;
647 *Pattern = '\0';
648 #endif // !_WIN32
649 *Fpath = '\0';
650 *Direc = '\0';
651 *Fname = '\0';
652 *Ftype = '\0';
653 } // end of Init
654
TDBDIR(PDIRDEF tdp)655 TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
656 {
657 To_File = tdp->Fn;
658 Nodir = tdp->Nodir;
659 Init();
660 } // end of TDBDIR standard constructor
661
TDBDIR(PSZ fpat)662 TDBDIR::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 /***********************************************************************/
Path(PGLOBAL g)672 char* TDBDIR::Path(PGLOBAL g)
673 {
674 (void) PlgGetCatalog(g); // XXX Should be removed?
675 PTABDEF defp = (PTABDEF)To_Def;
676
677 #if defined(_WIN32)
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 // !_WIN32
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 // !_WIN32
695 } // end of Path
696
697 /***********************************************************************/
698 /* Allocate DIR column description block. */
699 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)700 PCOL 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 /***********************************************************************/
GetMaxSize(PGLOBAL g)708 int TDBDIR::GetMaxSize(PGLOBAL g)
709 {
710 if (MaxSize < 0) {
711 int n = -1;
712 #if defined(_WIN32)
713 int rc;
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 // !_WIN32
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 // !_WIN32
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 /***********************************************************************/
OpenDB(PGLOBAL g)788 bool 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(_WIN32)
804 Path(g); // Be sure it is done
805 Dir = NULL; // For ReadDB
806 #endif // !_WIN32
807 return false;
808 } // end of OpenDB
809
810 /***********************************************************************/
811 /* Data Base read routine for DIR access method. */
812 /***********************************************************************/
ReadDB(PGLOBAL g)813 int TDBDIR::ReadDB(PGLOBAL g)
814 {
815 int rc = RC_OK;
816
817 #if defined(_WIN32)
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 // !_WIN32
881
882 return rc;
883 } // end of ReadDB
884
885 /***********************************************************************/
886 /* Data Base write routine for DIR access method. */
887 /***********************************************************************/
WriteDB(PGLOBAL g)888 int 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 /***********************************************************************/
DeleteDB(PGLOBAL g,int)897 int 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 /***********************************************************************/
CloseDB(PGLOBAL)906 void TDBDIR::CloseDB(PGLOBAL)
907 {
908 #if defined(_WIN32)
909 // Close the search handle.
910 FindClose(hSearch);
911 hSearch = INVALID_HANDLE_VALUE;
912 #else // !_WIN32
913 // Close the DIR handle
914 if (Dir) {
915 closedir(Dir);
916 Dir = NULL;
917 } // endif dir
918 #endif // !_WIN32
919 iFile = 0;
920 } // end of CloseDB
921
922 // ------------------------ DIRCOL functions ----------------------------
923
924 /***********************************************************************/
925 /* DIRCOL public constructor. */
926 /***********************************************************************/
DIRCOL(PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i,PCSZ)927 DIRCOL::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 /***********************************************************************/
DIRCOL(DIRCOL * col1,PTDB tdbp)947 DIRCOL::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(_WIN32)
954 /***********************************************************************/
955 /* Retrieve time information from FileData. */
956 /***********************************************************************/
SetTimeValue(PGLOBAL g,FILETIME & ftime)957 void 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 // _WIN32
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 /***********************************************************************/
ReadColumn(PGLOBAL g)986 void 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(_WIN32)
997 case 0: Value->SetValue_psz(Tdbp->Drive); break;
998 #endif // _WIN32
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(_WIN32)
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 // !_WIN32
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 // !_WIN32
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 /***********************************************************************/
GetMaxSize(PGLOBAL g)1029 int 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 /***********************************************************************/
FindInDir(PGLOBAL g)1042 int TDBSDR::FindInDir(PGLOBAL g)
1043 {
1044 int n = 0;
1045 size_t m = strlen(Direc);
1046
1047 // Start searching files in the target directory.
1048 #if defined(_WIN32)
1049 int rc;
1050 HANDLE h;
1051
1052 #if defined(PATHMATCHSPEC)
1053 if (!*Drive)
1054 Path(g);
1055
1056 _makepath(Fpath, Drive, Direc, "*", "*");
1057
1058 h = FindFirstFile(Fpath, &FileData);
1059
1060 if (h == INVALID_HANDLE_VALUE) {
1061 rc = GetLastError();
1062
1063 if (rc != ERROR_FILE_NOT_FOUND) {
1064 char buf[512];
1065
1066 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1067 FORMAT_MESSAGE_IGNORE_INSERTS,
1068 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
1069 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
1070 return -1;
1071 } // endif rc
1072
1073 return 0;
1074 } // endif h
1075
1076 while (true) {
1077 if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
1078 *FileData.cFileName != '.') {
1079 // Look in the name sub-directory
1080 strcat(strcat(Direc, FileData.cFileName), "/");
1081 n += FindInDir(g);
1082 Direc[m] = '\0'; // Restore path
1083 } else if (PathMatchSpec(FileData.cFileName, Fpath))
1084 n++;
1085
1086 if (!FindNextFile(h, &FileData)) {
1087 rc = GetLastError();
1088
1089 if (rc != ERROR_NO_MORE_FILES) {
1090 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1091 FindClose(h);
1092 return -1;
1093 } // endif rc
1094
1095 break;
1096 } // endif Next
1097
1098 } // endwhile
1099 #else // !PATHMATCHSPEC
1100 h = FindFirstFile(Path(g), &FileData);
1101
1102 if (h == INVALID_HANDLE_VALUE) {
1103 rc = GetLastError();
1104
1105 if (rc != ERROR_FILE_NOT_FOUND) {
1106 char buf[512];
1107
1108 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1109 FORMAT_MESSAGE_IGNORE_INSERTS,
1110 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
1111 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
1112 return -1;
1113 } // endif rc
1114
1115 return 0;
1116 } // endif hSearch
1117
1118 while (true) {
1119 n++;
1120
1121 if (!FindNextFile(h, &FileData)) {
1122 rc = GetLastError();
1123
1124 if (rc != ERROR_NO_MORE_FILES) {
1125 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1126 FindClose(h);
1127 return -1;
1128 } // endif rc
1129
1130 break;
1131 } // endif Next
1132
1133 } // endwhile
1134
1135 // Now search files in sub-directories.
1136 _makepath(Fpath, Drive, Direc, "*", ".");
1137 h = FindFirstFile(Fpath, &FileData);
1138
1139 if (h != INVALID_HANDLE_VALUE) {
1140 while (true) {
1141 if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
1142 *FileData.cFileName != '.') {
1143 // Look in the name sub-directory
1144 strcat(strcat(Direc, FileData.cFileName), "/");
1145 n += FindInDir(g);
1146 Direc[m] = '\0'; // Restore path
1147 } // endif SUBDIR
1148
1149 if (!FindNextFile(h, &FileData))
1150 break;
1151
1152 } // endwhile
1153
1154 } // endif h
1155 #endif // !PATHMATCHSPEC
1156
1157 // Close the search handle.
1158 FindClose(h);
1159 #else // !_WIN32
1160 int k;
1161 DIR *dir = opendir(Direc);
1162
1163 if (!dir) {
1164 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
1165 return -1;
1166 } // endif dir
1167
1168 while ((Entry = readdir(dir))) {
1169 strcat(strcpy(Fpath, Direc), Entry->d_name);
1170
1171 if (lstat(Fpath, &Fileinfo) < 0) {
1172 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
1173 return -1;
1174 } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
1175 // Look in the name sub-directory
1176 strcat(strcat(Direc, Entry->d_name), "/");
1177
1178 if ((k= FindInDir(g)) < 0)
1179 return k;
1180 else
1181 n += k;
1182
1183 Direc[m] = '\0'; // Restore path
1184 } else if (S_ISREG(Fileinfo.st_mode))
1185 // Test whether the file name matches the table name filter
1186 if (!fnmatch(Pattern, Entry->d_name, 0))
1187 n++; // We have a match
1188
1189 } // endwhile readdir
1190
1191 // Close the DIR handle.
1192 closedir(dir);
1193 #endif // !_WIN32
1194
1195 return n;
1196 } // end of FindInDir
1197
1198 /***********************************************************************/
1199 /* DIR Access Method opening routine. */
1200 /* Open first file, other will be opened sequencially when reading. */
1201 /***********************************************************************/
OpenDB(PGLOBAL g)1202 bool TDBSDR::OpenDB(PGLOBAL g)
1203 {
1204 if (!Sub) {
1205 Path(g);
1206 Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1207 Sub->Next = NULL;
1208 Sub->Prev = NULL;
1209 #if defined(_WIN32)
1210 Sub->H = INVALID_HANDLE_VALUE;
1211 Sub->Len = strlen(Direc);
1212 #else // !_WIN32
1213 Sub->D = NULL;
1214 Sub->Len = 0;
1215 #endif // !_WIN32
1216 } // endif To_Sub
1217
1218 return TDBDIR::OpenDB(g);
1219 } // end of OpenDB
1220
1221 /***********************************************************************/
1222 /* Data Base read routine for SDR access method. */
1223 /***********************************************************************/
ReadDB(PGLOBAL g)1224 int TDBSDR::ReadDB(PGLOBAL g)
1225 {
1226 int rc;
1227
1228 #if defined(_WIN32)
1229 again:
1230 rc = TDBDIR::ReadDB(g);
1231
1232 if (rc == RC_EF) {
1233 // Are there more files in sub-directories
1234 retry:
1235 do {
1236 if (Sub->H == INVALID_HANDLE_VALUE) {
1237 // _makepath(Fpath, Drive, Direc, "*", "."); why was this made?
1238 _makepath(Fpath, Drive, Direc, "*", NULL);
1239 Sub->H = FindFirstFile(Fpath, &FileData);
1240 } else if (!FindNextFile(Sub->H, &FileData)) {
1241 FindClose(Sub->H);
1242 Sub->H = INVALID_HANDLE_VALUE;
1243 *FileData.cFileName= '\0';
1244 break;
1245 } // endif findnext
1246
1247 } while(!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1248 (*FileData.cFileName == '.' &&
1249 (!FileData.cFileName[1] || FileData.cFileName[1] == '.')));
1250
1251 if (Sub->H == INVALID_HANDLE_VALUE) {
1252 // No more sub-directories. Are we in a sub-directory?
1253 if (!Sub->Prev)
1254 return rc; // No, all is finished
1255
1256 // here we must continue in the parent directory
1257 Sub = Sub->Prev;
1258 goto retry;
1259 } else {
1260 // Search next sub-directory
1261 Direc[Sub->Len] = '\0';
1262
1263 if (!Sub->Next) {
1264 PSUBDIR sup;
1265
1266 sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1267 sup->Next = NULL;
1268 sup->Prev = Sub;
1269 sup->H = INVALID_HANDLE_VALUE;
1270 Sub->Next = sup;
1271 } // endif Next
1272
1273 Sub = Sub->Next;
1274 strcat(strcat(Direc, FileData.cFileName), "/");
1275 Sub->Len = strlen(Direc);
1276
1277 // Reset Hsearch used by TDBDIR::ReadDB
1278 FindClose(hSearch);
1279 hSearch = INVALID_HANDLE_VALUE;
1280 goto again;
1281 } // endif H
1282
1283 } // endif rc
1284 #else // !_WIN32
1285 rc = RC_NF;
1286
1287 again:
1288 if (!Sub->D)
1289 // Start searching files in the target directory.
1290 if (!(Sub->D = opendir(Direc))) {
1291 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
1292 rc = RC_FX;
1293 } // endif dir
1294
1295 while (rc == RC_NF)
1296 if ((Entry = readdir(Sub->D))) {
1297 // We need the Fileinfo structure to get info about the file
1298 strcat(strcpy(Fpath, Direc), Entry->d_name);
1299
1300 if (lstat(Fpath, &Fileinfo) < 0) {
1301 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
1302 rc = RC_FX;
1303 } else if (S_ISDIR(Fileinfo.st_mode) && strcmp(Entry->d_name, ".")
1304 && strcmp(Entry->d_name, "..")) {
1305 // Look in the name sub-directory
1306 if (!Sub->Next) {
1307 PSUBDIR sup;
1308
1309 sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1310 sup->Next = NULL;
1311 sup->Prev = Sub;
1312 Sub->Next = sup;
1313 } // endif Next
1314
1315 Sub = Sub->Next;
1316 Sub->D = NULL;
1317 Sub->Len = strlen(Direc);
1318 strcat(strcat(Direc, Entry->d_name), "/");
1319 goto again;
1320 } else if (S_ISREG(Fileinfo.st_mode))
1321 // Test whether the file name matches the table name filter
1322 if (!fnmatch(Pattern, Entry->d_name, 0)) {
1323 iFile++; // We have a match
1324 _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
1325 rc = RC_OK;
1326 } // endif fnmatch
1327
1328 } else {
1329 // No more files. Close the DIR handle.
1330 closedir(Sub->D);
1331
1332 // Are we in a sub-directory?
1333 if (Sub->Prev) {
1334 // Yes, we must continue in the parent directory
1335 Direc[Sub->Len] = '\0';
1336 Sub = Sub->Prev;
1337 } else
1338 rc = RC_EF; // No, all is finished
1339
1340 } // endif Entry
1341
1342 #endif // !_WIN32
1343
1344 return rc;
1345 } // end of ReadDB
1346
1347 #if 0
1348 /* ------------------------- Class TDBDHR ---------------------------- */
1349
1350 /***********************************************************************/
1351 /* TABDHR constructors. */
1352 /***********************************************************************/
1353 TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
1354 {
1355 memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
1356 Hsearch = INVALID_HANDLE_VALUE;
1357 iFile = 0;
1358 *Drive = '\0';
1359 *Direc = '\0';
1360 *Fname = '\0';
1361 *Ftype = '\0';
1362 } // end of TDBDHR standard constructor
1363
1364 TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
1365 {
1366 FileData = tdbp->FileData;
1367 Hsearch = tdbp->Hsearch;
1368 iFile = tdbp->iFile;
1369 strcpy(Drive, tdbp->Drive);
1370 strcpy(Direc, tdbp->Direc);
1371 strcpy(Fname, tdbp->Fname);
1372 strcpy(Ftype, tdbp->Ftype);
1373 } // end of TDBDHR copy constructor
1374
1375 // Method
1376 PTDB TDBDHR::Clone(PTABS t)
1377 {
1378 PTDB tp;
1379 PGLOBAL g = t->G; // Is this really useful ???
1380
1381 tp = new(g) TDBDHR(this);
1382 tp->Columns = Columns;
1383 return tp;
1384 } // end of Clone
1385
1386 /***********************************************************************/
1387 /* Allocate DHR column description block. */
1388 /***********************************************************************/
1389 PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
1390 {
1391 return new(g) DHRCOL(cdp, this, cprec, n);
1392 } // end of MakeCol
1393
1394 /***********************************************************************/
1395 /* DHR GetMaxSize: returns the number of retrieved files. */
1396 /***********************************************************************/
1397 int TDBDHR::GetMaxSize(PGLOBAL g)
1398 {
1399 if (MaxSize < 0) {
1400 char filename[_MAX_PATH];
1401 int i, rc;
1402 int n = -1;
1403 HANDLE h;
1404 PDBUSER dup = PlgGetUser(g);
1405
1406 PlugSetPath(filename, To_File, dup->Path);
1407
1408 // Start searching files in the target directory.
1409 h = FindFirstFile(filename, &FileData);
1410
1411 if (h == INVALID_HANDLE_VALUE) {
1412 switch (rc = GetLastError()) {
1413 case ERROR_NO_MORE_FILES:
1414 case ERROR_FILE_NOT_FOUND:
1415 n = 0;
1416 break;
1417 default:
1418 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1419 FORMAT_MESSAGE_IGNORE_INSERTS,
1420 NULL, rc, 0,
1421 (LPTSTR)&filename, sizeof(filename), NULL);
1422 sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
1423 } // endswitch rc
1424
1425 } else {
1426 for (n = 1;; n++)
1427 if (!FindNextFile(h, &FileData)) {
1428 rc = GetLastError();
1429
1430 if (rc != ERROR_NO_MORE_FILES) {
1431 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1432 n = -1;
1433 } // endif rc
1434
1435 break;
1436 } // endif FindNextFile
1437
1438 // Close the search handle.
1439 if (!FindClose(h) && n != -1)
1440 strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
1441
1442 } // endif Hsearch
1443
1444 MaxSize = n;
1445 } // endif MaxSize
1446
1447 return MaxSize;
1448 } // end of GetMaxSize
1449
1450 /***********************************************************************/
1451 /* DHR Access Method opening routine. */
1452 /* Open first file, other will be opened sequencially when reading. */
1453 /***********************************************************************/
1454 bool TDBDHR::OpenDB(PGLOBAL g)
1455 {
1456 if (trace(1))
1457 htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
1458 this, Tdb_No, Use, Mode);
1459
1460 if (Use == USE_OPEN) {
1461 /*******************************************************************/
1462 /* Table already open, reopen it. */
1463 /*******************************************************************/
1464 CloseDB(g);
1465 SetUse(USE_READY);
1466 } // endif use
1467
1468 /*********************************************************************/
1469 /* Direct access needed for join or sorting. */
1470 /*********************************************************************/
1471 if (NeedIndexing(g)) {
1472 // Direct access of DHR tables is not implemented yet
1473 sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
1474 return true;
1475 } // endif NeedIndexing
1476
1477 Use = USE_OPEN;
1478 return false;
1479 } // end of OpenDB
1480
1481 /***********************************************************************/
1482 /* Data Base read routine for DHR access method. */
1483 /***********************************************************************/
1484 int TDBDHR::ReadDB(PGLOBAL g)
1485 {
1486 int rc = RC_OK;
1487 DWORD erc;
1488
1489 if (Hsearch == INVALID_HANDLE_VALUE) {
1490 char *filename[_MAX_PATH];
1491 PDBUSER dup = PlgGetUser(g);
1492
1493 PlugSetPath(filename, To_File, dup->Path);
1494 _splitpath(filename, Drive, Direc, NULL, NULL);
1495
1496 /*******************************************************************/
1497 /* Start searching files in the target directory. */
1498 /*******************************************************************/
1499 Hsearch = FindFirstFile(filename, &FileData);
1500
1501 if (Hsearch != INVALID_HANDLE_VALUE)
1502 iFile = 1;
1503 else switch (erc = GetLastError()) {
1504 case ERROR_NO_MORE_FILES:
1505 case ERROR_FILE_NOT_FOUND:
1506 // case ERROR_PATH_NOT_FOUND: ???????
1507 rc = RC_EF;
1508 break;
1509 default:
1510 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1511 FORMAT_MESSAGE_IGNORE_INSERTS,
1512 NULL, erc, 0,
1513 (LPTSTR)&filename, sizeof(filename), NULL);
1514 sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
1515 rc = RC_FX;
1516 } // endswitch erc
1517
1518 } else {
1519 if (!FindNextFile(Hsearch, &FileData)) {
1520 DWORD erc = GetLastError();
1521
1522 if (erc != ERROR_NO_MORE_FILES) {
1523 sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
1524 FindClose(Hsearch);
1525 rc = RC_FX;
1526 } else
1527 rc = RC_EF;
1528
1529 } else
1530 iFile++;
1531
1532 } // endif Hsearch
1533
1534 if (rc == RC_OK)
1535 _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
1536
1537 return rc;
1538 } // end of ReadDB
1539
1540 /***********************************************************************/
1541 /* Data Base close routine for MUL access method. */
1542 /***********************************************************************/
1543 void TDBDHR::CloseDB(PGLOBAL g)
1544 {
1545 // Close the search handle.
1546 if (!FindClose(Hsearch)) {
1547 strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
1548 throw GetAmType();
1549 } // endif FindClose
1550
1551 iFile = 0;
1552 Hsearch = INVALID_HANDLE_VALUE;
1553 } // end of CloseDB
1554
1555 // ------------------------ DHRCOL functions ----------------------------
1556
1557 /***********************************************************************/
1558 /* DHRCOL public constructor. */
1559 /***********************************************************************/
1560 DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
1561 : COLBLK(cdp, tdbp, i)
1562 {
1563 if (cprec) {
1564 Next = cprec->GetNext();
1565 cprec->SetNext(this);
1566 } else {
1567 Next = tdbp->GetColumns();
1568 tdbp->SetColumns(this);
1569 } // endif cprec
1570
1571 // Set additional DHR access method information for column.
1572 N = cdp->GetOffset();
1573 } // end of DOSCOL constructor
1574
1575 /***********************************************************************/
1576 /* DHRCOL constructor used for copying columns. */
1577 /* tdbp is the pointer to the new table descriptor. */
1578 /***********************************************************************/
1579 DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
1580 {
1581 N = col1->N;
1582 } // end of DHRCOL copy constructor
1583
1584 /***********************************************************************/
1585 /* ReadColumn: what this routine does is to access the information */
1586 /* corresponding to this column and convert it to buffer type. */
1587 /***********************************************************************/
1588 void DHRCOL::ReadColumn(PGLOBAL g)
1589 {
1590 int rc;
1591 PTDBDHR tdbp = (PTDBDHR)To_Tdb;
1592
1593 if (trace(1))
1594 htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
1595 Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
1596
1597 /*********************************************************************/
1598 /* Retrieve the information corresponding to the column number. */
1599 /*********************************************************************/
1600 switch (N) {
1601 case 0: // Drive
1602 Value->SetValue(Drive, _MAX_DRIVE);
1603 break;
1604 case 1: // Path
1605 Value->SetValue(Direc, _MAX_DHR);
1606 break;
1607 case 2: // Name
1608 Value->SetValue(Fname, _MAX_FNAME);
1609 break;
1610 case 3: // Extention
1611 Value->SetValue(Ftype, _MAX_EXT);
1612 break;
1613 case 4: // Extention
1614 Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
1615 break;
1616 case 5:
1617 Value->SetValue(tdbp->FileData.dwFileAttributes);
1618 break;
1619 case 6:
1620 Value->SetValue(..................
1621 } // end of ReadColumn
1622 #endif // 0
1623
1624