mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	 0ccdf54b64
			
		
	
	
	0ccdf54b64
	
	
	
		
			
			I checked all stack overflow potential problems found with gcc -Wstack-usage=16384 and clang -Wframe-larger-than=16384 -no-inline Fixes: Added '#pragma clang diagnostic ignored "-Wframe-larger-than="' to a lot of function to where stack usage large but resonable. - Added stack check warnings to BUILD scrips when using clang and debug. Function changed to use malloc instead allocating things on stack: - read_bootstrap_query() now allocates line_buffer (20000 bytes) with malloc() instead of using stack. This has a small performance impact but this is not releant for bootstrap. - mroonga grn_select() used 65856 bytes on stack. Changed it to use malloc(). - Wsrep_schema::replay_transaction() and Wsrep_schema::recover_sr_transactions(). - Connect zipOpen3() Not fixed: - mroonga/vendor/groonga/lib/expr.c grn_proc_call() uses 43712 byte on stack. However this is not easy to fix as the stack used is caused by a lot of code generated by defines. - Most changes in mroonga/groonga where only adding of pragmas to disable stack warnings. - rocksdb/options/options_helper.cc uses 20288 of stack space. (no reason to fix except to get rid of the compiler warning) - Causes using alloca() where the allocation size is resonable. - An issue in libmariadb (reported to connectors).
		
			
				
	
	
		
			1627 lines
		
	
	
	
		
			51 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1627 lines
		
	
	
	
		
			51 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /************* TabMul C++ Program Source Code File (.CPP) **************/
 | |
| /* PROGRAM NAME: TABMUL                                                */
 | |
| /* -------------                                                       */
 | |
| /*  Version 1.9                                                        */
 | |
| /*                                                                     */
 | |
| /* COPYRIGHT:                                                          */
 | |
| /* ----------                                                          */
 | |
| /*  (C) Copyright to PlugDB Software Development          2003 - 2017  */
 | |
| /*  Author: Olivier BERTRAND                                           */
 | |
| /*                                                                     */
 | |
| /* WHAT THIS PROGRAM DOES:                                             */
 | |
| /* -----------------------                                             */
 | |
| /*  This program are the TDBMUL class DB routines.                     */
 | |
| /*                                                                     */
 | |
| /* WHAT YOU NEED TO COMPILE THIS PROGRAM:                              */
 | |
| /* --------------------------------------                              */
 | |
| /*                                                                     */
 | |
| /*  REQUIRED FILES:                                                    */
 | |
| /*  ---------------                                                    */
 | |
| /*    TABMUL.CPP     - Source code                                     */
 | |
| /*    PLGDBSEM.H     - DB application declaration file                 */
 | |
| /*    TABDOS.H       - TABDOS classes declaration file                 */
 | |
| /*    TABMUL.H       - TABFIX classes declaration file                 */
 | |
| /*    GLOBAL.H       - Global declaration file                         */
 | |
| /*                                                                     */
 | |
| /*  REQUIRED LIBRARIES:                                                */
 | |
| /*  -------------------                                                */
 | |
| /*    Large model C library                                            */
 | |
| /*                                                                     */
 | |
| /*  REQUIRED PROGRAMS:                                                 */
 | |
| /*  ------------------                                                 */
 | |
| /*    IBM, Borland, GNU or Microsoft C++ Compiler and Linker           */
 | |
| /*                                                                     */
 | |
| /***********************************************************************/
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Include relevant section of system dependant header files.         */
 | |
| /***********************************************************************/
 | |
| #include "my_global.h"
 | |
| #if defined(_WIN32)
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #if defined(__BORLANDC__)
 | |
| #define __MFC_COMPAT__                   // To define min/max as macro
 | |
| #endif
 | |
| //#include <windows.h>
 | |
| #if defined(PATHMATCHSPEC) 
 | |
| #include "Shlwapi.h"
 | |
| //using namespace std;
 | |
| #pragma comment(lib,"shlwapi.lib")
 | |
| #endif   //	PATHMATCHSPEC
 | |
| #else
 | |
| #if defined(UNIX)
 | |
| #include <fnmatch.h>
 | |
| #include <errno.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include "osutil.h"
 | |
| #else
 | |
| //#include <io.h>
 | |
| #endif
 | |
| //#include <fcntl.h>
 | |
| #endif
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Include application header files:                                  */
 | |
| /***********************************************************************/
 | |
| #include "global.h"      // global declarations
 | |
| #include "plgdbsem.h"    // DB application declarations
 | |
| #include "reldef.h"      // DB definition declares
 | |
| #include "filamtxt.h"
 | |
| #include "tabdos.h"      // TDBDOS and DOSCOL class dcls
 | |
| #include "tabmul.h"      // TDBMUL and MULCOL classes dcls
 | |
| 
 | |
| /* ------------------------- Class TDBMUL ---------------------------- */
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  TABMUL constructors.                                               */
 | |
| /***********************************************************************/
 | |
| TDBMUL::TDBMUL(PTDB tdbp) : TDBASE(tdbp->GetDef())
 | |
|   {
 | |
|   Tdbp = tdbp;
 | |
|   Filenames = NULL;
 | |
|   Rows = 0;
 | |
|   Mul = tdbp->GetDef()->GetMultiple();
 | |
|   NumFiles = 0;
 | |
|   iFile = 0;
 | |
|   } // end of TDBMUL standard constructor
 | |
| 
 | |
| TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp)
 | |
|   {
 | |
|   Tdbp = tdbp->Tdbp;
 | |
|   Filenames = tdbp->Filenames;
 | |
|   Rows = tdbp->Rows;
 | |
|   Mul = tdbp->Mul;
 | |
|   NumFiles = tdbp->NumFiles;
 | |
|   iFile = tdbp->iFile;
 | |
|   } // end of TDBMUL copy constructor
 | |
| 
 | |
| // Method
 | |
| PTDB TDBMUL::Clone(PTABS t)
 | |
|   {
 | |
|   PTDBMUL tp;
 | |
|   PGLOBAL g = t->G;        // Is this really useful ???
 | |
| 
 | |
|   tp = new(g) TDBMUL(this);
 | |
|   tp->Tdbp = Tdbp->Clone(t);
 | |
|   tp->Columns = tp->Tdbp->GetColumns();
 | |
|   return tp;
 | |
|   } // end of Clone
 | |
| 
 | |
| PTDB TDBMUL::Duplicate(PGLOBAL g)
 | |
|   {
 | |
|   PTDBMUL tmup = new(g) TDBMUL(this);
 | |
| 
 | |
|   tmup->Tdbp = Tdbp->Duplicate(g);
 | |
|   return tmup;
 | |
|   } // end of Duplicate
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Initializes the table filename list.                               */
 | |
| /*  Note: tables created by concatenating the file components without  */
 | |
| /*  specifying the LRECL value (that should be restricted to _MAX_PATH)*/
 | |
| /*  have a LRECL that is the sum of the lengths of all components.     */
 | |
| /*  This is why we use a big filename array to take care of that.      */
 | |
| /***********************************************************************/
 | |
| 
 | |
| PRAGMA_DISABLE_CHECK_STACK_FRAME
 | |
| 
 | |
| bool TDBMUL::InitFileNames(PGLOBAL g)
 | |
| {
 | |
| #define PFNZ  4096
 | |
| #define FNSZ  (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
 | |
| 	PTDBDIR dirp;
 | |
| 	PSZ     pfn[PFNZ];
 | |
|   PSZ     filename;
 | |
|   int     rc, n = 0;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("in InitFileName: fn[]=%d\n", FNSZ);
 | |
| 
 | |
|   filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
 | |
| 
 | |
|   // The sub table may need to refer to the Table original block
 | |
|   Tdbp->SetTable(To_Table);         // Was not set at construction
 | |
| 
 | |
|   PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("InitFileName: fn='%s'\n", filename);
 | |
| 
 | |
|   if (Mul != 2) {
 | |
|     /*******************************************************************/
 | |
|     /*  To_File is a multiple name with special characters             */
 | |
|     /*******************************************************************/
 | |
| 		if (Mul == 1)
 | |
| 			dirp = new(g) TDBDIR(PlugDup(g, filename));
 | |
| 		else // Mul == 3 (Subdir)
 | |
| 		  dirp = new(g) TDBSDR(PlugDup(g, filename));
 | |
| 
 | |
| 		if (dirp->OpenDB(g))
 | |
| 			return true;
 | |
| 
 | |
| 		if (trace(1) && Mul == 3) {
 | |
| 			int nf = ((PTDBSDR)dirp)->FindInDir(g);
 | |
| 			htrc("Number of files = %d\n", nf);
 | |
| 		} // endif trace
 | |
| 
 | |
| 		while (true)
 | |
| 			if ((rc = dirp->ReadDB(g)) == RC_OK) {
 | |
| #if defined(_WIN32)
 | |
| 				strcat(strcpy(filename, dirp->Drive), dirp->Direc);
 | |
| #else   // !_WIN32
 | |
| 				strcpy(filename, dirp->Direc);
 | |
| #endif  // !_WIN32
 | |
| 				strcat(strcat(filename, dirp->Fname), dirp->Ftype);
 | |
| 				pfn[n++] = PlugDup(g, filename);
 | |
| 			} else
 | |
| 				break;
 | |
| 
 | |
| 		dirp->CloseDB(g);
 | |
| 
 | |
| 		if (rc == RC_FX)
 | |
| 			return true;
 | |
| 
 | |
|   } else {
 | |
|     /*******************************************************************/
 | |
|     /*  To_File is the name of a file containing the file name list    */
 | |
|     /*******************************************************************/
 | |
|     char *p;
 | |
|     FILE *stream;
 | |
| 
 | |
|     if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r")))
 | |
|       return true;
 | |
| 
 | |
|     while (n < PFNZ) {
 | |
|       if (!fgets(filename, FNSZ, stream)) {
 | |
|         fclose(stream);
 | |
|         break;
 | |
|         } // endif fgets
 | |
| 
 | |
|       p = filename + strlen(filename) - 1;
 | |
| 
 | |
| #if !defined(_WIN32)
 | |
|       // Data files can be imported from Windows (having CRLF)
 | |
|       if (*p == '\n' || *p == '\r') {
 | |
|         // is this enough for Unix ???
 | |
|         p--;          // Eliminate ending CR or LF character
 | |
| 
 | |
|         if (p >= filename)
 | |
|           // is this enough for Unix ???
 | |
|           if (*p == '\n' || *p == '\r')
 | |
|             p--;    // Eliminate ending CR or LF character
 | |
| 
 | |
|         } // endif p
 | |
| 
 | |
| #else
 | |
|       if (*p == '\n')
 | |
|         p--;        // Eliminate ending new-line character
 | |
| #endif
 | |
|       // Trim rightmost blanks
 | |
|       for (; p >= filename && *p == ' '; p--) ;
 | |
| 
 | |
|       *(++p) = '\0';
 | |
| 
 | |
|       // Suballocate the file name
 | |
|       pfn[n++] = PlugDup(g, filename);
 | |
|     } // endfor n
 | |
| 
 | |
|   } // endif Mul
 | |
| 
 | |
|   if (n) {
 | |
|     Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
 | |
| 
 | |
|     for (int i = 0; i < n; i++)
 | |
|       Filenames[i] = pfn[i];
 | |
| 
 | |
|   } else {
 | |
|     Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
 | |
|     Filenames[0] = NULL;
 | |
|   } // endif n
 | |
| 
 | |
|   NumFiles = n;
 | |
|   return false;
 | |
|   } // end of InitFileNames
 | |
| PRAGMA_REENABLE_CHECK_STACK_FRAME
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  The table column list is the sub-table column list.                */
 | |
| /***********************************************************************/
 | |
| PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num)
 | |
|   {
 | |
|   PCOL cp;
 | |
| 
 | |
|   /*********************************************************************/
 | |
|   /*  Because special columns are directly added to the MUL block,     */
 | |
|   /*  make sure that the sub-table has the same column list, before    */
 | |
|   /*  and after the call to the ColDB function.                        */
 | |
|   /*********************************************************************/
 | |
|   Tdbp->SetColumns(Columns);
 | |
|   cp = Tdbp->ColDB(g, name, num);
 | |
|   Columns = Tdbp->GetColumns();
 | |
|   return cp;
 | |
| } // end of ColDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  MUL GetProgMax: get the max value for progress information.        */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::GetProgMax(PGLOBAL g)
 | |
|   {
 | |
|   if (!Filenames && InitFileNames(g))
 | |
|     return -1;
 | |
| 
 | |
|   return NumFiles;                // This is a temporary setting
 | |
|   } // end of GetProgMax
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  MUL GetProgCur: get the current value for progress information.    */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::GetProgCur(void)
 | |
|   {
 | |
|   return iFile;                   // This is a temporary setting
 | |
|   } // end of GetProgMax
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  MUL Cardinality: returns table cardinality in number of rows.      */
 | |
| /*  This function can be called with a null argument to test the       */
 | |
| /*  availability of Cardinality implementation (1 yes, 0 no).          */
 | |
| /*  Can be used on Multiple FIX table only.                            */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::Cardinality(PGLOBAL g)
 | |
|   {
 | |
|   if (!g)
 | |
|     return Tdbp->Cardinality(g);
 | |
| 
 | |
|   if (!Filenames && InitFileNames(g))
 | |
|     return -1;
 | |
| 
 | |
|   int n, card = 0;
 | |
| 
 | |
|   for (int i = 0; i < NumFiles; i++) {
 | |
|     Tdbp->SetFile(g, Filenames[i]);
 | |
|     Tdbp->ResetSize();
 | |
| 
 | |
|     if ((n = Tdbp->Cardinality(g)) < 0) {
 | |
| //    strcpy(g->Message, MSG(BAD_CARDINALITY));
 | |
|       return -1;
 | |
|       } // endif n
 | |
| 
 | |
|     card += n;
 | |
|     } // endfor i
 | |
| 
 | |
|   return card;
 | |
|   } // end of Cardinality
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Sum up the sizes of all sub-tables.                                */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::GetMaxSize(PGLOBAL g)
 | |
|   {
 | |
|   if (MaxSize < 0) {
 | |
|     int i;
 | |
|     int mxsz;
 | |
| 
 | |
|     if (trace(1))
 | |
|       htrc("TDBMUL::GetMaxSize: Filenames=%p\n", Filenames);
 | |
|     
 | |
|     if (!Filenames && InitFileNames(g))
 | |
|       return -1;
 | |
| 
 | |
|     if (Use == USE_OPEN) {
 | |
|       strcpy(g->Message, MSG(MAXSIZE_ERROR));
 | |
|       return -1;
 | |
|     } else
 | |
|       MaxSize = 0;
 | |
| 
 | |
|     for (i = 0; i < NumFiles; i++) {
 | |
|       Tdbp->SetFile(g, Filenames[i]);
 | |
|       Tdbp->ResetSize();
 | |
| 
 | |
|       if ((mxsz = Tdbp->GetMaxSize(g)) < 0) {
 | |
|         MaxSize = -1;
 | |
|         return mxsz;
 | |
|         } // endif mxsz
 | |
| 
 | |
|       MaxSize += mxsz;
 | |
|       } // endfor i
 | |
| 
 | |
|     } // endif MaxSize
 | |
| 
 | |
|   return MaxSize;
 | |
|   } // end of GetMaxSize
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Reset read/write position values.                                  */
 | |
| /***********************************************************************/
 | |
| void TDBMUL::ResetDB(void)
 | |
|   {
 | |
|   for (PCOL colp = Columns; colp; colp = colp->GetNext())
 | |
|     if (colp->GetAmType() == TYPE_AM_FILID)
 | |
|       colp->COLBLK::Reset();
 | |
| 
 | |
|   Tdbp->ResetDB();
 | |
|   } // end of ResetDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Returns RowId if b is false or Rownum if b is true.                */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::RowNumber(PGLOBAL g, bool b)
 | |
|   {
 | |
|   return ((b) ? 0 : Rows)
 | |
|        + ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1);
 | |
|   } // end of RowNumber
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  MUL Access Method opening routine.                                 */
 | |
| /*  Open first file, other will be opened sequencially when reading.   */
 | |
| /***********************************************************************/
 | |
| bool TDBMUL::OpenDB(PGLOBAL g)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
 | |
|       this, Tdb_No, Use, To_Key_Col, Mode);
 | |
| 
 | |
|   if (Use == USE_OPEN) {
 | |
|     /*******************************************************************/
 | |
|     /*  Table already open, replace it at its beginning.               */
 | |
|     /*******************************************************************/
 | |
|     if (Filenames[iFile = 0]) {
 | |
|       Tdbp->CloseDB(g);
 | |
|       Tdbp->SetUse(USE_READY);
 | |
|       Tdbp->SetFile(g, Filenames[iFile = 0]);
 | |
|       Tdbp->ResetSize();
 | |
|       Rows = 0;
 | |
|       ResetDB();
 | |
|       return Tdbp->OpenDB(g);  // Re-open with new file name
 | |
|     } else
 | |
|       return false;
 | |
| 
 | |
|     } // endif use
 | |
| 
 | |
|   /*********************************************************************/
 | |
|   /*  We need to calculate MaxSize before opening the query.           */
 | |
|   /*********************************************************************/
 | |
|   if (GetMaxSize(g) < 0)
 | |
|     return true;
 | |
| 
 | |
|   /*********************************************************************/
 | |
|   /*  Open the first table file of the list.                           */
 | |
|   /*********************************************************************/
 | |
| //if (!Filenames && InitFileNames(g))     // was done in GetMaxSize
 | |
| //  return true;
 | |
| 
 | |
|   if (Filenames[iFile = 0]) {
 | |
|     Tdbp->SetFile(g, Filenames[0]);
 | |
|     Tdbp->SetMode(Mode);
 | |
|     Tdbp->ResetDB();
 | |
|     Tdbp->ResetSize();
 | |
| 
 | |
|     if (Tdbp->OpenDB(g))
 | |
|       return true;
 | |
| 
 | |
|     } // endif *Filenames
 | |
| 
 | |
|   Use = USE_OPEN;
 | |
|   return false;
 | |
|   } // end of OpenDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  ReadDB: Data Base read routine for MUL access method.              */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::ReadDB(PGLOBAL g)
 | |
|   {
 | |
|   int rc;
 | |
| 
 | |
|   if (NumFiles == 0)
 | |
|     return RC_EF;
 | |
|   else if (To_Kindex) {
 | |
|     /*******************************************************************/
 | |
|     /*  Reading is by an index table.                                  */
 | |
|     /*******************************************************************/
 | |
|     strcpy(g->Message, MSG(NO_INDEX_READ));
 | |
|     rc = RC_FX;
 | |
|   } else {
 | |
|     /*******************************************************************/
 | |
|     /*  Now start the reading process.                                 */
 | |
|     /*******************************************************************/
 | |
|    retry:
 | |
|     rc = Tdbp->ReadDB(g);
 | |
| 
 | |
|     if (rc == RC_EF) {
 | |
|       if (Tdbp->GetDef()->GetPseudo() & 1)
 | |
|         // Total number of rows met so far
 | |
|         Rows += Tdbp->RowNumber(g) - 1;
 | |
| 
 | |
|       if (++iFile < NumFiles) {
 | |
|         /***************************************************************/
 | |
|         /*  Continue reading from next table file.                     */
 | |
|         /***************************************************************/
 | |
|         Tdbp->CloseDB(g);
 | |
|         Tdbp->SetUse(USE_READY);
 | |
|         Tdbp->SetFile(g, Filenames[iFile]);
 | |
|         Tdbp->ResetSize();
 | |
|         ResetDB();
 | |
| 
 | |
|         if (Tdbp->OpenDB(g))     // Re-open with new file name
 | |
|           return RC_FX;
 | |
| 
 | |
|         goto retry;
 | |
|         } // endif iFile
 | |
| 
 | |
|     } else if (rc == RC_FX)
 | |
|       strcat(strcat(strcat(g->Message, " ("), Tdbp->GetFile(g)), ")");
 | |
| 
 | |
|   } // endif To_Kindex
 | |
| 
 | |
|   return rc;
 | |
|   } // end of ReadDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base write routine for MUL access method.                     */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::WriteDB(PGLOBAL g)
 | |
|   {
 | |
|   return Tdbp->WriteDB(g);
 | |
| //  strcpy(g->Message, MSG(TABMUL_READONLY));
 | |
| //  return RC_FX;                    // NIY
 | |
|   } // end of WriteDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base delete line routine for MUL access method.               */
 | |
| /***********************************************************************/
 | |
| int TDBMUL::DeleteDB(PGLOBAL g, int)
 | |
|   {
 | |
|   // When implementing DELETE_MODE InitFileNames must be updated to
 | |
|   // eliminate CRLF under Windows if the file is read in binary.
 | |
|   strcpy(g->Message, MSG(TABMUL_READONLY));
 | |
|   return RC_FX;                                      // NIY
 | |
|   } // end of DeleteDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base close routine for MUL access method.                     */
 | |
| /***********************************************************************/
 | |
| void TDBMUL::CloseDB(PGLOBAL g)
 | |
|   {
 | |
|   if (NumFiles > 0) {
 | |
|     Tdbp->CloseDB(g);
 | |
|     iFile = NumFiles;
 | |
|     } // endif NumFiles
 | |
| 
 | |
|   } // end of CloseDB
 | |
| 
 | |
| #if 0
 | |
| /* ------------------------- Class TDBMSD ---------------------------- */
 | |
| 
 | |
| 	// Method
 | |
| PTDB TDBMSD::Clone(PTABS t)
 | |
| {
 | |
| 	PTDBMSD tp;
 | |
| 	PGLOBAL g = t->G;        // Is this really useful ???
 | |
| 
 | |
| 	tp = new(g) TDBMSD(this);
 | |
| 	tp->Tdbp = Tdbp->Clone(t);
 | |
| 	tp->Columns = tp->Tdbp->GetColumns();
 | |
| 	return tp;
 | |
| } // end of Clone
 | |
| 
 | |
| PTDB TDBMSD::Duplicate(PGLOBAL g)
 | |
| {
 | |
| 	PTDBMSD tmup = new(g) TDBMSD(this);
 | |
| 
 | |
| 	tmup->Tdbp = Tdbp->Duplicate(g);
 | |
| 	return tmup;
 | |
| } // end of Duplicate
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Initializes the table filename list.                               */
 | |
| /*  Note: tables created by concatenating the file components without  */
 | |
| /*  specifying the LRECL value (that should be restricted to _MAX_PATH)*/
 | |
| /*  have a LRECL that is the sum of the lengths of all components.     */
 | |
| /*  This is why we use a big filename array to take care of that.      */
 | |
| /***********************************************************************/
 | |
| bool TDBMSD::InitFileNames(PGLOBAL g)
 | |
| {
 | |
| #define PFNZ  4096
 | |
| #define FNSZ  (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
 | |
| 	PTDBSDR dirp;
 | |
| 	PSZ     pfn[PFNZ];
 | |
| 	PSZ     filename;
 | |
| 	int     rc, n = 0;
 | |
| 
 | |
| 	if (trace(1))
 | |
| 		htrc("in InitFileName: fn[]=%d\n", FNSZ);
 | |
| 
 | |
| 	filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
 | |
| 
 | |
| 	// The sub table may need to refer to the Table original block
 | |
| 	Tdbp->SetTable(To_Table);         // Was not set at construction
 | |
| 
 | |
| 	PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
 | |
| 
 | |
| 	if (trace(1))
 | |
| 		htrc("InitFileName: fn='%s'\n", filename);
 | |
| 
 | |
| 	dirp = new(g) TDBSDR(filename);
 | |
| 
 | |
| 	if (dirp->OpenDB(g))
 | |
| 		return true;
 | |
| 
 | |
| 	while (true)
 | |
| 		if ((rc = dirp->ReadDB(g)) == RC_OK) {
 | |
| #if defined(_WIN32)
 | |
| 			strcat(strcpy(filename, dirp->Drive), dirp->Direc);
 | |
| #else   // !_WIN32
 | |
| 			strcpy(filename, dirp->Direc);
 | |
| #endif  // !_WIN32
 | |
| 			strcat(strcat(filename, dirp->Fname), dirp->Ftype);
 | |
| 			pfn[n++] = PlugDup(g, filename);
 | |
| 		} else
 | |
| 			break;
 | |
| 
 | |
| 	if (rc == RC_FX)
 | |
| 		return true;
 | |
| 
 | |
| 	if (n) {
 | |
| 	  Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
 | |
| 
 | |
| 	  for (int i = 0; i < n; i++)
 | |
| 		  Filenames[i] = pfn[i];
 | |
| 
 | |
| 	} else {
 | |
| 	  Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
 | |
| 	  Filenames[0] = NULL;
 | |
| 	} // endif n
 | |
| 
 | |
| 	NumFiles = n;
 | |
| 	return false;
 | |
| } // end of InitFileNames
 | |
| #endif // 0
 | |
| 
 | |
| 	/* --------------------------- Class DIRDEF -------------------------- */
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DefineAM: define specific AM block values from XDB file.           */
 | |
| /***********************************************************************/
 | |
| bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR, int)
 | |
|   {
 | |
|   Desc = Fn = GetStringCatInfo(g, "Filename", NULL);
 | |
|   Incl = GetBoolCatInfo("Subdir", false);
 | |
| 	Huge = GetBoolCatInfo("Huge", false);
 | |
| 	Nodir = GetBoolCatInfo("Nodir", true);
 | |
|   return false;
 | |
|   } // end of DefineAM
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  GetTable: makes a new Table Description Block.                     */
 | |
| /***********************************************************************/
 | |
| PTDB DIRDEF::GetTable(PGLOBAL g, MODE)
 | |
|   {
 | |
| #if 0
 | |
|   if (Huge)
 | |
|     return new(g) TDBDHR(this);        // Not implemented yet
 | |
|   else
 | |
| #endif
 | |
|   if (Incl)
 | |
|     return new(g) TDBSDR(this);        // Including sub-directory files
 | |
|   else
 | |
|     return new(g) TDBDIR(this);    // Not Including sub-directory files
 | |
| 
 | |
|   } // end of GetTable
 | |
| 
 | |
| /* ------------------------- Class TDBDIR ---------------------------- */
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  TABDIR constructors.                                               */
 | |
| /***********************************************************************/
 | |
| void TDBDIR::Init(void)
 | |
| {
 | |
| 	iFile = 0;
 | |
| #if defined(_WIN32)
 | |
| 	Dvalp = NULL;
 | |
| 	memset(&FileData, 0, sizeof(_finddata_t));
 | |
| 	hSearch = INVALID_HANDLE_VALUE;
 | |
| 	*Drive = '\0';
 | |
| #else   // !_WIN32
 | |
| 	memset(&Fileinfo, 0, sizeof(struct stat));
 | |
| 	Entry = NULL;
 | |
| 	Dir = NULL;
 | |
| 	Done = false;
 | |
| 	*Pattern = '\0';
 | |
| #endif  // !_WIN32
 | |
| 	*Fpath = '\0';
 | |
| 	*Direc = '\0';
 | |
| 	*Fname = '\0';
 | |
| 	*Ftype = '\0';
 | |
| }	// end of Init
 | |
| 
 | |
| TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
 | |
| {
 | |
|   To_File = tdp->Fn;
 | |
| 	Nodir = tdp->Nodir;
 | |
| 	Init();
 | |
| } // end of TDBDIR standard constructor
 | |
| 
 | |
| TDBDIR::TDBDIR(PSZ fpat) : TDBASE((PTABDEF)NULL)
 | |
| {
 | |
| 	To_File = fpat;
 | |
| 	Nodir = true;
 | |
| 	Init();
 | |
| } // end of TDBDIR constructor
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Initialize/get the components of the search file pattern.          */
 | |
| /***********************************************************************/
 | |
| char* TDBDIR::Path(PGLOBAL g)
 | |
|   {
 | |
|     (void) PlgGetCatalog(g);                    // XXX Should be removed?
 | |
|     PTABDEF defp = (PTABDEF)To_Def;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
|   if (!*Drive) {
 | |
|     PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
 | |
|     _splitpath(Fpath, Drive, Direc, Fname, Ftype);
 | |
|   } else
 | |
|     _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull for TDBSDR
 | |
| 
 | |
|   return Fpath;
 | |
| #else   // !_WIN32
 | |
|   if (!Done) {
 | |
|     PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
 | |
|     _splitpath(Fpath, NULL, Direc, Fname, Ftype);
 | |
|     strcat(strcpy(Pattern, Fname), Ftype);
 | |
|     Done = true;
 | |
|     } // endif Done
 | |
| 
 | |
|   return Pattern;
 | |
| #endif  // !_WIN32
 | |
|   } // end of Path
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Allocate DIR column description block.                             */
 | |
| /***********************************************************************/
 | |
| PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
 | |
|   {
 | |
|   return new(g) DIRCOL(cdp, this, cprec, n);
 | |
|   } // end of MakeCol
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DIR GetMaxSize: returns the number of retrieved files.             */
 | |
| /***********************************************************************/
 | |
| int TDBDIR::GetMaxSize(PGLOBAL g)
 | |
|   {
 | |
|   if (MaxSize < 0) {
 | |
|     int n = -1;
 | |
| #if defined(_WIN32)
 | |
|     int rc;
 | |
|     // Start searching files in the target directory.
 | |
| 		hSearch = FindFirstFile(Path(g), &FileData);
 | |
| 
 | |
|     if (hSearch == INVALID_HANDLE_VALUE) {
 | |
| 			rc = GetLastError();
 | |
| 
 | |
| 			if (rc != ERROR_FILE_NOT_FOUND) {
 | |
| 				char buf[512];
 | |
| 
 | |
| 				FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | |
| 					            FORMAT_MESSAGE_IGNORE_INSERTS,
 | |
| 					NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
 | |
| 				snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), buf);
 | |
| 				return -1;
 | |
| 			} // endif rc
 | |
| 
 | |
| 			return 0;
 | |
| 		} // endif hSearch
 | |
| 
 | |
| 		while (true) {
 | |
| 			if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
 | |
| 				n++;
 | |
| 
 | |
| 			if (!FindNextFile(hSearch, &FileData)) {
 | |
| 				rc = GetLastError();
 | |
| 
 | |
| 				if (rc != ERROR_NO_MORE_FILES) {
 | |
| 					snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), rc);
 | |
| 					FindClose(hSearch);
 | |
| 					return -1;
 | |
| 				} // endif rc
 | |
| 
 | |
| 				break;
 | |
| 			} // endif Next
 | |
| 
 | |
| 		} // endwhile
 | |
| 
 | |
|     // Close the search handle.
 | |
| 		FindClose(hSearch);
 | |
| #else   // !_WIN32
 | |
|     Path(g);
 | |
| 
 | |
|     // Start searching files in the target directory.
 | |
|     if (!(Dir = opendir(Direc))) {
 | |
|       snprintf(g->Message, sizeof(g->Message), MSG(BAD_DIRECTORY), Direc, strerror(errno));
 | |
|       return -1;
 | |
|       } // endif dir
 | |
| 
 | |
|     while ((Entry = readdir(Dir))) {
 | |
|       strcat(strcpy(Fpath, Direc), Entry->d_name);
 | |
| 
 | |
|       if (lstat(Fpath, &Fileinfo) < 0) {
 | |
|         snprintf(g->Message, sizeof(g->Message), "%s: %s", Fpath, strerror(errno));
 | |
|         return -1;
 | |
|       } else if (S_ISREG(Fileinfo.st_mode))
 | |
|         // Test whether the file name matches the table name filter
 | |
|         if (!fnmatch(Pattern, Entry->d_name, 0))
 | |
|           n++;      // We have a match
 | |
| 
 | |
|       } // endwhile Entry
 | |
| 
 | |
|     // Close the DIR handle.
 | |
|     closedir(Dir);
 | |
| #endif  // !_WIN32
 | |
|     MaxSize = n;
 | |
|     } // endif MaxSize
 | |
| 
 | |
|   return MaxSize;
 | |
|   } // end of GetMaxSize
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DIR Access Method opening routine.                                 */
 | |
| /*  Open first file, other will be opened sequencially when reading.   */
 | |
| /***********************************************************************/
 | |
| bool TDBDIR::OpenDB(PGLOBAL g)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
 | |
|       this, Tdb_No, Use, Mode);
 | |
| 
 | |
|   if (Use == USE_OPEN) {
 | |
|     /*******************************************************************/
 | |
|     /*  Table already open, reopen it.                                 */
 | |
|     /*******************************************************************/
 | |
|     CloseDB(g);
 | |
|     SetUse(USE_READY);
 | |
|     } // endif use
 | |
| 
 | |
|   Use = USE_OPEN;
 | |
| #if !defined(_WIN32)
 | |
|   Path(g);                          // Be sure it is done
 | |
|   Dir = NULL;                       // For ReadDB
 | |
| #endif   // !_WIN32
 | |
|   return false;
 | |
|   } // end of OpenDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base read routine for DIR access method.                      */
 | |
| /***********************************************************************/
 | |
| int TDBDIR::ReadDB(PGLOBAL g)
 | |
|   {
 | |
|   int rc = RC_OK;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 	do {
 | |
| 		if (hSearch == INVALID_HANDLE_VALUE) {
 | |
| 			/*****************************************************************/
 | |
| 			/*  Start searching files in the target directory. The use of    */
 | |
| 			/*  the Path function is required when called from TDBSDR.       */
 | |
| 			/*****************************************************************/
 | |
| 			hSearch = FindFirstFile(Path(g), &FileData);
 | |
| 
 | |
| 			if (hSearch == INVALID_HANDLE_VALUE) {
 | |
| 				rc = RC_EF;
 | |
| 				break;
 | |
| 			} else
 | |
| 				iFile++;
 | |
| 
 | |
| 		} else {
 | |
| 			if (!FindNextFile(hSearch, &FileData)) {
 | |
| 				// Restore file name and type pattern
 | |
| 				_splitpath(To_File, NULL, NULL, Fname, Ftype);
 | |
| 				rc = RC_EF;
 | |
| 				break;
 | |
| 			} else
 | |
| 				iFile++;
 | |
| 
 | |
| 		} // endif hSearch
 | |
| 
 | |
| 	} while (Nodir && FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
 | |
| 
 | |
|   if (rc == RC_OK)
 | |
|     _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
 | |
| 
 | |
| #else   // !Win32
 | |
|   rc = RC_NF;
 | |
| 
 | |
|   if (!Dir)
 | |
|     // Start searching files in the target directory.
 | |
|     if (!(Dir = opendir(Direc))) {
 | |
|       snprintf(g->Message, sizeof(g->Message), MSG(BAD_DIRECTORY), Direc, strerror(errno));
 | |
|       rc = RC_FX;
 | |
|       } // endif dir
 | |
| 
 | |
|   while (rc == RC_NF)
 | |
|     if ((Entry = readdir(Dir))) {
 | |
|       // We need the Fileinfo structure to get info about the file
 | |
|       strcat(strcpy(Fpath, Direc), Entry->d_name);
 | |
| 
 | |
|       if (lstat(Fpath, &Fileinfo) < 0) {
 | |
|         snprintf(g->Message, sizeof(g->Message), "%s: %s", Fpath, strerror(errno));
 | |
|         rc = RC_FX;
 | |
|       } else if (S_ISREG(Fileinfo.st_mode))
 | |
|         // Test whether the file name matches the table name filter
 | |
|         if (!fnmatch(Pattern, Entry->d_name, 0)) {
 | |
|           iFile++;      // We have a match
 | |
|           _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
 | |
|           rc = RC_OK;
 | |
|           } // endif fnmatch
 | |
| 
 | |
|     } else {
 | |
|       // Restore file name and type pattern
 | |
|       _splitpath(To_File, NULL, NULL, Fname, Ftype);
 | |
|       rc = RC_EF;
 | |
|     } // endif Entry
 | |
| 
 | |
| #endif  // !_WIN32
 | |
| 
 | |
|   return rc;
 | |
|   } // end of ReadDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base write routine for DIR access method.                     */
 | |
| /***********************************************************************/
 | |
| int TDBDIR::WriteDB(PGLOBAL g)
 | |
|   {
 | |
|   strcpy(g->Message, MSG(TABDIR_READONLY));
 | |
|   return RC_FX;                    // NIY
 | |
|   } // end of WriteDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base delete line routine for DIR access method.               */
 | |
| /***********************************************************************/
 | |
| int TDBDIR::DeleteDB(PGLOBAL g, int)
 | |
|   {
 | |
|   strcpy(g->Message, MSG(TABDIR_READONLY));
 | |
|   return RC_FX;                                      // NIY
 | |
|   } // end of DeleteDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base close routine for MUL access method.                     */
 | |
| /***********************************************************************/
 | |
| void TDBDIR::CloseDB(PGLOBAL)
 | |
|   {
 | |
| #if defined(_WIN32)
 | |
|   // Close the search handle.
 | |
|   FindClose(hSearch);
 | |
| 	hSearch = INVALID_HANDLE_VALUE;
 | |
| #else   // !_WIN32
 | |
|   // Close the DIR handle
 | |
|   if (Dir) {
 | |
|     closedir(Dir);
 | |
|     Dir = NULL;
 | |
|     } // endif dir
 | |
| #endif  // !_WIN32
 | |
|   iFile = 0;
 | |
|   } // end of CloseDB
 | |
| 
 | |
| // ------------------------ DIRCOL functions ----------------------------
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DIRCOL public constructor.                                         */
 | |
| /***********************************************************************/
 | |
| DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
 | |
|   : COLBLK(cdp, tdbp, i)
 | |
|   {
 | |
|   if (cprec) {
 | |
|     Next = cprec->GetNext();
 | |
|     cprec->SetNext(this);
 | |
|   } else {
 | |
|     Next = tdbp->GetColumns();
 | |
|     tdbp->SetColumns(this);
 | |
|   } // endif cprec
 | |
| 
 | |
|   // Set additional DIR access method information for column.
 | |
| 	Tdbp = (PTDBDIR)tdbp;
 | |
|   N = cdp->GetOffset();
 | |
|   } // end of DIRCOL constructor
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DIRCOL constructor used for copying columns.                       */
 | |
| /*  tdbp is the pointer to the new table descriptor.                   */
 | |
| /***********************************************************************/
 | |
| DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
 | |
|   {
 | |
| 	Tdbp = (PTDBDIR)tdbp;
 | |
| 	N = col1->N;
 | |
|   } // end of DIRCOL copy constructor
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| /***********************************************************************/
 | |
| /*  Retrieve time information from FileData.                           */
 | |
| /***********************************************************************/
 | |
| void DIRCOL::SetTimeValue(PGLOBAL g, FILETIME& ftime)
 | |
| {
 | |
| 	char       tsp[24];
 | |
| 	SYSTEMTIME stp;
 | |
| 
 | |
| 	if (FileTimeToSystemTime(&ftime, &stp)) {
 | |
| 		sprintf(tsp, "%04d-%02d-%02d %02d:%02d:%02d",
 | |
| 			stp.wYear, stp.wMonth, stp.wDay, stp.wHour, stp.wMinute, stp.wSecond);
 | |
| 
 | |
| 		if (Value->GetType() != TYPE_STRING) {
 | |
| 			if (!Tdbp->Dvalp)
 | |
| 				Tdbp->Dvalp = AllocateValue(g, TYPE_DATE, 20, 0, false,
 | |
| 					"YYYY-MM-DD hh:mm:ss");
 | |
| 
 | |
| 			Tdbp->Dvalp->SetValue_psz(tsp);
 | |
| 			Value->SetValue_pval(Tdbp->Dvalp);
 | |
| 		} else
 | |
| 			Value->SetValue_psz(tsp);
 | |
| 
 | |
| 	} else
 | |
| 		Value->Reset();
 | |
| 
 | |
| } // end of SetTimeValue
 | |
| #endif   // _WIN32
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  ReadColumn: what this routine does is to access the information    */
 | |
| /*  corresponding to this column and convert it to buffer type.        */
 | |
| /***********************************************************************/
 | |
| void DIRCOL::ReadColumn(PGLOBAL g)
 | |
| 	{
 | |
|   if (trace(1))
 | |
|     htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
 | |
|       Name, Tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
 | |
| 
 | |
|   /*********************************************************************/
 | |
|   /*  Retrieve the information corresponding to the column number.     */
 | |
|   /*********************************************************************/
 | |
|   switch (N) {
 | |
| #if defined(_WIN32)
 | |
|     case  0: Value->SetValue_psz(Tdbp->Drive); break;
 | |
| #endif   // _WIN32
 | |
|     case  1: Value->SetValue_psz(Tdbp->Direc); break;
 | |
|     case  2: Value->SetValue_psz(Tdbp->Fname); break;
 | |
|     case  3: Value->SetValue_psz(Tdbp->Ftype); break;
 | |
| #if defined(_WIN32)
 | |
|     case  4: Value->SetValue((int)Tdbp->FileData.dwFileAttributes); break;
 | |
| 		case  5: Value->SetValue((int)Tdbp->FileData.nFileSizeLow); break;
 | |
|     case  6: SetTimeValue(g, Tdbp->FileData.ftLastWriteTime);   break;
 | |
|     case  7: SetTimeValue(g, Tdbp->FileData.ftCreationTime);    break;
 | |
|     case  8: SetTimeValue(g, Tdbp->FileData.ftLastAccessTime);  break;
 | |
| #else   // !_WIN32
 | |
|     case  4: Value->SetValue((int)Tdbp->Fileinfo.st_mode);  break;
 | |
|     case  5: Value->SetValue((int)Tdbp->Fileinfo.st_size);  break;
 | |
|     case  6: Value->SetValue((int)Tdbp->Fileinfo.st_mtime); break;
 | |
|     case  7: Value->SetValue((int)Tdbp->Fileinfo.st_ctime); break;
 | |
|     case  8: Value->SetValue((int)Tdbp->Fileinfo.st_atime); break;
 | |
|     case  9: Value->SetValue((int)Tdbp->Fileinfo.st_uid);   break;
 | |
|     case 10: Value->SetValue((int)Tdbp->Fileinfo.st_gid);   break;
 | |
| #endif  // !_WIN32
 | |
|     default:
 | |
|       snprintf(g->Message, sizeof(g->Message), MSG(INV_DIRCOL_OFST), N);
 | |
| 			throw GetAmType();
 | |
| 	} // endswitch N
 | |
| 
 | |
|   } // end of ReadColumn
 | |
| 
 | |
| /* ------------------------- Class TDBSDR ---------------------------- */
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  SDR GetMaxSize: returns the number of retrieved files.             */
 | |
| /***********************************************************************/
 | |
| int TDBSDR::GetMaxSize(PGLOBAL g)
 | |
|   {
 | |
|   if (MaxSize < 0) {
 | |
|     Path(g);
 | |
|     MaxSize = FindInDir(g);
 | |
|     } // endif MaxSize
 | |
| 
 | |
|   return MaxSize;
 | |
|   } // end of GetMaxSize
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  SDR FindInDir: returns the number of retrieved files.              */
 | |
| /***********************************************************************/
 | |
| int TDBSDR::FindInDir(PGLOBAL g)
 | |
|   {
 | |
|   int    n = 0;
 | |
|   size_t m = strlen(Direc);
 | |
| 
 | |
|   // Start searching files in the target directory.
 | |
| #if defined(_WIN32)
 | |
| 	int rc;
 | |
| 	HANDLE h;
 | |
| 
 | |
| #if defined(PATHMATCHSPEC)
 | |
| 	if (!*Drive)
 | |
| 		Path(g);
 | |
| 
 | |
| 	_makepath(Fpath, Drive, Direc, "*", "*");
 | |
| 
 | |
| 	h = FindFirstFile(Fpath, &FileData);
 | |
| 
 | |
|   if (h == INVALID_HANDLE_VALUE) {
 | |
| 		rc = GetLastError();
 | |
| 
 | |
| 		if (rc != ERROR_FILE_NOT_FOUND) {
 | |
| 			char buf[512];
 | |
| 
 | |
| 			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | |
| 				FORMAT_MESSAGE_IGNORE_INSERTS,
 | |
| 				NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
 | |
| 			snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), buf);
 | |
| 			return -1;
 | |
| 		} // endif rc
 | |
| 
 | |
| 		return 0;
 | |
| 	} // endif h
 | |
| 
 | |
| 	while (true) {
 | |
| 		if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
 | |
| 			  *FileData.cFileName != '.') {
 | |
| 			// Look in the name sub-directory
 | |
| 			strcat(strcat(Direc, FileData.cFileName), "/");
 | |
| 			n += FindInDir(g);
 | |
| 			Direc[m] = '\0';         // Restore path
 | |
| 		} else if (PathMatchSpec(FileData.cFileName, Fpath))
 | |
| 			n++;
 | |
| 
 | |
| 		if (!FindNextFile(h, &FileData)) {
 | |
| 			rc = GetLastError();
 | |
| 
 | |
| 			if (rc != ERROR_NO_MORE_FILES) {
 | |
| 				snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), rc);
 | |
| 				FindClose(h);
 | |
| 				return -1;
 | |
| 			} // endif rc
 | |
| 
 | |
| 			break;
 | |
| 		} // endif Next
 | |
| 
 | |
| 	} // endwhile
 | |
| #else   // !PATHMATCHSPEC
 | |
| 	h = FindFirstFile(Path(g), &FileData);
 | |
| 
 | |
| 	if (h == INVALID_HANDLE_VALUE) {
 | |
| 		rc = GetLastError();
 | |
| 
 | |
| 		if (rc != ERROR_FILE_NOT_FOUND) {
 | |
| 			char buf[512];
 | |
| 
 | |
| 			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | |
| 				FORMAT_MESSAGE_IGNORE_INSERTS,
 | |
| 				NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
 | |
| 			snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), buf);
 | |
| 			return -1;
 | |
| 		} // endif rc
 | |
| 
 | |
| 		return 0;
 | |
| 	} // endif hSearch
 | |
| 
 | |
| 	while (true) {
 | |
| 		n++;
 | |
| 
 | |
| 		if (!FindNextFile(h, &FileData)) {
 | |
| 			rc = GetLastError();
 | |
| 
 | |
| 			if (rc != ERROR_NO_MORE_FILES) {
 | |
| 				snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), rc);
 | |
| 				FindClose(h);
 | |
| 				return -1;
 | |
| 			} // endif rc
 | |
| 
 | |
| 			break;
 | |
| 		} // endif Next
 | |
| 
 | |
| 	} // endwhile
 | |
| 
 | |
| 	// Now search files in sub-directories.
 | |
| 	_makepath(Fpath, Drive, Direc, "*", ".");
 | |
| 	h = FindFirstFile(Fpath, &FileData);
 | |
| 
 | |
| 	if (h != INVALID_HANDLE_VALUE) {
 | |
| 		while (true) {
 | |
| 			if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
 | |
| 				  *FileData.cFileName != '.') {
 | |
| 				// Look in the name sub-directory
 | |
| 				strcat(strcat(Direc, FileData.cFileName), "/");
 | |
| 				n += FindInDir(g);
 | |
| 				Direc[m] = '\0';         // Restore path
 | |
| 			} // endif SUBDIR
 | |
| 
 | |
| 			if (!FindNextFile(h, &FileData))
 | |
| 				break;
 | |
| 
 | |
| 		} // endwhile
 | |
| 
 | |
| 	} // endif h
 | |
| #endif  // !PATHMATCHSPEC
 | |
| 
 | |
|   // Close the search handle.
 | |
| 	FindClose(h);
 | |
| #else   // !_WIN32
 | |
|   int k;
 | |
|   DIR *dir = opendir(Direc);
 | |
| 
 | |
|   if (!dir) {
 | |
|     snprintf(g->Message, sizeof(g->Message), MSG(BAD_DIRECTORY), Direc, strerror(errno));
 | |
|     return -1;
 | |
|     } // endif dir
 | |
| 
 | |
|   while ((Entry = readdir(dir))) {
 | |
|     strcat(strcpy(Fpath, Direc), Entry->d_name);
 | |
| 
 | |
|     if (lstat(Fpath, &Fileinfo) < 0) {
 | |
|       snprintf(g->Message, sizeof(g->Message), "%s: %s", Fpath, strerror(errno));
 | |
|       return -1;
 | |
|     } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
 | |
|       // Look in the name sub-directory
 | |
|       strcat(strcat(Direc, Entry->d_name), "/");
 | |
| 
 | |
|       if ((k= FindInDir(g)) < 0)
 | |
|         return k;
 | |
|       else
 | |
|         n += k;
 | |
| 
 | |
|       Direc[m] = '\0';         // Restore path
 | |
|     } else if (S_ISREG(Fileinfo.st_mode))
 | |
|       // Test whether the file name matches the table name filter
 | |
|       if (!fnmatch(Pattern, Entry->d_name, 0))
 | |
|         n++;      // We have a match
 | |
| 
 | |
|     } // endwhile readdir
 | |
| 
 | |
|   // Close the DIR handle.
 | |
|   closedir(dir);
 | |
| #endif  // !_WIN32
 | |
| 
 | |
|   return n;
 | |
|   } // end of FindInDir
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DIR Access Method opening routine.                                 */
 | |
| /*  Open first file, other will be opened sequencially when reading.   */
 | |
| /***********************************************************************/
 | |
| bool TDBSDR::OpenDB(PGLOBAL g)
 | |
|   {
 | |
|   if (!Sub) {
 | |
|     Path(g);
 | |
|     Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
 | |
|     Sub->Next = NULL;
 | |
|     Sub->Prev = NULL;
 | |
| #if defined(_WIN32)
 | |
|     Sub->H = INVALID_HANDLE_VALUE;
 | |
|     Sub->Len = strlen(Direc);
 | |
| #else   // !_WIN32
 | |
|     Sub->D = NULL;
 | |
|     Sub->Len = 0;
 | |
| #endif  // !_WIN32
 | |
|     } // endif To_Sub
 | |
| 
 | |
|   return TDBDIR::OpenDB(g);
 | |
|   } // end of OpenDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base read routine for SDR access method.                      */
 | |
| /***********************************************************************/
 | |
| int TDBSDR::ReadDB(PGLOBAL g)
 | |
|   {
 | |
|   int rc;
 | |
| 
 | |
| #if defined(_WIN32)
 | |
|  again:
 | |
|   rc = TDBDIR::ReadDB(g);
 | |
| 
 | |
|   if (rc == RC_EF) {
 | |
|     // Are there more files in sub-directories
 | |
|    retry:
 | |
|     do {
 | |
|       if (Sub->H == INVALID_HANDLE_VALUE) {
 | |
| //      _makepath(Fpath, Drive, Direc, "*", ".");		 why was this made?
 | |
| 				_makepath(Fpath, Drive, Direc, "*", NULL);
 | |
| 				Sub->H = FindFirstFile(Fpath, &FileData);
 | |
|       } else if (!FindNextFile(Sub->H, &FileData)) {
 | |
|         FindClose(Sub->H);
 | |
|         Sub->H = INVALID_HANDLE_VALUE;
 | |
|         *FileData.cFileName= '\0';
 | |
| 				break;
 | |
|       } // endif findnext
 | |
| 
 | |
|     } while(!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
 | |
|     		(*FileData.cFileName == '.' && 
 | |
| 			  (!FileData.cFileName[1] || FileData.cFileName[1] == '.')));
 | |
| 
 | |
|     if (Sub->H == INVALID_HANDLE_VALUE) {
 | |
|       // No more sub-directories. Are we in a sub-directory?
 | |
|       if (!Sub->Prev)
 | |
|         return rc;               // No, all is finished
 | |
| 
 | |
|       // here we must continue in the parent directory
 | |
|       Sub = Sub->Prev;
 | |
|       goto retry;
 | |
|     } else {
 | |
|       // Search next sub-directory
 | |
|       Direc[Sub->Len] = '\0';
 | |
| 
 | |
|       if (!Sub->Next) {
 | |
|         PSUBDIR sup;
 | |
| 
 | |
|         sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
 | |
|         sup->Next = NULL;
 | |
|         sup->Prev = Sub;
 | |
|         sup->H = INVALID_HANDLE_VALUE;
 | |
|         Sub->Next = sup;
 | |
|         } // endif Next
 | |
| 
 | |
|       Sub = Sub->Next;
 | |
|       strcat(strcat(Direc, FileData.cFileName), "/");
 | |
|       Sub->Len = strlen(Direc);
 | |
| 
 | |
|       // Reset Hsearch used by TDBDIR::ReadDB
 | |
| 			FindClose(hSearch);
 | |
| 			hSearch = INVALID_HANDLE_VALUE;
 | |
|       goto again;
 | |
|     } // endif H
 | |
| 
 | |
|     } // endif rc
 | |
| #else   // !_WIN32
 | |
|   rc = RC_NF;
 | |
| 
 | |
|  again:
 | |
|   if (!Sub->D)
 | |
|     // Start searching files in the target directory.
 | |
|     if (!(Sub->D = opendir(Direc))) {
 | |
|       snprintf(g->Message, sizeof(g->Message), MSG(BAD_DIRECTORY), Direc, strerror(errno));
 | |
|       rc = RC_FX;
 | |
|       } // endif dir
 | |
| 
 | |
|   while (rc == RC_NF)
 | |
|     if ((Entry = readdir(Sub->D))) {
 | |
|       // We need the Fileinfo structure to get info about the file
 | |
|       strcat(strcpy(Fpath, Direc), Entry->d_name);
 | |
| 
 | |
|       if (lstat(Fpath, &Fileinfo) < 0) {
 | |
|         snprintf(g->Message, sizeof(g->Message), "%s: %s", Fpath, strerror(errno));
 | |
|         rc = RC_FX;
 | |
|       } else if (S_ISDIR(Fileinfo.st_mode) && strcmp(Entry->d_name, ".")
 | |
| 			                                     && strcmp(Entry->d_name, "..")) {
 | |
|         // Look in the name sub-directory
 | |
|         if (!Sub->Next) {
 | |
|           PSUBDIR sup;
 | |
| 
 | |
|           sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
 | |
|           sup->Next = NULL;
 | |
|           sup->Prev = Sub;
 | |
|           Sub->Next = sup;
 | |
|           } // endif Next
 | |
| 
 | |
|         Sub = Sub->Next;
 | |
|         Sub->D = NULL;
 | |
|         Sub->Len = strlen(Direc);
 | |
|         strcat(strcat(Direc, Entry->d_name), "/");
 | |
|         goto again;
 | |
|       } else if (S_ISREG(Fileinfo.st_mode))
 | |
|         // Test whether the file name matches the table name filter
 | |
|         if (!fnmatch(Pattern, Entry->d_name, 0)) {
 | |
|           iFile++;      // We have a match
 | |
|           _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
 | |
|           rc = RC_OK;
 | |
|           } // endif fnmatch
 | |
| 
 | |
|     } else {
 | |
|       // No more files. Close the DIR handle.
 | |
|       closedir(Sub->D);
 | |
| 
 | |
|       // Are we in a sub-directory?
 | |
|       if (Sub->Prev) {
 | |
|         // Yes, we must continue in the parent directory
 | |
|         Direc[Sub->Len] = '\0';
 | |
|         Sub = Sub->Prev;
 | |
|       } else
 | |
|         rc = RC_EF;              // No, all is finished
 | |
| 
 | |
|     } // endif Entry
 | |
| 
 | |
| #endif  // !_WIN32
 | |
| 
 | |
|   return rc;
 | |
|   } // end of ReadDB
 | |
| 
 | |
| #if 0
 | |
| /* ------------------------- Class TDBDHR ---------------------------- */
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  TABDHR constructors.                                               */
 | |
| /***********************************************************************/
 | |
| TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
 | |
|   {
 | |
|   memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
 | |
|   Hsearch = INVALID_HANDLE_VALUE;
 | |
|   iFile = 0;
 | |
|   *Drive = '\0';
 | |
|   *Direc = '\0';
 | |
|   *Fname = '\0';
 | |
|   *Ftype = '\0';
 | |
|   } // end of TDBDHR standard constructor
 | |
| 
 | |
| TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
 | |
|   {
 | |
|   FileData = tdbp->FileData;
 | |
|   Hsearch = tdbp->Hsearch;
 | |
|   iFile = tdbp->iFile;
 | |
|   strcpy(Drive, tdbp->Drive);
 | |
|   strcpy(Direc, tdbp->Direc);
 | |
|   strcpy(Fname, tdbp->Fname);
 | |
|   strcpy(Ftype, tdbp->Ftype);
 | |
|   } // end of TDBDHR copy constructor
 | |
| 
 | |
| // Method
 | |
| PTDB TDBDHR::Clone(PTABS t)
 | |
|   {
 | |
|   PTDB    tp;
 | |
|   PGLOBAL g = t->G;        // Is this really useful ???
 | |
| 
 | |
|   tp = new(g) TDBDHR(this);
 | |
|   tp->Columns = Columns;
 | |
|   return tp;
 | |
|   } // end of Clone
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Allocate DHR column description block.                             */
 | |
| /***********************************************************************/
 | |
| PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
 | |
|   {
 | |
|   return new(g) DHRCOL(cdp, this, cprec, n);
 | |
|   } // end of MakeCol
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DHR GetMaxSize: returns the number of retrieved files.             */
 | |
| /***********************************************************************/
 | |
| int TDBDHR::GetMaxSize(PGLOBAL g)
 | |
|   {
 | |
|   if (MaxSize < 0) {
 | |
|     char    filename[_MAX_PATH];
 | |
|     int     i, rc;
 | |
|     int    n = -1;
 | |
|     HANDLE  h;
 | |
|     PDBUSER dup = PlgGetUser(g);
 | |
| 
 | |
|     PlugSetPath(filename, To_File, dup->Path);
 | |
| 
 | |
|     // Start searching files in the target directory.
 | |
|     h = FindFirstFile(filename, &FileData);
 | |
| 
 | |
|     if (h == INVALID_HANDLE_VALUE) {
 | |
|       switch (rc = GetLastError()) {
 | |
|         case ERROR_NO_MORE_FILES:
 | |
|         case ERROR_FILE_NOT_FOUND:
 | |
|           n = 0;
 | |
|           break;
 | |
|         default:
 | |
|           FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | |
|                         FORMAT_MESSAGE_IGNORE_INSERTS,
 | |
|                         NULL, rc, 0,
 | |
|                         (LPTSTR)&filename, sizeof(filename), NULL);
 | |
|           snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), filename);
 | |
|         } // endswitch rc
 | |
| 
 | |
|     } else {
 | |
|       for (n = 1;; n++)
 | |
|         if (!FindNextFile(h, &FileData)) {
 | |
|           rc = GetLastError();
 | |
| 
 | |
|           if (rc != ERROR_NO_MORE_FILES) {
 | |
|             snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), rc);
 | |
|             n = -1;
 | |
|             } // endif rc
 | |
| 
 | |
|           break;
 | |
|           } // endif FindNextFile
 | |
| 
 | |
|       // Close the search handle.
 | |
|       if (!FindClose(h) && n != -1)
 | |
|         strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
 | |
| 
 | |
|     } // endif Hsearch
 | |
| 
 | |
|     MaxSize = n;
 | |
|     } // endif MaxSize
 | |
| 
 | |
|   return MaxSize;
 | |
|   } // end of GetMaxSize
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DHR Access Method opening routine.                                 */
 | |
| /*  Open first file, other will be opened sequencially when reading.   */
 | |
| /***********************************************************************/
 | |
| bool TDBDHR::OpenDB(PGLOBAL g)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
 | |
|       this, Tdb_No, Use, Mode);
 | |
| 
 | |
|   if (Use == USE_OPEN) {
 | |
|     /*******************************************************************/
 | |
|     /*  Table already open, reopen it.                                 */
 | |
|     /*******************************************************************/
 | |
|     CloseDB(g);
 | |
|     SetUse(USE_READY);
 | |
|     } // endif use
 | |
| 
 | |
|   /*********************************************************************/
 | |
|   /*  Direct access needed for join or sorting.                        */
 | |
|   /*********************************************************************/
 | |
|   if (NeedIndexing(g)) {
 | |
|     // Direct access of DHR tables is not implemented yet
 | |
|     snprintf(g->Message, sizeof(g->Message), MSG(NO_DIR_INDX_RD), "DHR");
 | |
|     return true;
 | |
|     } // endif NeedIndexing
 | |
| 
 | |
|   Use = USE_OPEN;
 | |
|   return false;
 | |
|   } // end of OpenDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base read routine for DHR access method.                      */
 | |
| /***********************************************************************/
 | |
| int TDBDHR::ReadDB(PGLOBAL g)
 | |
|   {
 | |
|   int   rc = RC_OK;
 | |
|   DWORD erc;
 | |
| 
 | |
|   if (Hsearch == INVALID_HANDLE_VALUE) {
 | |
|     char   *filename[_MAX_PATH];
 | |
|     PDBUSER dup = PlgGetUser(g);
 | |
| 
 | |
|     PlugSetPath(filename, To_File, dup->Path);
 | |
|     _splitpath(filename, Drive, Direc, NULL, NULL);
 | |
| 
 | |
|     /*******************************************************************/
 | |
|     /*  Start searching files in the target directory.                 */
 | |
|     /*******************************************************************/
 | |
|     Hsearch = FindFirstFile(filename, &FileData);
 | |
| 
 | |
|     if (Hsearch != INVALID_HANDLE_VALUE)
 | |
|       iFile = 1;
 | |
|     else switch (erc = GetLastError()) {
 | |
|       case ERROR_NO_MORE_FILES:
 | |
|       case ERROR_FILE_NOT_FOUND:
 | |
| //    case ERROR_PATH_NOT_FOUND:               ???????
 | |
|         rc = RC_EF;
 | |
|         break;
 | |
|       default:
 | |
|         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
 | |
|                       FORMAT_MESSAGE_IGNORE_INSERTS,
 | |
|                       NULL, erc,  0,
 | |
|                       (LPTSTR)&filename, sizeof(filename), NULL);
 | |
|         snprintf(g->Message, sizeof(g->Message), MSG(BAD_FILE_HANDLE), filename);
 | |
|         rc = RC_FX;
 | |
|       } // endswitch erc
 | |
| 
 | |
|   } else {
 | |
|     if (!FindNextFile(Hsearch, &FileData)) {
 | |
|       DWORD erc = GetLastError();
 | |
| 
 | |
|       if (erc != ERROR_NO_MORE_FILES) {
 | |
|         snprintf(g->Message, sizeof(g->Message), MSG(NEXT_FILE_ERROR), erc);
 | |
|         FindClose(Hsearch);
 | |
|         rc = RC_FX;
 | |
|       } else
 | |
|         rc = RC_EF;
 | |
| 
 | |
|     } else
 | |
|       iFile++;
 | |
| 
 | |
|   } // endif Hsearch
 | |
| 
 | |
|   if (rc == RC_OK)
 | |
|     _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
 | |
| 
 | |
|   return rc;
 | |
|   } // end of ReadDB
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  Data Base close routine for MUL access method.                     */
 | |
| /***********************************************************************/
 | |
| void TDBDHR::CloseDB(PGLOBAL g)
 | |
|   {
 | |
|   // Close the search handle.
 | |
|   if (!FindClose(Hsearch)) {
 | |
|     strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
 | |
| 		throw GetAmType();
 | |
| 	} // endif FindClose
 | |
| 
 | |
|   iFile = 0;
 | |
|   Hsearch = INVALID_HANDLE_VALUE;
 | |
|   } // end of CloseDB
 | |
| 
 | |
| // ------------------------ DHRCOL functions ----------------------------
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DHRCOL public constructor.                                         */
 | |
| /***********************************************************************/
 | |
| DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
 | |
|       : COLBLK(cdp, tdbp, i)
 | |
|   {
 | |
|   if (cprec) {
 | |
|     Next = cprec->GetNext();
 | |
|     cprec->SetNext(this);
 | |
|   } else {
 | |
|     Next = tdbp->GetColumns();
 | |
|     tdbp->SetColumns(this);
 | |
|   } // endif cprec
 | |
| 
 | |
|   // Set additional DHR access method information for column.
 | |
|   N = cdp->GetOffset();
 | |
|   } // end of DOSCOL constructor
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  DHRCOL constructor used for copying columns.                       */
 | |
| /*  tdbp is the pointer to the new table descriptor.                   */
 | |
| /***********************************************************************/
 | |
| DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
 | |
|   {
 | |
|   N = col1->N;
 | |
|   } // end of DHRCOL copy constructor
 | |
| 
 | |
| /***********************************************************************/
 | |
| /*  ReadColumn: what this routine does is to access the information    */
 | |
| /*  corresponding to this column and convert it to buffer type.        */
 | |
| /***********************************************************************/
 | |
| void DHRCOL::ReadColumn(PGLOBAL g)
 | |
|   {
 | |
|   int     rc;
 | |
|   PTDBDHR tdbp = (PTDBDHR)To_Tdb;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
 | |
|       Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
 | |
| 
 | |
|   /*********************************************************************/
 | |
|   /*  Retrieve the information corresponding to the column number.     */
 | |
|   /*********************************************************************/
 | |
|   switch (N) {
 | |
|     case 0:                                // Drive
 | |
|       Value->SetValue(Drive, _MAX_DRIVE);
 | |
|       break;
 | |
|     case 1:                                // Path
 | |
|       Value->SetValue(Direc, _MAX_DHR);
 | |
|       break;
 | |
|     case 2:                                // Name
 | |
|       Value->SetValue(Fname, _MAX_FNAME);
 | |
|       break;
 | |
|     case 3:                                // Extention
 | |
|       Value->SetValue(Ftype, _MAX_EXT);
 | |
|       break;
 | |
|     case 4:                                // Extention
 | |
|       Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
 | |
|       break;
 | |
|     case 5:
 | |
|       Value->SetValue(tdbp->FileData.dwFileAttributes);
 | |
|       break;
 | |
|     case 6:
 | |
|       Value->SetValue(..................
 | |
|   } // end of ReadColumn
 | |
| #endif // 0
 | |
| 
 |