Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
8.8 KiB

  1. /*****************************************************************************
  2. *
  3. * string.cpp
  4. *
  5. * World's lamest string class.
  6. *
  7. *****************************************************************************/
  8. #include "sdview.h"
  9. _String::_String(LPTSTR pszBufOrig, UINT cchBufOrig)
  10. : _pszBufOrig(pszBufOrig)
  11. , _pszBuf(pszBufOrig)
  12. , _cchBuf(cchBufOrig)
  13. {
  14. Reset();
  15. }
  16. _String::~_String()
  17. {
  18. if (_pszBuf != _pszBufOrig) {
  19. LocalFree(_pszBuf);
  20. }
  21. }
  22. //
  23. // Notice that Reset does not free the allocated buffer. Once we've
  24. // switched to using an allocated buffer, we may as well continue to
  25. // use it.
  26. //
  27. void _String::Reset()
  28. {
  29. ASSERT(_cchBuf);
  30. _cchLen = 0;
  31. _pszBuf[0] = TEXT('\0');
  32. }
  33. BOOL _String::Append(LPCTSTR psz, int cch)
  34. {
  35. int cchNeeded = _cchLen + cch + 1;
  36. if (cchNeeded > _cchBuf)
  37. {
  38. LPTSTR pszNew;
  39. if (_pszBuf != _pszBufOrig) {
  40. pszNew = RECAST(LPTSTR, LocalReAlloc(_pszBuf, cchNeeded * sizeof(TCHAR), LMEM_MOVEABLE));
  41. } else {
  42. pszNew = RECAST(LPTSTR, LocalAlloc(LMEM_FIXED, cchNeeded * sizeof(TCHAR)));
  43. }
  44. if (!pszNew) {
  45. return FALSE;
  46. }
  47. if (_pszBuf == _pszBufOrig) {
  48. memcpy(pszNew, _pszBuf, _cchBuf * sizeof(TCHAR));
  49. }
  50. _cchBuf = cchNeeded;
  51. _pszBuf = pszNew;
  52. }
  53. if (psz) {
  54. lstrcpyn(_pszBuf + _cchLen, psz, cch + 1);
  55. }
  56. _cchLen += cch;
  57. _pszBuf[_cchLen] = TEXT('\0');
  58. return TRUE;
  59. }
  60. _String& _String::operator<<(int i)
  61. {
  62. TCHAR sz[64];
  63. wsprintf(sz, TEXT("%d"), i);
  64. return *this << sz;
  65. }
  66. //
  67. // This could be inline but it's not worth it.
  68. //
  69. _String& _String::operator<<(TCHAR tch)
  70. {
  71. Append(&tch, 1);
  72. return *this;
  73. }
  74. //
  75. // This could be inline but it's not worth it.
  76. //
  77. BOOL _String::Append(LPCTSTR psz)
  78. {
  79. return Append(psz, lstrlen(psz));
  80. }
  81. BOOL _String::Ensure(int cch)
  82. {
  83. BOOL f;
  84. if (Length() + cch < BufferLength()) {
  85. f = TRUE; // Already big enough
  86. } else {
  87. f = Grow(cch);
  88. if (f) {
  89. _cchLen -= cch;
  90. }
  91. }
  92. return f;
  93. }
  94. //
  95. // Remove any trailing CRLF
  96. //
  97. void _String::Chomp()
  98. {
  99. if (Length() > 0 && Buffer()[Length()-1] == TEXT('\n')) {
  100. Trim();
  101. }
  102. if (Length() > 0 && Buffer()[Length()-1] == TEXT('\r')) {
  103. Trim();
  104. }
  105. }
  106. OutputStringBuffer::~OutputStringBuffer()
  107. {
  108. if (Buffer() != OriginalBuffer()) {
  109. lstrcpyn(OriginalBuffer(), Buffer(), _cchBufOrig);
  110. }
  111. }
  112. /*****************************************************************************
  113. *
  114. * QuoteSpaces
  115. *
  116. * Append the string, quoting it if it contains any spaces
  117. * or if it is the null string.
  118. *
  119. *****************************************************************************/
  120. _String& operator<<(_String& str, QuoteSpaces qs)
  121. {
  122. if (qs) {
  123. if (qs[0] == TEXT('\0') || StrChr(qs, TEXT(' '))) {
  124. str << '"' << SAFECAST(LPCTSTR, qs) << '"';
  125. } else {
  126. str << SAFECAST(LPCTSTR, qs);
  127. }
  128. }
  129. return str;
  130. }
  131. /*****************************************************************************
  132. *
  133. * BranchOf
  134. *
  135. * Given a full depot path, append the branch name.
  136. *
  137. *****************************************************************************/
  138. _String& operator<<(_String& str, BranchOf bof)
  139. {
  140. if (bof && bof[0] == TEXT('/') && bof[1] == TEXT('/')) {
  141. //
  142. // Skip over the word "//depot" -- or whatever it is.
  143. // Some admins are stupid and give the root of the depot
  144. // some other strange name.
  145. //
  146. LPCTSTR pszBranch = StrChr(bof + 2, TEXT('/'));
  147. if (pszBranch) {
  148. pszBranch++;
  149. //
  150. // If the next phrase is "private", then we are in a
  151. // private branch; skip a step.
  152. //
  153. if (StringBeginsWith(pszBranch, TEXT("private/"))) {
  154. pszBranch += 8;
  155. }
  156. LPCTSTR pszSlash = StrChr(pszBranch, TEXT('/'));
  157. if (pszSlash) {
  158. str << Substring(pszBranch, pszSlash);
  159. }
  160. }
  161. }
  162. return str;
  163. }
  164. /*****************************************************************************
  165. *
  166. * FilenameOf
  167. *
  168. * Given a full depot path, possibly with revision tag,
  169. * append just the filename part.
  170. *
  171. *****************************************************************************/
  172. _String& operator<<(_String& str, FilenameOf fof)
  173. {
  174. if (fof) {
  175. LPCTSTR pszFile = StrRChr(fof, NULL, TEXT('/'));
  176. if (pszFile) {
  177. pszFile++;
  178. } else {
  179. pszFile = fof;
  180. }
  181. str.Append(pszFile, StrCSpn(pszFile, TEXT("#")));
  182. }
  183. return str;
  184. }
  185. /*****************************************************************************
  186. *
  187. * StringResource
  188. *
  189. * Given a string resource identifier, append the corresponding string.
  190. *
  191. *****************************************************************************/
  192. _String& operator<<(_String& str, StringResource sr)
  193. {
  194. HRSRC hrsrc = FindResource(g_hinst, MAKEINTRESOURCE(1 + sr / 16), RT_STRING);
  195. if (hrsrc) {
  196. HGLOBAL hglob = LoadResource(g_hinst, hrsrc);
  197. if (hglob) {
  198. LPWSTR pwch = RECAST(LPWSTR, LockResource(hglob));
  199. if (pwch) {
  200. UINT ui;
  201. for (ui = 0; ui < sr % 16; ui++) {
  202. pwch += *pwch + 1;
  203. }
  204. #ifdef UNICODE
  205. str.Append(pwch+1, *pwch);
  206. #else
  207. int cch = WideCharToMultiByte(CP_ACP, 0, pwch+1, *pwch,
  208. NULL, 0, NULL, NULL);
  209. if (str.Grow(cch)) {
  210. WideCharToMultiByte(CP_ACP, 0, pwch+1, *pwch,
  211. str.Buffer() + str.Length() - cch,
  212. cch,
  213. NULL, NULL);
  214. }
  215. #endif
  216. }
  217. }
  218. }
  219. return str;
  220. }
  221. /*****************************************************************************
  222. *
  223. * ResolveBranchAndQuoteSpaces
  224. *
  225. * If the file specifier contains a "branch:" prefix, resolve it.
  226. * Then append the result (with spaces quoted).
  227. *
  228. *****************************************************************************/
  229. //
  230. // The real work happens in the worker function.
  231. //
  232. _String& _ResolveBranchAndQuoteSpaces(_String& strOut, LPCTSTR pszSpec, LPCTSTR pszColon)
  233. {
  234. String str;
  235. String strFull;
  236. LPCTSTR pszSD = pszColon + 1;
  237. if (MapToFullDepotPath(pszSD, strFull)) {
  238. //
  239. // Copy the word "//depot" -- or whatever it is.
  240. // Some admins are stupid and give the root of the depot
  241. // some other strange name.
  242. //
  243. LPCTSTR pszBranch = StrChr(strFull + 2, TEXT('/'));
  244. if (pszBranch) {
  245. pszBranch++; // Include the slash
  246. str << Substring(strFull, pszBranch);
  247. //
  248. // Bonus: If the branch name begins with "/" then
  249. // we treat it as a private branch.
  250. //
  251. if (pszSpec[0] == TEXT('/')) {
  252. str << "private";
  253. }
  254. str << Substring(pszSpec, pszColon);
  255. //
  256. // If the next phrase is "private", then we are in a
  257. // private branch; skip a step.
  258. //
  259. if (StringBeginsWith(pszBranch, TEXT("private/"))) {
  260. pszBranch += 8;
  261. }
  262. LPCTSTR pszSlash = StrChr(pszBranch, TEXT('/'));
  263. if (pszSlash) {
  264. str << pszSlash;
  265. }
  266. strOut << QuoteSpaces(str);
  267. } else {
  268. str << QuoteSpaces(strFull);
  269. }
  270. } else {
  271. //
  272. // If anything went wrong, then just ignore the branch prefix.
  273. //
  274. str << QuoteSpaces(pszSD);
  275. }
  276. return str;
  277. }
  278. _String& operator<<(_String& str, ResolveBranchAndQuoteSpaces rb)
  279. {
  280. Substring ss;
  281. if (Parse(TEXT("$b:"), rb, &ss)) {
  282. ASSERT(ss._pszMax[0] == TEXT(':'));
  283. return _ResolveBranchAndQuoteSpaces(str, rb, ss._pszMax);
  284. } else {
  285. return str << QuoteSpaces(rb);
  286. }
  287. }
  288. /*****************************************************************************
  289. *
  290. * _StringCache=
  291. *
  292. *****************************************************************************/
  293. _StringCache& _StringCache::operator=(LPCTSTR psz)
  294. {
  295. if (_psz) {
  296. LocalFree(_psz);
  297. }
  298. if (psz) {
  299. _psz = StrDup(psz);
  300. } else {
  301. _psz = NULL;
  302. }
  303. return *this;
  304. }