winnt-win2000-win98-afs-client-updates-20010623
[openafs.git] / src / WINNT / license / multistring.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <windows.h>
11 #include "multistring.h"
12
13
14 static int lstrncmpi (LPCTSTR pszA, LPCTSTR pszB, size_t cch)
15 {
16    if (!pszA || !pszB)
17       {
18       return (!pszB) - (!pszA);   // A,!B:1, !A,B:-1, !A,!B:0
19       }
20
21    for ( ; cch > 0; cch--, pszA = CharNext(pszA), pszB = CharNext(pszB))
22       {
23       TCHAR chA = toupper( *pszA );
24       TCHAR chB = toupper( *pszB );
25
26       if (!chA || !chB)
27          return (!chB) - (!chA);    // A,!B:1, !A,B:-1, !A,!B:0
28
29       if (chA != chB)
30          return (int)(chA) - (int)(chB);   // -1:A<B, 0:A==B, 1:A>B
31       }
32
33    return 0;  // no differences before told to stop comparing, so A==B
34 }
35
36
37 /*
38  * mstralloc - Allocates space for a given-length multistring
39  * mstrfree - Frees a multistring
40  * mstrwalk - Allows iterative progression along a multistring
41  * mstrlen - Returns the length of a given multistring, including all \0's
42  * mstrcount - Returns the number of entries in a given multistring
43  * mstrstr - Determines if a given substring exists in a multistring
44  * mstrcat - Adds a substring to a multistring (doesn't do any checking first)
45  * mstrdel - Removes a substring from a multistring
46  *
47  */
48
49 LPTSTR mstralloc (size_t cchMax)
50 {
51    LPTSTR msz;
52    if ((msz = (LPTSTR)GlobalAlloc (GMEM_FIXED, sizeof(TCHAR) * (1+cchMax))) != NULL)
53       memset (msz, 0x00, sizeof(TCHAR) * (1+cchMax));
54    return msz;
55 }
56
57
58 void mstrfree (LPCTSTR msz)
59 {
60    if (msz)
61       GlobalFree ((HGLOBAL)msz);
62 }
63
64
65 BOOL mstrwalk (LPCTSTR msz, TCHAR chSep, LPTSTR *ppSegment, size_t *pchSegment)
66 {
67    // If the caller supplied {*ppSegment} as NULL, we should return the
68    // first segment. Otherwise, advance {*pchSegment} characters and
69    // return the next segment.
70    //
71    if (!*ppSegment)
72       *ppSegment = (LPTSTR)msz;
73    else if (*(*ppSegment += *pchSegment) == chSep)
74       (*ppSegment) ++;
75    else
76       return FALSE;
77
78    if (!*ppSegment || !*(*ppSegment))
79       return FALSE;
80
81    *pchSegment = 0;
82    while ((*ppSegment)[*pchSegment] && ((*ppSegment)[*pchSegment] != chSep))
83       (*pchSegment)++;
84
85    return TRUE;
86 }
87
88
89 size_t mstrlen (LPCTSTR msz, TCHAR chSep)
90 {
91    LPTSTR pSegment = NULL;
92    size_t cchSegment = 0;
93
94    size_t cchTotal = 0;
95    while (mstrwalk (msz, chSep, &pSegment, &cchSegment))
96       cchTotal += cchSegment+1;
97
98    if (!chSep || !cchTotal)
99       cchTotal ++;     // To terminate the string
100
101    return cchTotal;
102 }
103
104
105 size_t mstrcount (LPCTSTR msz, TCHAR chSep)
106 {
107    LPTSTR pSegment = NULL;
108    size_t cchSegment = 0;
109
110    size_t cSegments = 0;
111    while (mstrwalk (msz, chSep, &pSegment, &cchSegment))
112       cSegments ++;
113
114    return cSegments;
115 }
116
117
118 BOOL mstrstr (LPCTSTR msz, TCHAR chSep, LPCTSTR pszTest)
119 {
120    LPTSTR pSegment = NULL;
121    size_t cchSegment = 0;
122
123    size_t cchTotal = 0;
124    while (mstrwalk (msz, chSep, &pSegment, &cchSegment))
125       {
126       if ( (cchSegment == (size_t)lstrlen(pszTest)) &&
127            (!lstrncmpi (pSegment, pszTest, cchSegment)) )
128          return TRUE;
129       }
130
131    return FALSE;
132 }
133
134
135 BOOL mstrcat (LPTSTR *pmsz, TCHAR chSep, LPCTSTR pszAppend)
136 {
137    size_t cchOld = mstrlen(*pmsz,chSep);
138    size_t cchAdd = (pszAppend) ? lstrlen(pszAppend) : 0;
139    size_t cchRetain = (chSep && (cchOld!=1)) ? cchOld : (cchOld-1);
140
141    LPTSTR mszNew;
142    if ((mszNew = mstralloc (cchRetain + cchAdd + 2)) == NULL)
143       return FALSE;
144
145    if (cchRetain)
146       memcpy (mszNew, *pmsz, sizeof(TCHAR) * cchRetain);
147
148    if (cchRetain)
149       mszNew[ cchRetain-1 ] = chSep;
150
151    lstrcpy (&mszNew[ cchRetain ], pszAppend);
152
153    if (!chSep)
154       mszNew[ cchRetain + cchAdd +1 ] = 0;
155
156    if (*pmsz)
157       mstrfree (*pmsz);
158    *pmsz = mszNew;
159    return TRUE;
160 }
161
162
163 BOOL mstrdel (LPTSTR *pmsz, TCHAR chSep, LPCTSTR pszRemove)
164 {
165    LPTSTR mszNew;
166    if ((mszNew = mstralloc (mstrlen(*pmsz,chSep))) == NULL)
167       return FALSE;
168
169    LPTSTR pSegmentWrite = mszNew;
170    LPTSTR pSegmentRead = NULL;
171    size_t cchSegment = 0;
172
173    size_t cchTotal = 0;
174    while (mstrwalk (*pmsz, chSep, &pSegmentRead, &cchSegment))
175       {
176       if ( (cchSegment == (size_t)lstrlen(pszRemove)) &&
177            (!lstrncmpi (pSegmentRead, pszRemove, cchSegment)) )
178          continue;
179
180       for (size_t ich = 0; ich < cchSegment; ++ich)
181          *pSegmentWrite++ = pSegmentRead[ ich ];
182       *pSegmentWrite++ = chSep;
183       }
184    if ((pSegmentWrite != mszNew) && (chSep)) // don't need trailing separator
185       pSegmentWrite--;
186    *pSegmentWrite = 0;
187
188    if (*pmsz)
189       mstrfree (*pmsz);
190    *pmsz = mszNew;
191    return TRUE;
192 }
193