summaryrefslogtreecommitdiff
path: root/storage/connect/tabmul.cpp
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mnogosearch.org>2013-02-07 13:34:27 +0400
committerAlexander Barkov <bar@mnogosearch.org>2013-02-07 13:34:27 +0400
commit30c4b0ebc24fe0106e146b1f6577a4150e71e258 (patch)
tree592673d8c2f5b418833c3ee5fcfeb9dbf4ba1681 /storage/connect/tabmul.cpp
parent60c4cab3bd00621cc03afb1be6de01c8fab0c5f0 (diff)
downloadmariadb-git-30c4b0ebc24fe0106e146b1f6577a4150e71e258.tar.gz
- Fixing TAB to 2 spaces
- Fixing line endings from "\r\n" to "\n"
Diffstat (limited to 'storage/connect/tabmul.cpp')
-rw-r--r--storage/connect/tabmul.cpp2948
1 files changed, 1474 insertions, 1474 deletions
diff --git a/storage/connect/tabmul.cpp b/storage/connect/tabmul.cpp
index 1b272196e0f..eddc6afa08b 100644
--- a/storage/connect/tabmul.cpp
+++ b/storage/connect/tabmul.cpp
@@ -1,1474 +1,1474 @@
-/************* TabMul C++ Program Source Code File (.CPP) **************/
-/* PROGRAM NAME: TABMUL */
-/* ------------- */
-/* Version 1.7 */
-/* */
-/* COPYRIGHT: */
-/* ---------- */
-/* (C) Copyright to PlugDB Software Development 2003 - 2012 */
-/* 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>
-#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(PTDBASE 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::CopyOne(PTABS t)
- {
- PTDBMUL tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBMUL(this);
- tp->Tdbp = (PTDBASE)Tdbp->CopyOne(t);
- tp->Columns = tp->Tdbp->GetColumns();
- return tp;
- } // end of CopyOne
-
-PTDB TDBMUL::Duplicate(PGLOBAL g)
- {
- PTDBMUL tmup = new(g) TDBMUL(this);
-
- tmup->Tdbp = (PTDBASE)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 TDBMUL::InitFileNames(PGLOBAL g)
- {
-#define PFNZ 8192
- char *pfn[PFNZ], filename[_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT];
- int rc, n = 0;
-
- // 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 (Mul == 1) {
- /*******************************************************************/
- /* To_File is a multiple name with special characters */
- /*******************************************************************/
-#if defined(WIN32)
- char drive[_MAX_DRIVE], direc[_MAX_DIR];
- WIN32_FIND_DATA FileData;
- HANDLE hSearch;
-
- _splitpath(filename, drive, direc, NULL, NULL);
-
- // Start searching files in the target directory.
- hSearch = FindFirstFile(filename, &FileData);
-
- if (hSearch == INVALID_HANDLE_VALUE) {
- rc = GetLastError();
-
- if (rc != ERROR_FILE_NOT_FOUND) {
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(), 0,
- (LPTSTR)&filename, sizeof(filename), NULL);
- sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
- return true;
- } // endif rc
-
- goto suite;
- } // endif hSearch
-
- while (n < PFNZ) {
- strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName);
- pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
- strcpy(pfn[n++], filename);
-
- if (!FindNextFile(hSearch, &FileData)) {
- rc = GetLastError();
-
- if (rc != ERROR_NO_MORE_FILES) {
- sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
- FindClose(hSearch);
- return true;
- } // endif rc
-
- break;
- } // endif FindNextFile
-
- } // endwhile n
-
- // Close the search handle.
- if (!FindClose(hSearch)) {
- strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
- return true;
- } // endif FindClose
-
-#else // !WIN32
- struct stat fileinfo;
- char fn[PATH_MAX], direc[PATH_MAX], pattern[256], ftype[8];
- DIR *dir;
- struct dirent *entry;
-
- _splitpath(filename, NULL, direc, pattern, ftype);
- strcat(pattern, ftype);
-
- // Start searching files in the target directory.
- if (!(dir = opendir(direc))) {
- sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno));
- return true;
- } // endif dir
-
- while ((entry = readdir(dir)) && n < PFNZ) {
- strcat(strcpy(fn, direc), entry->d_name);
-
- if (lstat(fn, &fileinfo) < 0) {
- sprintf(g->Message, "%s: %s", fn, strerror(errno));
- return true;
- } else if (!S_ISREG(fileinfo.st_mode))
- continue; // Not a regular file (should test for links)
-
- /*******************************************************************/
- /* Test whether the file name matches the table name filter. */
- /*******************************************************************/
- if (fnmatch(pattern, entry->d_name, 0))
- continue; // Not a match
-
- strcat(strcpy(filename, direc), entry->d_name);
- pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
- strcpy(pfn[n++], filename);
- } // endwhile readdir
-
- // Close the dir handle.
- closedir(dir);
-#endif // !WIN32
-
- } 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, sizeof(filename), stream)) {
- fclose(stream);
- break;
- } // endif fgets
-
- p = filename + strlen(filename) - 1;
-
-#if defined(UNIX)
- // 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] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
- strcpy(pfn[n++], filename);
- } // endfor n
-
- } // endif Mul
-
- suite:
- 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
-
-/***********************************************************************/
-/* 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 (!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)
- {
-#ifdef DEBTRACE
- htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
- this, Tdb_No, Use, To_Key_Col, Mode);
-#endif
-
- 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)) 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 irc)
- {
- // 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
-
-/* --------------------------- Class DIRDEF -------------------------- */
-
-/***********************************************************************/
-/* DefineAM: define specific AM block values from XDB file. */
-/***********************************************************************/
-bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
- {
- Desc = Fn = Cat->GetStringCatInfo(g, Name, "Filename", "");
- Incl = (Cat->GetIntCatInfo(Name, "Subdir", 0) != 0);
- Huge = (Cat->GetIntCatInfo(Name, "Huge", 0) != 0);
- return false;
- } // end of DefineAM
-
-/***********************************************************************/
-/* GetTable: makes a new Table Description Block. */
-/***********************************************************************/
-PTDB DIRDEF::GetTable(PGLOBAL g, MODE m)
- {
-#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. */
-/***********************************************************************/
-TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
- {
- To_File = tdp->Fn;
- iFile = 0;
-#if defined(WIN32)
- memset(&FileData, 0, sizeof(_finddata_t));
- Hsearch = -1;
- *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 TDBDIR standard constructor
-
-TDBDIR::TDBDIR(PTDBDIR tdbp) : TDBASE(tdbp)
- {
- To_File = tdbp->To_File;
- iFile = tdbp->iFile;
-#if defined(WIN32)
- FileData = tdbp->FileData;
- Hsearch = tdbp->Hsearch;
- strcpy(Drive, tdbp->Drive);
-#else // !WIN32
- Fileinfo = tdbp->Fileinfo;
- Entry = tdbp->Entry;
- Dir = tdbp->Dir;
- Done = tdbp->Done;
- strcpy(Pattern, tdbp->Pattern);
-#endif // !WIN32
- strcpy(Direc, tdbp->Direc);
- strcpy(Fname, tdbp->Fname);
- strcpy(Ftype, tdbp->Ftype);
- } // end of TDBDIR copy constructor
-
-// Method
-PTDB TDBDIR::CopyOne(PTABS t)
- {
- PTDB tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBDIR(this);
- tp->SetColumns(Columns);
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* Initialize/get the components of the search file pattern. */
-/***********************************************************************/
-char* TDBDIR::Path(PGLOBAL g)
- {
- PCATLG cat = PlgGetCatalog(g);
-
-#if defined(WIN32)
- if (!*Drive) {
- PlugSetPath(Fpath, To_File, cat->GetDataPath());
- _splitpath(Fpath, Drive, Direc, Fname, Ftype);
- } else
- _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull ???
-
- return Fpath;
-#else // !WIN32
- if (!Done) {
- PlugSetPath(Fpath, To_File, cat->GetDataPath());
- _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 h;
-
- // Start searching files in the target directory.
- h = _findfirst(Path(g), &FileData);
-
- if (h != -1) {
- for (n = 1;; n++)
- if (_findnext(h, &FileData))
- break;
-
- // Close the search handle.
- _findclose(h);
- } else
- n = 0;
-
-#else // !WIN32
- Path(g);
-
- // Start searching files in the target directory.
- if (!(Dir = opendir(Direc))) {
- sprintf(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) {
- sprintf(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)
- {
-#ifdef DEBTRACE
- htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
- this, Tdb_No, Use, Mode);
-#endif
-
- 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)
- if (Hsearch == -1) {
- /*******************************************************************/
- /* Start searching files in the target directory. The use of the */
- /* Path function is required when called from TDBSDR. */
- /*******************************************************************/
- Hsearch = _findfirst(Path(g), &FileData);
-
- if (Hsearch == -1)
- rc = RC_EF;
- else
- iFile++;
-
- } else {
- if (_findnext(Hsearch, &FileData)) {
- // Restore file name and type pattern
- _splitpath(To_File, NULL, NULL, Fname, Ftype);
- rc = RC_EF;
- } else
- iFile++;
-
- } // endif Hsearch
-
- if (rc == RC_OK)
- _splitpath(FileData.name, NULL, NULL, Fname, Ftype);
-
-#else // !Win32
- rc = RC_NF;
-
- if (!Dir)
- // Start searching files in the target directory.
- if (!(Dir = opendir(Direc))) {
- sprintf(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) {
- sprintf(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 irc)
- {
- 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 g)
- {
-#if defined(WIN32)
- // Close the search handle.
- _findclose(Hsearch);
- Hsearch = -1;
-#else // !WIN32
- // Close the DIR handle.
- closedir(Dir);
- Dir = NULL;
-#endif // !WIN32
- iFile = 0;
- } // end of CloseDB
-
-// ------------------------ DIRCOL functions ----------------------------
-
-/***********************************************************************/
-/* DIRCOL public constructor. */
-/***********************************************************************/
-DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
- : 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.
- 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)
- {
- N = col1->N;
- } // end of DIRCOL copy constructor
-
-/***********************************************************************/
-/* 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)
- {
- PTDBDIR tdbp = (PTDBDIR)To_Tdb;
-
-#ifdef DEBTRACE
- fprintf(debug,
- "DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
- Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
-#endif
-
- /*********************************************************************/
- /* 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.attrib); break;
- case 5: Value->SetValue((int)tdbp->FileData.size); break;
- case 6: Value->SetValue((int)tdbp->FileData.time_write); break;
- case 7: Value->SetValue((int)tdbp->FileData.time_create); break;
- case 8: Value->SetValue((int)tdbp->FileData.time_access); 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:
- sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
- longjmp(g->jumper[g->jump_level], GetAmType());
- } // endswitch N
-
- } // end of ReadColumn
-
-/* ------------------------- Class TDBSDR ---------------------------- */
-
-/***********************************************************************/
-/* TABSDR copy constructors. */
-/***********************************************************************/
-TDBSDR::TDBSDR(PTDBSDR tdbp) : TDBDIR(tdbp)
- {
- Sub = tdbp->Sub;
- } // end of TDBSDR copy constructor
-
-// Method
-PTDB TDBSDR::CopyOne(PTABS t)
- {
- PTDB tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBSDR(this);
- tp->SetColumns(Columns);
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* 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 GetMaxSize: 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 h = _findfirst(Path(g), &FileData);
-
- if (h != -1) {
- for (n = 1;; n++)
- if (_findnext(h, &FileData))
- break;
-
- // Close the search handle.
- _findclose(h);
- } // endif h
-
- // Now search files in sub-directories.
- _makepath(Fpath, Drive, Direc, "*", "");
- h = _findfirst(Fpath, &FileData);
-
- if (h != -1) {
- while (true) {
- if (FileData.attrib & _A_SUBDIR && *FileData.name != '.') {
- // Look in the name sub-directory
- strcat(strcat(Direc, FileData.name), "\\");
- n += FindInDir(g);
- Direc[m] = '\0'; // Restore path
- } // endif SUBDIR
-
- if (_findnext(h, &FileData))
- break;
-
- } // endwhile
-
- // Close the search handle.
- _findclose(h);
- } // endif h
-#else // !WIN32
- int k;
- DIR *dir = opendir(Direc);
-
- if (!dir) {
- sprintf(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) {
- sprintf(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 = -1;
- 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 == -1) {
- _makepath(Fpath, Drive, Direc, "*", "");
- Sub->H = _findfirst(Fpath, &FileData);
- } else if (_findnext(Sub->H, &FileData)) {
- _findclose(Sub->H);
- Sub->H = -1;
- *FileData.name = '\0';
- } // endif findnext
-
- } while(*FileData.name == '.');
-
- if (Sub->H == -1) {
- // 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 = -1;
- Sub->Next = sup;
- } // endif Next
-
- Sub = Sub->Next;
- strcat(strcat(Direc, FileData.name), "\\");
- Sub->Len = strlen(Direc);
-
- // Reset Hsearch used by TDBDIR::ReadDB
- _findclose(Hsearch);
- Hsearch = -1;
- 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))) {
- sprintf(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) {
- sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
- rc = RC_FX;
- } else if (S_ISDIR(Fileinfo.st_mode) && *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::CopyOne(PTABS t)
- {
- PTDB tp;
- PGLOBAL g = t->G; // Is this really useful ???
-
- tp = new(g) TDBDHR(this);
- tp->Columns = Columns;
- return tp;
- } // end of CopyOne
-
-/***********************************************************************/
-/* 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);
- sprintf(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) {
- sprintf(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)
- {
-#ifdef DEBTRACE
- htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
- this, Tdb_No, Use, Mode);
-#endif
-
- 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
- sprintf(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);
- sprintf(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) {
- sprintf(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));
- longjmp(g->jumper[g->jump_level], 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, PSZ 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;
-
-#ifdef DEBTRACE
- fprintf(debug,
- "DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
- Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
-#endif
-
- /*********************************************************************/
- /* 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
-
+/************* TabMul C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABMUL */
+/* ------------- */
+/* Version 1.7 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to PlugDB Software Development 2003 - 2012 */
+/* 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>
+#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(PTDBASE 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::CopyOne(PTABS t)
+ {
+ PTDBMUL tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBMUL(this);
+ tp->Tdbp = (PTDBASE)Tdbp->CopyOne(t);
+ tp->Columns = tp->Tdbp->GetColumns();
+ return tp;
+ } // end of CopyOne
+
+PTDB TDBMUL::Duplicate(PGLOBAL g)
+ {
+ PTDBMUL tmup = new(g) TDBMUL(this);
+
+ tmup->Tdbp = (PTDBASE)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 TDBMUL::InitFileNames(PGLOBAL g)
+ {
+#define PFNZ 8192
+ char *pfn[PFNZ], filename[_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT];
+ int rc, n = 0;
+
+ // 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 (Mul == 1) {
+ /*******************************************************************/
+ /* To_File is a multiple name with special characters */
+ /*******************************************************************/
+#if defined(WIN32)
+ char drive[_MAX_DRIVE], direc[_MAX_DIR];
+ WIN32_FIND_DATA FileData;
+ HANDLE hSearch;
+
+ _splitpath(filename, drive, direc, NULL, NULL);
+
+ // Start searching files in the target directory.
+ hSearch = FindFirstFile(filename, &FileData);
+
+ if (hSearch == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+
+ if (rc != ERROR_FILE_NOT_FOUND) {
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0,
+ (LPTSTR)&filename, sizeof(filename), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
+ return true;
+ } // endif rc
+
+ goto suite;
+ } // endif hSearch
+
+ while (n < PFNZ) {
+ strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName);
+ pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
+ strcpy(pfn[n++], filename);
+
+ if (!FindNextFile(hSearch, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ FindClose(hSearch);
+ return true;
+ } // endif rc
+
+ break;
+ } // endif FindNextFile
+
+ } // endwhile n
+
+ // Close the search handle.
+ if (!FindClose(hSearch)) {
+ strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
+ return true;
+ } // endif FindClose
+
+#else // !WIN32
+ struct stat fileinfo;
+ char fn[PATH_MAX], direc[PATH_MAX], pattern[256], ftype[8];
+ DIR *dir;
+ struct dirent *entry;
+
+ _splitpath(filename, NULL, direc, pattern, ftype);
+ strcat(pattern, ftype);
+
+ // Start searching files in the target directory.
+ if (!(dir = opendir(direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno));
+ return true;
+ } // endif dir
+
+ while ((entry = readdir(dir)) && n < PFNZ) {
+ strcat(strcpy(fn, direc), entry->d_name);
+
+ if (lstat(fn, &fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", fn, strerror(errno));
+ return true;
+ } else if (!S_ISREG(fileinfo.st_mode))
+ continue; // Not a regular file (should test for links)
+
+ /*******************************************************************/
+ /* Test whether the file name matches the table name filter. */
+ /*******************************************************************/
+ if (fnmatch(pattern, entry->d_name, 0))
+ continue; // Not a match
+
+ strcat(strcpy(filename, direc), entry->d_name);
+ pfn[n] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
+ strcpy(pfn[n++], filename);
+ } // endwhile readdir
+
+ // Close the dir handle.
+ closedir(dir);
+#endif // !WIN32
+
+ } 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, sizeof(filename), stream)) {
+ fclose(stream);
+ break;
+ } // endif fgets
+
+ p = filename + strlen(filename) - 1;
+
+#if defined(UNIX)
+ // 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] = (char*)PlugSubAlloc(g, NULL, strlen(filename) + 1);
+ strcpy(pfn[n++], filename);
+ } // endfor n
+
+ } // endif Mul
+
+ suite:
+ 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
+
+/***********************************************************************/
+/* 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 (!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)
+ {
+#ifdef DEBTRACE
+ htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+#endif
+
+ 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)) 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 irc)
+ {
+ // 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
+
+/* --------------------------- Class DIRDEF -------------------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ Desc = Fn = Cat->GetStringCatInfo(g, Name, "Filename", "");
+ Incl = (Cat->GetIntCatInfo(Name, "Subdir", 0) != 0);
+ Huge = (Cat->GetIntCatInfo(Name, "Huge", 0) != 0);
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB DIRDEF::GetTable(PGLOBAL g, MODE m)
+ {
+#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. */
+/***********************************************************************/
+TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
+ {
+ To_File = tdp->Fn;
+ iFile = 0;
+#if defined(WIN32)
+ memset(&FileData, 0, sizeof(_finddata_t));
+ Hsearch = -1;
+ *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 TDBDIR standard constructor
+
+TDBDIR::TDBDIR(PTDBDIR tdbp) : TDBASE(tdbp)
+ {
+ To_File = tdbp->To_File;
+ iFile = tdbp->iFile;
+#if defined(WIN32)
+ FileData = tdbp->FileData;
+ Hsearch = tdbp->Hsearch;
+ strcpy(Drive, tdbp->Drive);
+#else // !WIN32
+ Fileinfo = tdbp->Fileinfo;
+ Entry = tdbp->Entry;
+ Dir = tdbp->Dir;
+ Done = tdbp->Done;
+ strcpy(Pattern, tdbp->Pattern);
+#endif // !WIN32
+ strcpy(Direc, tdbp->Direc);
+ strcpy(Fname, tdbp->Fname);
+ strcpy(Ftype, tdbp->Ftype);
+ } // end of TDBDIR copy constructor
+
+// Method
+PTDB TDBDIR::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBDIR(this);
+ tp->SetColumns(Columns);
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* Initialize/get the components of the search file pattern. */
+/***********************************************************************/
+char* TDBDIR::Path(PGLOBAL g)
+ {
+ PCATLG cat = PlgGetCatalog(g);
+
+#if defined(WIN32)
+ if (!*Drive) {
+ PlugSetPath(Fpath, To_File, cat->GetDataPath());
+ _splitpath(Fpath, Drive, Direc, Fname, Ftype);
+ } else
+ _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull ???
+
+ return Fpath;
+#else // !WIN32
+ if (!Done) {
+ PlugSetPath(Fpath, To_File, cat->GetDataPath());
+ _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 h;
+
+ // Start searching files in the target directory.
+ h = _findfirst(Path(g), &FileData);
+
+ if (h != -1) {
+ for (n = 1;; n++)
+ if (_findnext(h, &FileData))
+ break;
+
+ // Close the search handle.
+ _findclose(h);
+ } else
+ n = 0;
+
+#else // !WIN32
+ Path(g);
+
+ // Start searching files in the target directory.
+ if (!(Dir = opendir(Direc))) {
+ sprintf(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) {
+ sprintf(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)
+ {
+#ifdef DEBTRACE
+ htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+#endif
+
+ 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)
+ if (Hsearch == -1) {
+ /*******************************************************************/
+ /* Start searching files in the target directory. The use of the */
+ /* Path function is required when called from TDBSDR. */
+ /*******************************************************************/
+ Hsearch = _findfirst(Path(g), &FileData);
+
+ if (Hsearch == -1)
+ rc = RC_EF;
+ else
+ iFile++;
+
+ } else {
+ if (_findnext(Hsearch, &FileData)) {
+ // Restore file name and type pattern
+ _splitpath(To_File, NULL, NULL, Fname, Ftype);
+ rc = RC_EF;
+ } else
+ iFile++;
+
+ } // endif Hsearch
+
+ if (rc == RC_OK)
+ _splitpath(FileData.name, NULL, NULL, Fname, Ftype);
+
+#else // !Win32
+ rc = RC_NF;
+
+ if (!Dir)
+ // Start searching files in the target directory.
+ if (!(Dir = opendir(Direc))) {
+ sprintf(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) {
+ sprintf(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 irc)
+ {
+ 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 g)
+ {
+#if defined(WIN32)
+ // Close the search handle.
+ _findclose(Hsearch);
+ Hsearch = -1;
+#else // !WIN32
+ // Close the DIR handle.
+ closedir(Dir);
+ Dir = NULL;
+#endif // !WIN32
+ iFile = 0;
+ } // end of CloseDB
+
+// ------------------------ DIRCOL functions ----------------------------
+
+/***********************************************************************/
+/* DIRCOL public constructor. */
+/***********************************************************************/
+DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PSZ am)
+ : 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.
+ 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)
+ {
+ N = col1->N;
+ } // end of DIRCOL copy constructor
+
+/***********************************************************************/
+/* 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)
+ {
+ PTDBDIR tdbp = (PTDBDIR)To_Tdb;
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ "DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
+#endif
+
+ /*********************************************************************/
+ /* 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.attrib); break;
+ case 5: Value->SetValue((int)tdbp->FileData.size); break;
+ case 6: Value->SetValue((int)tdbp->FileData.time_write); break;
+ case 7: Value->SetValue((int)tdbp->FileData.time_create); break;
+ case 8: Value->SetValue((int)tdbp->FileData.time_access); 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:
+ sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
+ longjmp(g->jumper[g->jump_level], GetAmType());
+ } // endswitch N
+
+ } // end of ReadColumn
+
+/* ------------------------- Class TDBSDR ---------------------------- */
+
+/***********************************************************************/
+/* TABSDR copy constructors. */
+/***********************************************************************/
+TDBSDR::TDBSDR(PTDBSDR tdbp) : TDBDIR(tdbp)
+ {
+ Sub = tdbp->Sub;
+ } // end of TDBSDR copy constructor
+
+// Method
+PTDB TDBSDR::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBSDR(this);
+ tp->SetColumns(Columns);
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* 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 GetMaxSize: 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 h = _findfirst(Path(g), &FileData);
+
+ if (h != -1) {
+ for (n = 1;; n++)
+ if (_findnext(h, &FileData))
+ break;
+
+ // Close the search handle.
+ _findclose(h);
+ } // endif h
+
+ // Now search files in sub-directories.
+ _makepath(Fpath, Drive, Direc, "*", "");
+ h = _findfirst(Fpath, &FileData);
+
+ if (h != -1) {
+ while (true) {
+ if (FileData.attrib & _A_SUBDIR && *FileData.name != '.') {
+ // Look in the name sub-directory
+ strcat(strcat(Direc, FileData.name), "\\");
+ n += FindInDir(g);
+ Direc[m] = '\0'; // Restore path
+ } // endif SUBDIR
+
+ if (_findnext(h, &FileData))
+ break;
+
+ } // endwhile
+
+ // Close the search handle.
+ _findclose(h);
+ } // endif h
+#else // !WIN32
+ int k;
+ DIR *dir = opendir(Direc);
+
+ if (!dir) {
+ sprintf(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) {
+ sprintf(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 = -1;
+ 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 == -1) {
+ _makepath(Fpath, Drive, Direc, "*", "");
+ Sub->H = _findfirst(Fpath, &FileData);
+ } else if (_findnext(Sub->H, &FileData)) {
+ _findclose(Sub->H);
+ Sub->H = -1;
+ *FileData.name = '\0';
+ } // endif findnext
+
+ } while(*FileData.name == '.');
+
+ if (Sub->H == -1) {
+ // 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 = -1;
+ Sub->Next = sup;
+ } // endif Next
+
+ Sub = Sub->Next;
+ strcat(strcat(Direc, FileData.name), "\\");
+ Sub->Len = strlen(Direc);
+
+ // Reset Hsearch used by TDBDIR::ReadDB
+ _findclose(Hsearch);
+ Hsearch = -1;
+ 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))) {
+ sprintf(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) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ rc = RC_FX;
+ } else if (S_ISDIR(Fileinfo.st_mode) && *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::CopyOne(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBDHR(this);
+ tp->Columns = Columns;
+ return tp;
+ } // end of CopyOne
+
+/***********************************************************************/
+/* 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);
+ sprintf(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) {
+ sprintf(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)
+ {
+#ifdef DEBTRACE
+ htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+#endif
+
+ 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
+ sprintf(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);
+ sprintf(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) {
+ sprintf(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));
+ longjmp(g->jumper[g->jump_level], 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, PSZ 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;
+
+#ifdef DEBTRACE
+ fprintf(debug,
+ "DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
+#endif
+
+ /*********************************************************************/
+ /* 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
+