/************* 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 #include #if defined(__BORLANDC__) #define __MFC_COMPAT__ // To define min/max as macro #endif //#include #if defined(PATHMATCHSPEC) #include "Shlwapi.h" //using namespace std; #pragma comment(lib,"shlwapi.lib") #endif // PATHMATCHSPEC #else #if defined(UNIX) #include #include #include #include #include #include "osutil.h" #else //#include #endif //#include #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. */ /***********************************************************************/ 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 /***********************************************************************/ /* 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); sprintf(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) { sprintf(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))) { 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) { 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))) { 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) { 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: sprintf(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); sprintf(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) { sprintf(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); sprintf(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) { sprintf(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) { 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 = 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))) { 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) && 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); 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) { 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 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)); 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