|
|
1.1 root 1: // This is a part of the Microsoft Foundation Classes C++ library.
2: // Copyright (C) 1992 Microsoft Corporation
3: // All rights reserved.
4: //
5: // This source code is only intended as a supplement to the
6: // Microsoft Foundation Classes Reference and Microsoft
7: // QuickHelp documentation provided with the library.
8: // See these sources for detailed information regarding the
9: // Microsoft Foundation Classes product.
10:
11:
12: #include "afx.h"
13: #pragma hdrstop
14: #include <limits.h>
15:
16: #ifdef AFX_CORE_SEG
17: #pragma code_seg(AFX_CORE_SEG)
18: #endif
19:
20: #ifdef _DEBUG
21: #undef THIS_FILE
22: static char BASED_CODE THIS_FILE[] = __FILE__;
23: #endif
24:
25: #define new DEBUG_NEW
26:
27: /////////////////////////////////////////////////////////////////////////////
28: // static class data, special inlines
29:
30: char _afxChNil = '\0';
31:
32: // For an empty string, m_???Data will point here
33: // (note: avoids a lot of NULL pointer tests when we call standard
34: // C runtime libraries
35:
36: extern const CString NEAR afxEmptyString;
37: const CString NEAR afxEmptyString;
38:
39: void CString::Init()
40: {
41: m_nDataLength = m_nAllocLength = 0;
42: m_pchData = &_afxChNil;
43: }
44:
45: //////////////////////////////////////////////////////////////////////////////
46: // Construction/Destruction
47:
48: CString::CString()
49: {
50: Init();
51: }
52:
53: CString::CString(const CString& stringSrc)
54: {
55: // if constructing a CString from another CString, we make a copy of the
56: // original string data to enforce value semantics (i.e. each string
57: // gets a copy of it's own
58:
59: stringSrc.AllocCopy(*this, stringSrc.m_nDataLength, 0, 0);
60: }
61:
62: void CString::AllocBuffer(int nLen)
63: // always allocate one extra character for '\0' termination
64: // assumes [optimistically] that data length will equal allocation length
65: {
66: ASSERT(nLen >= 0);
67: ASSERT(nLen < INT_MAX - 1); // max size (enough room for 1 extra)
68:
69: if (nLen == 0)
70: {
71: Init();
72: }
73: else
74: {
75: m_pchData = new char[nLen+1]; // may throw an exception
76: m_pchData[nLen] = '\0';
77: m_nDataLength = nLen;
78: m_nAllocLength = nLen;
79: }
80: }
81:
82: void CString::Empty()
83: {
84: if (m_pchData != &_afxChNil)
85: {
86: delete [] m_pchData;
87: Init();
88: }
89: ASSERT(m_nDataLength == 0);
90: ASSERT(m_nAllocLength == 0);
91: }
92:
93: CString::~CString()
94: // free any attached data
95: {
96: if (m_pchData != &_afxChNil)
97: delete [] m_pchData; // NOTE: not type safe
98: }
99:
100: //////////////////////////////////////////////////////////////////////////////
101: // Helpers for the rest of the implementation
102:
103: static inline int SafeStrlen(const char* psz)
104: { return (psz == NULL) ? NULL : strlen(psz); }
105:
106: void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
107: int nExtraLen) const
108: {
109: // will clone the data attached to this string
110: // allocating 'nExtraLen' characters
111: // Places results in uninitialized string 'dest'
112: // Will copy the part or all of original data to start of new string
113:
114: int nNewLen = nCopyLen + nExtraLen;
115:
116: if (nNewLen == 0)
117: {
118: dest.Init();
119: }
120: else
121: {
122: dest.AllocBuffer(nNewLen);
123: memcpy(dest.m_pchData, &m_pchData[nCopyIndex], nCopyLen);
124: }
125: }
126:
127: //////////////////////////////////////////////////////////////////////////////
128: // More sophisticated construction
129:
130: CString::CString(const char* psz)
131: {
132: int nLen;
133: if ((nLen = SafeStrlen(psz)) == 0)
134: Init();
135: else
136: {
137: AllocBuffer(nLen);
138: memcpy(m_pchData, psz, nLen);
139: }
140: }
141:
142: //////////////////////////////////////////////////////////////////////////////
143: // Diagnostic support
144:
145: #ifdef _DEBUG
146:
147: CDumpContext&
148: operator <<(CDumpContext& dc, const CString& string)
149: {
150: dc << string.m_pchData;
151: return dc;
152: }
153:
154: #endif //_DEBUG
155:
156: //////////////////////////////////////////////////////////////////////////////
157: // Assignment operators
158: // All assign a new value to the string
159: // (a) first see if the buffer is big enough
160: // (b) if enough room, copy on top of old buffer, set size and type
161: // (c) otherwise free old string data, and create a new one
162: //
163: // All routines return the new string (but as a 'const CString&' so that
164: // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
165: //
166:
167: void CString::AssignCopy(int nSrcLen, const char* pszSrcData)
168: {
169: // check if it will fit
170: if (nSrcLen > m_nAllocLength)
171: {
172: // it won't fit, allocate another one
173: Empty();
174: AllocBuffer(nSrcLen);
175: }
176: if (nSrcLen != 0)
177: memcpy(m_pchData, pszSrcData, nSrcLen);
178: m_nDataLength = nSrcLen;
179: m_pchData[nSrcLen] = '\0';
180: }
181:
182: const CString&
183: CString::operator =(const CString& stringSrc)
184: {
185: AssignCopy(stringSrc.m_nDataLength, stringSrc.m_pchData);
186: return *this;
187: }
188:
189: const CString&
190: CString::operator =(const char* psz)
191: {
192: AssignCopy(SafeStrlen(psz), psz);
193: return *this;
194: }
195:
196:
197: //////////////////////////////////////////////////////////////////////////////
198: // concatenation
199:
200: // NOTE: "operator +" is done as friend functions for simplicity
201: // There are three variants:
202: // CString + CString
203: // and for ? = char, const char*
204: // CString + ?
205: // ? + CString
206:
207: void
208: CString::ConcatCopy(int nSrc1Len, const char* pszSrc1Data,
209: int nSrc2Len, const char* pszSrc2Data)
210: {
211: // -- master concatenation routine
212: // Concatenate two sources
213: // -- assume that 'this' is a new CString object
214:
215: int nNewLen = nSrc1Len + nSrc2Len;
216: AllocBuffer(nNewLen);
217: memcpy(m_pchData, pszSrc1Data, nSrc1Len);
218: memcpy(&m_pchData[nSrc1Len], pszSrc2Data, nSrc2Len);
219: }
220:
221: CString
222: operator +(const CString& string1, const CString& string2)
223: {
224: CString s;
225: s.ConcatCopy(string1.m_nDataLength, string1.m_pchData,
226: string2.m_nDataLength, string2.m_pchData);
227: return s;
228: }
229:
230: CString
231: operator +(const CString& string, const char* psz)
232: {
233: CString s;
234: s.ConcatCopy(string.m_nDataLength, string.m_pchData, SafeStrlen(psz), psz);
235: return s;
236: }
237:
238:
239: CString
240: operator +(const char* psz, const CString& string)
241: {
242: CString s;
243: s.ConcatCopy(SafeStrlen(psz), psz, string.m_nDataLength, string.m_pchData);
244: return s;
245: }
246:
247: //////////////////////////////////////////////////////////////////////////////
248: // concatenate in place
249:
250: void
251: CString::ConcatInPlace(int nSrcLen, const char* pszSrcData)
252: {
253: // -- the main routine for += operators
254:
255: // if the buffer is too small, or we have a width mis-match, just
256: // allocate a new buffer (slow but sure)
257: if (m_nDataLength + nSrcLen > m_nAllocLength)
258: {
259: // we have to grow the buffer, use the Concat in place routine
260: char* pszOldData = m_pchData;
261: ConcatCopy(m_nDataLength, pszOldData, nSrcLen, pszSrcData);
262: ASSERT(pszOldData != NULL);
263: if (pszOldData != &_afxChNil)
264: delete [] pszOldData;
265: }
266: else
267: {
268: // fast concatenation when buffer big enough
269: memcpy(&m_pchData[m_nDataLength], pszSrcData, nSrcLen);
270: m_nDataLength += nSrcLen;
271: }
272: ASSERT(m_nDataLength <= m_nAllocLength);
273: m_pchData[m_nDataLength] = '\0';
274: }
275:
276: const CString&
277: CString::operator +=(const char* psz)
278: {
279: ConcatInPlace(SafeStrlen(psz), psz);
280: return *this;
281: }
282:
283: const CString&
284: CString::operator +=(const CString& string)
285: {
286: ConcatInPlace(string.m_nDataLength, string.m_pchData);
287: return *this;
288: }
289:
290:
291: ///////////////////////////////////////////////////////////////////////////////
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.