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.

912 lines
17 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. /*++
  4. Copyright (c) 1990 Microsoft Corporation
  5. Module Name:
  6. misc.c
  7. Abstract:
  8. Misc stuff
  9. Author:
  10. Ramon J. San Andres (ramonsa) January 1991
  11. --*/
  12. //*************************************************************************
  13. //
  14. // Strings
  15. //
  16. //*************************************************************************
  17. SZ
  18. SzDup(
  19. SZ sz
  20. )
  21. {
  22. SZ NewSz = NULL;
  23. if ( sz ) {
  24. if ( (NewSz = (SZ)SAlloc( strlen(sz) + 1 )) ) {
  25. strcpy( NewSz, sz );
  26. }
  27. }
  28. return NewSz;
  29. }
  30. SZ
  31. SzListValueFromPath(
  32. SZ szPath
  33. )
  34. {
  35. RGSZ rgszPath;
  36. SZ szList = NULL;
  37. if ( rgszPath = RgszFromPath( szPath ) ) {
  38. szList = SzListValueFromRgsz( rgszPath );
  39. RgszFree( rgszPath );
  40. }
  41. return szList;
  42. }
  43. //*************************************************************************
  44. //
  45. // RGSZ management
  46. //
  47. //*************************************************************************
  48. RGSZ
  49. RgszAlloc(
  50. DWORD Size
  51. )
  52. {
  53. RGSZ rgsz = NULL;
  54. DWORD i;
  55. if ( Size > 0 ) {
  56. if ( (rgsz = SAlloc( Size * sizeof(SZ) )) ) {
  57. for ( i=0; i<Size; i++ ) {
  58. rgsz[i] = NULL;
  59. }
  60. }
  61. }
  62. return rgsz;
  63. }
  64. RGSZ
  65. RgszFromPath(
  66. SZ szPath
  67. )
  68. /*
  69. * History: SUNILP Modified to return NULL elements and also semicolons at
  70. * the end.
  71. */
  72. {
  73. RGSZ rgsz;
  74. SZ pBegin, pLast, pEnd;
  75. SZ sz;
  76. BOOL fOkay = fTrue;
  77. if (rgsz = RgszAlloc(1)) {
  78. pBegin = szPath;
  79. pLast = pBegin + strlen( pBegin );
  80. do {
  81. pEnd = strchr(pBegin, ';' );
  82. if ( pEnd == NULL ) {
  83. pEnd = pBegin + strlen( pBegin );
  84. }
  85. *pEnd = '\0';
  86. if ( !(sz = SzDup( pBegin )) ) {
  87. fOkay = fFalse;
  88. break;
  89. }
  90. if ( !RgszAdd( &rgsz, sz ) ) {
  91. SFree( sz );
  92. fOkay = fFalse;
  93. break;
  94. }
  95. pBegin = pEnd+1;
  96. } while ( pBegin <= pLast );
  97. if ( !fOkay ) {
  98. RgszFree( rgsz );
  99. rgsz = NULL;
  100. }
  101. }
  102. return rgsz;
  103. }
  104. VOID
  105. RgszFree(
  106. RGSZ rgsz
  107. )
  108. {
  109. INT i;
  110. for (i = 0; rgsz[i]; i++ ) {
  111. SFree( rgsz[i] );
  112. }
  113. SFree(rgsz);
  114. }
  115. VOID
  116. RgszFreeCount(
  117. RGSZ rgsz,
  118. DWORD Count
  119. )
  120. {
  121. DWORD i;
  122. for (i = 0; i<Count; i++ ) {
  123. if ( rgsz[i] ) {
  124. SFree( rgsz[i] );
  125. }
  126. }
  127. SFree(rgsz);
  128. }
  129. DWORD
  130. RgszCount(
  131. RGSZ rgsz
  132. )
  133. /*
  134. Return the number of elements in an RGSZ
  135. */
  136. {
  137. DWORD i ;
  138. for ( i = 0 ; rgsz[i] ; i++ ) ;
  139. return i ;
  140. }
  141. BOOL
  142. RgszAdd(
  143. RGSZ *prgsz,
  144. SZ sz
  145. )
  146. {
  147. INT i;
  148. RGSZ rgszNew;
  149. for ( i=0; (*prgsz)[i]; i++ ) {
  150. }
  151. rgszNew = SRealloc( *prgsz, (i+2)*sizeof(SZ) );
  152. if ( rgszNew ) {
  153. rgszNew[i] = sz;
  154. rgszNew[i+1] = NULL;
  155. *prgsz = rgszNew;
  156. return fTrue;
  157. }
  158. return fFalse;
  159. }
  160. #define cListItemsMax 0x07FF
  161. #define cbItemMax (CB)0x2000
  162. //
  163. // #ifdef'ed out: overlapped with oldexe
  164. //
  165. #if 0
  166. /*
  167. ** Purpose:
  168. ** Determines if a string is a list value.
  169. ** Arguments:
  170. ** szValue: non-NULL, zero terminated string to be tested.
  171. ** Returns:
  172. ** fTrue if a list; fFalse otherwise.
  173. **
  174. **************************************************************************/
  175. BOOL FListValue(szValue)
  176. SZ szValue;
  177. {
  178. if (*szValue++ != '{')
  179. return(fFalse);
  180. while (*szValue != '}' && *szValue != '\0')
  181. {
  182. if (*szValue++ != '"')
  183. return(fFalse);
  184. while (*szValue != '\0')
  185. {
  186. if (*szValue != '"')
  187. szValue = SzNextChar(szValue);
  188. else if (*(szValue + 1) == '"')
  189. szValue += 2;
  190. else
  191. break;
  192. }
  193. if (*szValue++ != '"')
  194. return(fFalse);
  195. if (*szValue == ',')
  196. if (*(++szValue) == '}')
  197. return(fFalse);
  198. }
  199. if (*szValue != '}')
  200. return(fFalse);
  201. return(fTrue);
  202. }
  203. ""
  204. #define cbListMax (CB)0x2000
  205. /*
  206. ** Purpose:
  207. ** Converts an RGSZ into a list value.
  208. ** Arguments:
  209. ** rgsz: non-NULL, NULL-terminated array of zero-terminated strings to
  210. ** be converted.
  211. ** Returns:
  212. ** NULL if an error occurred.
  213. ** Non-NULL SZ if the conversion was successful.
  214. **
  215. **************************************************************************/
  216. SZ SzListValueFromRgsz(rgsz)
  217. RGSZ rgsz;
  218. {
  219. SZ szValue;
  220. SZ szAddPoint;
  221. SZ szItem;
  222. BOOL fFirstItem = fTrue;
  223. //ChkArg(rgsz != (RGSZ)NULL, 1, (SZ)NULL);
  224. if ((szAddPoint = szValue = (SZ)SAlloc(cbListMax)) == (SZ)NULL)
  225. return((SZ)NULL);
  226. *szAddPoint++ = '{';
  227. while ((szItem = *rgsz) != (SZ)NULL)
  228. {
  229. if (fFirstItem)
  230. fFirstItem = fFalse;
  231. else
  232. *szAddPoint++ = ',';
  233. *szAddPoint++ = '"';
  234. while (*szItem != '\0')
  235. {
  236. if (*szItem == '"')
  237. {
  238. *szAddPoint++ = '"';
  239. *szAddPoint++ = '"';
  240. szItem++;
  241. }
  242. else
  243. {
  244. SZ szNext = SzNextChar(szItem);
  245. while (szItem < szNext)
  246. *szAddPoint++ = *szItem++;
  247. }
  248. }
  249. *szAddPoint++ = '"';
  250. rgsz++;
  251. }
  252. *szAddPoint++ = '}';
  253. *szAddPoint = '\0';
  254. //AssertRet(strlen(szValue) < cbListMax, (SZ)NULL);
  255. szItem = SzDup(szValue);
  256. SFree(szValue);
  257. return(szItem);
  258. }
  259. /*
  260. ** Purpose:
  261. ** Converts a list value into an RGSZ.
  262. ** Arguments:
  263. ** szListValue: non-NULL, zero terminated string to be converted.
  264. ** Returns:
  265. ** NULL if an error occurred.
  266. ** Non-NULL RGSZ if the conversion was successful.
  267. **
  268. **************************************************************************/
  269. RGSZ RgszFromSzListValue(szListValue)
  270. SZ szListValue;
  271. {
  272. USHORT cItems;
  273. SZ szCur;
  274. RGSZ rgsz;
  275. if (!FListValue(szListValue))
  276. {
  277. if ((rgsz = (RGSZ)SAlloc((CB)(2 * sizeof(SZ)))) == (RGSZ)NULL ||
  278. (rgsz[0] = SzDup(szListValue)) == (SZ)NULL)
  279. return((RGSZ)NULL);
  280. rgsz[1] = (SZ)NULL;
  281. return(rgsz);
  282. }
  283. if ((rgsz = (RGSZ)SAlloc((CB)((cListItemsMax + 1) * sizeof(SZ)))) ==
  284. (RGSZ)NULL)
  285. return((RGSZ)NULL);
  286. cItems = 0;
  287. szCur = szListValue + 1;
  288. while (*szCur != '}' &&
  289. *szCur != '\0' &&
  290. cItems < cListItemsMax)
  291. {
  292. SZ szValue;
  293. SZ szAddPoint;
  294. if( *szCur != '"' ) {
  295. return( (RGSZ) NULL );
  296. }
  297. szCur++;
  298. if ((szAddPoint = szValue = (SZ)SAlloc(cbItemMax)) == (SZ)NULL)
  299. {
  300. rgsz[cItems] = (SZ)NULL;
  301. RgszFree(rgsz);
  302. return((RGSZ)NULL);
  303. }
  304. while (*szCur != '\0')
  305. {
  306. if (*szCur == '"')
  307. {
  308. if (*(szCur + 1) != '"')
  309. break;
  310. szCur += 2;
  311. *szAddPoint++ = '"';
  312. }
  313. else
  314. {
  315. SZ szNext = SzNextChar(szCur);
  316. while (szCur < szNext)
  317. *szAddPoint++ = *szCur++;
  318. }
  319. }
  320. *szAddPoint = '\0';
  321. if (*szCur++ != '"' ||
  322. lstrlen(szValue) >= cbItemMax ||
  323. (szAddPoint = SzDup(szValue)) == (SZ)NULL)
  324. {
  325. SFree(szValue);
  326. rgsz[cItems] = (SZ)NULL;
  327. RgszFree(rgsz);
  328. return((RGSZ)NULL);
  329. }
  330. SFree(szValue);
  331. if (*szCur == ',')
  332. szCur++;
  333. rgsz[cItems++] = szAddPoint;
  334. }
  335. rgsz[cItems] = (SZ)NULL;
  336. if (*szCur != '}' || cItems >= cListItemsMax)
  337. {
  338. RgszFree(rgsz);
  339. return((RGSZ)NULL);
  340. }
  341. if (cItems < cListItemsMax)
  342. rgsz = (RGSZ)SRealloc((PB)rgsz, (CB)((cItems + 1) * sizeof(SZ)));
  343. return(rgsz);
  344. }
  345. LPSTR
  346. RgszToMultiSz(
  347. IN RGSZ rgsz
  348. )
  349. {
  350. ULONG Size;
  351. ULONG Str;
  352. LPSTR MultiSz;
  353. //
  354. // First determine the size of the block to hold the multisz.
  355. //
  356. Size = 0;
  357. Str = 0;
  358. while(rgsz[Str]) {
  359. Size += strlen(rgsz[Str++]) + 1;
  360. }
  361. Size++; // for extra NUL to terminate the multisz.
  362. MultiSz = SAlloc(Size);
  363. if(MultiSz == NULL) {
  364. return(NULL);
  365. }
  366. Str = 0;
  367. Size = 0;
  368. while(rgsz[Str]) {
  369. lstrcpy(MultiSz + Size, rgsz[Str]);
  370. Size += lstrlen(rgsz[Str++]) + 1;
  371. }
  372. MultiSz[Size] = 0;
  373. return(MultiSz);
  374. }
  375. #endif
  376. // ***************************************************************************
  377. //
  378. // Text file manipulation functions
  379. //
  380. // ***************************************************************************
  381. //
  382. // Opens a text file
  383. //
  384. BOOL
  385. TextFileOpen(
  386. IN SZ szFile,
  387. OUT PTEXTFILE pTextFile
  388. )
  389. {
  390. BOOL fOkay = fFalse;
  391. pTextFile->Handle = CreateFile( szFile,
  392. GENERIC_READ,
  393. FILE_SHARE_READ | FILE_SHARE_WRITE,
  394. NULL,
  395. OPEN_EXISTING,
  396. 0,
  397. NULL );
  398. if ( pTextFile->Handle != INVALID_HANDLE_VALUE ) {
  399. pTextFile->UserBufferSize = USER_BUFFER_SIZE;
  400. pTextFile->CharsLeftInBuffer = 0;
  401. pTextFile->NextChar = pTextFile->Buffer;
  402. fOkay = fTrue;
  403. }
  404. return fOkay;
  405. }
  406. //
  407. // Closes a text file
  408. //
  409. BOOL
  410. TextFileClose (
  411. OUT PTEXTFILE pTextFile
  412. )
  413. {
  414. CloseHandle( pTextFile->Handle );
  415. return fTrue;
  416. }
  417. //
  418. // Reads one character
  419. //
  420. INT
  421. TextFileReadChar (
  422. OUT PTEXTFILE pTextFile
  423. )
  424. {
  425. //
  426. // Check to see if buffer is empty
  427. //
  428. if (pTextFile->CharsLeftInBuffer == 0) {
  429. //
  430. // Check to see if a fill of the buffer fails
  431. //
  432. if (!ReadFile (pTextFile->Handle, pTextFile->Buffer, BUFFER_SIZE, &pTextFile->CharsLeftInBuffer, NULL)) {
  433. //
  434. // Fill failed, indicate buffer is empty and return EOF
  435. //
  436. pTextFile->CharsLeftInBuffer = 0;
  437. return -1;
  438. }
  439. //
  440. // Check to see if nothing read
  441. //
  442. if (pTextFile->CharsLeftInBuffer == 0) {
  443. return -1;
  444. }
  445. pTextFile->NextChar = pTextFile->Buffer;
  446. }
  447. //
  448. // Buffer has pTextFile->CharsLeftInBuffer chars left starting at
  449. // pTextFile->NextChar
  450. //
  451. pTextFile->CharsLeftInBuffer--;
  452. return *pTextFile->NextChar++;
  453. }
  454. //
  455. // Read one line
  456. //
  457. BOOL
  458. TextFileReadLine (
  459. OUT PTEXTFILE pTextFile
  460. )
  461. {
  462. PCHAR p;
  463. PCHAR pEnd;
  464. INT c;
  465. //
  466. // Set pointer to beginning of output buffer
  467. //
  468. p = pTextFile->UserBuffer;
  469. pEnd = p + pTextFile->UserBufferSize - 1;
  470. //
  471. // read in chars, ignoring \r until buffer is full, \n, or \0
  472. //
  473. while (p < pEnd) {
  474. c = TextFileReadChar (pTextFile);
  475. if ((CHAR)c == '\r') {
  476. continue;
  477. }
  478. if (c == -1 || (CHAR)c == '\n') {
  479. break;
  480. }
  481. *p++ = (CHAR)c;
  482. }
  483. *p = '\0';
  484. return ( (c != -1) || (strlen (pTextFile->UserBuffer) != 0) );
  485. }
  486. //
  487. // Skip blanks
  488. //
  489. SZ
  490. TextFileSkipBlanks(
  491. IN SZ sz
  492. )
  493. {
  494. size_t Idx;
  495. Idx = strspn( sz, " \t" );
  496. if ( Idx < strlen(sz) ) {
  497. return sz + Idx;
  498. }
  499. return NULL;
  500. }
  501. static long cvtToLong ( SZ sz )
  502. {
  503. static char * chHex = "0123456789ABCDEF" ;
  504. static char * chDec = "0123456789" ;
  505. char * chTbl = chDec ;
  506. int base = 10 ;
  507. long result ;
  508. BOOL ok = FALSE ;
  509. while ( *sz == ' ' )
  510. sz++ ;
  511. if ( sz[0] == '0' && toupper( sz[1] ) == 'X' )
  512. {
  513. base = 16 ;
  514. chTbl = chHex ;
  515. sz++ ;
  516. }
  517. for ( result = 0 ; *sz ; sz++, ok = TRUE )
  518. {
  519. char * pch = strchr( chTbl, toupper( *sz ) ) ;
  520. if ( pch == NULL )
  521. break ;
  522. result = result * base + (long)(pch - chTbl) ;
  523. }
  524. return ok ? result : -1 ;
  525. }
  526. typedef struct {
  527. SZ szItem ;
  528. DWORD dwIndex ;
  529. LONG lValue ;
  530. } RGSZ_INT_SORT ;
  531. static BOOL bQsortAscending ;
  532. static BOOL bQsortCaseSens ;
  533. static BOOL bQsortNumeric ;
  534. // Compare two RGSZ_INT_SORT items
  535. static int __cdecl compareRgi ( const void * p1, const void * p2 )
  536. {
  537. INT i ;
  538. RGSZ_INT_SORT * pr1 = (RGSZ_INT_SORT *) p1 ;
  539. RGSZ_INT_SORT * pr2 = (RGSZ_INT_SORT *) p2 ;
  540. SZ sz1 = pr1->szItem ;
  541. SZ sz2 = pr2->szItem ;
  542. if ( bQsortNumeric )
  543. {
  544. i = pr1->lValue < pr2->lValue
  545. ? -1
  546. : (pr1->lValue != pr2->lValue) ;
  547. }
  548. else
  549. if ( bQsortCaseSens )
  550. {
  551. i = lstrcmp( sz1, sz2 ) ;
  552. }
  553. else
  554. {
  555. i = lstrcmpi( sz1, sz2 ) ;
  556. }
  557. if ( ! bQsortAscending )
  558. i *= -1 ;
  559. return i ;
  560. }
  561. static SZ szFromDword ( DWORD dw )
  562. {
  563. char chBuffer [50] ;
  564. SZ szInt ;
  565. sprintf( chBuffer, "%ld", dw ) ;
  566. szInt = SAlloc( strlen( chBuffer ) + 3 ) ;
  567. if ( szInt == NULL )
  568. return NULL ;
  569. strcpy( szInt, chBuffer ) ;
  570. return szInt ;
  571. }
  572. SZ
  573. GenerateSortedIntList (
  574. IN SZ szList,
  575. BOOL bAscending,
  576. BOOL bCaseSens
  577. )
  578. /*
  579. Given an INF list in standard form, return a list of its element
  580. numbers (1-based) as they would occur if the list were sorted.
  581. Sort the list as numeric (decimal or hex) if "case sensitive" is
  582. FALSE and EVERY list item can be converted to a valid non-empty
  583. number (i.e., at least one valid digit). Hex values must be
  584. prefixed with "0x" or "0X".
  585. Algorithm: Create an RGSZ from the list
  586. Create an array containing ordered pairs; one pair
  587. member points to the SZ in question, and the other
  588. has the number of the element in its original position.
  589. Use qsort and lstrcmp{i}() to sort the array.
  590. Generate a new RGSZ using ASCII decimal versions of the
  591. integer element position.
  592. Convert the RGSZ result into an INF list.
  593. Return it.
  594. For example: {"dog","cat","bird"}
  595. results in: {"3","2","1"}
  596. */
  597. {
  598. RGSZ rgszIn = NULL ;
  599. RGSZ rgszIntList = NULL ;
  600. SZ szResult = NULL ;
  601. DWORD dwCount, dwi, dwNumeric ;
  602. RGSZ_INT_SORT * prgiSort = NULL ;
  603. do // Pseudo loop
  604. {
  605. // Convert the input list to RGSZ (list of strings) format
  606. rgszIn = RgszFromSzListValue( szList ) ;
  607. if ( rgszIn == NULL )
  608. break ;
  609. // Count the number of items; return the empty list if
  610. // input list is empty.
  611. if ( (dwCount = RgszCount( rgszIn )) == 0 )
  612. {
  613. szResult = SzListValueFromRgsz( rgszIn ) ;
  614. break ;
  615. }
  616. // Allocate the intermediate sort array
  617. prgiSort = (RGSZ_INT_SORT *) SAlloc( dwCount * sizeof (RGSZ_INT_SORT) ) ;
  618. if ( prgiSort == NULL )
  619. break ;
  620. // Fill the sort array with string pointers and indices
  621. // Check to see if every entry can be converted to numbers.
  622. for ( dwNumeric = dwi = 0 ; dwi < dwCount ; dwi++ )
  623. {
  624. prgiSort[dwi].szItem = rgszIn[dwi] ;
  625. prgiSort[dwi].dwIndex = dwi + 1 ;
  626. if ( ! bCaseSens )
  627. {
  628. if ( (prgiSort[dwi].lValue = cvtToLong( rgszIn[dwi] )) >= 0 )
  629. dwNumeric++ ;
  630. }
  631. }
  632. // Sort
  633. bQsortAscending = bAscending ;
  634. bQsortCaseSens = bCaseSens ;
  635. bQsortNumeric = dwNumeric == dwCount ;
  636. qsort( (PVOID) prgiSort, dwCount, sizeof *prgiSort, compareRgi ) ;
  637. // Allocate an RGSZ to convert the DWORDs into an INF list
  638. rgszIntList = SAlloc( sizeof (SZ) * (dwCount + 1) ) ;
  639. if ( rgszIntList == NULL )
  640. break ;
  641. // Fill the RGSZ with string representations of the integers.
  642. for ( dwi = 0 ; dwi < dwCount ; dwi++ )
  643. {
  644. rgszIntList[dwi] = szFromDword( prgiSort[dwi].dwIndex ) ;
  645. if ( rgszIntList[dwi] == NULL )
  646. break ;
  647. }
  648. // Delimit the new RGSZ
  649. rgszIntList[dwi] = NULL ;
  650. if ( dwi < dwCount )
  651. break ;
  652. // Convert to INF list format
  653. szResult = SzListValueFromRgsz( rgszIntList ) ;
  654. } while ( FALSE ) ;
  655. if ( rgszIn )
  656. {
  657. RgszFree( rgszIn ) ;
  658. }
  659. if ( rgszIntList )
  660. {
  661. RgszFree( rgszIntList ) ;
  662. }
  663. if ( prgiSort )
  664. {
  665. SFree(prgiSort);
  666. }
  667. return szResult ;
  668. }