1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6
7 This file is part of the OpenJK source code.
8
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22
23 #include "GenericParser2.h"
24
25 #include <cstring>
26 #include "qcommon/qcommon.h"
27
28 #define MAX_TOKEN_SIZE 1024
29 static char token[MAX_TOKEN_SIZE];
30
GetToken(char ** text,bool allowLineBreaks,bool readUntilEOL=false)31 static char *GetToken(char **text, bool allowLineBreaks, bool readUntilEOL = false)
32 {
33 char *pointer = *text;
34 int length = 0;
35 int c = 0;
36 bool foundLineBreak;
37
38 token[0] = 0;
39 if (!pointer)
40 {
41 return token;
42 }
43
44 while(1)
45 {
46 foundLineBreak = false;
47 while(1)
48 {
49 c = *pointer;
50 if (c > ' ')
51 {
52 break;
53 }
54 if (!c)
55 {
56 *text = 0;
57 return token;
58 }
59 if (c == '\n')
60 {
61 foundLineBreak = true;
62 }
63 pointer++;
64 }
65 if (foundLineBreak && !allowLineBreaks)
66 {
67 *text = pointer;
68 return token;
69 }
70
71 c = *pointer;
72
73 // skip single line comment
74 if (c == '/' && pointer[1] == '/')
75 {
76 pointer += 2;
77 while (*pointer && *pointer != '\n')
78 {
79 pointer++;
80 }
81 }
82 // skip multi line comments
83 else if (c == '/' && pointer[1] == '*')
84 {
85 pointer += 2;
86 while (*pointer && (*pointer != '*' || pointer[1] != '/'))
87 {
88 pointer++;
89 }
90 if (*pointer)
91 {
92 pointer += 2;
93 }
94 }
95 else
96 { // found the start of a token
97 break;
98 }
99 }
100
101 if (c == '\"')
102 { // handle a string
103 pointer++;
104 while (1)
105 {
106 c = *pointer++;
107 if (c == '\"')
108 {
109 // token[length++] = c;
110 break;
111 }
112 else if (!c)
113 {
114 break;
115 }
116 else if (length < MAX_TOKEN_SIZE)
117 {
118 token[length++] = c;
119 }
120 }
121 }
122 else if (readUntilEOL)
123 {
124 // absorb all characters until EOL
125 while(c != '\n' && c != '\r')
126 {
127 if (c == '/' && ((*(pointer+1)) == '/' || (*(pointer+1)) == '*'))
128 {
129 break;
130 }
131
132 if (length < MAX_TOKEN_SIZE)
133 {
134 token[length++] = c;
135 }
136 pointer++;
137 c = *pointer;
138 }
139 // remove trailing white space
140 while(length && token[length-1] < ' ')
141 {
142 length--;
143 }
144 }
145 else
146 {
147 while(c > ' ')
148 {
149 if (length < MAX_TOKEN_SIZE)
150 {
151 token[length++] = c;
152 }
153 pointer++;
154 c = *pointer;
155 }
156 }
157
158 if (token[0] == '\"')
159 { // remove start quote
160 length--;
161 memmove(token, token+1, length);
162
163 if (length && token[length-1] == '\"')
164 { // remove end quote
165 length--;
166 }
167 }
168
169 if (length >= MAX_TOKEN_SIZE)
170 {
171 length = 0;
172 }
173 token[length] = 0;
174 *text = (char *)pointer;
175
176 return token;
177 }
178
CTextPool(int initSize)179 CTextPool::CTextPool(int initSize) :
180 mNext(0),
181 mSize(initSize),
182 mUsed(0)
183 {
184 // mPool = (char *)Z_Malloc(mSize, TAG_GP2);
185 mPool = (char *)Z_Malloc(mSize, TAG_TEXTPOOL, qtrue);
186 }
187
~CTextPool(void)188 CTextPool::~CTextPool(void)
189 {
190 Z_Free(mPool);
191 }
192
AllocText(char * text,bool addNULL,CTextPool ** poolPtr)193 char *CTextPool::AllocText(char *text, bool addNULL, CTextPool **poolPtr)
194 {
195 int length = strlen(text) + (addNULL ? 1 : 0);
196
197 if (mUsed + length + 1> mSize)
198 { // extra 1 to put a null on the end
199 if (poolPtr)
200 {
201 (*poolPtr)->SetNext(new CTextPool(mSize));
202 *poolPtr = (*poolPtr)->GetNext();
203
204 return (*poolPtr)->AllocText(text, addNULL);
205 }
206
207 return 0;
208 }
209
210 strcpy(mPool + mUsed, text);
211 mUsed += length;
212 mPool[mUsed] = 0;
213
214 return mPool + mUsed - length;
215 }
216
CleanTextPool(CTextPool * pool)217 void CleanTextPool(CTextPool *pool)
218 {
219 CTextPool *next;
220
221 while(pool)
222 {
223 next = pool->GetNext();
224 delete pool;
225 pool = next;
226 }
227 }
228
229
230
231
232
233
234
CGPObject(const char * initName)235 CGPObject::CGPObject(const char *initName) :
236 mName(initName),
237 mNext(0),
238 mInOrderNext(0),
239 mInOrderPrevious(0)
240 {
241 }
242
WriteText(CTextPool ** textPool,const char * text)243 bool CGPObject::WriteText(CTextPool **textPool, const char *text)
244 {
245 if (strchr(text, ' ') || !text[0])
246 {
247 (*textPool)->AllocText("\"", false, textPool);
248 (*textPool)->AllocText((char *)text, false, textPool);
249 (*textPool)->AllocText("\"", false, textPool);
250 }
251 else
252 {
253 (*textPool)->AllocText((char *)text, false, textPool);
254 }
255
256 return true;
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
CGPValue(const char * initName,const char * initValue)272 CGPValue::CGPValue(const char *initName, const char *initValue) :
273 CGPObject(initName),
274 mList(0)
275 {
276 if (initValue)
277 {
278 AddValue(initValue);
279 }
280 }
281
~CGPValue(void)282 CGPValue::~CGPValue(void)
283 {
284 CGPObject *next;
285
286 while(mList)
287 {
288 next = mList->GetNext();
289 delete mList;
290 mList = next;
291 }
292 }
293
Duplicate(CTextPool ** textPool)294 CGPValue *CGPValue::Duplicate(CTextPool **textPool)
295 {
296 CGPValue *newValue;
297 CGPObject *iterator;
298 char *name;
299
300 if (textPool)
301 {
302 name = (*textPool)->AllocText((char *)mName, true, textPool);
303 }
304 else
305 {
306 name = (char *)mName;
307 }
308
309 newValue = new CGPValue(name);
310 iterator = mList;
311 while(iterator)
312 {
313 if (textPool)
314 {
315 name = (*textPool)->AllocText((char *)iterator->GetName(), true, textPool);
316 }
317 else
318 {
319 name = (char *)iterator->GetName();
320 }
321 newValue->AddValue(name);
322 iterator = iterator->GetNext();
323 }
324
325 return newValue;
326 }
327
IsList(void)328 bool CGPValue::IsList(void)
329 {
330 if (!mList || !mList->GetNext())
331 {
332 return false;
333 }
334
335 return true;
336 }
337
GetTopValue(void)338 const char *CGPValue::GetTopValue(void)
339 {
340 if (mList)
341 {
342 return mList->GetName();
343 }
344
345 return 0;
346 }
347
AddValue(const char * newValue,CTextPool ** textPool)348 void CGPValue::AddValue(const char *newValue, CTextPool **textPool)
349 {
350 if (textPool)
351 {
352 newValue = (*textPool)->AllocText((char *)newValue, true, textPool);
353 }
354
355 if (mList == 0)
356 {
357 mList = new CGPObject(newValue);
358 mList->SetInOrderNext(mList);
359 }
360 else
361 {
362 mList->GetInOrderNext()->SetNext(new CGPObject(newValue));
363 mList->SetInOrderNext(mList->GetInOrderNext()->GetNext());
364 }
365 }
366
Parse(char ** dataPtr,CTextPool ** textPool)367 bool CGPValue::Parse(char **dataPtr, CTextPool **textPool)
368 {
369 char *token;
370 char *value;
371
372 while(1)
373 {
374 token = GetToken(dataPtr, true, true);
375
376 if (!token[0])
377 { // end of data - error!
378 return false;
379 }
380 else if (Q_stricmp(token, "]") == 0)
381 { // ending brace for this list
382 break;
383 }
384
385 value = (*textPool)->AllocText(token, true, textPool);
386 AddValue(value);
387 }
388
389 return true;
390 }
391
Write(CTextPool ** textPool,int depth)392 bool CGPValue::Write(CTextPool **textPool, int depth)
393 {
394 int i;
395 CGPObject *next;
396
397 if (!mList)
398 {
399 return true;
400 }
401
402 for(i=0;i<depth;i++)
403 {
404 (*textPool)->AllocText("\t", false, textPool);
405 }
406
407 WriteText(textPool, mName);
408
409 if (!mList->GetNext())
410 {
411 (*textPool)->AllocText("\t\t", false, textPool);
412 mList->WriteText(textPool, mList->GetName());
413 (*textPool)->AllocText("\r\n", false, textPool);
414 }
415 else
416 {
417 (*textPool)->AllocText("\r\n", false, textPool);
418
419 for(i=0;i<depth;i++)
420 {
421 (*textPool)->AllocText("\t", false, textPool);
422 }
423 (*textPool)->AllocText("[\r\n", false, textPool);
424
425 next = mList;
426 while(next)
427 {
428 for(i=0;i<depth+1;i++)
429 {
430 (*textPool)->AllocText("\t", false, textPool);
431 }
432 mList->WriteText(textPool, next->GetName());
433 (*textPool)->AllocText("\r\n", false, textPool);
434
435 next = next->GetNext();
436 }
437
438 for(i=0;i<depth;i++)
439 {
440 (*textPool)->AllocText("\t", false, textPool);
441 }
442 (*textPool)->AllocText("]\r\n", false, textPool);
443 }
444
445 return true;
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
CGPGroup(const char * initName,CGPGroup * initParent)463 CGPGroup::CGPGroup(const char *initName, CGPGroup *initParent) :
464 CGPObject(initName),
465 mPairs(0),
466 mInOrderPairs(0),
467 mCurrentPair(0),
468 mSubGroups(0),
469 mInOrderSubGroups(0),
470 mCurrentSubGroup(0),
471 mParent(initParent),
472 mWriteable(false)
473 {
474 }
475
~CGPGroup(void)476 CGPGroup::~CGPGroup(void)
477 {
478 Clean();
479 }
480
GetNumSubGroups(void)481 int CGPGroup::GetNumSubGroups(void)
482 {
483 int count;
484 CGPGroup *group;
485
486 count = 0;
487 group = mSubGroups;
488 do
489 {
490 count++;
491 group = (CGPGroup *)group->GetNext();
492 }
493 while(group);
494
495 return(count);
496 }
497
GetNumPairs(void)498 int CGPGroup::GetNumPairs(void)
499 {
500 int count;
501 CGPValue *pair;
502
503 count = 0;
504 pair = mPairs;
505 do
506 {
507 count++;
508 pair = (CGPValue *)pair->GetNext();
509 }
510 while(pair);
511
512 return(count);
513 }
514
Clean(void)515 void CGPGroup::Clean(void)
516 {
517 while(mPairs)
518 {
519 mCurrentPair = (CGPValue *)mPairs->GetNext();
520 delete mPairs;
521 mPairs = mCurrentPair;
522 }
523
524 while(mSubGroups)
525 {
526 mCurrentSubGroup = (CGPGroup *)mSubGroups->GetNext();
527 delete mSubGroups;
528 mSubGroups = mCurrentSubGroup;
529 }
530
531 mPairs = mInOrderPairs = mCurrentPair = 0;
532 mSubGroups = mInOrderSubGroups = mCurrentSubGroup = 0;
533 mParent = 0;
534 mWriteable = false;
535 }
536
Duplicate(CTextPool ** textPool,CGPGroup * initParent)537 CGPGroup *CGPGroup::Duplicate(CTextPool **textPool, CGPGroup *initParent)
538 {
539 CGPGroup *newGroup, *subSub, *newSub;
540 CGPValue *newPair, *subPair;
541 char *name;
542
543 if (textPool)
544 {
545 name = (*textPool)->AllocText((char *)mName, true, textPool);
546 }
547 else
548 {
549 name = (char *)mName;
550 }
551
552 newGroup = new CGPGroup(name);
553
554 subSub = mSubGroups;
555 while(subSub)
556 {
557 newSub = subSub->Duplicate(textPool, newGroup);
558 newGroup->AddGroup(newSub);
559
560 subSub = (CGPGroup *)subSub->GetNext();
561 }
562
563 subPair = mPairs;
564 while(subPair)
565 {
566 newPair = subPair->Duplicate(textPool);
567 newGroup->AddPair(newPair);
568
569 subPair = (CGPValue *)subPair->GetNext();
570 }
571
572 return newGroup;
573 }
574
SortObject(CGPObject * object,CGPObject ** unsortedList,CGPObject ** sortedList,CGPObject ** lastObject)575 void CGPGroup::SortObject(CGPObject *object, CGPObject **unsortedList, CGPObject **sortedList,
576 CGPObject **lastObject)
577 {
578 CGPObject *test, *last;
579
580 if (!*unsortedList)
581 {
582 *unsortedList = *sortedList = object;
583 }
584 else
585 {
586 (*lastObject)->SetNext(object);
587
588 test = *sortedList;
589 last = 0;
590 while(test)
591 {
592 if (Q_stricmp(object->GetName(), test->GetName()) < 0)
593 {
594 break;
595 }
596
597 last = test;
598 test = test->GetInOrderNext();
599 }
600
601 if (test)
602 {
603 test->SetInOrderPrevious(object);
604 object->SetInOrderNext(test);
605 }
606 if (last)
607 {
608 last->SetInOrderNext(object);
609 object->SetInOrderPrevious(last);
610 }
611 else
612 {
613 *sortedList = object;
614 }
615 }
616
617 *lastObject = object;
618 }
619
AddPair(const char * name,const char * value,CTextPool ** textPool)620 CGPValue *CGPGroup::AddPair(const char *name, const char *value, CTextPool **textPool)
621 {
622 CGPValue *newPair;
623
624 if (textPool)
625 {
626 name = (*textPool)->AllocText((char *)name, true, textPool);
627 if (value)
628 {
629 value = (*textPool)->AllocText((char *)value, true, textPool);
630 }
631 }
632
633 newPair = new CGPValue(name, value);
634
635 AddPair(newPair);
636
637 return newPair;
638 }
639
AddPair(CGPValue * NewPair)640 void CGPGroup::AddPair(CGPValue *NewPair)
641 {
642 SortObject(NewPair, (CGPObject **)&mPairs, (CGPObject **)&mInOrderPairs,
643 (CGPObject **)&mCurrentPair);
644 }
645
AddGroup(const char * name,CTextPool ** textPool)646 CGPGroup *CGPGroup::AddGroup(const char *name, CTextPool **textPool)
647 {
648 CGPGroup *newGroup;
649
650 if (textPool)
651 {
652 name = (*textPool)->AllocText((char *)name, true, textPool);
653 }
654
655 newGroup = new CGPGroup(name, this);
656
657 AddGroup(newGroup);
658
659 return newGroup;
660 }
661
AddGroup(CGPGroup * NewGroup)662 void CGPGroup::AddGroup(CGPGroup *NewGroup)
663 {
664 SortObject(NewGroup, (CGPObject **)&mSubGroups, (CGPObject **)&mInOrderSubGroups,
665 (CGPObject **)&mCurrentSubGroup);
666 }
667
FindSubGroup(const char * name)668 CGPGroup *CGPGroup::FindSubGroup(const char *name)
669 {
670 CGPGroup *group;
671
672 group = mSubGroups;
673 while(group)
674 {
675 if(!Q_stricmp(name, group->GetName()))
676 {
677 return(group);
678 }
679 group = (CGPGroup *)group->GetNext();
680 }
681 return(NULL);
682 }
683
Parse(char ** dataPtr,CTextPool ** textPool)684 bool CGPGroup::Parse(char **dataPtr, CTextPool **textPool)
685 {
686 char *token;
687 char lastToken[MAX_TOKEN_SIZE];
688 CGPGroup *newSubGroup;
689 CGPValue *newPair;
690
691 while(1)
692 {
693 token = GetToken(dataPtr, true);
694
695 if (!token[0])
696 { // end of data - error!
697 if (mParent)
698 {
699 return false;
700 }
701 else
702 {
703 break;
704 }
705 }
706 else if (Q_stricmp(token, "}") == 0)
707 { // ending brace for this group
708 break;
709 }
710
711 strcpy(lastToken, token);
712
713 // read ahead to see what we are doing
714 token = GetToken(dataPtr, true, true);
715 if (Q_stricmp(token, "{") == 0)
716 { // new sub group
717 newSubGroup = AddGroup(lastToken, textPool);
718 newSubGroup->SetWriteable(mWriteable);
719 if (!newSubGroup->Parse(dataPtr, textPool))
720 {
721 return false;
722 }
723 }
724 else if (Q_stricmp(token, "[") == 0)
725 { // new pair list
726 newPair = AddPair(lastToken, 0, textPool);
727 if (!newPair->Parse(dataPtr, textPool))
728 {
729 return false;
730 }
731 }
732 else
733 { // new pair
734 AddPair(lastToken, token, textPool);
735 }
736 }
737
738 return true;
739 }
740
Write(CTextPool ** textPool,int depth)741 bool CGPGroup::Write(CTextPool **textPool, int depth)
742 {
743 int i;
744 CGPValue *mPair = mPairs;
745 CGPGroup *mSubGroup = mSubGroups;
746
747 if (depth >= 0)
748 {
749 for(i=0;i<depth;i++)
750 {
751 (*textPool)->AllocText("\t", false, textPool);
752 }
753 WriteText(textPool, mName);
754 (*textPool)->AllocText("\r\n", false, textPool);
755
756 for(i=0;i<depth;i++)
757 {
758 (*textPool)->AllocText("\t", false, textPool);
759 }
760 (*textPool)->AllocText("{\r\n", false, textPool);
761 }
762
763 while(mPair)
764 {
765 mPair->Write(textPool, depth+1);
766 mPair = (CGPValue *)mPair->GetNext();
767 }
768
769 while(mSubGroup)
770 {
771 mSubGroup->Write(textPool, depth+1);
772 mSubGroup = (CGPGroup *)mSubGroup->GetNext();
773 }
774
775 if (depth >= 0)
776 {
777 for(i=0;i<depth;i++)
778 {
779 (*textPool)->AllocText("\t", false, textPool);
780 }
781 (*textPool)->AllocText("}\r\n", false, textPool);
782 }
783
784 return true;
785 }
786
787 /************************************************************************************************
788 * CGPGroup::FindPair
789 * This function will search for the pair with the specified key name. Multiple keys may be
790 * searched if you specify "||" inbetween each key name in the string. The first key to be
791 * found (from left to right) will be returned.
792 *
793 * Input
794 * key: the name of the key(s) to be searched for.
795 *
796 * Output / Return
797 * the group belonging to the first key found or 0 if no group was found.
798 *
799 ************************************************************************************************/
FindPair(const char * key)800 CGPValue *CGPGroup::FindPair(const char *key)
801 {
802 CGPValue *pair;
803 size_t length;
804 const char *pos, *separator, *next;
805
806 pos = key;
807 while(pos[0])
808 {
809 separator = strstr(pos, "||");
810 if (separator)
811 {
812 length = separator - pos;
813 next = separator + 2;
814 }
815 else
816 {
817 length = strlen(pos);
818 next = pos + length;
819 }
820
821 pair = mPairs;
822 while(pair)
823 {
824 if (strlen(pair->GetName()) == length &&
825 Q_stricmpn(pair->GetName(), pos, length) == 0)
826 {
827 return pair;
828 }
829
830 pair = pair->GetNext();
831 }
832
833 pos = next;
834 }
835
836 return 0;
837 }
838
FindPairValue(const char * key,const char * defaultVal)839 const char *CGPGroup::FindPairValue(const char *key, const char *defaultVal)
840 {
841 CGPValue *pair = FindPair(key);
842
843 if (pair)
844 {
845 return pair->GetTopValue();
846 }
847
848 return defaultVal;
849 }
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
CGenericParser2(void)865 CGenericParser2::CGenericParser2(void) :
866 mTextPool(0),
867 mWriteable(false)
868 {
869 }
870
~CGenericParser2(void)871 CGenericParser2::~CGenericParser2(void)
872 {
873 Clean();
874 }
875
Parse(char ** dataPtr,bool cleanFirst,bool writeable)876 bool CGenericParser2::Parse(char **dataPtr, bool cleanFirst, bool writeable)
877 {
878 CTextPool *topPool;
879
880 if (cleanFirst)
881 {
882 Clean();
883 }
884
885 if (!mTextPool)
886 {
887 mTextPool = new CTextPool;
888 }
889
890 SetWriteable(writeable);
891 mTopLevel.SetWriteable(writeable);
892 topPool = mTextPool;
893 bool ret = mTopLevel.Parse(dataPtr, &topPool);
894
895 return ret;
896 }
897
Clean(void)898 void CGenericParser2::Clean(void)
899 {
900 mTopLevel.Clean();
901
902 CleanTextPool(mTextPool);
903 mTextPool = 0;
904 }
905
Write(CTextPool * textPool)906 bool CGenericParser2::Write(CTextPool *textPool)
907 {
908 return mTopLevel.Write(&textPool, -1);
909 }
910
911
912
913
914
915
916
917
918
919 // The following groups of routines are used for a C interface into GP2.
920 // C++ users should just use the objects as normally and not call these routines below
921 //
922 // CGenericParser2 (void *) routines
GP_Parse(char ** dataPtr,bool cleanFirst,bool writeable)923 TGenericParser2 GP_Parse(char **dataPtr, bool cleanFirst, bool writeable)
924 {
925 CGenericParser2 *parse;
926
927 parse = new CGenericParser2;
928 if (parse->Parse(dataPtr, cleanFirst, writeable))
929 {
930 return parse;
931 }
932
933 delete parse;
934 return 0;
935 }
936
GP_Clean(TGenericParser2 GP2)937 void GP_Clean(TGenericParser2 GP2)
938 {
939 if (!GP2)
940 {
941 return;
942 }
943
944 ((CGenericParser2 *)GP2)->Clean();
945 }
946
GP_Delete(TGenericParser2 * GP2)947 void GP_Delete(TGenericParser2 *GP2)
948 {
949 if (!GP2 || !(*GP2))
950 {
951 return;
952 }
953
954 delete ((CGenericParser2 *)(*GP2));
955 (*GP2) = 0;
956 }
957
GP_GetBaseParseGroup(TGenericParser2 GP2)958 TGPGroup GP_GetBaseParseGroup(TGenericParser2 GP2)
959 {
960 if (!GP2)
961 {
962 return 0;
963 }
964
965 return ((CGenericParser2 *)GP2)->GetBaseParseGroup();
966 }
967
968
969
970
971 // CGPGroup (void *) routines
GPG_GetName(TGPGroup GPG)972 const char *GPG_GetName(TGPGroup GPG)
973 {
974 if (!GPG)
975 {
976 return "";
977 }
978
979 return ((CGPGroup *)GPG)->GetName();
980 }
981
GPG_GetName(TGPGroup GPG,char * Value)982 bool GPG_GetName(TGPGroup GPG, char *Value)
983 {
984 if (!GPG)
985 {
986 Value[0] = 0;
987 return false;
988 }
989
990 strcpy(Value, ((CGPGroup *)GPG)->GetName());
991 return true;
992 }
993
GPG_GetNext(TGPGroup GPG)994 TGPGroup GPG_GetNext(TGPGroup GPG)
995 {
996 if (!GPG)
997 {
998 return 0;
999 }
1000
1001 return ((CGPGroup *)GPG)->GetNext();
1002 }
1003
GPG_GetInOrderNext(TGPGroup GPG)1004 TGPGroup GPG_GetInOrderNext(TGPGroup GPG)
1005 {
1006 if (!GPG)
1007 {
1008 return 0;
1009 }
1010
1011 return ((CGPGroup *)GPG)->GetInOrderNext();
1012 }
1013
GPG_GetInOrderPrevious(TGPGroup GPG)1014 TGPGroup GPG_GetInOrderPrevious(TGPGroup GPG)
1015 {
1016 if (!GPG)
1017 {
1018 return 0;
1019 }
1020
1021 return ((CGPGroup *)GPG)->GetInOrderPrevious();
1022 }
1023
GPG_GetPairs(TGPGroup GPG)1024 TGPGroup GPG_GetPairs(TGPGroup GPG)
1025 {
1026 if (!GPG)
1027 {
1028 return 0;
1029 }
1030
1031 return ((CGPGroup *)GPG)->GetPairs();
1032 }
1033
GPG_GetInOrderPairs(TGPGroup GPG)1034 TGPGroup GPG_GetInOrderPairs(TGPGroup GPG)
1035 {
1036 if (!GPG)
1037 {
1038 return 0;
1039 }
1040
1041 return ((CGPGroup *)GPG)->GetInOrderPairs();
1042 }
1043
GPG_GetSubGroups(TGPGroup GPG)1044 TGPGroup GPG_GetSubGroups(TGPGroup GPG)
1045 {
1046 if (!GPG)
1047 {
1048 return 0;
1049 }
1050
1051 return ((CGPGroup *)GPG)->GetSubGroups();
1052 }
1053
GPG_GetInOrderSubGroups(TGPGroup GPG)1054 TGPGroup GPG_GetInOrderSubGroups(TGPGroup GPG)
1055 {
1056 if (!GPG)
1057 {
1058 return 0;
1059 }
1060
1061 return ((CGPGroup *)GPG)->GetInOrderSubGroups();
1062 }
1063
GPG_FindSubGroup(TGPGroup GPG,const char * name)1064 TGPGroup GPG_FindSubGroup(TGPGroup GPG, const char *name)
1065 {
1066 if (!GPG)
1067 {
1068 return 0;
1069 }
1070
1071 return ((CGPGroup *)GPG)->FindSubGroup(name);
1072 }
1073
GPG_FindPair(TGPGroup GPG,const char * key)1074 TGPValue GPG_FindPair(TGPGroup GPG, const char *key)
1075 {
1076 if (!GPG)
1077 {
1078 return 0;
1079 }
1080
1081 return ((CGPGroup *)GPG)->FindPair(key);
1082 }
1083
GPG_FindPairValue(TGPGroup GPG,const char * key,const char * defaultVal)1084 const char *GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal)
1085 {
1086 if (!GPG)
1087 {
1088 return defaultVal;
1089 }
1090
1091 return ((CGPGroup *)GPG)->FindPairValue(key, defaultVal);
1092 }
1093
GPG_FindPairValue(TGPGroup GPG,const char * key,const char * defaultVal,char * Value)1094 bool GPG_FindPairValue(TGPGroup GPG, const char *key, const char *defaultVal, char *Value)
1095 {
1096 strcpy(Value, GPG_FindPairValue(GPG, key, defaultVal));
1097
1098 return true;
1099 }
1100
1101
1102
1103
1104 // CGPValue (void *) routines
GPV_GetName(TGPValue GPV)1105 const char *GPV_GetName(TGPValue GPV)
1106 {
1107 if (!GPV)
1108 {
1109 return "";
1110 }
1111
1112 return ((CGPValue *)GPV)->GetName();
1113 }
1114
GPV_GetName(TGPValue GPV,char * Value)1115 bool GPV_GetName(TGPValue GPV, char *Value)
1116 {
1117 if (!GPV)
1118 {
1119 Value[0] = 0;
1120 return false;
1121 }
1122
1123 strcpy(Value, ((CGPValue *)GPV)->GetName());
1124 return true;
1125 }
1126
GPV_GetNext(TGPValue GPV)1127 TGPValue GPV_GetNext(TGPValue GPV)
1128 {
1129 if (!GPV)
1130 {
1131 return 0;
1132 }
1133
1134 return ((CGPValue *)GPV)->GetNext();
1135 }
1136
GPV_GetInOrderNext(TGPValue GPV)1137 TGPValue GPV_GetInOrderNext(TGPValue GPV)
1138 {
1139 if (!GPV)
1140 {
1141 return 0;
1142 }
1143
1144 return ((CGPValue *)GPV)->GetInOrderNext();
1145 }
1146
GPV_GetInOrderPrevious(TGPValue GPV)1147 TGPValue GPV_GetInOrderPrevious(TGPValue GPV)
1148 {
1149 if (!GPV)
1150 {
1151 return 0;
1152 }
1153
1154 return ((CGPValue *)GPV)->GetInOrderPrevious();
1155 }
1156
GPV_IsList(TGPValue GPV)1157 bool GPV_IsList(TGPValue GPV)
1158 {
1159 if (!GPV)
1160 {
1161 return 0;
1162 }
1163
1164 return ((CGPValue *)GPV)->IsList();
1165 }
1166
GPV_GetTopValue(TGPValue GPV)1167 const char *GPV_GetTopValue(TGPValue GPV)
1168 {
1169 if (!GPV)
1170 {
1171 return "";
1172 }
1173
1174 return ((CGPValue *)GPV)->GetTopValue();
1175 }
1176
GPV_GetTopValue(TGPValue GPV,char * Value)1177 bool GPV_GetTopValue(TGPValue GPV, char *Value)
1178 {
1179 if (!GPV)
1180 {
1181 Value[0] = 0;
1182 return false;
1183 }
1184
1185 strcpy(Value, ((CGPValue *)GPV)->GetTopValue());
1186
1187 return true;
1188 }
1189
GPV_GetList(TGPValue GPV)1190 TGPValue GPV_GetList(TGPValue GPV)
1191 {
1192 if (!GPV)
1193 {
1194 return 0;
1195 }
1196
1197 return ((CGPValue *)GPV)->GetList();
1198 }
1199