2 #include "multistring.h"
5 static int lstrncmpi (LPCTSTR pszA, LPCTSTR pszB, size_t cch)
9 return (!pszB) - (!pszA); // A,!B:1, !A,B:-1, !A,!B:0
12 for ( ; cch > 0; cch--, pszA = CharNext(pszA), pszB = CharNext(pszB))
14 TCHAR chA = toupper( *pszA );
15 TCHAR chB = toupper( *pszB );
18 return (!chB) - (!chA); // A,!B:1, !A,B:-1, !A,!B:0
21 return (int)(chA) - (int)(chB); // -1:A<B, 0:A==B, 1:A>B
24 return 0; // no differences before told to stop comparing, so A==B
29 * mstralloc - Allocates space for a given-length multistring
30 * mstrfree - Frees a multistring
31 * mstrwalk - Allows iterative progression along a multistring
32 * mstrlen - Returns the length of a given multistring, including all \0's
33 * mstrcount - Returns the number of entries in a given multistring
34 * mstrstr - Determines if a given substring exists in a multistring
35 * mstrcat - Adds a substring to a multistring (doesn't do any checking first)
36 * mstrdel - Removes a substring from a multistring
40 LPTSTR mstralloc (size_t cchMax)
43 if ((msz = (LPTSTR)GlobalAlloc (GMEM_FIXED, sizeof(TCHAR) * (1+cchMax))) != NULL)
44 memset (msz, 0x00, sizeof(TCHAR) * (1+cchMax));
49 void mstrfree (LPCTSTR msz)
52 GlobalFree ((HGLOBAL)msz);
56 BOOL mstrwalk (LPCTSTR msz, TCHAR chSep, LPTSTR *ppSegment, size_t *pchSegment)
58 // If the caller supplied {*ppSegment} as NULL, we should return the
59 // first segment. Otherwise, advance {*pchSegment} characters and
60 // return the next segment.
63 *ppSegment = (LPTSTR)msz;
64 else if (*(*ppSegment += *pchSegment) == chSep)
69 if (!*ppSegment || !*(*ppSegment))
73 while ((*ppSegment)[*pchSegment] && ((*ppSegment)[*pchSegment] != chSep))
80 size_t mstrlen (LPCTSTR msz, TCHAR chSep)
82 LPTSTR pSegment = NULL;
83 size_t cchSegment = 0;
86 while (mstrwalk (msz, chSep, &pSegment, &cchSegment))
87 cchTotal += cchSegment+1;
89 if (!chSep || !cchTotal)
90 cchTotal ++; // To terminate the string
96 size_t mstrcount (LPCTSTR msz, TCHAR chSep)
98 LPTSTR pSegment = NULL;
99 size_t cchSegment = 0;
101 size_t cSegments = 0;
102 while (mstrwalk (msz, chSep, &pSegment, &cchSegment))
109 BOOL mstrstr (LPCTSTR msz, TCHAR chSep, LPCTSTR pszTest)
111 LPTSTR pSegment = NULL;
112 size_t cchSegment = 0;
115 while (mstrwalk (msz, chSep, &pSegment, &cchSegment))
117 if ( (cchSegment == (size_t)lstrlen(pszTest)) &&
118 (!lstrncmpi (pSegment, pszTest, cchSegment)) )
126 BOOL mstrcat (LPTSTR *pmsz, TCHAR chSep, LPCTSTR pszAppend)
128 size_t cchOld = mstrlen(*pmsz,chSep);
129 size_t cchAdd = (pszAppend) ? lstrlen(pszAppend) : 0;
130 size_t cchRetain = (chSep && (cchOld!=1)) ? cchOld : (cchOld-1);
133 if ((mszNew = mstralloc (cchRetain + cchAdd + 2)) == NULL)
137 memcpy (mszNew, *pmsz, sizeof(TCHAR) * cchRetain);
140 mszNew[ cchRetain-1 ] = chSep;
142 lstrcpy (&mszNew[ cchRetain ], pszAppend);
145 mszNew[ cchRetain + cchAdd +1 ] = 0;
154 BOOL mstrdel (LPTSTR *pmsz, TCHAR chSep, LPCTSTR pszRemove)
157 if ((mszNew = mstralloc (mstrlen(*pmsz,chSep))) == NULL)
160 LPTSTR pSegmentWrite = mszNew;
161 LPTSTR pSegmentRead = NULL;
162 size_t cchSegment = 0;
165 while (mstrwalk (*pmsz, chSep, &pSegmentRead, &cchSegment))
167 if ( (cchSegment == (size_t)lstrlen(pszRemove)) &&
168 (!lstrncmpi (pSegmentRead, pszRemove, cchSegment)) )
171 for (size_t ich = 0; ich < cchSegment; ++ich)
172 *pSegmentWrite++ = pSegmentRead[ ich ];
173 *pSegmentWrite++ = chSep;
175 if ((pSegmentWrite != mszNew) && (chSep)) // don't need trailing separator