1 | /************* TabMul C++ Program Source Code File (.CPP) **************/ |
2 | /* PROGRAM NAME: TABMUL */ |
3 | /* ------------- */ |
4 | /* Version 1.9 */ |
5 | /* */ |
6 | /* COPYRIGHT: */ |
7 | /* ---------- */ |
8 | /* (C) Copyright to PlugDB Software Development 2003 - 2017 */ |
9 | /* Author: Olivier BERTRAND */ |
10 | /* */ |
11 | /* WHAT THIS PROGRAM DOES: */ |
12 | /* ----------------------- */ |
13 | /* This program are the TDBMUL class DB routines. */ |
14 | /* */ |
15 | /* WHAT YOU NEED TO COMPILE THIS PROGRAM: */ |
16 | /* -------------------------------------- */ |
17 | /* */ |
18 | /* REQUIRED FILES: */ |
19 | /* --------------- */ |
20 | /* TABMUL.CPP - Source code */ |
21 | /* PLGDBSEM.H - DB application declaration file */ |
22 | /* TABDOS.H - TABDOS classes declaration file */ |
23 | /* TABMUL.H - TABFIX classes declaration file */ |
24 | /* GLOBAL.H - Global declaration file */ |
25 | /* */ |
26 | /* REQUIRED LIBRARIES: */ |
27 | /* ------------------- */ |
28 | /* Large model C library */ |
29 | /* */ |
30 | /* REQUIRED PROGRAMS: */ |
31 | /* ------------------ */ |
32 | /* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */ |
33 | /* */ |
34 | /***********************************************************************/ |
35 | |
36 | /***********************************************************************/ |
37 | /* Include relevant section of system dependant header files. */ |
38 | /***********************************************************************/ |
39 | #include "my_global.h" |
40 | #if defined(__WIN__) |
41 | #include <stdlib.h> |
42 | #include <stdio.h> |
43 | #if defined(__BORLANDC__) |
44 | #define __MFC_COMPAT__ // To define min/max as macro |
45 | #endif |
46 | //#include <windows.h> |
47 | #if defined(PATHMATCHSPEC) |
48 | #include "Shlwapi.h" |
49 | //using namespace std; |
50 | #pragma comment(lib,"shlwapi.lib") |
51 | #endif // PATHMATCHSPEC |
52 | #else |
53 | #if defined(UNIX) |
54 | #include <fnmatch.h> |
55 | #include <errno.h> |
56 | #include <stdlib.h> |
57 | #include <stdio.h> |
58 | #include <string.h> |
59 | #include "osutil.h" |
60 | #else |
61 | //#include <io.h> |
62 | #endif |
63 | //#include <fcntl.h> |
64 | #endif |
65 | |
66 | /***********************************************************************/ |
67 | /* Include application header files: */ |
68 | /***********************************************************************/ |
69 | #include "global.h" // global declarations |
70 | #include "plgdbsem.h" // DB application declarations |
71 | #include "reldef.h" // DB definition declares |
72 | #include "filamtxt.h" |
73 | #include "tabdos.h" // TDBDOS and DOSCOL class dcls |
74 | #include "tabmul.h" // TDBMUL and MULCOL classes dcls |
75 | |
76 | /* ------------------------- Class TDBMUL ---------------------------- */ |
77 | |
78 | /***********************************************************************/ |
79 | /* TABMUL constructors. */ |
80 | /***********************************************************************/ |
81 | TDBMUL::TDBMUL(PTDB tdbp) : TDBASE(tdbp->GetDef()) |
82 | { |
83 | Tdbp = tdbp; |
84 | Filenames = NULL; |
85 | Rows = 0; |
86 | Mul = tdbp->GetDef()->GetMultiple(); |
87 | NumFiles = 0; |
88 | iFile = 0; |
89 | } // end of TDBMUL standard constructor |
90 | |
91 | TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp) |
92 | { |
93 | Tdbp = tdbp->Tdbp; |
94 | Filenames = tdbp->Filenames; |
95 | Rows = tdbp->Rows; |
96 | Mul = tdbp->Mul; |
97 | NumFiles = tdbp->NumFiles; |
98 | iFile = tdbp->iFile; |
99 | } // end of TDBMUL copy constructor |
100 | |
101 | // Method |
102 | PTDB TDBMUL::Clone(PTABS t) |
103 | { |
104 | PTDBMUL tp; |
105 | PGLOBAL g = t->G; // Is this really useful ??? |
106 | |
107 | tp = new(g) TDBMUL(this); |
108 | tp->Tdbp = Tdbp->Clone(t); |
109 | tp->Columns = tp->Tdbp->GetColumns(); |
110 | return tp; |
111 | } // end of Clone |
112 | |
113 | PTDB TDBMUL::Duplicate(PGLOBAL g) |
114 | { |
115 | PTDBMUL tmup = new(g) TDBMUL(this); |
116 | |
117 | tmup->Tdbp = Tdbp->Duplicate(g); |
118 | return tmup; |
119 | } // end of Duplicate |
120 | |
121 | /***********************************************************************/ |
122 | /* Initializes the table filename list. */ |
123 | /* Note: tables created by concatenating the file components without */ |
124 | /* specifying the LRECL value (that should be restricted to _MAX_PATH)*/ |
125 | /* have a LRECL that is the sum of the lengths of all components. */ |
126 | /* This is why we use a big filename array to take care of that. */ |
127 | /***********************************************************************/ |
128 | bool TDBMUL::InitFileNames(PGLOBAL g) |
129 | { |
130 | #define PFNZ 4096 |
131 | #define FNSZ (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT) |
132 | PTDBDIR dirp; |
133 | PSZ pfn[PFNZ]; |
134 | PSZ filename; |
135 | int rc, n = 0; |
136 | |
137 | if (trace(1)) |
138 | htrc("in InitFileName: fn[]=%d\n" , FNSZ); |
139 | |
140 | filename = (char*)PlugSubAlloc(g, NULL, FNSZ); |
141 | |
142 | // The sub table may need to refer to the Table original block |
143 | Tdbp->SetTable(To_Table); // Was not set at construction |
144 | |
145 | PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath()); |
146 | |
147 | if (trace(1)) |
148 | htrc("InitFileName: fn='%s'\n" , filename); |
149 | |
150 | if (Mul != 2) { |
151 | /*******************************************************************/ |
152 | /* To_File is a multiple name with special characters */ |
153 | /*******************************************************************/ |
154 | if (Mul == 1) |
155 | dirp = new(g) TDBDIR(PlugDup(g, filename)); |
156 | else // Mul == 3 (Subdir) |
157 | dirp = new(g) TDBSDR(PlugDup(g, filename)); |
158 | |
159 | if (dirp->OpenDB(g)) |
160 | return true; |
161 | |
162 | if (trace(1) && Mul == 3) { |
163 | int nf = ((PTDBSDR)dirp)->FindInDir(g); |
164 | htrc("Number of files = %d\n" , nf); |
165 | } // endif trace |
166 | |
167 | while (true) |
168 | if ((rc = dirp->ReadDB(g)) == RC_OK) { |
169 | #if defined(__WIN__) |
170 | strcat(strcpy(filename, dirp->Drive), dirp->Direc); |
171 | #else // !__WIN__ |
172 | strcpy(filename, dirp->Direc); |
173 | #endif // !__WIN__ |
174 | strcat(strcat(filename, dirp->Fname), dirp->Ftype); |
175 | pfn[n++] = PlugDup(g, filename); |
176 | } else |
177 | break; |
178 | |
179 | dirp->CloseDB(g); |
180 | |
181 | if (rc == RC_FX) |
182 | return true; |
183 | |
184 | } else { |
185 | /*******************************************************************/ |
186 | /* To_File is the name of a file containing the file name list */ |
187 | /*******************************************************************/ |
188 | char *p; |
189 | FILE *stream; |
190 | |
191 | if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r" ))) |
192 | return true; |
193 | |
194 | while (n < PFNZ) { |
195 | if (!fgets(filename, FNSZ, stream)) { |
196 | fclose(stream); |
197 | break; |
198 | } // endif fgets |
199 | |
200 | p = filename + strlen(filename) - 1; |
201 | |
202 | #if !defined(__WIN__) |
203 | // Data files can be imported from Windows (having CRLF) |
204 | if (*p == '\n' || *p == '\r') { |
205 | // is this enough for Unix ??? |
206 | p--; // Eliminate ending CR or LF character |
207 | |
208 | if (p >= filename) |
209 | // is this enough for Unix ??? |
210 | if (*p == '\n' || *p == '\r') |
211 | p--; // Eliminate ending CR or LF character |
212 | |
213 | } // endif p |
214 | |
215 | #else |
216 | if (*p == '\n') |
217 | p--; // Eliminate ending new-line character |
218 | #endif |
219 | // Trim rightmost blanks |
220 | for (; p >= filename && *p == ' '; p--) ; |
221 | |
222 | *(++p) = '\0'; |
223 | |
224 | // Suballocate the file name |
225 | pfn[n++] = PlugDup(g, filename); |
226 | } // endfor n |
227 | |
228 | } // endif Mul |
229 | |
230 | if (n) { |
231 | Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*)); |
232 | |
233 | for (int i = 0; i < n; i++) |
234 | Filenames[i] = pfn[i]; |
235 | |
236 | } else { |
237 | Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*)); |
238 | Filenames[0] = NULL; |
239 | } // endif n |
240 | |
241 | NumFiles = n; |
242 | return false; |
243 | } // end of InitFileNames |
244 | |
245 | /***********************************************************************/ |
246 | /* The table column list is the sub-table column list. */ |
247 | /***********************************************************************/ |
248 | PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num) |
249 | { |
250 | PCOL cp; |
251 | |
252 | /*********************************************************************/ |
253 | /* Because special columns are directly added to the MUL block, */ |
254 | /* make sure that the sub-table has the same column list, before */ |
255 | /* and after the call to the ColDB function. */ |
256 | /*********************************************************************/ |
257 | Tdbp->SetColumns(Columns); |
258 | cp = Tdbp->ColDB(g, name, num); |
259 | Columns = Tdbp->GetColumns(); |
260 | return cp; |
261 | } // end of ColDB |
262 | |
263 | /***********************************************************************/ |
264 | /* MUL GetProgMax: get the max value for progress information. */ |
265 | /***********************************************************************/ |
266 | int TDBMUL::GetProgMax(PGLOBAL g) |
267 | { |
268 | if (!Filenames && InitFileNames(g)) |
269 | return -1; |
270 | |
271 | return NumFiles; // This is a temporary setting |
272 | } // end of GetProgMax |
273 | |
274 | /***********************************************************************/ |
275 | /* MUL GetProgCur: get the current value for progress information. */ |
276 | /***********************************************************************/ |
277 | int TDBMUL::GetProgCur(void) |
278 | { |
279 | return iFile; // This is a temporary setting |
280 | } // end of GetProgMax |
281 | |
282 | /***********************************************************************/ |
283 | /* MUL Cardinality: returns table cardinality in number of rows. */ |
284 | /* This function can be called with a null argument to test the */ |
285 | /* availability of Cardinality implementation (1 yes, 0 no). */ |
286 | /* Can be used on Multiple FIX table only. */ |
287 | /***********************************************************************/ |
288 | int TDBMUL::Cardinality(PGLOBAL g) |
289 | { |
290 | if (!g) |
291 | return Tdbp->Cardinality(g); |
292 | |
293 | if (!Filenames && InitFileNames(g)) |
294 | return -1; |
295 | |
296 | int n, card = 0; |
297 | |
298 | for (int i = 0; i < NumFiles; i++) { |
299 | Tdbp->SetFile(g, Filenames[i]); |
300 | Tdbp->ResetSize(); |
301 | |
302 | if ((n = Tdbp->Cardinality(g)) < 0) { |
303 | // strcpy(g->Message, MSG(BAD_CARDINALITY)); |
304 | return -1; |
305 | } // endif n |
306 | |
307 | card += n; |
308 | } // endfor i |
309 | |
310 | return card; |
311 | } // end of Cardinality |
312 | |
313 | /***********************************************************************/ |
314 | /* Sum up the sizes of all sub-tables. */ |
315 | /***********************************************************************/ |
316 | int TDBMUL::GetMaxSize(PGLOBAL g) |
317 | { |
318 | if (MaxSize < 0) { |
319 | int i; |
320 | int mxsz; |
321 | |
322 | if (trace(1)) |
323 | htrc("TDBMUL::GetMaxSize: Filenames=%p\n" , Filenames); |
324 | |
325 | if (!Filenames && InitFileNames(g)) |
326 | return -1; |
327 | |
328 | if (Use == USE_OPEN) { |
329 | strcpy(g->Message, MSG(MAXSIZE_ERROR)); |
330 | return -1; |
331 | } else |
332 | MaxSize = 0; |
333 | |
334 | for (i = 0; i < NumFiles; i++) { |
335 | Tdbp->SetFile(g, Filenames[i]); |
336 | Tdbp->ResetSize(); |
337 | |
338 | if ((mxsz = Tdbp->GetMaxSize(g)) < 0) { |
339 | MaxSize = -1; |
340 | return mxsz; |
341 | } // endif mxsz |
342 | |
343 | MaxSize += mxsz; |
344 | } // endfor i |
345 | |
346 | } // endif MaxSize |
347 | |
348 | return MaxSize; |
349 | } // end of GetMaxSize |
350 | |
351 | /***********************************************************************/ |
352 | /* Reset read/write position values. */ |
353 | /***********************************************************************/ |
354 | void TDBMUL::ResetDB(void) |
355 | { |
356 | for (PCOL colp = Columns; colp; colp = colp->GetNext()) |
357 | if (colp->GetAmType() == TYPE_AM_FILID) |
358 | colp->COLBLK::Reset(); |
359 | |
360 | Tdbp->ResetDB(); |
361 | } // end of ResetDB |
362 | |
363 | /***********************************************************************/ |
364 | /* Returns RowId if b is false or Rownum if b is true. */ |
365 | /***********************************************************************/ |
366 | int TDBMUL::RowNumber(PGLOBAL g, bool b) |
367 | { |
368 | return ((b) ? 0 : Rows) |
369 | + ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1); |
370 | } // end of RowNumber |
371 | |
372 | /***********************************************************************/ |
373 | /* MUL Access Method opening routine. */ |
374 | /* Open first file, other will be opened sequencially when reading. */ |
375 | /***********************************************************************/ |
376 | bool TDBMUL::OpenDB(PGLOBAL g) |
377 | { |
378 | if (trace(1)) |
379 | htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n" , |
380 | this, Tdb_No, Use, To_Key_Col, Mode); |
381 | |
382 | if (Use == USE_OPEN) { |
383 | /*******************************************************************/ |
384 | /* Table already open, replace it at its beginning. */ |
385 | /*******************************************************************/ |
386 | if (Filenames[iFile = 0]) { |
387 | Tdbp->CloseDB(g); |
388 | Tdbp->SetUse(USE_READY); |
389 | Tdbp->SetFile(g, Filenames[iFile = 0]); |
390 | Tdbp->ResetSize(); |
391 | Rows = 0; |
392 | ResetDB(); |
393 | return Tdbp->OpenDB(g); // Re-open with new file name |
394 | } else |
395 | return false; |
396 | |
397 | } // endif use |
398 | |
399 | /*********************************************************************/ |
400 | /* We need to calculate MaxSize before opening the query. */ |
401 | /*********************************************************************/ |
402 | if (GetMaxSize(g) < 0) |
403 | return true; |
404 | |
405 | /*********************************************************************/ |
406 | /* Open the first table file of the list. */ |
407 | /*********************************************************************/ |
408 | //if (!Filenames && InitFileNames(g)) // was done in GetMaxSize |
409 | // return true; |
410 | |
411 | if (Filenames[iFile = 0]) { |
412 | Tdbp->SetFile(g, Filenames[0]); |
413 | Tdbp->SetMode(Mode); |
414 | Tdbp->ResetDB(); |
415 | Tdbp->ResetSize(); |
416 | |
417 | if (Tdbp->OpenDB(g)) |
418 | return true; |
419 | |
420 | } // endif *Filenames |
421 | |
422 | Use = USE_OPEN; |
423 | return false; |
424 | } // end of OpenDB |
425 | |
426 | /***********************************************************************/ |
427 | /* ReadDB: Data Base read routine for MUL access method. */ |
428 | /***********************************************************************/ |
429 | int TDBMUL::ReadDB(PGLOBAL g) |
430 | { |
431 | int rc; |
432 | |
433 | if (NumFiles == 0) |
434 | return RC_EF; |
435 | else if (To_Kindex) { |
436 | /*******************************************************************/ |
437 | /* Reading is by an index table. */ |
438 | /*******************************************************************/ |
439 | strcpy(g->Message, MSG(NO_INDEX_READ)); |
440 | rc = RC_FX; |
441 | } else { |
442 | /*******************************************************************/ |
443 | /* Now start the reading process. */ |
444 | /*******************************************************************/ |
445 | retry: |
446 | rc = Tdbp->ReadDB(g); |
447 | |
448 | if (rc == RC_EF) { |
449 | if (Tdbp->GetDef()->GetPseudo() & 1) |
450 | // Total number of rows met so far |
451 | Rows += Tdbp->RowNumber(g) - 1; |
452 | |
453 | if (++iFile < NumFiles) { |
454 | /***************************************************************/ |
455 | /* Continue reading from next table file. */ |
456 | /***************************************************************/ |
457 | Tdbp->CloseDB(g); |
458 | Tdbp->SetUse(USE_READY); |
459 | Tdbp->SetFile(g, Filenames[iFile]); |
460 | Tdbp->ResetSize(); |
461 | ResetDB(); |
462 | |
463 | if (Tdbp->OpenDB(g)) // Re-open with new file name |
464 | return RC_FX; |
465 | |
466 | goto retry; |
467 | } // endif iFile |
468 | |
469 | } else if (rc == RC_FX) |
470 | strcat(strcat(strcat(g->Message, " (" ), Tdbp->GetFile(g)), ")" ); |
471 | |
472 | } // endif To_Kindex |
473 | |
474 | return rc; |
475 | } // end of ReadDB |
476 | |
477 | /***********************************************************************/ |
478 | /* Data Base write routine for MUL access method. */ |
479 | /***********************************************************************/ |
480 | int TDBMUL::WriteDB(PGLOBAL g) |
481 | { |
482 | return Tdbp->WriteDB(g); |
483 | // strcpy(g->Message, MSG(TABMUL_READONLY)); |
484 | // return RC_FX; // NIY |
485 | } // end of WriteDB |
486 | |
487 | /***********************************************************************/ |
488 | /* Data Base delete line routine for MUL access method. */ |
489 | /***********************************************************************/ |
490 | int TDBMUL::DeleteDB(PGLOBAL g, int) |
491 | { |
492 | // When implementing DELETE_MODE InitFileNames must be updated to |
493 | // eliminate CRLF under Windows if the file is read in binary. |
494 | strcpy(g->Message, MSG(TABMUL_READONLY)); |
495 | return RC_FX; // NIY |
496 | } // end of DeleteDB |
497 | |
498 | /***********************************************************************/ |
499 | /* Data Base close routine for MUL access method. */ |
500 | /***********************************************************************/ |
501 | void TDBMUL::CloseDB(PGLOBAL g) |
502 | { |
503 | if (NumFiles > 0) { |
504 | Tdbp->CloseDB(g); |
505 | iFile = NumFiles; |
506 | } // endif NumFiles |
507 | |
508 | } // end of CloseDB |
509 | |
510 | #if 0 |
511 | /* ------------------------- Class TDBMSD ---------------------------- */ |
512 | |
513 | // Method |
514 | PTDB TDBMSD::Clone(PTABS t) |
515 | { |
516 | PTDBMSD tp; |
517 | PGLOBAL g = t->G; // Is this really useful ??? |
518 | |
519 | tp = new(g) TDBMSD(this); |
520 | tp->Tdbp = Tdbp->Clone(t); |
521 | tp->Columns = tp->Tdbp->GetColumns(); |
522 | return tp; |
523 | } // end of Clone |
524 | |
525 | PTDB TDBMSD::Duplicate(PGLOBAL g) |
526 | { |
527 | PTDBMSD tmup = new(g) TDBMSD(this); |
528 | |
529 | tmup->Tdbp = Tdbp->Duplicate(g); |
530 | return tmup; |
531 | } // end of Duplicate |
532 | |
533 | /***********************************************************************/ |
534 | /* Initializes the table filename list. */ |
535 | /* Note: tables created by concatenating the file components without */ |
536 | /* specifying the LRECL value (that should be restricted to _MAX_PATH)*/ |
537 | /* have a LRECL that is the sum of the lengths of all components. */ |
538 | /* This is why we use a big filename array to take care of that. */ |
539 | /***********************************************************************/ |
540 | bool TDBMSD::InitFileNames(PGLOBAL g) |
541 | { |
542 | #define PFNZ 4096 |
543 | #define FNSZ (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT) |
544 | PTDBSDR dirp; |
545 | PSZ pfn[PFNZ]; |
546 | PSZ filename; |
547 | int rc, n = 0; |
548 | |
549 | if (trace(1)) |
550 | htrc("in InitFileName: fn[]=%d\n" , FNSZ); |
551 | |
552 | filename = (char*)PlugSubAlloc(g, NULL, FNSZ); |
553 | |
554 | // The sub table may need to refer to the Table original block |
555 | Tdbp->SetTable(To_Table); // Was not set at construction |
556 | |
557 | PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath()); |
558 | |
559 | if (trace(1)) |
560 | htrc("InitFileName: fn='%s'\n" , filename); |
561 | |
562 | dirp = new(g) TDBSDR(filename); |
563 | |
564 | if (dirp->OpenDB(g)) |
565 | return true; |
566 | |
567 | while (true) |
568 | if ((rc = dirp->ReadDB(g)) == RC_OK) { |
569 | #if defined(__WIN__) |
570 | strcat(strcpy(filename, dirp->Drive), dirp->Direc); |
571 | #else // !__WIN__ |
572 | strcpy(filename, dirp->Direc); |
573 | #endif // !__WIN__ |
574 | strcat(strcat(filename, dirp->Fname), dirp->Ftype); |
575 | pfn[n++] = PlugDup(g, filename); |
576 | } else |
577 | break; |
578 | |
579 | if (rc == RC_FX) |
580 | return true; |
581 | |
582 | if (n) { |
583 | Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*)); |
584 | |
585 | for (int i = 0; i < n; i++) |
586 | Filenames[i] = pfn[i]; |
587 | |
588 | } else { |
589 | Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*)); |
590 | Filenames[0] = NULL; |
591 | } // endif n |
592 | |
593 | NumFiles = n; |
594 | return false; |
595 | } // end of InitFileNames |
596 | #endif // 0 |
597 | |
598 | /* --------------------------- Class DIRDEF -------------------------- */ |
599 | |
600 | /***********************************************************************/ |
601 | /* DefineAM: define specific AM block values from XDB file. */ |
602 | /***********************************************************************/ |
603 | bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR, int) |
604 | { |
605 | Desc = Fn = GetStringCatInfo(g, "Filename" , NULL); |
606 | Incl = GetBoolCatInfo("Subdir" , false); |
607 | Huge = GetBoolCatInfo("Huge" , false); |
608 | Nodir = GetBoolCatInfo("Nodir" , true); |
609 | return false; |
610 | } // end of DefineAM |
611 | |
612 | /***********************************************************************/ |
613 | /* GetTable: makes a new Table Description Block. */ |
614 | /***********************************************************************/ |
615 | PTDB DIRDEF::GetTable(PGLOBAL g, MODE) |
616 | { |
617 | #if 0 |
618 | if (Huge) |
619 | return new(g) TDBDHR(this); // Not implemented yet |
620 | else |
621 | #endif |
622 | if (Incl) |
623 | return new(g) TDBSDR(this); // Including sub-directory files |
624 | else |
625 | return new(g) TDBDIR(this); // Not Including sub-directory files |
626 | |
627 | } // end of GetTable |
628 | |
629 | /* ------------------------- Class TDBDIR ---------------------------- */ |
630 | |
631 | /***********************************************************************/ |
632 | /* TABDIR constructors. */ |
633 | /***********************************************************************/ |
634 | void TDBDIR::Init(void) |
635 | { |
636 | iFile = 0; |
637 | #if defined(__WIN__) |
638 | Dvalp = NULL; |
639 | memset(&FileData, 0, sizeof(_finddata_t)); |
640 | hSearch = INVALID_HANDLE_VALUE; |
641 | *Drive = '\0'; |
642 | #else // !__WIN__ |
643 | memset(&Fileinfo, 0, sizeof(struct stat)); |
644 | Entry = NULL; |
645 | Dir = NULL; |
646 | Done = false; |
647 | *Pattern = '\0'; |
648 | #endif // !__WIN__ |
649 | *Fpath = '\0'; |
650 | *Direc = '\0'; |
651 | *Fname = '\0'; |
652 | *Ftype = '\0'; |
653 | } // end of Init |
654 | |
655 | TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp) |
656 | { |
657 | To_File = tdp->Fn; |
658 | Nodir = tdp->Nodir; |
659 | Init(); |
660 | } // end of TDBDIR standard constructor |
661 | |
662 | TDBDIR::TDBDIR(PSZ fpat) : TDBASE((PTABDEF)NULL) |
663 | { |
664 | To_File = fpat; |
665 | Nodir = true; |
666 | Init(); |
667 | } // end of TDBDIR constructor |
668 | |
669 | /***********************************************************************/ |
670 | /* Initialize/get the components of the search file pattern. */ |
671 | /***********************************************************************/ |
672 | char* TDBDIR::Path(PGLOBAL g) |
673 | { |
674 | PCATLG cat = PlgGetCatalog(g); |
675 | PTABDEF defp = (PTABDEF)To_Def; |
676 | |
677 | #if defined(__WIN__) |
678 | if (!*Drive) { |
679 | PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL); |
680 | _splitpath(Fpath, Drive, Direc, Fname, Ftype); |
681 | } else |
682 | _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull for TDBSDR |
683 | |
684 | return Fpath; |
685 | #else // !__WIN__ |
686 | if (!Done) { |
687 | PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL); |
688 | _splitpath(Fpath, NULL, Direc, Fname, Ftype); |
689 | strcat(strcpy(Pattern, Fname), Ftype); |
690 | Done = true; |
691 | } // endif Done |
692 | |
693 | return Pattern; |
694 | #endif // !__WIN__ |
695 | } // end of Path |
696 | |
697 | /***********************************************************************/ |
698 | /* Allocate DIR column description block. */ |
699 | /***********************************************************************/ |
700 | PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
701 | { |
702 | return new(g) DIRCOL(cdp, this, cprec, n); |
703 | } // end of MakeCol |
704 | |
705 | /***********************************************************************/ |
706 | /* DIR GetMaxSize: returns the number of retrieved files. */ |
707 | /***********************************************************************/ |
708 | int TDBDIR::GetMaxSize(PGLOBAL g) |
709 | { |
710 | if (MaxSize < 0) { |
711 | int rc, n = -1; |
712 | #if defined(__WIN__) |
713 | |
714 | // Start searching files in the target directory. |
715 | hSearch = FindFirstFile(Path(g), &FileData); |
716 | |
717 | if (hSearch == INVALID_HANDLE_VALUE) { |
718 | rc = GetLastError(); |
719 | |
720 | if (rc != ERROR_FILE_NOT_FOUND) { |
721 | char buf[512]; |
722 | |
723 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | |
724 | FORMAT_MESSAGE_IGNORE_INSERTS, |
725 | NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL); |
726 | sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf); |
727 | return -1; |
728 | } // endif rc |
729 | |
730 | return 0; |
731 | } // endif hSearch |
732 | |
733 | while (true) { |
734 | if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) |
735 | n++; |
736 | |
737 | if (!FindNextFile(hSearch, &FileData)) { |
738 | rc = GetLastError(); |
739 | |
740 | if (rc != ERROR_NO_MORE_FILES) { |
741 | sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc); |
742 | FindClose(hSearch); |
743 | return -1; |
744 | } // endif rc |
745 | |
746 | break; |
747 | } // endif Next |
748 | |
749 | } // endwhile |
750 | |
751 | // Close the search handle. |
752 | FindClose(hSearch); |
753 | #else // !__WIN__ |
754 | Path(g); |
755 | |
756 | // Start searching files in the target directory. |
757 | if (!(Dir = opendir(Direc))) { |
758 | sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno)); |
759 | return -1; |
760 | } // endif dir |
761 | |
762 | while ((Entry = readdir(Dir))) { |
763 | strcat(strcpy(Fpath, Direc), Entry->d_name); |
764 | |
765 | if (lstat(Fpath, &Fileinfo) < 0) { |
766 | sprintf(g->Message, "%s: %s" , Fpath, strerror(errno)); |
767 | return -1; |
768 | } else if (S_ISREG(Fileinfo.st_mode)) |
769 | // Test whether the file name matches the table name filter |
770 | if (!fnmatch(Pattern, Entry->d_name, 0)) |
771 | n++; // We have a match |
772 | |
773 | } // endwhile Entry |
774 | |
775 | // Close the DIR handle. |
776 | closedir(Dir); |
777 | #endif // !__WIN__ |
778 | MaxSize = n; |
779 | } // endif MaxSize |
780 | |
781 | return MaxSize; |
782 | } // end of GetMaxSize |
783 | |
784 | /***********************************************************************/ |
785 | /* DIR Access Method opening routine. */ |
786 | /* Open first file, other will be opened sequencially when reading. */ |
787 | /***********************************************************************/ |
788 | bool TDBDIR::OpenDB(PGLOBAL g) |
789 | { |
790 | if (trace(1)) |
791 | htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n" , |
792 | this, Tdb_No, Use, Mode); |
793 | |
794 | if (Use == USE_OPEN) { |
795 | /*******************************************************************/ |
796 | /* Table already open, reopen it. */ |
797 | /*******************************************************************/ |
798 | CloseDB(g); |
799 | SetUse(USE_READY); |
800 | } // endif use |
801 | |
802 | Use = USE_OPEN; |
803 | #if !defined(__WIN__) |
804 | Path(g); // Be sure it is done |
805 | Dir = NULL; // For ReadDB |
806 | #endif // !__WIN__ |
807 | return false; |
808 | } // end of OpenDB |
809 | |
810 | /***********************************************************************/ |
811 | /* Data Base read routine for DIR access method. */ |
812 | /***********************************************************************/ |
813 | int TDBDIR::ReadDB(PGLOBAL g) |
814 | { |
815 | int rc = RC_OK; |
816 | |
817 | #if defined(__WIN__) |
818 | do { |
819 | if (hSearch == INVALID_HANDLE_VALUE) { |
820 | /*****************************************************************/ |
821 | /* Start searching files in the target directory. The use of */ |
822 | /* the Path function is required when called from TDBSDR. */ |
823 | /*****************************************************************/ |
824 | hSearch = FindFirstFile(Path(g), &FileData); |
825 | |
826 | if (hSearch == INVALID_HANDLE_VALUE) { |
827 | rc = RC_EF; |
828 | break; |
829 | } else |
830 | iFile++; |
831 | |
832 | } else { |
833 | if (!FindNextFile(hSearch, &FileData)) { |
834 | // Restore file name and type pattern |
835 | _splitpath(To_File, NULL, NULL, Fname, Ftype); |
836 | rc = RC_EF; |
837 | break; |
838 | } else |
839 | iFile++; |
840 | |
841 | } // endif hSearch |
842 | |
843 | } while (Nodir && FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); |
844 | |
845 | if (rc == RC_OK) |
846 | _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype); |
847 | |
848 | #else // !Win32 |
849 | rc = RC_NF; |
850 | |
851 | if (!Dir) |
852 | // Start searching files in the target directory. |
853 | if (!(Dir = opendir(Direc))) { |
854 | sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno)); |
855 | rc = RC_FX; |
856 | } // endif dir |
857 | |
858 | while (rc == RC_NF) |
859 | if ((Entry = readdir(Dir))) { |
860 | // We need the Fileinfo structure to get info about the file |
861 | strcat(strcpy(Fpath, Direc), Entry->d_name); |
862 | |
863 | if (lstat(Fpath, &Fileinfo) < 0) { |
864 | sprintf(g->Message, "%s: %s" , Fpath, strerror(errno)); |
865 | rc = RC_FX; |
866 | } else if (S_ISREG(Fileinfo.st_mode)) |
867 | // Test whether the file name matches the table name filter |
868 | if (!fnmatch(Pattern, Entry->d_name, 0)) { |
869 | iFile++; // We have a match |
870 | _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype); |
871 | rc = RC_OK; |
872 | } // endif fnmatch |
873 | |
874 | } else { |
875 | // Restore file name and type pattern |
876 | _splitpath(To_File, NULL, NULL, Fname, Ftype); |
877 | rc = RC_EF; |
878 | } // endif Entry |
879 | |
880 | #endif // !__WIN__ |
881 | |
882 | return rc; |
883 | } // end of ReadDB |
884 | |
885 | /***********************************************************************/ |
886 | /* Data Base write routine for DIR access method. */ |
887 | /***********************************************************************/ |
888 | int TDBDIR::WriteDB(PGLOBAL g) |
889 | { |
890 | strcpy(g->Message, MSG(TABDIR_READONLY)); |
891 | return RC_FX; // NIY |
892 | } // end of WriteDB |
893 | |
894 | /***********************************************************************/ |
895 | /* Data Base delete line routine for DIR access method. */ |
896 | /***********************************************************************/ |
897 | int TDBDIR::DeleteDB(PGLOBAL g, int) |
898 | { |
899 | strcpy(g->Message, MSG(TABDIR_READONLY)); |
900 | return RC_FX; // NIY |
901 | } // end of DeleteDB |
902 | |
903 | /***********************************************************************/ |
904 | /* Data Base close routine for MUL access method. */ |
905 | /***********************************************************************/ |
906 | void TDBDIR::CloseDB(PGLOBAL) |
907 | { |
908 | #if defined(__WIN__) |
909 | // Close the search handle. |
910 | FindClose(hSearch); |
911 | hSearch = INVALID_HANDLE_VALUE; |
912 | #else // !__WIN__ |
913 | // Close the DIR handle |
914 | if (Dir) { |
915 | closedir(Dir); |
916 | Dir = NULL; |
917 | } // endif dir |
918 | #endif // !__WIN__ |
919 | iFile = 0; |
920 | } // end of CloseDB |
921 | |
922 | // ------------------------ DIRCOL functions ---------------------------- |
923 | |
924 | /***********************************************************************/ |
925 | /* DIRCOL public constructor. */ |
926 | /***********************************************************************/ |
927 | DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ) |
928 | : COLBLK(cdp, tdbp, i) |
929 | { |
930 | if (cprec) { |
931 | Next = cprec->GetNext(); |
932 | cprec->SetNext(this); |
933 | } else { |
934 | Next = tdbp->GetColumns(); |
935 | tdbp->SetColumns(this); |
936 | } // endif cprec |
937 | |
938 | // Set additional DIR access method information for column. |
939 | Tdbp = (PTDBDIR)tdbp; |
940 | N = cdp->GetOffset(); |
941 | } // end of DIRCOL constructor |
942 | |
943 | /***********************************************************************/ |
944 | /* DIRCOL constructor used for copying columns. */ |
945 | /* tdbp is the pointer to the new table descriptor. */ |
946 | /***********************************************************************/ |
947 | DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) |
948 | { |
949 | Tdbp = (PTDBDIR)tdbp; |
950 | N = col1->N; |
951 | } // end of DIRCOL copy constructor |
952 | |
953 | #if defined(__WIN__) |
954 | /***********************************************************************/ |
955 | /* Retrieve time information from FileData. */ |
956 | /***********************************************************************/ |
957 | void DIRCOL::SetTimeValue(PGLOBAL g, FILETIME& ftime) |
958 | { |
959 | char tsp[24]; |
960 | SYSTEMTIME stp; |
961 | |
962 | if (FileTimeToSystemTime(&ftime, &stp)) { |
963 | sprintf(tsp, "%04d-%02d-%02d %02d:%02d:%02d" , |
964 | stp.wYear, stp.wMonth, stp.wDay, stp.wHour, stp.wMinute, stp.wSecond); |
965 | |
966 | if (Value->GetType() != TYPE_STRING) { |
967 | if (!Tdbp->Dvalp) |
968 | Tdbp->Dvalp = AllocateValue(g, TYPE_DATE, 20, 0, false, |
969 | "YYYY-MM-DD hh:mm:ss" ); |
970 | |
971 | Tdbp->Dvalp->SetValue_psz(tsp); |
972 | Value->SetValue_pval(Tdbp->Dvalp); |
973 | } else |
974 | Value->SetValue_psz(tsp); |
975 | |
976 | } else |
977 | Value->Reset(); |
978 | |
979 | } // end of SetTimeValue |
980 | #endif // __WIN__ |
981 | |
982 | /***********************************************************************/ |
983 | /* ReadColumn: what this routine does is to access the information */ |
984 | /* corresponding to this column and convert it to buffer type. */ |
985 | /***********************************************************************/ |
986 | void DIRCOL::ReadColumn(PGLOBAL g) |
987 | { |
988 | if (trace(1)) |
989 | htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n" , |
990 | Name, Tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N); |
991 | |
992 | /*********************************************************************/ |
993 | /* Retrieve the information corresponding to the column number. */ |
994 | /*********************************************************************/ |
995 | switch (N) { |
996 | #if defined(__WIN__) |
997 | case 0: Value->SetValue_psz(Tdbp->Drive); break; |
998 | #endif // __WIN__ |
999 | case 1: Value->SetValue_psz(Tdbp->Direc); break; |
1000 | case 2: Value->SetValue_psz(Tdbp->Fname); break; |
1001 | case 3: Value->SetValue_psz(Tdbp->Ftype); break; |
1002 | #if defined(__WIN__) |
1003 | case 4: Value->SetValue((int)Tdbp->FileData.dwFileAttributes); break; |
1004 | case 5: Value->SetValue((int)Tdbp->FileData.nFileSizeLow); break; |
1005 | case 6: SetTimeValue(g, Tdbp->FileData.ftLastWriteTime); break; |
1006 | case 7: SetTimeValue(g, Tdbp->FileData.ftCreationTime); break; |
1007 | case 8: SetTimeValue(g, Tdbp->FileData.ftLastAccessTime); break; |
1008 | #else // !__WIN__ |
1009 | case 4: Value->SetValue((int)Tdbp->Fileinfo.st_mode); break; |
1010 | case 5: Value->SetValue((int)Tdbp->Fileinfo.st_size); break; |
1011 | case 6: Value->SetValue((int)Tdbp->Fileinfo.st_mtime); break; |
1012 | case 7: Value->SetValue((int)Tdbp->Fileinfo.st_ctime); break; |
1013 | case 8: Value->SetValue((int)Tdbp->Fileinfo.st_atime); break; |
1014 | case 9: Value->SetValue((int)Tdbp->Fileinfo.st_uid); break; |
1015 | case 10: Value->SetValue((int)Tdbp->Fileinfo.st_gid); break; |
1016 | #endif // !__WIN__ |
1017 | default: |
1018 | sprintf(g->Message, MSG(INV_DIRCOL_OFST), N); |
1019 | throw GetAmType(); |
1020 | } // endswitch N |
1021 | |
1022 | } // end of ReadColumn |
1023 | |
1024 | /* ------------------------- Class TDBSDR ---------------------------- */ |
1025 | |
1026 | /***********************************************************************/ |
1027 | /* SDR GetMaxSize: returns the number of retrieved files. */ |
1028 | /***********************************************************************/ |
1029 | int TDBSDR::GetMaxSize(PGLOBAL g) |
1030 | { |
1031 | if (MaxSize < 0) { |
1032 | Path(g); |
1033 | MaxSize = FindInDir(g); |
1034 | } // endif MaxSize |
1035 | |
1036 | return MaxSize; |
1037 | } // end of GetMaxSize |
1038 | |
1039 | /***********************************************************************/ |
1040 | /* SDR FindInDir: returns the number of retrieved files. */ |
1041 | /***********************************************************************/ |
1042 | int TDBSDR::FindInDir(PGLOBAL g) |
1043 | { |
1044 | int rc, n = 0; |
1045 | size_t m = strlen(Direc); |
1046 | |
1047 | // Start searching files in the target directory. |
1048 | #if defined(__WIN__) |
1049 | HANDLE h; |
1050 | |
1051 | #if defined(PATHMATCHSPEC) |
1052 | if (!*Drive) |
1053 | Path(g); |
1054 | |
1055 | _makepath(Fpath, Drive, Direc, "*" , "*" ); |
1056 | |
1057 | h = FindFirstFile(Fpath, &FileData); |
1058 | |
1059 | if (h == INVALID_HANDLE_VALUE) { |
1060 | rc = GetLastError(); |
1061 | |
1062 | if (rc != ERROR_FILE_NOT_FOUND) { |
1063 | char buf[512]; |
1064 | |
1065 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | |
1066 | FORMAT_MESSAGE_IGNORE_INSERTS, |
1067 | NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL); |
1068 | sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf); |
1069 | return -1; |
1070 | } // endif rc |
1071 | |
1072 | return 0; |
1073 | } // endif h |
1074 | |
1075 | while (true) { |
1076 | if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && |
1077 | *FileData.cFileName != '.') { |
1078 | // Look in the name sub-directory |
1079 | strcat(strcat(Direc, FileData.cFileName), "/" ); |
1080 | n += FindInDir(g); |
1081 | Direc[m] = '\0'; // Restore path |
1082 | } else if (PathMatchSpec(FileData.cFileName, Fpath)) |
1083 | n++; |
1084 | |
1085 | if (!FindNextFile(h, &FileData)) { |
1086 | rc = GetLastError(); |
1087 | |
1088 | if (rc != ERROR_NO_MORE_FILES) { |
1089 | sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc); |
1090 | FindClose(h); |
1091 | return -1; |
1092 | } // endif rc |
1093 | |
1094 | break; |
1095 | } // endif Next |
1096 | |
1097 | } // endwhile |
1098 | #else // !PATHMATCHSPEC |
1099 | h = FindFirstFile(Path(g), &FileData); |
1100 | |
1101 | if (h == INVALID_HANDLE_VALUE) { |
1102 | rc = GetLastError(); |
1103 | |
1104 | if (rc != ERROR_FILE_NOT_FOUND) { |
1105 | char buf[512]; |
1106 | |
1107 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | |
1108 | FORMAT_MESSAGE_IGNORE_INSERTS, |
1109 | NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL); |
1110 | sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf); |
1111 | return -1; |
1112 | } // endif rc |
1113 | |
1114 | return 0; |
1115 | } // endif hSearch |
1116 | |
1117 | while (true) { |
1118 | n++; |
1119 | |
1120 | if (!FindNextFile(h, &FileData)) { |
1121 | rc = GetLastError(); |
1122 | |
1123 | if (rc != ERROR_NO_MORE_FILES) { |
1124 | sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc); |
1125 | FindClose(h); |
1126 | return -1; |
1127 | } // endif rc |
1128 | |
1129 | break; |
1130 | } // endif Next |
1131 | |
1132 | } // endwhile |
1133 | |
1134 | // Now search files in sub-directories. |
1135 | _makepath(Fpath, Drive, Direc, "*" , "." ); |
1136 | h = FindFirstFile(Fpath, &FileData); |
1137 | |
1138 | if (h != INVALID_HANDLE_VALUE) { |
1139 | while (true) { |
1140 | if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && |
1141 | *FileData.cFileName != '.') { |
1142 | // Look in the name sub-directory |
1143 | strcat(strcat(Direc, FileData.cFileName), "/" ); |
1144 | n += FindInDir(g); |
1145 | Direc[m] = '\0'; // Restore path |
1146 | } // endif SUBDIR |
1147 | |
1148 | if (!FindNextFile(h, &FileData)) |
1149 | break; |
1150 | |
1151 | } // endwhile |
1152 | |
1153 | } // endif h |
1154 | #endif // !PATHMATCHSPEC |
1155 | |
1156 | // Close the search handle. |
1157 | FindClose(h); |
1158 | #else // !__WIN__ |
1159 | int k; |
1160 | DIR *dir = opendir(Direc); |
1161 | |
1162 | if (!dir) { |
1163 | sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno)); |
1164 | return -1; |
1165 | } // endif dir |
1166 | |
1167 | while ((Entry = readdir(dir))) { |
1168 | strcat(strcpy(Fpath, Direc), Entry->d_name); |
1169 | |
1170 | if (lstat(Fpath, &Fileinfo) < 0) { |
1171 | sprintf(g->Message, "%s: %s" , Fpath, strerror(errno)); |
1172 | return -1; |
1173 | } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') { |
1174 | // Look in the name sub-directory |
1175 | strcat(strcat(Direc, Entry->d_name), "/" ); |
1176 | |
1177 | if ((k = FindInDir(g)) < 0) |
1178 | return k; |
1179 | else |
1180 | n += k; |
1181 | |
1182 | Direc[m] = '\0'; // Restore path |
1183 | } else if (S_ISREG(Fileinfo.st_mode)) |
1184 | // Test whether the file name matches the table name filter |
1185 | if (!fnmatch(Pattern, Entry->d_name, 0)) |
1186 | n++; // We have a match |
1187 | |
1188 | } // endwhile readdir |
1189 | |
1190 | // Close the DIR handle. |
1191 | closedir(dir); |
1192 | #endif // !__WIN__ |
1193 | |
1194 | return n; |
1195 | } // end of FindInDir |
1196 | |
1197 | /***********************************************************************/ |
1198 | /* DIR Access Method opening routine. */ |
1199 | /* Open first file, other will be opened sequencially when reading. */ |
1200 | /***********************************************************************/ |
1201 | bool TDBSDR::OpenDB(PGLOBAL g) |
1202 | { |
1203 | if (!Sub) { |
1204 | Path(g); |
1205 | Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR)); |
1206 | Sub->Next = NULL; |
1207 | Sub->Prev = NULL; |
1208 | #if defined(__WIN__) |
1209 | Sub->H = INVALID_HANDLE_VALUE; |
1210 | Sub->Len = strlen(Direc); |
1211 | #else // !__WIN__ |
1212 | Sub->D = NULL; |
1213 | Sub->Len = 0; |
1214 | #endif // !__WIN__ |
1215 | } // endif To_Sub |
1216 | |
1217 | return TDBDIR::OpenDB(g); |
1218 | } // end of OpenDB |
1219 | |
1220 | /***********************************************************************/ |
1221 | /* Data Base read routine for SDR access method. */ |
1222 | /***********************************************************************/ |
1223 | int TDBSDR::ReadDB(PGLOBAL g) |
1224 | { |
1225 | int rc; |
1226 | |
1227 | #if defined(__WIN__) |
1228 | again: |
1229 | rc = TDBDIR::ReadDB(g); |
1230 | |
1231 | if (rc == RC_EF) { |
1232 | // Are there more files in sub-directories |
1233 | retry: |
1234 | do { |
1235 | if (Sub->H == INVALID_HANDLE_VALUE) { |
1236 | // _makepath(Fpath, Drive, Direc, "*", "."); why was this made? |
1237 | _makepath(Fpath, Drive, Direc, "*" , NULL); |
1238 | Sub->H = FindFirstFile(Fpath, &FileData); |
1239 | } else if (!FindNextFile(Sub->H, &FileData)) { |
1240 | FindClose(Sub->H); |
1241 | Sub->H = INVALID_HANDLE_VALUE; |
1242 | *FileData.cFileName= '\0'; |
1243 | break; |
1244 | } // endif findnext |
1245 | |
1246 | } while(!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || |
1247 | (*FileData.cFileName == '.' && |
1248 | (!FileData.cFileName[1] || FileData.cFileName[1] == '.'))); |
1249 | |
1250 | if (Sub->H == INVALID_HANDLE_VALUE) { |
1251 | // No more sub-directories. Are we in a sub-directory? |
1252 | if (!Sub->Prev) |
1253 | return rc; // No, all is finished |
1254 | |
1255 | // here we must continue in the parent directory |
1256 | Sub = Sub->Prev; |
1257 | goto retry; |
1258 | } else { |
1259 | // Search next sub-directory |
1260 | Direc[Sub->Len] = '\0'; |
1261 | |
1262 | if (!Sub->Next) { |
1263 | PSUBDIR sup; |
1264 | |
1265 | sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR)); |
1266 | sup->Next = NULL; |
1267 | sup->Prev = Sub; |
1268 | sup->H = INVALID_HANDLE_VALUE; |
1269 | Sub->Next = sup; |
1270 | } // endif Next |
1271 | |
1272 | Sub = Sub->Next; |
1273 | strcat(strcat(Direc, FileData.cFileName), "/" ); |
1274 | Sub->Len = strlen(Direc); |
1275 | |
1276 | // Reset Hsearch used by TDBDIR::ReadDB |
1277 | FindClose(hSearch); |
1278 | hSearch = INVALID_HANDLE_VALUE; |
1279 | goto again; |
1280 | } // endif H |
1281 | |
1282 | } // endif rc |
1283 | #else // !__WIN__ |
1284 | rc = RC_NF; |
1285 | |
1286 | again: |
1287 | if (!Sub->D) |
1288 | // Start searching files in the target directory. |
1289 | if (!(Sub->D = opendir(Direc))) { |
1290 | sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno)); |
1291 | rc = RC_FX; |
1292 | } // endif dir |
1293 | |
1294 | while (rc == RC_NF) |
1295 | if ((Entry = readdir(Sub->D))) { |
1296 | // We need the Fileinfo structure to get info about the file |
1297 | strcat(strcpy(Fpath, Direc), Entry->d_name); |
1298 | |
1299 | if (lstat(Fpath, &Fileinfo) < 0) { |
1300 | sprintf(g->Message, "%s: %s" , Fpath, strerror(errno)); |
1301 | rc = RC_FX; |
1302 | } else if (S_ISDIR(Fileinfo.st_mode) && strcmp(Entry->d_name, "." ) |
1303 | && strcmp(Entry->d_name, ".." )) { |
1304 | // Look in the name sub-directory |
1305 | if (!Sub->Next) { |
1306 | PSUBDIR sup; |
1307 | |
1308 | sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR)); |
1309 | sup->Next = NULL; |
1310 | sup->Prev = Sub; |
1311 | Sub->Next = sup; |
1312 | } // endif Next |
1313 | |
1314 | Sub = Sub->Next; |
1315 | Sub->D = NULL; |
1316 | Sub->Len = strlen(Direc); |
1317 | strcat(strcat(Direc, Entry->d_name), "/" ); |
1318 | goto again; |
1319 | } else if (S_ISREG(Fileinfo.st_mode)) |
1320 | // Test whether the file name matches the table name filter |
1321 | if (!fnmatch(Pattern, Entry->d_name, 0)) { |
1322 | iFile++; // We have a match |
1323 | _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype); |
1324 | rc = RC_OK; |
1325 | } // endif fnmatch |
1326 | |
1327 | } else { |
1328 | // No more files. Close the DIR handle. |
1329 | closedir(Sub->D); |
1330 | |
1331 | // Are we in a sub-directory? |
1332 | if (Sub->Prev) { |
1333 | // Yes, we must continue in the parent directory |
1334 | Direc[Sub->Len] = '\0'; |
1335 | Sub = Sub->Prev; |
1336 | } else |
1337 | rc = RC_EF; // No, all is finished |
1338 | |
1339 | } // endif Entry |
1340 | |
1341 | #endif // !__WIN__ |
1342 | |
1343 | return rc; |
1344 | } // end of ReadDB |
1345 | |
1346 | #if 0 |
1347 | /* ------------------------- Class TDBDHR ---------------------------- */ |
1348 | |
1349 | /***********************************************************************/ |
1350 | /* TABDHR constructors. */ |
1351 | /***********************************************************************/ |
1352 | TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp) |
1353 | { |
1354 | memset(&FileData, 0, sizeof(WIN32_FIND_DATA)); |
1355 | Hsearch = INVALID_HANDLE_VALUE; |
1356 | iFile = 0; |
1357 | *Drive = '\0'; |
1358 | *Direc = '\0'; |
1359 | *Fname = '\0'; |
1360 | *Ftype = '\0'; |
1361 | } // end of TDBDHR standard constructor |
1362 | |
1363 | TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp) |
1364 | { |
1365 | FileData = tdbp->FileData; |
1366 | Hsearch = tdbp->Hsearch; |
1367 | iFile = tdbp->iFile; |
1368 | strcpy(Drive, tdbp->Drive); |
1369 | strcpy(Direc, tdbp->Direc); |
1370 | strcpy(Fname, tdbp->Fname); |
1371 | strcpy(Ftype, tdbp->Ftype); |
1372 | } // end of TDBDHR copy constructor |
1373 | |
1374 | // Method |
1375 | PTDB TDBDHR::Clone(PTABS t) |
1376 | { |
1377 | PTDB tp; |
1378 | PGLOBAL g = t->G; // Is this really useful ??? |
1379 | |
1380 | tp = new(g) TDBDHR(this); |
1381 | tp->Columns = Columns; |
1382 | return tp; |
1383 | } // end of Clone |
1384 | |
1385 | /***********************************************************************/ |
1386 | /* Allocate DHR column description block. */ |
1387 | /***********************************************************************/ |
1388 | PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
1389 | { |
1390 | return new(g) DHRCOL(cdp, this, cprec, n); |
1391 | } // end of MakeCol |
1392 | |
1393 | /***********************************************************************/ |
1394 | /* DHR GetMaxSize: returns the number of retrieved files. */ |
1395 | /***********************************************************************/ |
1396 | int TDBDHR::GetMaxSize(PGLOBAL g) |
1397 | { |
1398 | if (MaxSize < 0) { |
1399 | char filename[_MAX_PATH]; |
1400 | int i, rc; |
1401 | int n = -1; |
1402 | HANDLE h; |
1403 | PDBUSER dup = PlgGetUser(g); |
1404 | |
1405 | PlugSetPath(filename, To_File, dup->Path); |
1406 | |
1407 | // Start searching files in the target directory. |
1408 | h = FindFirstFile(filename, &FileData); |
1409 | |
1410 | if (h == INVALID_HANDLE_VALUE) { |
1411 | switch (rc = GetLastError()) { |
1412 | case ERROR_NO_MORE_FILES: |
1413 | case ERROR_FILE_NOT_FOUND: |
1414 | n = 0; |
1415 | break; |
1416 | default: |
1417 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | |
1418 | FORMAT_MESSAGE_IGNORE_INSERTS, |
1419 | NULL, rc, 0, |
1420 | (LPTSTR)&filename, sizeof(filename), NULL); |
1421 | sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename); |
1422 | } // endswitch rc |
1423 | |
1424 | } else { |
1425 | for (n = 1;; n++) |
1426 | if (!FindNextFile(h, &FileData)) { |
1427 | rc = GetLastError(); |
1428 | |
1429 | if (rc != ERROR_NO_MORE_FILES) { |
1430 | sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc); |
1431 | n = -1; |
1432 | } // endif rc |
1433 | |
1434 | break; |
1435 | } // endif FindNextFile |
1436 | |
1437 | // Close the search handle. |
1438 | if (!FindClose(h) && n != -1) |
1439 | strcpy(g->Message, MSG(SRCH_CLOSE_ERR)); |
1440 | |
1441 | } // endif Hsearch |
1442 | |
1443 | MaxSize = n; |
1444 | } // endif MaxSize |
1445 | |
1446 | return MaxSize; |
1447 | } // end of GetMaxSize |
1448 | |
1449 | /***********************************************************************/ |
1450 | /* DHR Access Method opening routine. */ |
1451 | /* Open first file, other will be opened sequencially when reading. */ |
1452 | /***********************************************************************/ |
1453 | bool TDBDHR::OpenDB(PGLOBAL g) |
1454 | { |
1455 | if (trace(1)) |
1456 | htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n" , |
1457 | this, Tdb_No, Use, Mode); |
1458 | |
1459 | if (Use == USE_OPEN) { |
1460 | /*******************************************************************/ |
1461 | /* Table already open, reopen it. */ |
1462 | /*******************************************************************/ |
1463 | CloseDB(g); |
1464 | SetUse(USE_READY); |
1465 | } // endif use |
1466 | |
1467 | /*********************************************************************/ |
1468 | /* Direct access needed for join or sorting. */ |
1469 | /*********************************************************************/ |
1470 | if (NeedIndexing(g)) { |
1471 | // Direct access of DHR tables is not implemented yet |
1472 | sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR" ); |
1473 | return true; |
1474 | } // endif NeedIndexing |
1475 | |
1476 | Use = USE_OPEN; |
1477 | return false; |
1478 | } // end of OpenDB |
1479 | |
1480 | /***********************************************************************/ |
1481 | /* Data Base read routine for DHR access method. */ |
1482 | /***********************************************************************/ |
1483 | int TDBDHR::ReadDB(PGLOBAL g) |
1484 | { |
1485 | int rc = RC_OK; |
1486 | DWORD erc; |
1487 | |
1488 | if (Hsearch == INVALID_HANDLE_VALUE) { |
1489 | char *filename[_MAX_PATH]; |
1490 | PDBUSER dup = PlgGetUser(g); |
1491 | |
1492 | PlugSetPath(filename, To_File, dup->Path); |
1493 | _splitpath(filename, Drive, Direc, NULL, NULL); |
1494 | |
1495 | /*******************************************************************/ |
1496 | /* Start searching files in the target directory. */ |
1497 | /*******************************************************************/ |
1498 | Hsearch = FindFirstFile(filename, &FileData); |
1499 | |
1500 | if (Hsearch != INVALID_HANDLE_VALUE) |
1501 | iFile = 1; |
1502 | else switch (erc = GetLastError()) { |
1503 | case ERROR_NO_MORE_FILES: |
1504 | case ERROR_FILE_NOT_FOUND: |
1505 | // case ERROR_PATH_NOT_FOUND: ??????? |
1506 | rc = RC_EF; |
1507 | break; |
1508 | default: |
1509 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | |
1510 | FORMAT_MESSAGE_IGNORE_INSERTS, |
1511 | NULL, erc, 0, |
1512 | (LPTSTR)&filename, sizeof(filename), NULL); |
1513 | sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename); |
1514 | rc = RC_FX; |
1515 | } // endswitch erc |
1516 | |
1517 | } else { |
1518 | if (!FindNextFile(Hsearch, &FileData)) { |
1519 | DWORD erc = GetLastError(); |
1520 | |
1521 | if (erc != ERROR_NO_MORE_FILES) { |
1522 | sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc); |
1523 | FindClose(Hsearch); |
1524 | rc = RC_FX; |
1525 | } else |
1526 | rc = RC_EF; |
1527 | |
1528 | } else |
1529 | iFile++; |
1530 | |
1531 | } // endif Hsearch |
1532 | |
1533 | if (rc == RC_OK) |
1534 | _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype); |
1535 | |
1536 | return rc; |
1537 | } // end of ReadDB |
1538 | |
1539 | /***********************************************************************/ |
1540 | /* Data Base close routine for MUL access method. */ |
1541 | /***********************************************************************/ |
1542 | void TDBDHR::CloseDB(PGLOBAL g) |
1543 | { |
1544 | // Close the search handle. |
1545 | if (!FindClose(Hsearch)) { |
1546 | strcpy(g->Message, MSG(SRCH_CLOSE_ERR)); |
1547 | throw GetAmType(); |
1548 | } // endif FindClose |
1549 | |
1550 | iFile = 0; |
1551 | Hsearch = INVALID_HANDLE_VALUE; |
1552 | } // end of CloseDB |
1553 | |
1554 | // ------------------------ DHRCOL functions ---------------------------- |
1555 | |
1556 | /***********************************************************************/ |
1557 | /* DHRCOL public constructor. */ |
1558 | /***********************************************************************/ |
1559 | DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) |
1560 | : COLBLK(cdp, tdbp, i) |
1561 | { |
1562 | if (cprec) { |
1563 | Next = cprec->GetNext(); |
1564 | cprec->SetNext(this); |
1565 | } else { |
1566 | Next = tdbp->GetColumns(); |
1567 | tdbp->SetColumns(this); |
1568 | } // endif cprec |
1569 | |
1570 | // Set additional DHR access method information for column. |
1571 | N = cdp->GetOffset(); |
1572 | } // end of DOSCOL constructor |
1573 | |
1574 | /***********************************************************************/ |
1575 | /* DHRCOL constructor used for copying columns. */ |
1576 | /* tdbp is the pointer to the new table descriptor. */ |
1577 | /***********************************************************************/ |
1578 | DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp) |
1579 | { |
1580 | N = col1->N; |
1581 | } // end of DHRCOL copy constructor |
1582 | |
1583 | /***********************************************************************/ |
1584 | /* ReadColumn: what this routine does is to access the information */ |
1585 | /* corresponding to this column and convert it to buffer type. */ |
1586 | /***********************************************************************/ |
1587 | void DHRCOL::ReadColumn(PGLOBAL g) |
1588 | { |
1589 | int rc; |
1590 | PTDBDHR tdbp = (PTDBDHR)To_Tdb; |
1591 | |
1592 | if (trace(1)) |
1593 | htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n" , |
1594 | Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N); |
1595 | |
1596 | /*********************************************************************/ |
1597 | /* Retrieve the information corresponding to the column number. */ |
1598 | /*********************************************************************/ |
1599 | switch (N) { |
1600 | case 0: // Drive |
1601 | Value->SetValue(Drive, _MAX_DRIVE); |
1602 | break; |
1603 | case 1: // Path |
1604 | Value->SetValue(Direc, _MAX_DHR); |
1605 | break; |
1606 | case 2: // Name |
1607 | Value->SetValue(Fname, _MAX_FNAME); |
1608 | break; |
1609 | case 3: // Extention |
1610 | Value->SetValue(Ftype, _MAX_EXT); |
1611 | break; |
1612 | case 4: // Extention |
1613 | Value->SetValue(tdbp->FileData.cAlternateFileName, 14); |
1614 | break; |
1615 | case 5: |
1616 | Value->SetValue(tdbp->FileData.dwFileAttributes); |
1617 | break; |
1618 | case 6: |
1619 | Value->SetValue(.................. |
1620 | } // end of ReadColumn |
1621 | #endif // 0 |
1622 | |
1623 | |