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(__WIN__)
16#if defined(__BORLANDC__)
17#define __MFC_COMPAT__ // To define min/max as macro
18#endif // __BORLANDC__
19//#include <windows.h>
20#else // !__WIN__
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 // !__WIN__
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(__WIN__)
40#include "osutil.h"
41#endif // !__WIN__
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(__WIN__)
52#define GetPrivateProfileSectionNames(S,L,I) \
53 GetPrivateProfileString(NULL,NULL,"",S,L,I)
54#endif // !__WIN__
55
56/* -------------- Implementation of the INI classes ------------------ */
57
58/***********************************************************************/
59/* Constructor. */
60/***********************************************************************/
61INIDEF::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/***********************************************************************/
73bool 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/***********************************************************************/
99PTDB 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/***********************************************************************/
118bool 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(__WIN__)
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/***********************************************************************/
143TDBINI::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
152TDBINI::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 ???
162PTDB 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/***********************************************************************/
181char *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/***********************************************************************/
198PCOL 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/***********************************************************************/
206int 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/***********************************************************************/
229int 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/***********************************************************************/
240bool 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/***********************************************************************/
280int 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/***********************************************************************/
300int 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/***********************************************************************/
313int 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/***********************************************************************/
346void TDBINI::CloseDB(PGLOBAL)
347 {
348#if !defined(__WIN__)
349 PROFILE_Close(Ifile);
350#endif // !__WIN__
351 } // end of CloseDB
352
353// ------------------------ INICOL functions ----------------------------
354
355/***********************************************************************/
356/* INICOL public constructor. */
357/***********************************************************************/
358INICOL::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/***********************************************************************/
380INICOL::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/***********************************************************************/
391void 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/***********************************************************************/
401bool 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/***********************************************************************/
452void 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/***********************************************************************/
490void 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/***********************************************************************/
551TDBXIN::TDBXIN(PINIDEF tdp) : TDBINI(tdp)
552 {
553 Keylist = NULL;
554 Keycur = NULL;
555 Keylen = Seclen;
556 Oldsec = -1;
557 } // end of TDBXIN constructor
558
559TDBXIN::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 ???
568PTDB 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/***********************************************************************/
587char *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/***********************************************************************/
599PCOL 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/***********************************************************************/
607int 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/***********************************************************************/
631int 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/***********************************************************************/
646bool 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/***********************************************************************/
668bool 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/***********************************************************************/
677int 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/***********************************************************************/
728int 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/***********************************************************************/
743int 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/***********************************************************************/
772XINCOL::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/***********************************************************************/
781XINCOL::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/***********************************************************************/
790void 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/***********************************************************************/
820void 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