foam to Tecplot360 converter
[OpenFOAM-1.6.x.git] / applications / utilities / postProcessing / dataConversion / foamToTecplot360 / tecio / tecsrc / strlist.cpp
blobab34a5274c9eac16224facd1c66456348a718c5b
1 /*
2 * NOTICE and LICENSE for Tecplot Input/Output Library (TecIO) - OpenFOAM
4 * Copyright (C) 1988-2009 Tecplot, Inc. All rights reserved worldwide.
6 * Tecplot hereby grants OpenCFD limited authority to distribute without
7 * alteration the source code to the Tecplot Input/Output library, known
8 * as TecIO, as part of its distribution of OpenFOAM and the
9 * OpenFOAM_to_Tecplot converter. Users of this converter are also hereby
10 * granted access to the TecIO source code, and may redistribute it for the
11 * purpose of maintaining the converter. However, no authority is granted
12 * to alter the TecIO source code in any form or manner.
14 * This limited grant of distribution does not supersede Tecplot, Inc.'s
15 * copyright in TecIO. Contact Tecplot, Inc. for further information.
17 * Tecplot, Inc.
18 * 3535 Factoria Blvd, Ste. 550
19 * Bellevue, WA 98006, USA
20 * Phone: +1 425 653 1200
21 * http://www.tecplot.com/
24 #include "stdafx.h"
25 #include "MASTER.h"
26 #define TECPLOTENGINEMODULE
29 ******************************************************************
30 ******************************************************************
31 ******* ********
32 ****** (C) 1988-2008 Tecplot, Inc. *******
33 ******* ********
34 ******************************************************************
35 ******************************************************************
38 #define STRLISTMODULE
39 #include "GLOBAL.h"
40 #include "TASSERT.h"
41 #include "Q_UNICODE.h"
42 #include "STRUTIL.h"
43 #include "ALLOC.h"
44 #if defined TECPLOTKERNEL
45 /* CORE SOURCE CODE REMOVED */
46 #endif
47 #include "ARRLIST.h"
48 #include "STRLIST.h"
50 /* END HEADER */
52 using namespace tecplot::strutil;
55 * This set of functions provide a wrapper around the array list utilities
56 * thereby making it aware of item allocation and deallocation. All strings
57 * given to the string list and returned to the client are copies. Therefore
58 * it is the client's responsibility to deallocate string results when no
59 * longer needed.
64 * Destructor for cleaning up string allocations.
66 * param ItemRef
67 * Reference to the string item to destroy.
68 * param ClientData
69 * Any client data needed for destroying the string.
71 * return
72 * TRUE is a requirement
74 static Boolean_t StringListItemDestructor(void *ItemRef,
75 ArbParam_t ClientData)
77 char **StringRef = (char **)ItemRef;
79 REQUIRE(VALID_REF(StringRef));
80 REQUIRE(VALID_REF(*StringRef) || *StringRef == NULL);
82 if (*StringRef != NULL)
84 FREE_ARRAY(*StringRef, "string");
85 *StringRef = NULL;
88 ENSURE(*StringRef == NULL);
89 return TRUE;
93 * String item duplicator.
95 * param TargetItemRef
96 * Reference to the string list item to receive the duplicate.
97 * param SourceItemRef
98 * Reference to the string list item to duplicate.
99 * param ClientData
100 * Any client data required for duplication.
102 * return
103 * TRUE if the duplication was a success
104 * FALSE otherwise. If the duplication failed it
105 * is the client's responsibility to cleanup any
106 * partial duplication
108 static Boolean_t StringListItemDuplicator(void *TargetItemRef,
109 void *SourceItemRef,
110 ArbParam_t ClientData)
112 Boolean_t IsOk = TRUE;
113 char **TargetStringRef = (char **)TargetItemRef;
114 char **SourceStringRef = (char **)SourceItemRef;
116 REQUIRE(VALID_REF(TargetStringRef));
117 REQUIRE(VALID_REF(SourceStringRef));
118 REQUIRE(VALID_REF(*SourceStringRef) || *SourceStringRef == NULL);
120 if (*SourceStringRef != NULL)
121 IsOk = ((*TargetStringRef = DupString(dontTranslate(*SourceStringRef))) != NULL);
122 else
123 *TargetStringRef = NULL;
125 ENSURE(VALID_REF(*TargetStringRef) || *TargetStringRef == NULL);
126 ENSURE(VALID_BOOLEAN(IsOk));
127 return IsOk;
132 * Determine if the string list handle and its members are sane.
134 Boolean_t StringListValid(StringList_pa stringList)
136 Boolean_t isValid = ArrayListIsValid((ArrayList_pa)stringList);
138 if (isValid)
140 LgIndex_t stringCount = ArrayListGetCount((ArrayList_pa)stringList);
142 #if defined PERFORM_EXPENSIVE_STRLIST_TESTS
144 for (LgIndex_t index = 0; index < stringCount; index++)
146 char *string = ArrayListGetCharPtr((ArrayList_pa)stringList, index);
147 if (string != NULL && !VALID_REF(string))
149 isValid = FALSE;
150 break;
153 #else
155 /* Check first and last only */
156 if (stringCount > 0)
158 char *string = ArrayListGetCharPtr((ArrayList_pa)stringList, 0);
159 if (string != NULL && !VALID_REF(string))
161 isValid = FALSE;
164 if (isValid && stringCount > 1)
166 char *string = ArrayListGetCharPtr((ArrayList_pa)stringList, stringCount - 1);
167 if (string != NULL && !VALID_REF(string))
169 isValid = FALSE;
173 #endif /* PERFORM_SKIP_EXPENSIVE_STRLIST_TESTS */
176 ENSURE(VALID_BOOLEAN(isValid));
177 return isValid;
182 * Remove all members of the string list.
184 void StringListClear(StringList_pa StringList)
186 REQUIRE(StringListValid(StringList));
188 ArrayListDeleteAllItems((ArrayList_pa)StringList, StringListItemDestructor, 0);
190 ENSURE(StringListValid(StringList) && StringListCount(StringList) == 0);
195 * Remove 'Count' strings from the list beginning at the specified offset.
196 * The members following the items removed are shifted down accordingly to
197 * fill the vacated space.
199 void StringListRemoveStrings(StringList_pa StringList,
200 LgIndex_t StringOffset,
201 LgIndex_t Count)
203 REQUIRE(StringListValid(StringList));
204 REQUIRE(0 <= StringOffset && StringOffset <= StringListCount(StringList) - 1);
205 REQUIRE(1 <= Count && StringOffset + Count <= StringListCount(StringList));
207 ArrayListDeleteItems((ArrayList_pa)StringList, StringOffset, Count,
208 StringListItemDestructor, 0);
210 ENSURE(StringListValid(StringList));
215 * Remove the string from the list at the specified offset. The members
216 * following the item removed are shifted down accordingly to fill the
217 * vacated space.
219 void StringListRemoveString(StringList_pa StringList,
220 LgIndex_t StringOffset)
222 REQUIRE(StringListValid(StringList));
223 REQUIRE(0 <= StringOffset && StringOffset <= StringListCount(StringList) - 1);
225 ArrayListDeleteItems((ArrayList_pa)StringList, StringOffset, 1,
226 StringListItemDestructor, 0);
228 ENSURE(StringListValid(StringList));
233 * Deallocate the string list members and handle and set the handle to NULL.
235 void LIBCALL StringListDealloc(StringList_pa *StringList)
237 REQUIRE(VALID_REF(StringList));
238 REQUIRE(*StringList == NULL || StringListValid(*StringList));
240 if (*StringList != NULL)
241 ArrayListDealloc((ArrayList_pa *)StringList, StringListItemDestructor, 0);
243 ENSURE(*StringList == NULL);
248 * Allocate a string list handle. A handle of NULL is
249 * returned if sufficient memory is not available.
251 StringList_pa StringListAlloc(void)
253 StringList_pa Result;
255 Result = (StringList_pa)ArrayListAlloc(0, ArrayListType_CharPtr, NULL, 0);
257 ENSURE(Result == NULL || StringListValid(Result));
258 return Result;
263 * Append a copy of the string to the string list. The string list will be
264 * expanded to accommodate the additional item. A return value of TRUE
265 * indicates the operation was successful otherwise FALSE is returned
266 * indicating that sufficient memory was not available for the additional
267 * item.
269 Boolean_t StringListAppendString(StringList_pa StringList,
270 const char *String)
272 Boolean_t IsOk;
274 REQUIRE(StringListValid(StringList));
275 REQUIRE(String == NULL || VALID_REF(String));
277 IsOk = StringListSetString(StringList, StringListCount(StringList), String);
279 ENSURE(StringListValid(StringList));
280 ENSURE(VALID_BOOLEAN(IsOk));
281 return IsOk;
286 * Return the number of strings currently in the string list.
288 LgIndex_t LIBCALL StringListCount(StringList_pa StringList)
290 LgIndex_t Result;
292 REQUIRE(StringListValid(StringList));
294 Result = ArrayListGetCount((ArrayList_pa)StringList);
296 ENSURE(Result >= 0);
297 return Result;
302 * Return a copy of the string at the specified offset in the string list.
304 char * LIBCALL StringListGetString(StringList_pa StringList,
305 LgIndex_t StringOffset)
307 char *Result;
308 const char *StringRef;
310 REQUIRE(StringListValid(StringList));
311 REQUIRE(0 <= StringOffset && StringOffset <= StringListCount(StringList) - 1);
313 StringRef = StringListGetStringRef(StringList, StringOffset);
314 if (StringRef == NULL)
315 Result = NULL;
316 else
317 Result = DupString(dontTranslate(StringRef));
319 ENSURE(Result == NULL || VALID_REF(Result));
320 return Result;
324 #if !defined USE_MACROS_FOR_FUNCTIONS
326 * Returns actual string at the specified offset in the string list. Do not
327 * attempt to free this string. Changing this string should be done with
328 * utmost caution.
330 const char *StringListGetStringRef_FUNC(StringList_pa StringList,
331 LgIndex_t StringOffset)
333 const char *Result;
335 REQUIRE(StringListValid(StringList));
336 REQUIRE(0 <= StringOffset && StringOffset <= StringListCount(StringList) - 1);
338 Result = StringListGetStringRef_MACRO(StringList, StringOffset);
340 ENSURE(Result == NULL || VALID_REF(Result));
341 return Result;
343 #endif
347 * Place a copy of the specified string at the specified offset. If the offset
348 * is beyond the end of the string list it is sized accordingly and the
349 * intervening string references between the last item of the original
350 * state and the last item of the new state are assigned NULL. If a string
351 * already exists at the specified location its resources are released.
352 * A return value of TRUE indicates the operation was successful otherwise
353 * FALSE is returned indicating that sufficient memory was not available
354 * for the additional item at the specified offset.
356 Boolean_t StringListSetString(StringList_pa StringList,
357 LgIndex_t StringOffset,
358 const char *String)
360 Boolean_t IsOk;
361 ArrayListItem_u ItemCopy;
363 REQUIRE(StringListValid(StringList));
364 REQUIRE(StringOffset >= 0);
365 REQUIRE(String == NULL || VALID_REF(String));
367 if (String != NULL)
369 ItemCopy.CharPtr = DupString(dontTranslate(String));
370 IsOk = (ItemCopy.CharPtr != NULL);
372 else
374 ItemCopy.CharPtr = NULL;
375 IsOk = TRUE;
378 if (IsOk)
379 IsOk = ArrayListSetItem((ArrayList_pa)StringList, StringOffset, ItemCopy,
380 StringListItemDestructor, 0);
382 ENSURE(StringListValid(StringList));
383 ENSURE(VALID_BOOLEAN(IsOk));
384 return IsOk;
389 * Insert a copy of the string into the string list at the specified offset.
390 * The string list will be expanded to accommodate the additional item.
391 * A return value of TRUE indicates the operation was successful otherwise
392 * FALSE is returned indicating that sufficient memory was not available
393 * for the additional item.
395 Boolean_t StringListInsertString(StringList_pa StringList,
396 LgIndex_t StringOffset,
397 const char *String)
399 Boolean_t IsOk;
400 ArrayListItem_u ItemCopy;
402 REQUIRE(StringListValid(StringList));
403 REQUIRE(StringOffset >= 0);
404 REQUIRE(String == NULL || VALID_REF(String));
406 if (String != NULL)
408 ItemCopy.CharPtr = DupString(dontTranslate(String));
409 IsOk = (ItemCopy.CharPtr != NULL);
411 else
413 ItemCopy.CharPtr = NULL;
414 IsOk = TRUE;
417 if (IsOk)
418 IsOk = ArrayListInsertItem(
419 (ArrayList_pa)StringList, StringOffset, ItemCopy);
421 ENSURE(StringListValid(StringList));
422 ENSURE(VALID_BOOLEAN(IsOk));
423 return IsOk;
428 * Return a handle to a duplicate of the specified string list and its contents.
429 * A handle of NULL is returned if sufficient memory is not available.
431 StringList_pa StringListCopy(StringList_pa StringList)
433 StringList_pa Result;
435 REQUIRE(StringListValid(StringList));
437 Result = (StringList_pa)ArrayListCopy((ArrayList_pa)StringList,
438 StringListItemDuplicator, 0);
440 ENSURE(Result == NULL ||
441 (StringListValid(Result) &&
442 StringListCount(Result) == StringListCount(StringList)));
443 return Result;
449 * Append a copy of the contents of the source list to the target list.
450 * A return value of TRUE indicates the operation was successful otherwise
451 * FALSE is returned indicating that sufficient memory was not available
452 * for the request.
454 Boolean_t StringListAppend(StringList_pa Target,
455 StringList_pa Source)
457 Boolean_t IsOk;
458 StringList_pa SourceCopy;
460 REQUIRE(StringListValid(Target));
461 REQUIRE(StringListValid(Source));
463 SourceCopy = StringListCopy(Source);
464 IsOk = (SourceCopy != NULL);
465 if (IsOk)
467 ArrayListAppend((ArrayList_pa)Target, (ArrayList_pa)SourceCopy);
468 /* deallocate the list but not the string items since Target now owns them */
469 ArrayListDealloc((ArrayList_pa *)(void *)&SourceCopy, NULL, 0);
472 ENSURE(StringListValid(Target));
473 ENSURE(VALID_BOOLEAN(IsOk));
474 return IsOk;
480 * Return a new line, '\n', separated string representation of the string list.
481 * Caller is responsible for de-allocating the result.
483 char *StringListToNLString(StringList_pa StringList)
485 char *Result;
486 int Count;
487 size_t Length = 0;
489 REQUIRE(StringListValid(StringList));
491 /* determine the resulting new line, '\n', separated string length */
492 Count = StringListCount(StringList);
493 if (Count >= 1)
495 int Index;
496 for (Index = 0, Length = strlen("\n") * (Count - 1);
497 Index < Count;
498 Index++)
500 char *String = ArrayListGetCharPtr((ArrayList_pa)StringList, Index);
501 if (String != NULL)
502 Length += strlen(String);
506 /* create a new line, '\n', separated string */
507 Result = ALLOC_ARRAY(Length + 1, char, "new line separated string");
508 if (Result != NULL)
510 int Index;
511 for (Index = 0, strcpy(Result, "");
512 Index < Count;
513 Index++)
515 char *String = ArrayListGetCharPtr(
516 (ArrayList_pa)StringList, Index);
518 if (Index != 0)
519 strcat(Result, "\n");
521 if (String != NULL)
522 strcat(Result, String);
526 ENSURE(Result == NULL || VALID_REF(Result));
527 return Result;
532 * Create a string list from the new line, '\n', separated string. The string
533 * is copied and therefore owned and managed by the caller.
535 StringList_pa StringListFromNLString(const char *String)
537 StringList_pa Result;
538 LgIndex_t StartIndex;
539 LgIndex_t EndIndex;
541 REQUIRE(VALID_REF(String));
543 /* create the string list and scan the entire string */
544 Result = StringListAlloc();
545 for (StartIndex = EndIndex = 0; Result != NULL; EndIndex++)
547 /* end of sub-string ? */
548 if (String[EndIndex] == '\n' || String[EndIndex] == '\0')
550 /* extract the sub-string and append it to the string list */
551 LgIndex_t Length = EndIndex - StartIndex;
552 char *SubString = ALLOC_ARRAY(Length + 1, char, "sub string");
553 if (SubString != NULL)
555 CopySubString(SubString, String, StartIndex, Length);
556 StringListAppendString(Result, SubString);
558 FREE_ARRAY(SubString, "sub string");
560 if (String[EndIndex] != '\0')
561 StartIndex = EndIndex + 1;
562 else
563 break; /* nothing left to scan */
565 else
567 /* memory allocation failure: bail out */
568 StringListDealloc(&Result);
569 Result = NULL;
570 break;
575 ENSURE(Result == NULL || StringListValid(Result));
576 return Result;
581 * Return a 'C' string array representation of the string list.
582 * Caller is responsible for de-allocating the result.
584 char **StringListToArray(StringList_pa StringList)
586 char **Result;
588 REQUIRE(StringListValid(StringList));
590 Result = (char **)ArrayListToArray((ArrayList_pa)StringList,
591 StringListItemDuplicator, 0);
593 ENSURE(Result == NULL || VALID_REF(Result));
594 return Result;
600 * Create a string list from the 'C' string array. The string array
601 * is copied and therefore owned and managed by the caller.
603 StringList_pa StringListFromArray(const char **StringArray,
604 LgIndex_t Count)
606 StringList_pa Result;
608 REQUIRE((Count == 0 && StringArray == NULL) ||
609 (Count >= 1 && VALID_REF(StringArray)));
611 Result = (StringList_pa)ArrayListFromArray((void *)StringArray,
612 Count, ArrayListType_CharPtr,
613 StringListItemDuplicator, 0);
615 ENSURE(Result == NULL || StringListValid(Result));
616 return Result;
621 #define ISJOINCHAR(c) ((c == ';') || (c == '+'))
623 static void SkipWhiteSpaceOrComma(const char **CPtr)
625 REQUIRE(VALID_REF(CPtr) && VALID_REF(*CPtr));
626 while (ISWHITESPACE(**CPtr) || (**CPtr == ','))
627 (*CPtr)++;
631 * Obtain the next sub-string. This can be of the form:
633 * [del]any-character-sequence[del]
635 * or
637 * limited-character-sequence
639 * where a limited-character-sequence cannot contain
640 * any of the following characters: +;,<space>
643 static Boolean_t GetNextSubString(const char **OriginalCPtr,
644 char **NextSubString)
646 Boolean_t IsOk = TRUE;
647 const char *CStart;
648 const char *CPtr;
649 char InsideDelimiter = '\0';
651 REQUIRE(VALID_REF(OriginalCPtr) && (VALID_REF(*OriginalCPtr)));
652 REQUIRE(VALID_REF(NextSubString));
654 *NextSubString = NULL;
656 CPtr = *OriginalCPtr;
657 SkipWhiteSpaceOrComma(&CPtr);
659 if (*CPtr == '"' || *CPtr == '\'')
661 InsideDelimiter = *CPtr;
662 CPtr++;
665 CStart = CPtr;
667 while (*CPtr &&
668 ((InsideDelimiter && (*CPtr != InsideDelimiter)) ||
669 (!InsideDelimiter && (*CPtr != ',') &&
670 !ISJOINCHAR(*CPtr) &&
671 !ISWHITESPACE(*CPtr))))
673 if (InsideDelimiter &&
674 (*CPtr == '\\') &&
675 (*(CPtr + 1) == InsideDelimiter))
676 CPtr += 2;
677 else
678 CPtr++;
681 if (InsideDelimiter && (*CPtr != InsideDelimiter))
682 IsOk = FALSE;
685 if (IsOk && CStart < CPtr)
687 size_t StrLen = (size_t)(CPtr - CStart);
688 *NextSubString = ALLOC_ARRAY(StrLen + 1, char, "GetNextSubString: NextSubString");
689 if (*NextSubString)
691 char *NPtr = *NextSubString;
693 * Don't just copy the string because escaped delimiters need to have
694 * the escape removed...
696 while (CStart < CPtr)
698 if ((*CStart == '\\') && (*(CStart + 1) == InsideDelimiter))
699 CStart++;
700 *NPtr++ = *CStart++;
702 *NPtr = '\0';
704 else
705 IsOk = FALSE;
708 if (IsOk)
710 if (InsideDelimiter)
711 CPtr++;
712 SkipWhiteSpaceOrComma(&CPtr);
713 *OriginalCPtr = CPtr;
716 ENSURE(VALID_BOOLEAN(IsOk));
717 return IsOk;
724 * Return a string list representation of a compound string.
726 * The compound String parameter has the following form:
728 * [del]<character-sequence>[del] [GroupJoinCharacter] [del]<character-sequence>[del] [GroupJoinCharacter] .....
729 * or
730 * <nospace-character-sequence> <nospace-character-sequence> ...
732 * where:
733 * [del] is an optional single quote or a double quote. [del] must be used
734 * if <character-sequence> contains spaces, commas, or the plus symbol.
736 * GroupJoinCharacter can be either a "+" or a ";"
738 * The GroupJoinCharacter symbol is used to separate character sequences that
739 * are to be grouped together. If the GroupJoinCharacter symbol is omitted then
740 * a new group is started.
742 * Internally, the original string is converted to a list of strings where
743 * each string uses newlines to separate one sub-string from the next.
745 StringList_pa StringListFromCompound(const char *String)
747 const char *CPtr;
748 StringList_pa Result;
749 Boolean_t IsOk = TRUE;
750 char *CurString = NULL;
752 REQUIRE(VALID_REF(String));
753 SkipWhiteSpaceOrComma(&String);
754 REQUIRE(!ISJOINCHAR(*String));
756 /* extract character sequences */
757 Result = StringListAlloc();
758 CPtr = String;
760 while (IsOk && *CPtr != '\0')
762 char *NextSubString = NULL;
763 Boolean_t WantsToJoin = FALSE;
765 if (ISJOINCHAR(*CPtr))
767 WantsToJoin = TRUE;
768 CPtr++;
769 SkipWhiteSpaceOrComma(&CPtr);
772 IsOk = GetNextSubString(&CPtr,
773 &NextSubString);
775 if (IsOk)
778 * Tack on the sub-string to the running string.
780 if (WantsToJoin)
781 TackOnChar(&CurString, '\n');
782 if (NextSubString != NULL && strlen(NextSubString) != 0)
783 IsOk = TackOnString(&CurString, NextSubString, FALSE, FALSE);
784 else if (CurString == NULL)
785 CurString = DupString(dontTranslate(""));
788 if (NextSubString != NULL)
789 FREE_ARRAY(NextSubString, "StringListFromCompound: NextSubString");
792 * If this is the end of processing or if the next character is
793 * not a join character then add the current string to the stringlist.
796 if (IsOk && !ISJOINCHAR(*CPtr))
798 StringListAppendString(Result, CurString);
799 if (CurString != NULL)
800 FREE_ARRAY(CurString, "current string");
801 CurString = NULL;
805 if (CurString != NULL)
806 FREE_ARRAY(CurString, "current string");
808 if (!IsOk)
809 StringListDealloc(&Result);
811 ENSURE(Result == NULL || StringListValid(Result));
812 return Result;
817 * Return a compound string representation of a string list.
819 * One common usage in Tecplot:
820 * The $!OpenLayout command in tecplot has the sub-option
821 * ALTDATALOADINSTRUCTIONS that has the form:
822 * '"instr-string1" [GroupJoinCharacter] "instr-string2" [+] ...'
824 char *StringListToCompound(StringList_pa StringList,
825 char GroupJoinCharacter,
826 const char *CharsToEscape)
828 Boolean_t IsOk = TRUE;
829 LgIndex_t Index;
830 LgIndex_t Count;
831 char *Result = NULL;
833 REQUIRE(StringListValid(StringList));
834 REQUIRE(StringListCount(StringList) >= 1);
835 REQUIRE(ISJOINCHAR(GroupJoinCharacter));
836 REQUIRE(VALID_REF(CharsToEscape));
838 for (Index = 0, Count = StringListCount(StringList), IsOk = TRUE;
839 Index < Count && IsOk;
840 Index++)
842 char *String = StringListGetString(StringList, Index);
844 if (String != NULL && strlen(String) != 0)
846 char *CStart = NULL;
847 char *CEnd = NULL;
848 char *EscapedString = NULL;
849 const char *EscChar = NULL;
850 char *StrChar = NULL;
852 /* First scan the string and escape any specified characters. */
853 /* Note that the Escape sequence is a double backslash because */
854 /* it the first escape escapes the escape for variable usage. */
855 for (StrChar = String; *StrChar != '\0'; StrChar++)
857 for (EscChar = CharsToEscape; *EscChar != '\0'; EscChar++)
858 if (*StrChar == *EscChar)
860 IsOk = TackOnChar(&EscapedString, '\\');
861 IsOk = TackOnChar(&EscapedString, '\\');
862 break;
864 IsOk = TackOnChar(&EscapedString, *StrChar);
867 CEnd = EscapedString;
868 while (IsOk && *CEnd != '\0')
870 int Len = 0;
871 char *TString;
873 CStart = CEnd;
874 while (*CEnd != '\0' && *CEnd != '\n')
876 Len++;
877 if (*CEnd == '"')
878 Len++;
879 CEnd++;
882 TString = ALLOC_ARRAY(Len + 4, char, "temp compound sub-string");
883 if (TString != NULL)
885 char *TStr;
887 /* prepend the new string with either */
888 /* a space character or the plus symbol */
889 if (CStart == EscapedString)
891 if (Index != 0)
892 IsOk = TackOnChar(&Result, ' ');
894 else
896 IsOk = TackOnChar(&Result, GroupJoinCharacter);
899 /* stuff TString and append the new string */
900 TStr = TString;
901 *TStr++ = '"';
902 while (CStart != CEnd)
904 if (*CStart == '"')
905 *TStr++ = '\\';
906 *TStr++ = *CStart++;
908 *TStr++ = '"';
909 *TStr = '\0';
911 TackOnString(&Result, TString, FALSE, FALSE);
912 FREE_ARRAY(TString, "StringListToCompound");
913 TString = NULL;
914 if (*CEnd)
915 CEnd++;
917 else
919 IsOk = FALSE;
923 if (EscapedString != NULL)
924 FREE_ARRAY(EscapedString, "escaped string");
926 else
928 /* a null pointer or length of zero indicates an empty sub-string */
929 if (Index == 0)
930 TackOnString(&Result, "\"\"", FALSE, FALSE);
931 else
932 TackOnString(&Result, " \"\"", FALSE, FALSE);
935 if (String != NULL)
936 FREE_ARRAY(String, "string list item");
939 if (!IsOk)
941 if (Result != NULL)
943 FREE_ARRAY(Result, "StringListToCompound");
944 Result = NULL;
948 ENSURE(Result == NULL || VALID_REF(Result));
949 return Result;
954 * Holds the comparator function pointer.
956 static StringListStringComparator_pf ComparatorFunction = NULL;
960 * Forwards the comparison test to the 'Comparator' supplied to the
961 * 'StringListSort' function.
963 * param Item1
964 * Item to compare against Item2.
965 * param Item2
966 * Item to compare against Item1.
967 * param ClientData
968 * Contextual information that was passed to the 'ArrayListQSort' function.
970 * return
971 * -1: if Item1 is less than Item2
972 * 0: if Item1 is equal to Item2
973 * 1: if Item1 is greater than Item2
975 static int STDCALL ComparatorProxy(ArrayListItem_u Item1,
976 ArrayListItem_u Item2,
977 ArbParam_t ClientData)
979 /* forward the request */
980 return ComparatorFunction(Item1.CharPtr, Item2.CharPtr, ClientData);
985 * Compares two strings from a list string. Note that either string may be
986 * NULL as StringLists allow for NULL elements.
988 * param String1
989 * String to compare against String2.
990 * param String2
991 * String to compare against String1.
992 * param ClientData
993 * Contextual information that was passed to the 'StringListSort' function.
995 * return
996 * - A value less than zero if String1 is less than String2.
997 * - A value of zero if String1 is equal to String2.
998 * - A value greater than zero if String1 is greater than String2.
1000 static int STDCALL DefaultStrcmpComparator(const char *String1,
1001 const char *String2,
1002 ArbParam_t ClientData)
1004 int Result = 0; /* ...quite compiler */
1006 REQUIRE(VALID_REF(String1) || String1 == NULL);
1007 REQUIRE(VALID_REF(String2) || String2 == NULL);
1009 if (String1 != NULL && String2 != NULL)
1011 Result = strcmp(String1, String2);
1012 if (Result < 0)
1013 Result = -1;
1014 else if (Result > 0)
1015 Result = 1;
1017 else if (String1 == NULL && String2 == NULL)
1018 Result = 0;
1019 else if (String1 == NULL)
1020 Result = -1;
1021 else if (String2 == NULL)
1022 Result = 1;
1023 else
1024 CHECK(FALSE);
1026 ENSURE((Result == -1) || (Result == 0) || (Result == 1));
1027 return Result;
1031 * Sorts the string list by repeatedly calling the 'Comparator' function until
1032 * the list is in order.
1034 * param StringList
1035 * String list to sort.
1036 * param Comparator
1037 * Function called to compare two string list strings or NULL for the
1038 * default sort. The default sorting handles NULL elements and uses the
1039 * system's strcmp utility for comparing valid strings elements.
1040 * param ClientData
1041 * Contextual information that is passed along to the comparator function.
1043 void StringListSort(StringList_pa StringList,
1044 StringListStringComparator_pf Comparator,
1045 ArbParam_t ClientData)
1047 #if defined TECPLOTKERNEL
1048 /* CORE SOURCE CODE REMOVED */
1049 #endif
1050 REQUIRE(VALID_REF(StringList));
1051 REQUIRE(VALID_FN_REF(Comparator) || Comparator == NULL);
1053 /* set up for comparator proxy */
1054 if (Comparator != NULL)
1055 ComparatorFunction = Comparator;
1056 else
1057 ComparatorFunction = DefaultStrcmpComparator;
1059 /* sort the array using the comparator proxy to forward */
1060 /* the comparison request to the supplied comparator */
1061 ArrayListQSort((ArrayList_pa)StringList, ComparatorProxy, ClientData);
1063 /* cleanup */
1064 ComparatorFunction = NULL;