1 /************* TabSys C++ Program Source Code File (.CPP) **************/
2 /* PROGRAM NAME: TABSYS */
3 /* ------------- */
4 /* Version 2.4 */
5 /* */
6 /* Author Olivier BERTRAND 2004-2017 */
7 /* */
8 /* This program are the INI/CFG tables classes. */
9 /***********************************************************************/
10
11 /***********************************************************************/
12 /* Include relevant sections of the System header files. */
13 /***********************************************************************/
14 #include "my_global.h"
15 #if defined(_WIN32)
16 #if defined(__BORLANDC__)
17 #define __MFC_COMPAT__ // To define min/max as macro
18 #endif // __BORLANDC__
19 //#include <windows.h>
20 #else // !_WIN32
21 #if defined(UNIX)
22 #include <errno.h>
23 #include <unistd.h>
24 #else // !UNIX
25 #include <io.h>
26 #endif // !UNIX
27 #include <fcntl.h>
28 #endif // !_WIN32
29
30 /***********************************************************************/
31 /* Include application header files: */
32 /* global.h is header containing all global declarations. */
33 /* plgdbsem.h is header containing the DB application declarations. */
34 /* tabdos.h is header containing the TABDOS class declarations. */
35 /***********************************************************************/
36 #include "global.h"
37 #include "plgdbsem.h"
38 #include "reldef.h"
39 #if !defined(_WIN32)
40 #include "osutil.h"
41 #endif // !_WIN32
42 #include "filamtxt.h"
43 #include "tabdos.h"
44 #include "tabsys.h"
45 #include "tabmul.h"
46 #include "inihandl.h"
47
48 #define CSZ 36 // Column section name length
49 #define CDZ 256 // Column definition length
50
51 #if !defined(_WIN32)
52 #define GetPrivateProfileSectionNames(S,L,I) \
53 GetPrivateProfileString(NULL,NULL,"",S,L,I)
54 #endif // !_WIN32
55
56 /* -------------- Implementation of the INI classes ------------------ */
57
58 /***********************************************************************/
59 /* Constructor. */
60 /***********************************************************************/
INIDEF(void)61 INIDEF::INIDEF(void)
62 {
63 Pseudo = 3;
64 Fn = NULL;
65 Xname = NULL;
66 Layout = '?';
67 Ln = 0;
68 } // end of INIDEF constructor
69
70 /***********************************************************************/
71 /* DefineAM: define specific AM block values from XDB file. */
72 /***********************************************************************/
DefineAM(PGLOBAL g,LPCSTR,int)73 bool INIDEF::DefineAM(PGLOBAL g, LPCSTR, int)
74 {
75 char buf[8];
76
77 Fn = GetStringCatInfo(g, "Filename", NULL);
78 GetCharCatInfo("Layout", "C", buf, sizeof(buf));
79 Layout = toupper(*buf);
80
81 if (Fn) {
82 char *p = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
83
84 PlugSetPath(p, Fn, GetPath());
85 Fn = p;
86 } else {
87 strcpy(g->Message, MSG(MISSING_FNAME));
88 return true;
89 } // endif Fn
90
91 Ln = GetSizeCatInfo("Secsize", "8K");
92 Desc = Fn;
93 return false;
94 } // end of DefineAM
95
96 /***********************************************************************/
97 /* GetTable: makes a new TDB of the proper type. */
98 /***********************************************************************/
GetTable(PGLOBAL g,MODE)99 PTDB INIDEF::GetTable(PGLOBAL g, MODE)
100 {
101 PTDBASE tdbp;
102
103 if (Layout == 'C')
104 tdbp = new(g) TDBINI(this);
105 else
106 tdbp = new(g) TDBXIN(this);
107
108 if (Multiple)
109 tdbp = new(g) TDBMUL(tdbp); // No block optimization yet
110
111 return tdbp;
112 } // end of GetTable
113
114 #if 0
115 /***********************************************************************/
116 /* DeleteTableFile: Delete INI table files using platform API. */
117 /***********************************************************************/
118 bool INIDEF::DeleteTableFile(PGLOBAL g)
119 {
120 char filename[_MAX_PATH];
121 bool rc;
122
123 // Delete the INI table file if not protected
124 if (!IsReadOnly()) {
125 PlugSetPath(filename, Fn, GetPath());
126 #if defined(_WIN32)
127 rc = !DeleteFile(filename);
128 #else // UNIX
129 rc = remove(filename);
130 #endif // UNIX
131 } else
132 rc =true;
133
134 return rc; // Return true if error
135 } // end of DeleteTableFile
136 #endif // 0
137
138 /* ------------------------------------------------------------------- */
139
140 /***********************************************************************/
141 /* Implementation of the TDBINI class. */
142 /***********************************************************************/
TDBINI(PINIDEF tdp)143 TDBINI::TDBINI(PINIDEF tdp) : TDBASE(tdp)
144 {
145 Ifile = tdp->Fn;
146 Seclist = NULL;
147 Section = NULL;
148 Seclen = tdp->Ln;
149 N = 0;
150 } // end of TDBINI constructor
151
TDBINI(PTDBINI tdbp)152 TDBINI::TDBINI(PTDBINI tdbp) : TDBASE(tdbp)
153 {
154 Ifile = tdbp->Ifile;
155 Seclist = tdbp->Seclist;
156 Section = tdbp->Section;
157 Seclen = tdbp->Seclen;
158 N = tdbp->N;
159 } // end of TDBINI copy constructor
160
161 // Is this really useful ???
Clone(PTABS t)162 PTDB TDBINI::Clone(PTABS t)
163 {
164 PTDB tp;
165 PINICOL cp1, cp2;
166 PGLOBAL g = t->G;
167
168 tp = new(g) TDBINI(this);
169
170 for (cp1 = (PINICOL)Columns; cp1; cp1 = (PINICOL)cp1->GetNext()) {
171 cp2 = new(g) INICOL(cp1, tp); // Make a copy
172 NewPointer(t, cp1, cp2);
173 } // endfor cp1
174
175 return tp;
176 } // end of Clone
177
178 /***********************************************************************/
179 /* Get the section list from the INI file. */
180 /***********************************************************************/
GetSeclist(PGLOBAL g)181 char *TDBINI::GetSeclist(PGLOBAL g)
182 {
183 if (trace(1))
184 htrc("GetSeclist: Seclist=%p\n", Seclist);
185
186 if (!Seclist) {
187 // Result will be retrieved from the INI file
188 Seclist = (char*)PlugSubAlloc(g, NULL, Seclen);
189 GetPrivateProfileSectionNames(Seclist, Seclen, Ifile);
190 } // endif Seclist
191
192 return Seclist;
193 } // end of GetSeclist
194
195 /***********************************************************************/
196 /* Allocate INI column description block. */
197 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)198 PCOL TDBINI::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
199 {
200 return new(g) INICOL(cdp, this, cprec, n);
201 } // end of MakeCol
202
203 /***********************************************************************/
204 /* INI Cardinality: returns the number of sections in the INI file. */
205 /***********************************************************************/
Cardinality(PGLOBAL g)206 int TDBINI::Cardinality(PGLOBAL g)
207 {
208 if (!g)
209 return 1;
210
211 if (Cardinal < 0) {
212 // Count the number of sections from the section list
213 char *p = GetSeclist(g);
214
215 Cardinal = 0;
216
217 if (p)
218 for (; *p; p += (strlen(p) + 1))
219 Cardinal++;
220
221 } // endif Cardinal
222
223 return Cardinal;
224 } // end of Cardinality
225
226 /***********************************************************************/
227 /* INI GetMaxSize: returns the table cardinality. */
228 /***********************************************************************/
GetMaxSize(PGLOBAL g)229 int TDBINI::GetMaxSize(PGLOBAL g)
230 {
231 if (MaxSize < 0)
232 MaxSize = Cardinality(g);
233
234 return MaxSize;
235 } // end of GetMaxSize
236
237 /***********************************************************************/
238 /* INI Access Method opening routine. */
239 /***********************************************************************/
OpenDB(PGLOBAL g)240 bool TDBINI::OpenDB(PGLOBAL g)
241 {
242 PINICOL colp;
243
244 if (Use == USE_OPEN) {
245 #if 0
246 if (To_Kindex)
247 /*****************************************************************/
248 /* Table is to be accessed through a sorted index table. */
249 /*****************************************************************/
250 To_Kindex->Reset();
251 #endif // 0
252 Section = NULL;
253 N = 0;
254 return false;
255 } // endif use
256
257 /*********************************************************************/
258 /* OpenDB: initialize the INI file processing. */
259 /*********************************************************************/
260 GetSeclist(g);
261 Use = USE_OPEN; // Do it now in case we are recursively called
262
263 /*********************************************************************/
264 /* Allocate the buffers that will contain key values. */
265 /*********************************************************************/
266 for (colp = (PINICOL)Columns; colp; colp = (PINICOL)colp->GetNext())
267 if (!colp->IsSpecial()) // Not a pseudo column
268 colp->AllocBuf(g);
269
270 if (trace(1))
271 htrc("INI OpenDB: seclist=%s seclen=%d ifile=%s\n",
272 Seclist, Seclen, Ifile);
273
274 return false;
275 } // end of OpenDB
276
277 /***********************************************************************/
278 /* Data Base read routine for INI access method. */
279 /***********************************************************************/
ReadDB(PGLOBAL)280 int TDBINI::ReadDB(PGLOBAL)
281 {
282 /*********************************************************************/
283 /* Now start the pseudo reading process. */
284 /*********************************************************************/
285 if (!Section)
286 Section = Seclist;
287 else
288 Section += (strlen(Section) + 1);
289
290 if (trace(2))
291 htrc("INI ReadDB: section=%s N=%d\n", Section, N);
292
293 N++;
294 return (*Section) ? RC_OK : RC_EF;
295 } // end of ReadDB
296
297 /***********************************************************************/
298 /* WriteDB: Data Base write routine for INI access methods. */
299 /***********************************************************************/
WriteDB(PGLOBAL)300 int TDBINI::WriteDB(PGLOBAL)
301 {
302 // This is to check that section name was given when inserting
303 if (Mode == MODE_INSERT)
304 Section = NULL;
305
306 // Nothing else to do because all was done in WriteColumn
307 return RC_OK;
308 } // end of WriteDB
309
310 /***********************************************************************/
311 /* Data Base delete line routine for INI access methods. */
312 /***********************************************************************/
DeleteDB(PGLOBAL g,int irc)313 int TDBINI::DeleteDB(PGLOBAL g, int irc)
314 {
315 switch (irc) {
316 case RC_EF:
317 break;
318 case RC_FX:
319 while (ReadDB(g) == RC_OK)
320 if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
321 sprintf(g->Message, "Error %d accessing %s",
322 GetLastError(), Ifile);
323 return RC_FX;
324 } // endif
325
326 break;
327 default:
328 if (!Section) {
329 strcpy(g->Message, MSG(NO_SECTION_NAME));
330 return RC_FX;
331 } else
332 if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
333 sprintf(g->Message, "Error %d accessing %s",
334 GetLastError(), Ifile);
335 return RC_FX;
336 } // endif rc
337
338 } // endswitch irc
339
340 return RC_OK;
341 } // end of DeleteDB
342
343 /***********************************************************************/
344 /* Data Base close routine for INI access methods. */
345 /***********************************************************************/
CloseDB(PGLOBAL)346 void TDBINI::CloseDB(PGLOBAL)
347 {
348 #if !defined(_WIN32)
349 PROFILE_Close(Ifile);
350 #endif // !_WIN32
351 } // end of CloseDB
352
353 // ------------------------ INICOL functions ----------------------------
354
355 /***********************************************************************/
356 /* INICOL public constructor. */
357 /***********************************************************************/
INICOL(PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i,PCSZ)358 INICOL::INICOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
359 : COLBLK(cdp, tdbp, i)
360 {
361 if (cprec) {
362 Next = cprec->GetNext();
363 cprec->SetNext(this);
364 } else {
365 Next = tdbp->GetColumns();
366 tdbp->SetColumns(this);
367 } // endif cprec
368
369 // Set additional INI access method information for column.
370 Valbuf = NULL;
371 Flag = cdp->GetOffset();
372 Long = cdp->GetLong();
373 To_Val = NULL;
374 } // end of INICOL constructor
375
376 /***********************************************************************/
377 /* INICOL constructor used for copying columns. */
378 /* tdbp is the pointer to the new table descriptor. */
379 /***********************************************************************/
INICOL(INICOL * col1,PTDB tdbp)380 INICOL::INICOL(INICOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
381 {
382 Valbuf = col1->Valbuf;
383 Flag = col1->Flag;
384 Long = col1->Long;
385 To_Val = col1->To_Val;
386 } // end of INICOL copy constructor
387
388 /***********************************************************************/
389 /* Allocate a buffer of the proper size. */
390 /***********************************************************************/
AllocBuf(PGLOBAL g)391 void INICOL::AllocBuf(PGLOBAL g)
392 {
393 if (!Valbuf)
394 Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1);
395
396 } // end of AllocBuf
397
398 /***********************************************************************/
399 /* SetBuffer: prepare a column block for write operation. */
400 /***********************************************************************/
SetBuffer(PGLOBAL g,PVAL value,bool ok,bool check)401 bool INICOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
402 {
403 if (!(To_Val = value)) {
404 sprintf(g->Message, MSG(VALUE_ERROR), Name);
405 return true;
406 } else if (Buf_Type == value->GetType()) {
407 // Values are of the (good) column type
408 if (Buf_Type == TYPE_DATE) {
409 // If any of the date values is formatted
410 // output format must be set for the receiving table
411 if (GetDomain() || ((DTVAL *)value)->IsFormatted())
412 goto newval; // This will make a new value;
413
414 } else if (Buf_Type == TYPE_DOUBLE || Buf_Type == TYPE_DECIM)
415 // Float values must be written with the correct (column) precision
416 // Note: maybe this should be forced by ShowValue instead of this ?
417 value->SetPrec(GetScale());
418
419 Value = value; // Directly access the external value
420 } else {
421 // Values are not of the (good) column type
422 if (check) {
423 sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
424 GetTypeName(Buf_Type), GetTypeName(value->GetType()));
425 return true;
426 } // endif check
427
428 newval:
429 if (InitValue(g)) // Allocate the matching value block
430 return true;
431
432 } // endif's Value, Buf_Type
433
434 // Allocate the internal value buffer
435 AllocBuf(g);
436
437 // Because Colblk's have been made from a copy of the original TDB in
438 // case of Update, we must reset them to point to the original one.
439 if (To_Tdb->GetOrig())
440 To_Tdb = (PTDB)To_Tdb->GetOrig();
441
442 // Set the Column
443 Status = (ok) ? BUF_EMPTY : BUF_NO;
444 return false;
445 } // end of SetBuffer
446
447 /***********************************************************************/
448 /* ReadColumn: what this routine does is to access the key buffer set */
449 /* from the corresponding section, extract from it the key value */
450 /* corresponding to this column name and convert it to buffer type. */
451 /***********************************************************************/
ReadColumn(PGLOBAL)452 void INICOL::ReadColumn(PGLOBAL)
453 {
454 PTDBINI tdbp = (PTDBINI)To_Tdb;
455
456 if (trace(2))
457 htrc("INI ReadColumn: col %s R%d flag=%d\n",
458 Name, tdbp->GetTdb_No(), Flag);
459
460 /*********************************************************************/
461 /* Get the key value from the INI file. */
462 /*********************************************************************/
463 switch (Flag) {
464 case 1:
465 strncpy(Valbuf, tdbp->Section, Long); // Section name
466 Valbuf[Long] = '\0';
467 break;
468 default:
469 GetPrivateProfileString(tdbp->Section, Name, "\b",
470 Valbuf, Long + 1, tdbp->Ifile);
471 break;
472 } // endswitch Flag
473
474 // Missing keys are interpreted as null values
475 if (!strcmp(Valbuf, "\b")) {
476 if (Nullable)
477 Value->SetNull(true);
478
479 Value->Reset(); // Null value
480 } else
481 Value->SetValue_psz(Valbuf);
482
483 } // end of ReadColumn
484
485 /***********************************************************************/
486 /* WriteColumn: what this routine does is to access the last line */
487 /* read from the corresponding table, and rewrite the field */
488 /* corresponding to this column from the column buffer and type. */
489 /***********************************************************************/
WriteColumn(PGLOBAL g)490 void INICOL::WriteColumn(PGLOBAL g)
491 {
492 char *p;
493 bool rc;
494 PTDBINI tdbp = (PTDBINI)To_Tdb;
495
496 if (trace(2))
497 htrc("INI WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
498 Name, tdbp->GetTdb_No(), ColUse, Status);
499
500 /*********************************************************************/
501 /* Get the string representation of Value according to column type. */
502 /*********************************************************************/
503 if (Value != To_Val)
504 Value->SetValue_pval(To_Val, false); // Convert the updated value
505
506 // Null key are missing keys
507 if (Value->IsNull())
508 return;
509
510 p = Value->GetCharString(Valbuf);
511
512 if (strlen(p) > (unsigned)Long) {
513 sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
514 throw 31;
515 } else if (Flag == 1) {
516 if (tdbp->Mode == MODE_UPDATE) {
517 strcpy(g->Message, MSG(NO_SEC_UPDATE));
518 throw 31;
519 } else if (*p) {
520 tdbp->Section = p;
521 } else
522 tdbp->Section = NULL;
523
524 return;
525 } else if (!tdbp->Section) {
526 strcpy(g->Message, MSG(SEC_NAME_FIRST));
527 throw 31;
528 } // endif's
529
530 /*********************************************************************/
531 /* Updating must be done only when not in checking pass. */
532 /*********************************************************************/
533 if (Status) {
534 rc = WritePrivateProfileString(tdbp->Section, Name, p, tdbp->Ifile);
535
536 if (!rc) {
537 sprintf(g->Message, "Error %d writing to %s",
538 GetLastError(), tdbp->Ifile);
539 throw 31;
540 } // endif rc
541
542 } // endif Status
543
544 } // end of WriteColumn
545
546 /* ------------------------------------------------------------------- */
547
548 /***********************************************************************/
549 /* Implementation of the TDBXIN class. */
550 /***********************************************************************/
TDBXIN(PINIDEF tdp)551 TDBXIN::TDBXIN(PINIDEF tdp) : TDBINI(tdp)
552 {
553 Keylist = NULL;
554 Keycur = NULL;
555 Keylen = Seclen;
556 Oldsec = -1;
557 } // end of TDBXIN constructor
558
TDBXIN(PTDBXIN tdbp)559 TDBXIN::TDBXIN(PTDBXIN tdbp) : TDBINI(tdbp)
560 {
561 Keylist = tdbp->Keylist;
562 Keycur = tdbp->Keycur;
563 Keylen = tdbp->Keylen;
564 Oldsec = tdbp->Oldsec;
565 } // end of TDBXIN copy constructor
566
567 // Is this really useful ???
Clone(PTABS t)568 PTDB TDBXIN::Clone(PTABS t)
569 {
570 PTDB tp;
571 PXINCOL cp1, cp2;
572 PGLOBAL g = t->G;
573
574 tp = new(g) TDBXIN(this);
575
576 for (cp1 = (PXINCOL)Columns; cp1; cp1 = (PXINCOL)cp1->GetNext()) {
577 cp2 = new(g) XINCOL(cp1, tp); // Make a copy
578 NewPointer(t, cp1, cp2);
579 } // endfor cp1
580
581 return tp;
582 } // end of Clone
583
584 /***********************************************************************/
585 /* Get the key list from the INI file. */
586 /***********************************************************************/
GetKeylist(PGLOBAL g,char * sec)587 char *TDBXIN::GetKeylist(PGLOBAL g, char *sec)
588 {
589 if (!Keylist)
590 Keylist = (char*)PlugSubAlloc(g, NULL, Keylen);
591
592 GetPrivateProfileString(sec, NULL, "", Keylist, Keylen, Ifile);
593 return Keylist;
594 } // end of GetKeylist
595
596 /***********************************************************************/
597 /* Allocate XIN column description block. */
598 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)599 PCOL TDBXIN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
600 {
601 return new(g) XINCOL(cdp, this, cprec, n);
602 } // end of MakeCol
603
604 /***********************************************************************/
605 /* XIN Cardinality: returns the number of keys in the XIN file. */
606 /***********************************************************************/
Cardinality(PGLOBAL g)607 int TDBXIN::Cardinality(PGLOBAL g)
608 {
609 if (!g)
610 return 1;
611
612 if (Cardinal < 0) {
613 // Count the number of keys from the section list
614 char *k, *p = GetSeclist(g);
615
616 Cardinal = 0;
617
618 if (p)
619 for (; *p; p += (strlen(p) + 1))
620 for (k = GetKeylist(g, p); *k; k += (strlen(k) + 1))
621 Cardinal++;
622
623 } // endif Cardinal
624
625 return Cardinal;
626 } // end of Cardinality
627
628 /***********************************************************************/
629 /* Record position is Section+Key. */
630 /***********************************************************************/
GetRecpos(void)631 int TDBXIN::GetRecpos(void)
632 {
633 union {
634 short X[2]; // Section and Key offsets
635 int Xpos; // File position
636 }; // end of union
637
638 X[0] = (short)(Section - Seclist);
639 X[1] = (short)(Keycur - Keylist);
640 return Xpos;
641 } // end of GetRecpos
642
643 /***********************************************************************/
644 /* Record position is Section+Key. */
645 /***********************************************************************/
SetRecpos(PGLOBAL g,int recpos)646 bool TDBXIN::SetRecpos(PGLOBAL g, int recpos)
647 {
648 union {
649 short X[2]; // Section and Key offsets
650 int Xpos; // File position
651 }; // end of union
652
653 Xpos = recpos;
654
655 if (X[0] != Oldsec) {
656 Section = Seclist + X[0];
657 Keycur = GetKeylist(g, Section) + X[1];
658 Oldsec = X[0];
659 } else
660 Keycur = Keylist + X[1];
661
662 return false;
663 } // end of SetRecpos
664
665 /***********************************************************************/
666 /* XIN Access Method opening routine. */
667 /***********************************************************************/
OpenDB(PGLOBAL g)668 bool TDBXIN::OpenDB(PGLOBAL g)
669 {
670 Oldsec = -1; // To replace the table at its beginning
671 return TDBINI::OpenDB(g);
672 } // end of OpenDB
673
674 /***********************************************************************/
675 /* Data Base read routine for XIN access method. */
676 /***********************************************************************/
ReadDB(PGLOBAL g)677 int TDBXIN::ReadDB(PGLOBAL g)
678 {
679 /*********************************************************************/
680 /* Now start the pseudo reading process. */
681 /*********************************************************************/
682 #if 0 // XIN tables are not indexable
683 if (To_Kindex) {
684 /*******************************************************************/
685 /* Reading is by an index table. */
686 /*******************************************************************/
687 int recpos = To_Kindex->Fetch(g);
688
689 switch (recpos) {
690 case -1: // End of file reached
691 return RC_EF;
692 case -2: // No match for join
693 return RC_NF;
694 case -3: // Same record as last non null one
695 return RC_OK;
696 default:
697 SetRecpos(g, recpos);
698 } // endswitch recpos
699
700 } else {
701 #endif // 0
702 do {
703 if (!Keycur || !*Keycur) {
704 if (!Section)
705 Section = Seclist;
706 else
707 Section += (strlen(Section) + 1);
708
709 if (*Section)
710 Keycur = GetKeylist(g, Section);
711 else
712 return RC_EF;
713
714 } else
715 Keycur += (strlen(Keycur) + 1);
716
717 } while (!*Keycur);
718
719 N++;
720 //} // endif To_Kindex
721
722 return RC_OK;
723 } // end of ReadDB
724
725 /***********************************************************************/
726 /* WriteDB: Data Base write routine for XIN access methods. */
727 /***********************************************************************/
728 int TDBXIN::WriteDB(PGLOBAL)
729 {
730 // To check that section and key names were given when inserting
731 if (Mode == MODE_INSERT) {
732 Section = NULL;
733 Keycur = NULL;
734 } // endif Mode
735
736 // Nothing else to do because all was done in WriteColumn
737 return RC_OK;
738 } // end of WriteDB
739
740 /***********************************************************************/
741 /* Data Base delete line routine for XIN access methods. */
742 /***********************************************************************/
743 int TDBXIN::DeleteDB(PGLOBAL g, int irc)
744 {
745 if (irc == RC_EF) {
746 } else if (irc == RC_FX) {
747 for (Section = Seclist; *Section; Section += (strlen(Section) + 1))
748 if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
749 sprintf(g->Message, "Error %d accessing %s",
750 GetLastError(), Ifile);
751 return RC_FX;
752 } // endif
753
754 } else if (!Section) {
755 strcpy(g->Message, MSG(NO_SECTION_NAME));
756 return RC_FX;
757 } else
758 if (!WritePrivateProfileString(Section, Keycur, NULL, Ifile)) {
759 sprintf(g->Message, "Error %d accessing %s",
760 GetLastError(), Ifile);
761 return RC_FX;
762 } // endif
763
764 return RC_OK;
765 } // end of DeleteDB
766
767 // ------------------------ XINCOL functions ----------------------------
768
769 /***********************************************************************/
770 /* XINCOL public constructor. */
771 /***********************************************************************/
772 XINCOL::XINCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
773 : INICOL(cdp, tdbp, cprec, i, am)
774 {
775 } // end of XINCOL constructor
776
777 /***********************************************************************/
778 /* XINCOL constructor used for copying columns. */
779 /* tdbp is the pointer to the new table descriptor. */
780 /***********************************************************************/
781 XINCOL::XINCOL(XINCOL *col1, PTDB tdbp) : INICOL(col1, tdbp)
782 {
783 } // end of XINCOL copy constructor
784
785 /***********************************************************************/
786 /* ReadColumn: what this routine does is to access the key buffer set */
787 /* from the corresponding section, extract from it the key value */
788 /* corresponding to this column name and convert it to buffer type. */
789 /***********************************************************************/
790 void XINCOL::ReadColumn(PGLOBAL)
791 {
792 PTDBXIN tdbp = (PTDBXIN)To_Tdb;
793
794 /*********************************************************************/
795 /* Get the key value from the XIN file. */
796 /*********************************************************************/
797 switch (Flag) {
798 case 1:
799 strncpy(Valbuf, tdbp->Section, Long); // Section name
800 Valbuf[Long] = '\0';
801 break;
802 case 2:
803 strncpy(Valbuf, tdbp->Keycur, Long); // Key name
804 Valbuf[Long] = '\0';
805 break;
806 default:
807 GetPrivateProfileString(tdbp->Section, tdbp->Keycur, "",
808 Valbuf, Long + 1, tdbp->Ifile);
809 break;
810 } // endswitch Flag
811
812 Value->SetValue_psz(Valbuf);
813 } // end of ReadColumn
814
815 /***********************************************************************/
816 /* WriteColumn: what this routine does is to access the last line */
817 /* read from the corresponding table, and rewrite the field */
818 /* corresponding to this column from the column buffer and type. */
819 /***********************************************************************/
820 void XINCOL::WriteColumn(PGLOBAL g)
821 {
822 char *p;
823 bool rc;
824 PTDBXIN tdbp = (PTDBXIN)To_Tdb;
825
826 if (trace(2))
827 htrc("XIN WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
828 Name, tdbp->GetTdb_No(), ColUse, Status);
829
830 /*********************************************************************/
831 /* Get the string representation of Value according to column type. */
832 /*********************************************************************/
833 if (Value != To_Val)
834 Value->SetValue_pval(To_Val, false); // Convert the updated value
835
836 p = Value->GetCharString(Valbuf);
837
838 if (strlen(p) > (unsigned)Long) {
839 sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
840 throw 31;
841 } else if (Flag == 1) {
842 if (tdbp->Mode == MODE_UPDATE) {
843 strcpy(g->Message, MSG(NO_SEC_UPDATE));
844 throw 31;
845 } else if (*p) {
846 tdbp->Section = p;
847 } else
848 tdbp->Section = NULL;
849
850 return;
851 } else if (Flag == 2) {
852 if (tdbp->Mode == MODE_UPDATE) {
853 strcpy(g->Message, MSG(NO_KEY_UPDATE));
854 throw 31;
855 } else if (*p) {
856 tdbp->Keycur = p;
857 } else
858 tdbp->Keycur = NULL;
859
860 return;
861 } else if (!tdbp->Section || !tdbp->Keycur) {
862 strcpy(g->Message, MSG(SEC_KEY_FIRST));
863 throw 31;
864 } // endif's
865
866 /*********************************************************************/
867 /* Updating must be done only when not in checking pass. */
868 /*********************************************************************/
869 if (Status) {
870 rc = WritePrivateProfileString(tdbp->Section, tdbp->Keycur, p, tdbp->Ifile);
871
872 if (!rc) {
873 sprintf(g->Message, "Error %d writing to %s",
874 GetLastError(), tdbp->Ifile);
875 throw 31;
876 } // endif rc
877
878 } // endif Status
879
880 } // end of WriteColumn
881
882 /* ------------------------ End of System ---------------------------- */
883
884
885