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