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 PCATLG cat __attribute__((unused))= PlgGetCatalog(g);
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
715 // Start searching files in the target directory.
716 hSearch = FindFirstFile(Path(g), &FileData);
717
718 if (hSearch == INVALID_HANDLE_VALUE) {
719 rc = GetLastError();
720
721 if (rc != ERROR_FILE_NOT_FOUND) {
722 char buf[512];
723
724 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
725 FORMAT_MESSAGE_IGNORE_INSERTS,
726 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
727 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
728 return -1;
729 } // endif rc
730
731 return 0;
732 } // endif hSearch
733
734 while (true) {
735 if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
736 n++;
737
738 if (!FindNextFile(hSearch, &FileData)) {
739 rc = GetLastError();
740
741 if (rc != ERROR_NO_MORE_FILES) {
742 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
743 FindClose(hSearch);
744 return -1;
745 } // endif rc
746
747 break;
748 } // endif Next
749
750 } // endwhile
751
752 // Close the search handle.
753 FindClose(hSearch);
754 #else // !_WIN32
755 Path(g);
756
757 // Start searching files in the target directory.
758 if (!(Dir = opendir(Direc))) {
759 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
760 return -1;
761 } // endif dir
762
763 while ((Entry = readdir(Dir))) {
764 strcat(strcpy(Fpath, Direc), Entry->d_name);
765
766 if (lstat(Fpath, &Fileinfo) < 0) {
767 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
768 return -1;
769 } else if (S_ISREG(Fileinfo.st_mode))
770 // Test whether the file name matches the table name filter
771 if (!fnmatch(Pattern, Entry->d_name, 0))
772 n++; // We have a match
773
774 } // endwhile Entry
775
776 // Close the DIR handle.
777 closedir(Dir);
778 #endif // !_WIN32
779 MaxSize = n;
780 } // endif MaxSize
781
782 return MaxSize;
783 } // end of GetMaxSize
784
785 /***********************************************************************/
786 /* DIR Access Method opening routine. */
787 /* Open first file, other will be opened sequencially when reading. */
788 /***********************************************************************/
OpenDB(PGLOBAL g)789 bool TDBDIR::OpenDB(PGLOBAL g)
790 {
791 if (trace(1))
792 htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
793 this, Tdb_No, Use, Mode);
794
795 if (Use == USE_OPEN) {
796 /*******************************************************************/
797 /* Table already open, reopen it. */
798 /*******************************************************************/
799 CloseDB(g);
800 SetUse(USE_READY);
801 } // endif use
802
803 Use = USE_OPEN;
804 #if !defined(_WIN32)
805 Path(g); // Be sure it is done
806 Dir = NULL; // For ReadDB
807 #endif // !_WIN32
808 return false;
809 } // end of OpenDB
810
811 /***********************************************************************/
812 /* Data Base read routine for DIR access method. */
813 /***********************************************************************/
ReadDB(PGLOBAL g)814 int TDBDIR::ReadDB(PGLOBAL g)
815 {
816 int rc = RC_OK;
817
818 #if defined(_WIN32)
819 do {
820 if (hSearch == INVALID_HANDLE_VALUE) {
821 /*****************************************************************/
822 /* Start searching files in the target directory. The use of */
823 /* the Path function is required when called from TDBSDR. */
824 /*****************************************************************/
825 hSearch = FindFirstFile(Path(g), &FileData);
826
827 if (hSearch == INVALID_HANDLE_VALUE) {
828 rc = RC_EF;
829 break;
830 } else
831 iFile++;
832
833 } else {
834 if (!FindNextFile(hSearch, &FileData)) {
835 // Restore file name and type pattern
836 _splitpath(To_File, NULL, NULL, Fname, Ftype);
837 rc = RC_EF;
838 break;
839 } else
840 iFile++;
841
842 } // endif hSearch
843
844 } while (Nodir && FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
845
846 if (rc == RC_OK)
847 _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
848
849 #else // !Win32
850 rc = RC_NF;
851
852 if (!Dir)
853 // Start searching files in the target directory.
854 if (!(Dir = opendir(Direc))) {
855 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
856 rc = RC_FX;
857 } // endif dir
858
859 while (rc == RC_NF)
860 if ((Entry = readdir(Dir))) {
861 // We need the Fileinfo structure to get info about the file
862 strcat(strcpy(Fpath, Direc), Entry->d_name);
863
864 if (lstat(Fpath, &Fileinfo) < 0) {
865 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
866 rc = RC_FX;
867 } else if (S_ISREG(Fileinfo.st_mode))
868 // Test whether the file name matches the table name filter
869 if (!fnmatch(Pattern, Entry->d_name, 0)) {
870 iFile++; // We have a match
871 _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
872 rc = RC_OK;
873 } // endif fnmatch
874
875 } else {
876 // Restore file name and type pattern
877 _splitpath(To_File, NULL, NULL, Fname, Ftype);
878 rc = RC_EF;
879 } // endif Entry
880
881 #endif // !_WIN32
882
883 return rc;
884 } // end of ReadDB
885
886 /***********************************************************************/
887 /* Data Base write routine for DIR access method. */
888 /***********************************************************************/
WriteDB(PGLOBAL g)889 int TDBDIR::WriteDB(PGLOBAL g)
890 {
891 strcpy(g->Message, MSG(TABDIR_READONLY));
892 return RC_FX; // NIY
893 } // end of WriteDB
894
895 /***********************************************************************/
896 /* Data Base delete line routine for DIR access method. */
897 /***********************************************************************/
DeleteDB(PGLOBAL g,int)898 int TDBDIR::DeleteDB(PGLOBAL g, int)
899 {
900 strcpy(g->Message, MSG(TABDIR_READONLY));
901 return RC_FX; // NIY
902 } // end of DeleteDB
903
904 /***********************************************************************/
905 /* Data Base close routine for MUL access method. */
906 /***********************************************************************/
CloseDB(PGLOBAL)907 void TDBDIR::CloseDB(PGLOBAL)
908 {
909 #if defined(_WIN32)
910 // Close the search handle.
911 FindClose(hSearch);
912 hSearch = INVALID_HANDLE_VALUE;
913 #else // !_WIN32
914 // Close the DIR handle
915 if (Dir) {
916 closedir(Dir);
917 Dir = NULL;
918 } // endif dir
919 #endif // !_WIN32
920 iFile = 0;
921 } // end of CloseDB
922
923 // ------------------------ DIRCOL functions ----------------------------
924
925 /***********************************************************************/
926 /* DIRCOL public constructor. */
927 /***********************************************************************/
DIRCOL(PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i,PCSZ)928 DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
929 : COLBLK(cdp, tdbp, i)
930 {
931 if (cprec) {
932 Next = cprec->GetNext();
933 cprec->SetNext(this);
934 } else {
935 Next = tdbp->GetColumns();
936 tdbp->SetColumns(this);
937 } // endif cprec
938
939 // Set additional DIR access method information for column.
940 Tdbp = (PTDBDIR)tdbp;
941 N = cdp->GetOffset();
942 } // end of DIRCOL constructor
943
944 /***********************************************************************/
945 /* DIRCOL constructor used for copying columns. */
946 /* tdbp is the pointer to the new table descriptor. */
947 /***********************************************************************/
DIRCOL(DIRCOL * col1,PTDB tdbp)948 DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
949 {
950 Tdbp = (PTDBDIR)tdbp;
951 N = col1->N;
952 } // end of DIRCOL copy constructor
953
954 #if defined(_WIN32)
955 /***********************************************************************/
956 /* Retrieve time information from FileData. */
957 /***********************************************************************/
SetTimeValue(PGLOBAL g,FILETIME & ftime)958 void DIRCOL::SetTimeValue(PGLOBAL g, FILETIME& ftime)
959 {
960 char tsp[24];
961 SYSTEMTIME stp;
962
963 if (FileTimeToSystemTime(&ftime, &stp)) {
964 sprintf(tsp, "%04d-%02d-%02d %02d:%02d:%02d",
965 stp.wYear, stp.wMonth, stp.wDay, stp.wHour, stp.wMinute, stp.wSecond);
966
967 if (Value->GetType() != TYPE_STRING) {
968 if (!Tdbp->Dvalp)
969 Tdbp->Dvalp = AllocateValue(g, TYPE_DATE, 20, 0, false,
970 "YYYY-MM-DD hh:mm:ss");
971
972 Tdbp->Dvalp->SetValue_psz(tsp);
973 Value->SetValue_pval(Tdbp->Dvalp);
974 } else
975 Value->SetValue_psz(tsp);
976
977 } else
978 Value->Reset();
979
980 } // end of SetTimeValue
981 #endif // _WIN32
982
983 /***********************************************************************/
984 /* ReadColumn: what this routine does is to access the information */
985 /* corresponding to this column and convert it to buffer type. */
986 /***********************************************************************/
ReadColumn(PGLOBAL g)987 void DIRCOL::ReadColumn(PGLOBAL g)
988 {
989 if (trace(1))
990 htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
991 Name, Tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
992
993 /*********************************************************************/
994 /* Retrieve the information corresponding to the column number. */
995 /*********************************************************************/
996 switch (N) {
997 #if defined(_WIN32)
998 case 0: Value->SetValue_psz(Tdbp->Drive); break;
999 #endif // _WIN32
1000 case 1: Value->SetValue_psz(Tdbp->Direc); break;
1001 case 2: Value->SetValue_psz(Tdbp->Fname); break;
1002 case 3: Value->SetValue_psz(Tdbp->Ftype); break;
1003 #if defined(_WIN32)
1004 case 4: Value->SetValue((int)Tdbp->FileData.dwFileAttributes); break;
1005 case 5: Value->SetValue((int)Tdbp->FileData.nFileSizeLow); break;
1006 case 6: SetTimeValue(g, Tdbp->FileData.ftLastWriteTime); break;
1007 case 7: SetTimeValue(g, Tdbp->FileData.ftCreationTime); break;
1008 case 8: SetTimeValue(g, Tdbp->FileData.ftLastAccessTime); break;
1009 #else // !_WIN32
1010 case 4: Value->SetValue((int)Tdbp->Fileinfo.st_mode); break;
1011 case 5: Value->SetValue((int)Tdbp->Fileinfo.st_size); break;
1012 case 6: Value->SetValue((int)Tdbp->Fileinfo.st_mtime); break;
1013 case 7: Value->SetValue((int)Tdbp->Fileinfo.st_ctime); break;
1014 case 8: Value->SetValue((int)Tdbp->Fileinfo.st_atime); break;
1015 case 9: Value->SetValue((int)Tdbp->Fileinfo.st_uid); break;
1016 case 10: Value->SetValue((int)Tdbp->Fileinfo.st_gid); break;
1017 #endif // !_WIN32
1018 default:
1019 sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
1020 throw GetAmType();
1021 } // endswitch N
1022
1023 } // end of ReadColumn
1024
1025 /* ------------------------- Class TDBSDR ---------------------------- */
1026
1027 /***********************************************************************/
1028 /* SDR GetMaxSize: returns the number of retrieved files. */
1029 /***********************************************************************/
GetMaxSize(PGLOBAL g)1030 int TDBSDR::GetMaxSize(PGLOBAL g)
1031 {
1032 if (MaxSize < 0) {
1033 Path(g);
1034 MaxSize = FindInDir(g);
1035 } // endif MaxSize
1036
1037 return MaxSize;
1038 } // end of GetMaxSize
1039
1040 /***********************************************************************/
1041 /* SDR FindInDir: returns the number of retrieved files. */
1042 /***********************************************************************/
FindInDir(PGLOBAL g)1043 int TDBSDR::FindInDir(PGLOBAL g)
1044 {
1045 int n = 0;
1046 size_t m = strlen(Direc);
1047
1048 // Start searching files in the target directory.
1049 #if defined(_WIN32)
1050 HANDLE h;
1051 int rc;
1052
1053 #if defined(PATHMATCHSPEC)
1054 if (!*Drive)
1055 Path(g);
1056
1057 _makepath(Fpath, Drive, Direc, "*", "*");
1058
1059 h = FindFirstFile(Fpath, &FileData);
1060
1061 if (h == INVALID_HANDLE_VALUE) {
1062 rc = GetLastError();
1063
1064 if (rc != ERROR_FILE_NOT_FOUND) {
1065 char buf[512];
1066
1067 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1068 FORMAT_MESSAGE_IGNORE_INSERTS,
1069 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
1070 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
1071 return -1;
1072 } // endif rc
1073
1074 return 0;
1075 } // endif h
1076
1077 while (true) {
1078 if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
1079 *FileData.cFileName != '.') {
1080 // Look in the name sub-directory
1081 strcat(strcat(Direc, FileData.cFileName), "/");
1082 n += FindInDir(g);
1083 Direc[m] = '\0'; // Restore path
1084 } else if (PathMatchSpec(FileData.cFileName, Fpath))
1085 n++;
1086
1087 if (!FindNextFile(h, &FileData)) {
1088 rc = GetLastError();
1089
1090 if (rc != ERROR_NO_MORE_FILES) {
1091 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1092 FindClose(h);
1093 return -1;
1094 } // endif rc
1095
1096 break;
1097 } // endif Next
1098
1099 } // endwhile
1100 #else // !PATHMATCHSPEC
1101 h = FindFirstFile(Path(g), &FileData);
1102
1103 if (h == INVALID_HANDLE_VALUE) {
1104 rc = GetLastError();
1105
1106 if (rc != ERROR_FILE_NOT_FOUND) {
1107 char buf[512];
1108
1109 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1110 FORMAT_MESSAGE_IGNORE_INSERTS,
1111 NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
1112 sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
1113 return -1;
1114 } // endif rc
1115
1116 return 0;
1117 } // endif hSearch
1118
1119 while (true) {
1120 n++;
1121
1122 if (!FindNextFile(h, &FileData)) {
1123 rc = GetLastError();
1124
1125 if (rc != ERROR_NO_MORE_FILES) {
1126 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1127 FindClose(h);
1128 return -1;
1129 } // endif rc
1130
1131 break;
1132 } // endif Next
1133
1134 } // endwhile
1135
1136 // Now search files in sub-directories.
1137 _makepath(Fpath, Drive, Direc, "*", ".");
1138 h = FindFirstFile(Fpath, &FileData);
1139
1140 if (h != INVALID_HANDLE_VALUE) {
1141 while (true) {
1142 if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
1143 *FileData.cFileName != '.') {
1144 // Look in the name sub-directory
1145 strcat(strcat(Direc, FileData.cFileName), "/");
1146 n += FindInDir(g);
1147 Direc[m] = '\0'; // Restore path
1148 } // endif SUBDIR
1149
1150 if (!FindNextFile(h, &FileData))
1151 break;
1152
1153 } // endwhile
1154
1155 } // endif h
1156 #endif // !PATHMATCHSPEC
1157
1158 // Close the search handle.
1159 FindClose(h);
1160 #else // !_WIN32
1161 int k;
1162 DIR *dir = opendir(Direc);
1163
1164 if (!dir) {
1165 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
1166 return -1;
1167 } // endif dir
1168
1169 while ((Entry = readdir(dir))) {
1170 strcat(strcpy(Fpath, Direc), Entry->d_name);
1171
1172 if (lstat(Fpath, &Fileinfo) < 0) {
1173 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
1174 return -1;
1175 } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
1176 // Look in the name sub-directory
1177 strcat(strcat(Direc, Entry->d_name), "/");
1178
1179 if ((k = FindInDir(g)) < 0)
1180 return k;
1181 else
1182 n += k;
1183
1184 Direc[m] = '\0'; // Restore path
1185 } else if (S_ISREG(Fileinfo.st_mode))
1186 // Test whether the file name matches the table name filter
1187 if (!fnmatch(Pattern, Entry->d_name, 0))
1188 n++; // We have a match
1189
1190 } // endwhile readdir
1191
1192 // Close the DIR handle.
1193 closedir(dir);
1194 #endif // !_WIN32
1195
1196 return n;
1197 } // end of FindInDir
1198
1199 /***********************************************************************/
1200 /* DIR Access Method opening routine. */
1201 /* Open first file, other will be opened sequencially when reading. */
1202 /***********************************************************************/
OpenDB(PGLOBAL g)1203 bool TDBSDR::OpenDB(PGLOBAL g)
1204 {
1205 if (!Sub) {
1206 Path(g);
1207 Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1208 Sub->Next = NULL;
1209 Sub->Prev = NULL;
1210 #if defined(_WIN32)
1211 Sub->H = INVALID_HANDLE_VALUE;
1212 Sub->Len = strlen(Direc);
1213 #else // !_WIN32
1214 Sub->D = NULL;
1215 Sub->Len = 0;
1216 #endif // !_WIN32
1217 } // endif To_Sub
1218
1219 return TDBDIR::OpenDB(g);
1220 } // end of OpenDB
1221
1222 /***********************************************************************/
1223 /* Data Base read routine for SDR access method. */
1224 /***********************************************************************/
ReadDB(PGLOBAL g)1225 int TDBSDR::ReadDB(PGLOBAL g)
1226 {
1227 int rc;
1228
1229 #if defined(_WIN32)
1230 again:
1231 rc = TDBDIR::ReadDB(g);
1232
1233 if (rc == RC_EF) {
1234 // Are there more files in sub-directories
1235 retry:
1236 do {
1237 if (Sub->H == INVALID_HANDLE_VALUE) {
1238 // _makepath(Fpath, Drive, Direc, "*", "."); why was this made?
1239 _makepath(Fpath, Drive, Direc, "*", NULL);
1240 Sub->H = FindFirstFile(Fpath, &FileData);
1241 } else if (!FindNextFile(Sub->H, &FileData)) {
1242 FindClose(Sub->H);
1243 Sub->H = INVALID_HANDLE_VALUE;
1244 *FileData.cFileName= '\0';
1245 break;
1246 } // endif findnext
1247
1248 } while(!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1249 (*FileData.cFileName == '.' &&
1250 (!FileData.cFileName[1] || FileData.cFileName[1] == '.')));
1251
1252 if (Sub->H == INVALID_HANDLE_VALUE) {
1253 // No more sub-directories. Are we in a sub-directory?
1254 if (!Sub->Prev)
1255 return rc; // No, all is finished
1256
1257 // here we must continue in the parent directory
1258 Sub = Sub->Prev;
1259 goto retry;
1260 } else {
1261 // Search next sub-directory
1262 Direc[Sub->Len] = '\0';
1263
1264 if (!Sub->Next) {
1265 PSUBDIR sup;
1266
1267 sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1268 sup->Next = NULL;
1269 sup->Prev = Sub;
1270 sup->H = INVALID_HANDLE_VALUE;
1271 Sub->Next = sup;
1272 } // endif Next
1273
1274 Sub = Sub->Next;
1275 strcat(strcat(Direc, FileData.cFileName), "/");
1276 Sub->Len = strlen(Direc);
1277
1278 // Reset Hsearch used by TDBDIR::ReadDB
1279 FindClose(hSearch);
1280 hSearch = INVALID_HANDLE_VALUE;
1281 goto again;
1282 } // endif H
1283
1284 } // endif rc
1285 #else // !_WIN32
1286 rc = RC_NF;
1287
1288 again:
1289 if (!Sub->D)
1290 // Start searching files in the target directory.
1291 if (!(Sub->D = opendir(Direc))) {
1292 sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
1293 rc = RC_FX;
1294 } // endif dir
1295
1296 while (rc == RC_NF)
1297 if ((Entry = readdir(Sub->D))) {
1298 // We need the Fileinfo structure to get info about the file
1299 strcat(strcpy(Fpath, Direc), Entry->d_name);
1300
1301 if (lstat(Fpath, &Fileinfo) < 0) {
1302 sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
1303 rc = RC_FX;
1304 } else if (S_ISDIR(Fileinfo.st_mode) && strcmp(Entry->d_name, ".")
1305 && strcmp(Entry->d_name, "..")) {
1306 // Look in the name sub-directory
1307 if (!Sub->Next) {
1308 PSUBDIR sup;
1309
1310 sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
1311 sup->Next = NULL;
1312 sup->Prev = Sub;
1313 Sub->Next = sup;
1314 } // endif Next
1315
1316 Sub = Sub->Next;
1317 Sub->D = NULL;
1318 Sub->Len = strlen(Direc);
1319 strcat(strcat(Direc, Entry->d_name), "/");
1320 goto again;
1321 } else if (S_ISREG(Fileinfo.st_mode))
1322 // Test whether the file name matches the table name filter
1323 if (!fnmatch(Pattern, Entry->d_name, 0)) {
1324 iFile++; // We have a match
1325 _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
1326 rc = RC_OK;
1327 } // endif fnmatch
1328
1329 } else {
1330 // No more files. Close the DIR handle.
1331 closedir(Sub->D);
1332
1333 // Are we in a sub-directory?
1334 if (Sub->Prev) {
1335 // Yes, we must continue in the parent directory
1336 Direc[Sub->Len] = '\0';
1337 Sub = Sub->Prev;
1338 } else
1339 rc = RC_EF; // No, all is finished
1340
1341 } // endif Entry
1342
1343 #endif // !_WIN32
1344
1345 return rc;
1346 } // end of ReadDB
1347
1348 #if 0
1349 /* ------------------------- Class TDBDHR ---------------------------- */
1350
1351 /***********************************************************************/
1352 /* TABDHR constructors. */
1353 /***********************************************************************/
1354 TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
1355 {
1356 memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
1357 Hsearch = INVALID_HANDLE_VALUE;
1358 iFile = 0;
1359 *Drive = '\0';
1360 *Direc = '\0';
1361 *Fname = '\0';
1362 *Ftype = '\0';
1363 } // end of TDBDHR standard constructor
1364
1365 TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
1366 {
1367 FileData = tdbp->FileData;
1368 Hsearch = tdbp->Hsearch;
1369 iFile = tdbp->iFile;
1370 strcpy(Drive, tdbp->Drive);
1371 strcpy(Direc, tdbp->Direc);
1372 strcpy(Fname, tdbp->Fname);
1373 strcpy(Ftype, tdbp->Ftype);
1374 } // end of TDBDHR copy constructor
1375
1376 // Method
1377 PTDB TDBDHR::Clone(PTABS t)
1378 {
1379 PTDB tp;
1380 PGLOBAL g = t->G; // Is this really useful ???
1381
1382 tp = new(g) TDBDHR(this);
1383 tp->Columns = Columns;
1384 return tp;
1385 } // end of Clone
1386
1387 /***********************************************************************/
1388 /* Allocate DHR column description block. */
1389 /***********************************************************************/
1390 PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
1391 {
1392 return new(g) DHRCOL(cdp, this, cprec, n);
1393 } // end of MakeCol
1394
1395 /***********************************************************************/
1396 /* DHR GetMaxSize: returns the number of retrieved files. */
1397 /***********************************************************************/
1398 int TDBDHR::GetMaxSize(PGLOBAL g)
1399 {
1400 if (MaxSize < 0) {
1401 char filename[_MAX_PATH];
1402 int i, rc;
1403 int n = -1;
1404 HANDLE h;
1405 PDBUSER dup = PlgGetUser(g);
1406
1407 PlugSetPath(filename, To_File, dup->Path);
1408
1409 // Start searching files in the target directory.
1410 h = FindFirstFile(filename, &FileData);
1411
1412 if (h == INVALID_HANDLE_VALUE) {
1413 switch (rc = GetLastError()) {
1414 case ERROR_NO_MORE_FILES:
1415 case ERROR_FILE_NOT_FOUND:
1416 n = 0;
1417 break;
1418 default:
1419 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1420 FORMAT_MESSAGE_IGNORE_INSERTS,
1421 NULL, rc, 0,
1422 (LPTSTR)&filename, sizeof(filename), NULL);
1423 sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
1424 } // endswitch rc
1425
1426 } else {
1427 for (n = 1;; n++)
1428 if (!FindNextFile(h, &FileData)) {
1429 rc = GetLastError();
1430
1431 if (rc != ERROR_NO_MORE_FILES) {
1432 sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
1433 n = -1;
1434 } // endif rc
1435
1436 break;
1437 } // endif FindNextFile
1438
1439 // Close the search handle.
1440 if (!FindClose(h) && n != -1)
1441 strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
1442
1443 } // endif Hsearch
1444
1445 MaxSize = n;
1446 } // endif MaxSize
1447
1448 return MaxSize;
1449 } // end of GetMaxSize
1450
1451 /***********************************************************************/
1452 /* DHR Access Method opening routine. */
1453 /* Open first file, other will be opened sequencially when reading. */
1454 /***********************************************************************/
1455 bool TDBDHR::OpenDB(PGLOBAL g)
1456 {
1457 if (trace(1))
1458 htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
1459 this, Tdb_No, Use, Mode);
1460
1461 if (Use == USE_OPEN) {
1462 /*******************************************************************/
1463 /* Table already open, reopen it. */
1464 /*******************************************************************/
1465 CloseDB(g);
1466 SetUse(USE_READY);
1467 } // endif use
1468
1469 /*********************************************************************/
1470 /* Direct access needed for join or sorting. */
1471 /*********************************************************************/
1472 if (NeedIndexing(g)) {
1473 // Direct access of DHR tables is not implemented yet
1474 sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
1475 return true;
1476 } // endif NeedIndexing
1477
1478 Use = USE_OPEN;
1479 return false;
1480 } // end of OpenDB
1481
1482 /***********************************************************************/
1483 /* Data Base read routine for DHR access method. */
1484 /***********************************************************************/
1485 int TDBDHR::ReadDB(PGLOBAL g)
1486 {
1487 int rc = RC_OK;
1488 DWORD erc;
1489
1490 if (Hsearch == INVALID_HANDLE_VALUE) {
1491 char *filename[_MAX_PATH];
1492 PDBUSER dup = PlgGetUser(g);
1493
1494 PlugSetPath(filename, To_File, dup->Path);
1495 _splitpath(filename, Drive, Direc, NULL, NULL);
1496
1497 /*******************************************************************/
1498 /* Start searching files in the target directory. */
1499 /*******************************************************************/
1500 Hsearch = FindFirstFile(filename, &FileData);
1501
1502 if (Hsearch != INVALID_HANDLE_VALUE)
1503 iFile = 1;
1504 else switch (erc = GetLastError()) {
1505 case ERROR_NO_MORE_FILES:
1506 case ERROR_FILE_NOT_FOUND:
1507 // case ERROR_PATH_NOT_FOUND: ???????
1508 rc = RC_EF;
1509 break;
1510 default:
1511 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1512 FORMAT_MESSAGE_IGNORE_INSERTS,
1513 NULL, erc, 0,
1514 (LPTSTR)&filename, sizeof(filename), NULL);
1515 sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
1516 rc = RC_FX;
1517 } // endswitch erc
1518
1519 } else {
1520 if (!FindNextFile(Hsearch, &FileData)) {
1521 DWORD erc = GetLastError();
1522
1523 if (erc != ERROR_NO_MORE_FILES) {
1524 sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
1525 FindClose(Hsearch);
1526 rc = RC_FX;
1527 } else
1528 rc = RC_EF;
1529
1530 } else
1531 iFile++;
1532
1533 } // endif Hsearch
1534
1535 if (rc == RC_OK)
1536 _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
1537
1538 return rc;
1539 } // end of ReadDB
1540
1541 /***********************************************************************/
1542 /* Data Base close routine for MUL access method. */
1543 /***********************************************************************/
1544 void TDBDHR::CloseDB(PGLOBAL g)
1545 {
1546 // Close the search handle.
1547 if (!FindClose(Hsearch)) {
1548 strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
1549 throw GetAmType();
1550 } // endif FindClose
1551
1552 iFile = 0;
1553 Hsearch = INVALID_HANDLE_VALUE;
1554 } // end of CloseDB
1555
1556 // ------------------------ DHRCOL functions ----------------------------
1557
1558 /***********************************************************************/
1559 /* DHRCOL public constructor. */
1560 /***********************************************************************/
1561 DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
1562 : COLBLK(cdp, tdbp, i)
1563 {
1564 if (cprec) {
1565 Next = cprec->GetNext();
1566 cprec->SetNext(this);
1567 } else {
1568 Next = tdbp->GetColumns();
1569 tdbp->SetColumns(this);
1570 } // endif cprec
1571
1572 // Set additional DHR access method information for column.
1573 N = cdp->GetOffset();
1574 } // end of DOSCOL constructor
1575
1576 /***********************************************************************/
1577 /* DHRCOL constructor used for copying columns. */
1578 /* tdbp is the pointer to the new table descriptor. */
1579 /***********************************************************************/
1580 DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
1581 {
1582 N = col1->N;
1583 } // end of DHRCOL copy constructor
1584
1585 /***********************************************************************/
1586 /* ReadColumn: what this routine does is to access the information */
1587 /* corresponding to this column and convert it to buffer type. */
1588 /***********************************************************************/
1589 void DHRCOL::ReadColumn(PGLOBAL g)
1590 {
1591 int rc;
1592 PTDBDHR tdbp = (PTDBDHR)To_Tdb;
1593
1594 if (trace(1))
1595 htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
1596 Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
1597
1598 /*********************************************************************/
1599 /* Retrieve the information corresponding to the column number. */
1600 /*********************************************************************/
1601 switch (N) {
1602 case 0: // Drive
1603 Value->SetValue(Drive, _MAX_DRIVE);
1604 break;
1605 case 1: // Path
1606 Value->SetValue(Direc, _MAX_DHR);
1607 break;
1608 case 2: // Name
1609 Value->SetValue(Fname, _MAX_FNAME);
1610 break;
1611 case 3: // Extention
1612 Value->SetValue(Ftype, _MAX_EXT);
1613 break;
1614 case 4: // Extention
1615 Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
1616 break;
1617 case 5:
1618 Value->SetValue(tdbp->FileData.dwFileAttributes);
1619 break;
1620 case 6:
1621 Value->SetValue(..................
1622 } // end of ReadColumn
1623 #endif // 0
1624
1625