Source code of Windows XP (NT5)
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.

878 lines
20 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. StrUtils.C
  5. Abstract:
  6. String utility functions
  7. Author:
  8. Bob Watson (a-robw)
  9. Revision History:
  10. 24 Jun 94 Written
  11. --*/
  12. //
  13. // Windows Include Files
  14. //
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <malloc.h>
  18. #include <tchar.h> // unicode macros
  19. #include <stdlib.h> // string to number conversions
  20. //
  21. // app include files
  22. //
  23. #include "otnboot.h"
  24. #include "otnbtdlg.h"
  25. //
  26. // Local constants
  27. //
  28. #define NUM_BUFS 8
  29. BOOL
  30. MatchFirst (
  31. IN LPCTSTR szStringA,
  32. IN LPCTSTR szStringB
  33. )
  34. /*++
  35. Routine Description:
  36. performs a case in-sensitive comparison of the two strings to
  37. the extent of the shortest string. If, up to the length
  38. of the shortest string, the strings match then TRUE is
  39. returned otherwise FALSE is returned.
  40. Arguments:
  41. IN LPCTSTR szStringA,
  42. pointer to first string
  43. IN LPCTSTR szStringB
  44. pointer to second string
  45. Return Value:
  46. TRUE if match found
  47. FALSE if not
  48. --*/
  49. {
  50. LPTSTR szAptr; // pointer to char in szStringA to compare
  51. LPTSTR szBptr; // pointer to char in szStringB to compare
  52. if ((szStringA != NULL) && (szStringB != NULL)) {
  53. szAptr = (LPTSTR)szStringA;
  54. szBptr = (LPTSTR)szStringB;
  55. while ((*szBptr != 0) && (*szAptr != 0)) {
  56. if (_totlower(*szBptr) != _totlower(*szAptr)) break;
  57. szBptr++;
  58. szAptr++;
  59. }
  60. if (((*szAptr == 0) && ((*szBptr == 0) || (*szBptr == cBackslash))) ||
  61. ((*szBptr == 0) && ((*szAptr == 0) || (*szAptr == cBackslash)))) {
  62. // then a matched directoryto the end of the shortest string
  63. return TRUE;
  64. } else {
  65. return FALSE;
  66. }
  67. } else {
  68. return FALSE;
  69. }
  70. }
  71. DWORD
  72. GetSizeFromInfString (
  73. IN LPCTSTR szString
  74. )
  75. /*++
  76. Routine Description:
  77. Reads the estimated size of the directory tree as stored in the
  78. inf file. The format of the INF string is:
  79. key=entry
  80. where:
  81. key = subdir name
  82. entry = NumberOfFiles,TotalBytes
  83. value must be less than 2**32
  84. Arguments:
  85. "entry" string read from INF file
  86. Return Value:
  87. DWORD value of TotalBytes in entry
  88. --*/
  89. {
  90. LPTSTR szSize; // size string parsed from input string
  91. LPTSTR szLastChar; // beginning of size value in string
  92. // size is second param in comma separated list
  93. // go to first comma
  94. szSize = (LPTSTR)szString;
  95. while ((*szSize != cComma) && (*szSize != 0)) szSize++;
  96. szSize++; // go to first char after comma
  97. return _tcstoul (szSize, &szLastChar, 10);
  98. }
  99. BOOL
  100. SavePathToRegistry (
  101. LPCTSTR szPath,
  102. LPCTSTR szServerKey,
  103. LPCTSTR szShareKey
  104. )
  105. /*++
  106. Routine Description:
  107. splits the path (which must be a UNC path) into server & sharepoint
  108. for loading into the system registry. The key used is the
  109. \HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Network
  110. and the NCAdmin key is created (if it doesn't exist) under which the
  111. Server is stored in the szServerKey value and the share point is
  112. stored under the szShareKey value
  113. Arguments:
  114. LPCTSTR szPath
  115. UNC path to store
  116. LPCTSTR szServerKey
  117. name of registry value to store server under
  118. LPCTSTR szShareKey
  119. name of registry value to store share under
  120. Return Value:
  121. TRUE values stored OK
  122. FALSE values not stored
  123. --*/
  124. {
  125. TCHAR szMachine[MAX_COMPUTERNAME_LENGTH+1]; // computer name buffer
  126. LPTSTR szShare; // share name buffer
  127. HKEY hkeyUserInfo; // registry key
  128. HKEY hkeyAppInfo; // registry key
  129. LONG lStatus; // local function status
  130. BOOL bReturn; // return value of this fn
  131. DWORD dwAppKeyDisp; // create/existing value
  132. szShare = GlobalAlloc (GPTR, MAX_PATH_BYTES);
  133. if (szShare == NULL) {
  134. // unable to alloc memory.
  135. return FALSE;
  136. }
  137. if (IsUncPath (szPath)) {
  138. // open registry key containing net apps
  139. lStatus = RegOpenKeyEx (
  140. HKEY_CURRENT_USER,
  141. cszUserInfoKey,
  142. 0L,
  143. KEY_READ,
  144. &hkeyUserInfo);
  145. if (lStatus != ERROR_SUCCESS) {
  146. // unable to open key so return error
  147. bReturn = FALSE;
  148. } else {
  149. // open registry key containing this app's info
  150. lStatus = RegCreateKeyEx (
  151. hkeyUserInfo,
  152. szAppName,
  153. 0L,
  154. (LPTSTR)cszEmptyString,
  155. REG_OPTION_NON_VOLATILE,
  156. KEY_WRITE,
  157. NULL,
  158. &hkeyAppInfo,
  159. &dwAppKeyDisp);
  160. if (lStatus != ERROR_SUCCESS) {
  161. // unable to open key so return false
  162. bReturn = FALSE;
  163. } else {
  164. if (!GetServerFromUnc (szPath, szMachine)) {
  165. // unable to read share so clear value
  166. szMachine[0] = 0;
  167. }
  168. // get server name from registry
  169. lStatus = RegSetValueEx (
  170. hkeyAppInfo,
  171. (LPTSTR)szServerKey,
  172. 0L,
  173. REG_SZ,
  174. (LPBYTE)&szMachine[0],
  175. (DWORD)(lstrlen(szMachine)*sizeof(TCHAR)));
  176. if (lStatus == ERROR_SUCCESS) {
  177. if (!GetShareFromUnc (szPath, szShare)) {
  178. szShare[0] = 0;
  179. }
  180. lStatus = RegSetValueEx (
  181. hkeyAppInfo,
  182. (LPTSTR)szShareKey,
  183. 0L,
  184. REG_SZ,
  185. (LPBYTE)&szShare[0],
  186. (DWORD)(lstrlen(szShare)*sizeof(TCHAR)));
  187. if (lStatus == ERROR_SUCCESS) {
  188. bReturn = TRUE;
  189. } else {
  190. bReturn = FALSE;
  191. }
  192. } else {
  193. bReturn = FALSE;
  194. }
  195. RegCloseKey (hkeyAppInfo);
  196. }
  197. RegCloseKey (hkeyUserInfo);
  198. }
  199. bReturn = TRUE;
  200. } else {
  201. // not a UNC path so return error
  202. bReturn = FALSE;
  203. }
  204. FREE_IF_ALLOC (szShare);
  205. return bReturn;
  206. }
  207. DWORD
  208. QuietGetPrivateProfileString (
  209. IN LPCTSTR lpszSection, /* address of section name */
  210. IN LPCTSTR lpszKey, /* address of key name */
  211. IN LPCTSTR lpszDefault, /* address of default string */
  212. OUT LPTSTR lpszReturnBuffer, /* address of destination buffer */
  213. IN DWORD cchReturnBuffer, /* size of destination buffer */
  214. IN LPCTSTR lpszFile /* address of initialization filename */
  215. )
  216. /*++
  217. Routine Description:
  218. Reads data from profile file without triggering OS error message if
  219. unable to access file.
  220. Arguments:
  221. IN LPCTSTR lpszSection
  222. address of section name
  223. IN LPCTSTR lpszKey
  224. address of key name
  225. IN LPCTSTR lpszDefault
  226. address of default string
  227. OUT LPTSTR lpszReturnBuffer
  228. address of destination buffer
  229. IN DWORD cchReturnBuffer
  230. size of destination buffer (in characters)
  231. IN LPCTSTR lpszFile
  232. address of initialization filename
  233. See HELP on GetPrivateProfileString for details on using these arguments.
  234. Return Value:
  235. number of characters copied into lpszReturnBuffer.
  236. --*/
  237. {
  238. DWORD dwReturn;
  239. UINT nErrorMode;
  240. // disable windows error message popup
  241. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  242. // call function
  243. dwReturn = GetPrivateProfileString (
  244. lpszSection, lpszKey, lpszDefault, lpszReturnBuffer,
  245. cchReturnBuffer, lpszFile);
  246. SetErrorMode (nErrorMode); // restore old error mode
  247. return dwReturn;
  248. }
  249. LPCTSTR
  250. GetKeyFromEntry (
  251. IN LPCTSTR szEntry
  252. )
  253. /*++
  254. Routine Description:
  255. copys the "key" from an INF string of the format:
  256. Key=Value. All text up to, but not including the "="
  257. is returned.
  258. Arguments:
  259. IN LPCTSTR szEntry
  260. line from INF file to process. must be in the format referenced
  261. above.
  262. Return Value:
  263. pointer to a read only string that contains the resulting key string.
  264. NOTE: this is stored in a static variable and should be copied to a
  265. local variable for further processing OR before calling this routine
  266. again.
  267. --*/
  268. {
  269. static TCHAR szReturnBuffer[MAX_PATH];
  270. LPTSTR szSource, szDest;
  271. szSource = (LPTSTR)szEntry;
  272. szDest = &szReturnBuffer[0];
  273. *szDest = 0;
  274. if (*szSource != 0) {
  275. // copy all chars from start to the equal sign
  276. // (or the end of the string)
  277. while ((*szSource != cEqual) && (*szSource != 0)) {
  278. *szDest++ = *szSource++;
  279. }
  280. *szDest = 0; //terminate destination string (key)
  281. }
  282. return szReturnBuffer;
  283. }
  284. LPCTSTR
  285. GetItemFromEntry (
  286. IN LPCTSTR szEntry,
  287. IN DWORD dwItem
  288. )
  289. /*++
  290. Routine Description:
  291. returns nth item from comma separated list returned from
  292. inf file. leaves (double)quoted strings intact.
  293. Arguments:
  294. IN LPCTSTR szEntry
  295. entry string returned from INF file
  296. IN DWORD dwItem
  297. 1-based index indicating which item to return. (i.e. 1= first item
  298. in list, 2= second, etc.)
  299. Return Value:
  300. pointer to buffer containing desired entry in string. Note, this
  301. routine may only be called 4 times before the string
  302. buffer is re-used. (i.e. don't use this function more than
  303. 4 times in another function call!!)
  304. --*/
  305. {
  306. static TCHAR szReturnBuffer[4][MAX_PATH];
  307. LPTSTR szSource, szDest;
  308. DWORD dwThisItem;
  309. static DWORD dwBuff;
  310. dwBuff = ++dwBuff % 4; // wrap buffer index
  311. szSource = (LPTSTR)szEntry;
  312. szDest = &szReturnBuffer[dwBuff][0];
  313. *szDest = 0;
  314. // go past ini key
  315. while ((*szSource != cEqual) && (*szSource != 0)) szSource++;
  316. if (*szSource == 0){
  317. // no equals found so start at beginning
  318. // presumably this is just the "value"
  319. szSource = (LPTSTR)szEntry;
  320. } else {
  321. szSource++;
  322. }
  323. dwThisItem = 1;
  324. while (dwThisItem < dwItem) {
  325. if (*szSource != 0) {
  326. while ((*szSource != cComma) && (*szSource != 0)) {
  327. if (*szSource == cDoubleQuote) {
  328. // if this is a quote, then go to the close quote
  329. szSource++;
  330. while ((*szSource != cDoubleQuote) && (*szSource != 0)) szSource++;
  331. }
  332. if (*szSource != 0) szSource++;
  333. }
  334. }
  335. dwThisItem++;
  336. if (*szSource != 0) szSource++;
  337. }
  338. // copy this entry to the return buffer
  339. if (*szSource != 0) {
  340. while ((*szSource != cComma) && (*szSource != 0)) {
  341. if (*szSource == cDoubleQuote) {
  342. // if this is a quote, then go to the close quote
  343. // don't copy quotes!
  344. szSource++;
  345. while ((*szSource != cDoubleQuote) && (*szSource != 0)) {
  346. *szDest++ = *szSource++;
  347. }
  348. if (*szSource != 0) szSource++;
  349. } else {
  350. *szDest++ = *szSource++;
  351. }
  352. }
  353. *szDest = 0;
  354. }
  355. return &szReturnBuffer[dwBuff][0];
  356. }
  357. LPCTSTR
  358. GetFileNameFromEntry (
  359. IN LPCTSTR szEntry
  360. )
  361. /*++
  362. Routine Description:
  363. returns pointer into szEntry where file name is found.
  364. first character after the ":"
  365. Arguments:
  366. string containing filename in format of:
  367. nn:filename.ext
  368. Return Value:
  369. returns pointer into szEntry where file name is found.
  370. first character after the ":"
  371. returns an empty string if no ":" char was found.
  372. --*/
  373. {
  374. LPTSTR szReturn;
  375. szReturn = (LPTSTR)szEntry;
  376. // go to COLON character
  377. while ((*szReturn != cColon) && (*szReturn != 0)) szReturn++;
  378. // scoot to next char
  379. if (*szReturn != 0) szReturn++;
  380. return szReturn;
  381. }
  382. BOOL
  383. TrimSpaces (
  384. IN OUT LPTSTR szString
  385. )
  386. /*++
  387. Routine Description:
  388. Trims leading and trailing spaces from szString argument, modifying
  389. the buffer passed in
  390. Arguments:
  391. IN OUT LPTSTR szString
  392. buffer to process
  393. Return Value:
  394. TRUE if string was modified
  395. FALSE if not
  396. --*/
  397. {
  398. LPTSTR szSource;
  399. LPTSTR szDest;
  400. LPTSTR szLast;
  401. BOOL bChars;
  402. szLast = szSource = szDest = szString;
  403. bChars = FALSE;
  404. while (*szSource != 0) {
  405. // skip leading non-space chars
  406. if (*szSource > cSpace) {
  407. szLast = szDest;
  408. bChars = TRUE;
  409. }
  410. if (bChars) {
  411. // remember last non-space character
  412. // copy source to destination & increment both
  413. *szDest++ = *szSource++;
  414. } else {
  415. szSource++;
  416. }
  417. }
  418. if (bChars) {
  419. *++szLast = 0; // terminate after last non-space char
  420. } else {
  421. // string was all spaces so return an empty (0-len) string
  422. *szString = 0;
  423. }
  424. return (szLast != szSource);
  425. }
  426. BOOL
  427. IsUncPath (
  428. IN LPCTSTR szPath
  429. )
  430. /*++
  431. Routine Description:
  432. examines path as a string looking for "tell-tale" double
  433. backslash indicating the machine name syntax of a UNC path
  434. Arguments:
  435. IN LPCTSTR szPath
  436. path to examine
  437. Return Value:
  438. TRUE if \\ found at start of string
  439. FALSE if not
  440. --*/
  441. {
  442. LPTSTR szPtChar;
  443. szPtChar = (LPTSTR)szPath;
  444. if (*szPtChar == cBackslash) {
  445. if (*++szPtChar == cBackslash) {
  446. return TRUE;
  447. }
  448. }
  449. return FALSE;
  450. }
  451. LPCTSTR
  452. GetEntryInMultiSz (
  453. IN LPCTSTR mszList,
  454. IN DWORD dwEntry
  455. )
  456. /*++
  457. Routine Description:
  458. Searches for the specified element in the mszList and returns the pointer
  459. to that element in the list.
  460. Arguments:
  461. IN LPCTSTR mszList Multi-SZ list to search
  462. IN DWORD dwEntry 1-based index of entry to return
  463. ReturnValue:
  464. !=cszEmptyString pointer to matching element in list
  465. cszEmptyString (pointer to 0-length string) entry is not in list
  466. --*/
  467. {
  468. LPCTSTR szThisString;
  469. DWORD dwIndex=0;
  470. if (mszList == NULL) return (LPCTSTR)cszEmptyString; // no list to process
  471. if (dwEntry == 0) return (LPCTSTR)cszEmptyString; // no string to find
  472. for (szThisString = mszList;
  473. *szThisString;
  474. szThisString += (lstrlen(szThisString)+ 1)) {
  475. dwIndex++;
  476. if (dwIndex == dwEntry) {
  477. return szThisString;
  478. }
  479. }
  480. return (LPCTSTR)cszEmptyString;
  481. }
  482. DWORD
  483. AddStringToMultiSz (
  484. LPTSTR OUT mszDest,
  485. LPCTSTR IN szSource
  486. )
  487. /*++
  488. Routine Description:
  489. appends the source string to the end of the destination MULTI_SZ
  490. string. Assumes that the destination is large enough!
  491. Arguments:
  492. LPTSTR OUT mszDest multi-sz string to be appended
  493. LPTSTR IN szSource ASCIZ string to be added to the end of the dest
  494. string
  495. ReturnValue:
  496. 1
  497. --*/
  498. {
  499. LPTSTR szDestElem;
  500. // check function arguments
  501. if ((mszDest == NULL) || (szSource == NULL)) return 0; // invalid buffers
  502. if (*szSource == '\0') return 0; // no string to add
  503. // go to end of dest string
  504. //
  505. for (szDestElem = mszDest;
  506. *szDestElem;
  507. szDestElem += (lstrlen(szDestElem)+1));
  508. // if here, then add string
  509. // szDestElem is at end of list
  510. lstrcpy (szDestElem, szSource);
  511. szDestElem += (lstrlen(szDestElem) + 1);
  512. *szDestElem = '\0'; // add second NULL
  513. return 1;
  514. }
  515. DWORD
  516. StringInMultiSz (
  517. IN LPCTSTR szString,
  518. IN LPCTSTR mszList
  519. )
  520. /*++
  521. Routine Description:
  522. Searches each element in the mszList and does a case-insensitive
  523. comparison with the szString argument.
  524. Arguments:
  525. IN LPCTSTR szString string to find in list
  526. IN LPCTSTR mszList list to search
  527. ReturnValue:
  528. >0 szString was found in the list, # returned is the
  529. index of the matching entry (1= first)
  530. 0 szString was NOT found
  531. --*/
  532. {
  533. LPTSTR szThisString;
  534. DWORD dwIndex=0;
  535. // check input arguments
  536. if ((szString == NULL) || (mszList == NULL)) return 0; // invalid buffer
  537. if (*szString == 0) return 0; // no string to find
  538. for (szThisString = (LPTSTR)mszList;
  539. *szThisString;
  540. szThisString += (lstrlen(szThisString)+ 1)) {
  541. dwIndex++;
  542. if (lstrcmpi(szThisString, szString) == 0) {
  543. return dwIndex;
  544. }
  545. }
  546. return 0;
  547. }
  548. LPCTSTR
  549. GetStringResource (
  550. IN UINT nId
  551. )
  552. /*++
  553. Routine Description:
  554. look up string resource and return string
  555. Arguments:
  556. IN UINT nId
  557. Resource ID of string to look up
  558. Return Value:
  559. pointer to string referenced by ID in arg list
  560. --*/
  561. {
  562. static TCHAR szBufArray[NUM_BUFS][SMALL_BUFFER_SIZE];
  563. static DWORD dwIndex;
  564. LPTSTR szBuffer;
  565. DWORD dwLength;
  566. dwIndex++;
  567. dwIndex %= NUM_BUFS;
  568. szBuffer = &szBufArray[dwIndex][0];
  569. dwLength = LoadString (
  570. GetModuleHandle (NULL),
  571. nId,
  572. szBuffer,
  573. SMALL_BUFFER_SIZE);
  574. return (LPCTSTR)szBuffer;
  575. }
  576. DWORD
  577. GetMultiSzLen (
  578. IN LPCTSTR mszInString
  579. )
  580. /*++
  581. Routine Description:
  582. Counts the number of characters in the multi-sz string (including
  583. NULL's between strings and terminating NULL char)
  584. Arguments:
  585. IN LPCTSTR mszInString
  586. multi-sz string to count
  587. Return Value:
  588. number of characters in string
  589. --*/
  590. {
  591. LPCTSTR szEndChar = mszInString;
  592. BOOL bEnd = FALSE;
  593. DWORD dwCharsInString = 0;
  594. while (!bEnd) {
  595. if (*szEndChar == 0) {
  596. // this is the end of a line so adjust the count to
  597. // account for the crlf being 2 chars
  598. szEndChar++;
  599. dwCharsInString += 2;
  600. if (*szEndChar == 0) {
  601. // this is the end of the MSZ
  602. dwCharsInString++; // for the CTRL-Z
  603. bEnd = TRUE;
  604. }
  605. } else {
  606. szEndChar++;
  607. dwCharsInString++;
  608. }
  609. }
  610. return dwCharsInString;
  611. }
  612. DWORD
  613. TranslateEscapeChars (
  614. IN LPTSTR szNewString,
  615. IN LPTSTR szString
  616. )
  617. /*++
  618. Translates the following escape sequences if found in the string.
  619. The translation is performed on szString and written to szNewString.
  620. The return value is the length of the resulting string in characters;
  621. --*/
  622. {
  623. LPTSTR szSource;
  624. LPTSTR szDest;
  625. szSource = szString;
  626. szDest = szNewString;
  627. while (*szSource != 0) {
  628. if (*szSource == '\\') {
  629. // this is an escape sequence so go to the next char
  630. // and see which one.
  631. szSource++;
  632. switch (*szSource) {
  633. case _T('b'):
  634. *szDest = _T('\b');
  635. break;
  636. case _T('f'):
  637. *szDest = _T('\f');
  638. break;
  639. case _T('n'):
  640. *szDest = _T('\n');
  641. break;
  642. case _T('r'):
  643. *szDest = _T('\r');
  644. break;
  645. case _T('t'):
  646. *szDest = _T('\t');
  647. break;
  648. case _T('v'):
  649. *szDest = _T('\v');
  650. break;
  651. case _T('?'):
  652. *szDest = _T('\?');
  653. break;
  654. case _T('\''):
  655. *szDest = _T('\'');
  656. break;
  657. case _T('\"'):
  658. *szDest = _T('\"');
  659. break;
  660. case _T('\\'):
  661. *szDest = _T('\\');
  662. break;
  663. default:
  664. *szDest = *szSource;
  665. break;
  666. }
  667. szDest++;
  668. szSource++;
  669. } else {
  670. // just a plain old character so copy it
  671. *szDest++ = *szSource++;
  672. }
  673. }
  674. return (DWORD)(szDest - szNewString);
  675. }