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.

1029 lines
26 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1997-1999 Microsoft Corporation
  4. // All rights reserved.
  5. //
  6. // File Name:
  7. // settngs.c
  8. //
  9. // Description:
  10. //
  11. // This file contains the support routines to deal with settings
  12. // in answer files.
  13. //
  14. // This wizard does not do in-place editting of answer files.
  15. // These apis must be used to write to the answer file.
  16. //
  17. // For most settings, the job is easy. Call SettingQueue_AddSetting,
  18. // and specify the [SectionName] KeyName=Value and which queue (the
  19. // answer file or the .udf for the case of multiple computer names).
  20. // Check common\savefile.c for tons of examples.
  21. //
  22. // Be aware that on an edit, these queues are initialized with the
  23. // settings loaded from the original file.
  24. //
  25. // When the user edits a script and pushes NEXT on the NewOrEdit
  26. // page, the settings in the existing answer file and .udf are loaded
  27. // onto the OrignalAnswerFileQueue and the OriginalUdfQueue.
  28. //
  29. // When the user pushes NEXT on the SaveScript page, the following
  30. // ocurrs. (the below code is in common\save.c)
  31. //
  32. // Empty(AnswerFileQueue)
  33. // Empty(UdfQueue)
  34. //
  35. // Copy original answer file settings to the AnswerFileQueue
  36. // Copy original .udf settings to the UdfQueue
  37. //
  38. // Call common\savefile.c to enqueue all new settings
  39. //
  40. // Flush(AnswerFileQueue)
  41. // Flush(UdfQueue)
  42. //
  43. // To support "Do not specify this setting", you must call
  44. // SettingQueue_AddSetting with an lpValue of "". SettingQueue_Flush
  45. // writes nothing if lpValue == "". Failure to do this results in
  46. // the original setting being preserved in the outputed answer file.
  47. //
  48. // You must also ensure that mutually excluded settings are cleared
  49. // by setting the lpValue to "". For example, if JoinWorkGroup=workgroup,
  50. // then, make sure to set JoinDomain="", CreateComputerAccount="" etc.
  51. //
  52. // A section can be marked as volatile. This is needed for the network
  53. // pages because many sections should be removed if (for example) the
  54. // user changes from CustomNet to TypicalNet. When the queue is flushed,
  55. // any sections still marked as volatile will not be written to the file.
  56. // Use SettingQueue_MarkVolatile to mark a section as such. Check
  57. // common\loadfile.c for examples.
  58. //
  59. // In contrast to in-place editing, being able to mark a section
  60. // as volatile at load time means that the answer file does not have
  61. // to be re-read to determine what should be removed at save time.
  62. //
  63. //----------------------------------------------------------------------------
  64. #include "pch.h"
  65. #include "settypes.h"
  66. //
  67. // Declare the queues
  68. //
  69. // AnswerFileQueue holds the settings to write
  70. // UdfQueue holds the settings in case of mulitple computers
  71. //
  72. // OrigAnswerFileQueue holds the settings loaded on an edit
  73. // OrigUdfFileQueue holds the settings loaded on an edit in the .udf
  74. //
  75. // The first 2 are "output queues"
  76. // The next 2 are "input queues"
  77. // The last is a queue for the HAL and SCSI OEM settings.
  78. //
  79. // First, we read the answer file and .udf at the NewOrEdit page and
  80. // place each setting on the Orig*Queue's.
  81. //
  82. // When user is way at the end of the wizard (SaveScript page), we
  83. // empty the AnswerFileQueue and UdfQueue and initialize it with a
  84. // copy of the original settings. This is all necessary because we
  85. // don't want to merge with garbage we previously put on the queue
  86. // if the user went back and forth in the wizard alot.
  87. //
  88. static LINKED_LIST AnswerFileQueue = { 0 };
  89. static LINKED_LIST UdfQueue = { 0 };
  90. static LINKED_LIST OrigAnswerFileQueue = { 0 };
  91. static LINKED_LIST OrigUdfQueue = { 0 };
  92. static LINKED_LIST TxtSetupOemQueue = { 0 };
  93. //
  94. // Local prototypes
  95. //
  96. SECTION_NODE *
  97. SettingQueue_AddSection(LPTSTR lpSection, QUEUENUM dwWhichQueue);
  98. static SECTION_NODE *FindQueuedSection(LPTSTR lpSection,
  99. QUEUENUM dwWhichQueue);
  100. VOID InsertNode(LINKED_LIST *pList, PVOID pNode);
  101. KEY_NODE* FindKey(LINKED_LIST *ListHead,
  102. LPTSTR lpKeyName);
  103. LINKED_LIST *SelectSettingQueue(QUEUENUM dwWhichQueue);
  104. static BOOL IsNecessaryToQuoteString(LPTSTR p);
  105. BOOL DoesSectionHaveKeys( SECTION_NODE *pSection );
  106. //----------------------------------------------------------------------------
  107. //
  108. // This section has the entry points for the wizard
  109. //
  110. //----------------------------------------------------------------------------
  111. //----------------------------------------------------------------------------
  112. //
  113. // Function: SettingQueue_AddSetting
  114. //
  115. // Purpose: Queues [section] key=value in internal structs.
  116. //
  117. // Arguments:
  118. // LPTSTR lpSection - name of section in .ini
  119. // LPTSTR lpKey - name of key in section
  120. // LPTSTR lpValue - value of setting
  121. // QUEUENUM dwWhichQueue - which settings queue
  122. //
  123. // Returns:
  124. // BOOL - fails only because of no memory
  125. //
  126. // Notes:
  127. //
  128. // - A lpValue = "" is interpreted to mean 'Do not write this setting'.
  129. //
  130. // - A lpKey = "" creates a [SectionName] header with no settings.
  131. //
  132. // - If the setting existed in the original answer file, it's value
  133. // is updated. An assert fires if the wizard tries to set the same
  134. // key twice.
  135. //
  136. //----------------------------------------------------------------------------
  137. BOOL SettingQueue_AddSetting(LPTSTR lpSection,
  138. LPTSTR lpKey,
  139. LPTSTR lpValue,
  140. QUEUENUM dwWhichQueue)
  141. {
  142. SECTION_NODE *pSectionNode;
  143. KEY_NODE *pKeyNode;
  144. //
  145. // You have to pass a section key and value. Section name cannot
  146. // be empty.
  147. //
  148. Assert(lpSection != NULL);
  149. Assert(lpKey != NULL);
  150. Assert(lpValue != NULL);
  151. Assert(lpSection[0]);
  152. //
  153. // See if a node for this section already exists. If not, create one.
  154. //
  155. pSectionNode = SettingQueue_AddSection(lpSection, dwWhichQueue);
  156. if ( pSectionNode == NULL )
  157. return FALSE;
  158. //
  159. // See if this key has already been set. If not, alloc a node and
  160. // set all of its fields except for the lpValue.
  161. //
  162. // If the node already exist, free the lpValue to make room for
  163. // the new value.
  164. //
  165. if ( lpKey[0] == _T('\0') ||
  166. (pKeyNode = FindKey( &pSectionNode->key_list, lpKey) ) == NULL ) {
  167. if ( (pKeyNode=malloc(sizeof(KEY_NODE))) == NULL )
  168. return FALSE;
  169. if ( (pKeyNode->lpKey = lstrdup(lpKey)) == NULL )
  170. {
  171. free(pKeyNode);
  172. return FALSE;
  173. }
  174. InsertNode(&pSectionNode->key_list, pKeyNode);
  175. } else {
  176. #if DBG
  177. //
  178. // If the wizard has already set this key once, assert.
  179. //
  180. if ( pKeyNode->bSetOnce ) {
  181. AssertMsg2(FALSE,
  182. "Section \"%S\" Key \"%S\" has already been set",
  183. lpSection, lpKey);
  184. }
  185. #endif
  186. free(pKeyNode->lpValue);
  187. }
  188. #if DBG
  189. //
  190. // If this is going to an output queue, mark this setting as
  191. // having already been set by the wizard.
  192. //
  193. // Note that when the input queue is copied to the output queue,
  194. // the copy function preserves this setting.
  195. //
  196. pKeyNode->bSetOnce = ( (dwWhichQueue == SETTING_QUEUE_ANSWERS) |
  197. (dwWhichQueue == SETTING_QUEUE_UDF) );
  198. #endif
  199. //
  200. // Put the (possibly new) value in
  201. //
  202. if ( (pKeyNode->lpValue = lstrdup(lpValue)) == NULL )
  203. return FALSE;
  204. return TRUE;
  205. }
  206. //----------------------------------------------------------------------------
  207. //
  208. // Function: SettingQueue_AddSection
  209. //
  210. // Purpose: Adds a section (by name) to either the answer file setting
  211. // queue, or the .udf queue.
  212. //
  213. // Returns: FALSE if out of memory
  214. //
  215. // Notes:
  216. //
  217. // - If the section is already on the given list, a pointer to it
  218. // is returned. Else a new one is created and put at the end of
  219. // the list.
  220. //
  221. //----------------------------------------------------------------------------
  222. SECTION_NODE *
  223. SettingQueue_AddSection(LPTSTR lpSection, QUEUENUM dwWhichQueue)
  224. {
  225. SECTION_NODE *pSectionNode;
  226. LINKED_LIST *pList;
  227. //
  228. // If it already exists, return a pointer to it.
  229. //
  230. // If we're modifying a section (or any of it's settings) on one
  231. // of the output queues, we must make sure that this section is not
  232. // marked volatile anymore.
  233. //
  234. pSectionNode = FindQueuedSection(lpSection, dwWhichQueue);
  235. if ( pSectionNode != NULL ) {
  236. if ( dwWhichQueue == SETTING_QUEUE_ANSWERS ||
  237. dwWhichQueue == SETTING_QUEUE_UDF ) {
  238. pSectionNode->bVolatile = FALSE;
  239. }
  240. return pSectionNode;
  241. }
  242. //
  243. // Create the new section node. They always begin not volatile.
  244. // Callers use MarkVolatile to mark a volatile section on in input
  245. // queue at answer file load time.
  246. //
  247. if ( (pSectionNode=malloc(sizeof(SECTION_NODE))) == NULL )
  248. return FALSE;
  249. if ( (pSectionNode->lpSection = lstrdup(lpSection)) == NULL )
  250. {
  251. free(pSectionNode);
  252. return FALSE;
  253. }
  254. pSectionNode->bVolatile = FALSE;
  255. memset(&pSectionNode->key_list, 0, sizeof(pSectionNode->key_list));
  256. //
  257. // Put this node at the tail of the correct list.
  258. //
  259. pList = SelectSettingQueue(dwWhichQueue);
  260. if ( pList != NULL )
  261. InsertNode(pList, pSectionNode);
  262. return pSectionNode;
  263. }
  264. //----------------------------------------------------------------------------
  265. //
  266. // Function: SettingQueue_RemoveSection
  267. //
  268. // Purpose:
  269. //
  270. // Returns:
  271. //
  272. // Notes:
  273. //
  274. //----------------------------------------------------------------------------
  275. VOID
  276. SettingQueue_RemoveSection( LPTSTR lpSection, QUEUENUM dwWhichQueue )
  277. {
  278. LINKED_LIST *pList;
  279. KEY_NODE *pKeyNode;
  280. SECTION_NODE *pSectionNode;
  281. SECTION_NODE *pPreviousSectionNode = NULL;
  282. pList = SelectSettingQueue( dwWhichQueue );
  283. if (pList == NULL)
  284. return;
  285. pSectionNode = (SECTION_NODE *) pList->Head;
  286. //
  287. // Iterate through all the sections.
  288. //
  289. while( pSectionNode ) {
  290. KEY_NODE *pTempKeyNode;
  291. //
  292. // If this section matches the one we are looking for, delete it.
  293. // Else advance to the next section.
  294. //
  295. if( lstrcmpi( pSectionNode->lpSection, lpSection ) == 0 ) {
  296. for( pKeyNode = (KEY_NODE *) pSectionNode->key_list.Head; pKeyNode; ) {
  297. free( pKeyNode->lpKey );
  298. free( pKeyNode->lpValue );
  299. pTempKeyNode = (KEY_NODE *) pKeyNode->Header.next;
  300. free( pKeyNode );
  301. pKeyNode = pTempKeyNode;
  302. }
  303. //
  304. // Special case if we are at the head of the list
  305. //
  306. if( pPreviousSectionNode == NULL ) {
  307. pList->Head = pSectionNode->Header.next;
  308. free( pSectionNode->lpSection );
  309. pSectionNode = (SECTION_NODE *) pList->Head;
  310. }
  311. else {
  312. pPreviousSectionNode->Header.next = pSectionNode->Header.next;
  313. free( pSectionNode->lpSection );
  314. pSectionNode = (SECTION_NODE *) pPreviousSectionNode->Header.next;
  315. }
  316. }
  317. else {
  318. pPreviousSectionNode = pSectionNode;
  319. pSectionNode = (SECTION_NODE *) pSectionNode->Header.next;
  320. }
  321. }
  322. }
  323. //----------------------------------------------------------------------------
  324. //
  325. // Function: SettingQueue_MarkVolatile
  326. //
  327. // Purpose: Marks or clears the Volatile flag for a section. Typically
  328. // one marks volatile sections at load time on the "Orig" queues.
  329. //
  330. // Later, at save time, the volatile flag gets cleared if you
  331. // ever call *_AddSetting() *_AddSection().
  332. //
  333. //----------------------------------------------------------------------------
  334. VOID
  335. SettingQueue_MarkVolatile(LPTSTR lpSection,
  336. QUEUENUM dwWhichQueue)
  337. {
  338. SECTION_NODE *p = FindQueuedSection(lpSection, dwWhichQueue);
  339. if ( p == NULL )
  340. return;
  341. p->bVolatile = TRUE;
  342. }
  343. //----------------------------------------------------------------------------
  344. //
  345. // Function: SettingQueue_Empty
  346. //
  347. // Purpose: This function emptys the queue of settings. Since the user
  348. // can go BACK and re-save a file, it must be emptied before
  349. // trying to save it again.
  350. //
  351. // Arguments: VOID
  352. //
  353. // Returns: VOID
  354. //
  355. //----------------------------------------------------------------------------
  356. VOID SettingQueue_Empty(QUEUENUM dwWhichQueue)
  357. {
  358. LINKED_LIST *pList;
  359. SECTION_NODE *p, *pn;
  360. KEY_NODE *q, *qn;
  361. //
  362. // Point to the proper queue to empty and start at the head of it
  363. //
  364. pList = SelectSettingQueue(dwWhichQueue);
  365. if (pList == NULL)
  366. return;
  367. p = (SECTION_NODE *) pList->Head;
  368. //
  369. // For each SECTION_NODE, walk down each KEY_NODE. Unlink and free all.
  370. //
  371. while ( p ) {
  372. for ( q = (KEY_NODE *) p->key_list.Head; q; ) {
  373. free(q->lpKey);
  374. free(q->lpValue);
  375. qn=(KEY_NODE *) q->Header.next;
  376. free(q);
  377. q=qn;
  378. }
  379. free(p->lpSection);
  380. pn=(SECTION_NODE *) p->Header.next;
  381. free(p);
  382. p=pn;
  383. }
  384. //
  385. // Zero out the head & tail pointers
  386. //
  387. pList->Head = NULL;
  388. pList->Tail = NULL;
  389. }
  390. //----------------------------------------------------------------------------
  391. //
  392. // Function: SettingQueue_Flush
  393. //
  394. // Purpose: This function is called (by the wizard) once all the settings
  395. // have been queued.
  396. //
  397. // Arguments:
  398. // LPTSTR lpFileName - name of file to create/edit
  399. // DWORD dwWhichQueue - which queue, answers file, .udf, ...
  400. //
  401. // Returns:
  402. // BOOL - success
  403. //
  404. //----------------------------------------------------------------------------
  405. BOOL
  406. SettingQueue_Flush(LPTSTR lpFileName,
  407. QUEUENUM dwWhichQueue)
  408. {
  409. LINKED_LIST *pList;
  410. SECTION_NODE *pSection;
  411. KEY_NODE *pKey;
  412. TCHAR Buffer[MAX_INILINE_LEN];
  413. FILE *fp;
  414. INT BufferSize = sizeof(Buffer) / sizeof(TCHAR);
  415. HRESULT hrPrintf;
  416. //
  417. // Point to the proper queue to flush
  418. //
  419. pList = SelectSettingQueue(dwWhichQueue);
  420. if (pList == NULL)
  421. return FALSE;
  422. pSection = (SECTION_NODE *) pList->Head;
  423. //
  424. // Start writing the file
  425. //
  426. if( ( fp = My_fopen( lpFileName, _T("w") ) ) == NULL ) {
  427. return( FALSE );
  428. }
  429. if( My_fputs( _T(";SetupMgrTag\n"), fp ) == _TEOF ) {
  430. My_fclose( fp );
  431. return( FALSE );
  432. }
  433. //
  434. // For each section ...
  435. //
  436. for ( pSection = (SECTION_NODE *) pList->Head;
  437. pSection;
  438. pSection = (SECTION_NODE *) pSection->Header.next ) {
  439. //
  440. // We don't write out sections that are still marked volatile.
  441. //
  442. if ( pSection->bVolatile )
  443. continue;
  444. //
  445. // Write the section name only if we will write keys below it
  446. //
  447. // ISSUE-2002/02/28-stelo- this causes problems because we want to write out
  448. // some sections without keys, like:
  449. //
  450. //[NetServices]
  451. // MS_SERVER=params.MS_SERVER
  452. //
  453. //[params.MS_SERVER]
  454. //
  455. // How can we get around this?
  456. //
  457. if( DoesSectionHaveKeys( pSection ) ) {
  458. hrPrintf=StringCchPrintf(Buffer,
  459. AS(Buffer),
  460. _T("[%s]\n"),
  461. pSection->lpSection);
  462. }
  463. else {
  464. continue;
  465. }
  466. if( My_fputs( Buffer, fp ) == _TEOF ) {
  467. My_fclose( fp );
  468. return( FALSE );
  469. }
  470. //
  471. // Write out each key=value
  472. //
  473. for ( pKey = (KEY_NODE *) pSection->key_list.Head;
  474. pKey;
  475. pKey = (KEY_NODE *) pKey->Header.next ) {
  476. BOOL bQuoteKey = FALSE;
  477. BOOL bQuoteValue = FALSE;
  478. TCHAR *p;
  479. //
  480. // An empty value means to not write it
  481. //
  482. if ( pKey->lpValue[0] == _T('\0') )
  483. continue;
  484. //
  485. // Double-quote the value if it has white-space and is not
  486. // already quoted
  487. //
  488. bQuoteKey = IsNecessaryToQuoteString( pKey->lpKey );
  489. bQuoteValue = IsNecessaryToQuoteString( pKey->lpValue );
  490. //
  491. // Put the key we want into Buffer
  492. // ISSUE-2002/02/28-stelo- text might get truncated here, should we show a warning?
  493. Buffer[0] = _T('\0');
  494. if( pKey->lpKey[0] != _T('\0') ) {
  495. if ( bQuoteKey ) {
  496. hrPrintf=StringCchPrintf(Buffer,
  497. AS(Buffer),
  498. _T(" \"%s\"="),
  499. pKey->lpKey);
  500. }
  501. else {
  502. hrPrintf=StringCchPrintf(Buffer,
  503. AS(Buffer),
  504. _T(" %s="),
  505. pKey->lpKey);
  506. }
  507. }
  508. //
  509. // Put the value we want into Buffer paying attention to
  510. // whether we want quotes around the it or not.
  511. //
  512. if ( bQuoteValue ) {
  513. lstrcatn( Buffer, _T("\""), BufferSize );
  514. lstrcatn( Buffer, pKey->lpValue, BufferSize );
  515. lstrcatn( Buffer, _T("\""), BufferSize );
  516. lstrcatn( Buffer, _T("\n"), BufferSize );
  517. }
  518. else {
  519. lstrcatn( Buffer, pKey->lpValue, BufferSize );
  520. lstrcatn( Buffer, _T("\n"), BufferSize );
  521. }
  522. if( My_fputs( Buffer, fp ) == _TEOF ) {
  523. My_fclose( fp );
  524. return( FALSE );
  525. }
  526. }
  527. //
  528. // Write a blank line at the end of the section
  529. //
  530. hrPrintf=StringCchPrintf(Buffer, AS(Buffer), _T("\n"));
  531. if( My_fputs( Buffer, fp ) == _TEOF ) {
  532. My_fclose( fp );
  533. return( FALSE );
  534. }
  535. }
  536. My_fclose( fp );
  537. return( TRUE );
  538. }
  539. //----------------------------------------------------------------------------
  540. //
  541. // Function: SettingQueue_Copy
  542. //
  543. // Purpose: Copies one settings queue to another. Used to copy the
  544. // input queues to the output queues.
  545. //
  546. // Look at common\save.c
  547. //
  548. //----------------------------------------------------------------------------
  549. VOID
  550. SettingQueue_Copy(QUEUENUM dwFrom, QUEUENUM dwTo)
  551. {
  552. LINKED_LIST *pListFrom = SelectSettingQueue(dwFrom);
  553. SECTION_NODE *p, *pSectionNode;
  554. KEY_NODE *q;
  555. #if DBG
  556. KEY_NODE *pKeyNode;
  557. #endif
  558. if (pListFrom == NULL)
  559. return;
  560. for ( p = (SECTION_NODE *) pListFrom->Head;
  561. p;
  562. p = (SECTION_NODE *) p->Header.next ) {
  563. //
  564. // Add the section to the output queue
  565. //
  566. SettingQueue_AddSetting(p->lpSection,
  567. _T(""),
  568. _T(""),
  569. dwTo);
  570. pSectionNode = FindQueuedSection(p->lpSection, dwTo);
  571. for ( q = (KEY_NODE *) p->key_list.Head;
  572. q;
  573. q = (KEY_NODE *) q->Header.next ) {
  574. //
  575. // Add the key=value
  576. //
  577. SettingQueue_AddSetting(p->lpSection,
  578. q->lpKey,
  579. q->lpValue,
  580. dwTo);
  581. #if DBG
  582. //
  583. // Retain the bSetOnce flag
  584. //
  585. pKeyNode = FindKey(&pSectionNode->key_list, q->lpKey);
  586. if ( pKeyNode != NULL ) {
  587. pKeyNode->bSetOnce = q->bSetOnce;
  588. }
  589. #endif
  590. }
  591. //
  592. // Retain the bVolatile flag on the section node.
  593. //
  594. if ( pSectionNode != NULL ) {
  595. pSectionNode->bVolatile = p->bVolatile;
  596. }
  597. }
  598. }
  599. //----------------------------------------------------------------------------
  600. //
  601. // Internal support routines
  602. //
  603. //----------------------------------------------------------------------------
  604. //----------------------------------------------------------------------------
  605. //
  606. // Function: DoesSectionHaveKeys
  607. //
  608. // Purpose: Determines if a section has keys to be written out or not
  609. //
  610. // Arguments:
  611. // SECTION_NODE *pSection - the section to determine if it has keys or not
  612. //
  613. // Returns:
  614. // TRUE - if this section contains keys
  615. // FALSE - if this section does not contain keys
  616. //
  617. //----------------------------------------------------------------------------
  618. BOOL
  619. DoesSectionHaveKeys( SECTION_NODE *pSection ) {
  620. KEY_NODE *pKey;
  621. for ( pKey = (KEY_NODE *) pSection->key_list.Head;
  622. pKey;
  623. pKey = (KEY_NODE *) pKey->Header.next ) {
  624. if ( pKey->lpValue[0] != _T('\0') ) {
  625. return( TRUE );
  626. }
  627. }
  628. return( FALSE );
  629. }
  630. //----------------------------------------------------------------------------
  631. //
  632. // Function: IsNecessaryToQuoteString
  633. //
  634. // Purpose: Determines if a string is already quoted and if it is not quoted,
  635. // if a string has white space or not
  636. //
  637. // Arguments:
  638. // LPTSTR p - the string to be scanned
  639. //
  640. // Returns:
  641. // TRUE - if the string needs to be quoted
  642. // FALSE - if the string does not need to be quoted
  643. //
  644. //----------------------------------------------------------------------------
  645. static BOOL
  646. IsNecessaryToQuoteString( LPTSTR p )
  647. {
  648. LPTSTR pCommaSearch;
  649. //
  650. // See if it is already quoted
  651. // We only check if the first char is a quote because the last char may
  652. // not be a quote. Example: ComputerType = "HAL Friendly Name", OEM
  653. //
  654. if( *p == _T('"') )
  655. {
  656. return( FALSE );
  657. }
  658. //
  659. // If it contains a comma, then don't quote it except for the printer
  660. // command that contains rundll32. This is kind of a hack.
  661. // This prevents keys like:
  662. //
  663. // ComputerType = "HAL Friendly Name", OEM
  664. //
  665. // from being quoted.
  666. //
  667. if( ! _tcsstr( p, _T("rundll32") ) )
  668. {
  669. for( pCommaSearch = p; *pCommaSearch; pCommaSearch++ )
  670. {
  671. if( *pCommaSearch == _T(',') )
  672. {
  673. return( FALSE );
  674. }
  675. }
  676. }
  677. //
  678. // Look for white space
  679. //
  680. for ( ; *p; p++ )
  681. {
  682. if( iswspace(*p) )
  683. {
  684. return( TRUE );
  685. }
  686. }
  687. return( FALSE );
  688. }
  689. //----------------------------------------------------------------------------
  690. //
  691. // Function: FindQueuedSection (static)
  692. //
  693. // Purpose: Finds the SECTION_NODE on the global settings queue with
  694. // the given name.
  695. //
  696. // Arguments:
  697. // LPTSTR lpSection - name of section in .ini
  698. //
  699. // Returns:
  700. // SECTION_NODE * or NULL if it does not exist
  701. //
  702. // Notes:
  703. // - Searches are case insensitive
  704. //
  705. //----------------------------------------------------------------------------
  706. static SECTION_NODE *FindQueuedSection(LPTSTR lpSection,
  707. QUEUENUM dwWhichQueue)
  708. {
  709. SECTION_NODE *p;
  710. LINKED_LIST *pList;
  711. pList = SelectSettingQueue(dwWhichQueue);
  712. if (pList == NULL)
  713. return NULL;
  714. p = (SECTION_NODE *) pList->Head;
  715. if ( p == NULL )
  716. return NULL;
  717. do {
  718. if ( _tcsicmp(p->lpSection, lpSection) == 0 )
  719. break;
  720. p = (SECTION_NODE *) p->Header.next;
  721. } while ( p );
  722. return p;
  723. }
  724. //----------------------------------------------------------------------------
  725. //
  726. // Function: InsertNode
  727. //
  728. // Purpose: Puts the given node at the tail of the given list. All nodes
  729. // must begin with a NODE_HEADER.
  730. //
  731. // Returns: VOID
  732. //
  733. // Notes:
  734. // - Allocates no memory, only links the node in.
  735. //
  736. //----------------------------------------------------------------------------
  737. VOID InsertNode(LINKED_LIST *pList, PVOID pNode)
  738. {
  739. NODE_HEADER *pNode2 = (NODE_HEADER *) pNode;
  740. //
  741. // Put it at the tail
  742. //
  743. pNode2->next = NULL;
  744. if ( pList->Tail )
  745. pList->Tail->next = pNode2;
  746. pList->Tail = pNode2;
  747. //
  748. // In case its the first one onto the list, fixup the head
  749. //
  750. if ( ! pList->Head )
  751. pList->Head = pNode2;
  752. }
  753. //----------------------------------------------------------------------------
  754. //
  755. // Function: FindKey
  756. //
  757. // Purpose: Searches the given list of keynodes and finds one with the
  758. // given name.
  759. //
  760. // Arguments:
  761. // LPTSTR lpSection - name of section in .ini
  762. //
  763. // Returns:
  764. // SECTION_NODE * or NULL if it does not exist
  765. //
  766. // Notes:
  767. // - Searches are case insensitive
  768. //
  769. //----------------------------------------------------------------------------
  770. KEY_NODE* FindKey(LINKED_LIST *ListHead,
  771. LPTSTR lpKeyName)
  772. {
  773. KEY_NODE *p = (KEY_NODE *) ListHead->Head;
  774. if ( p == NULL )
  775. return NULL;
  776. do {
  777. if ( _tcsicmp(p->lpKey, lpKeyName) == 0 )
  778. break;
  779. p = (KEY_NODE *) p->Header.next;
  780. } while ( p );
  781. return p;
  782. }
  783. //----------------------------------------------------------------------------
  784. //
  785. // Function: SelectSettingQueue
  786. //
  787. // Purpose: Translates dwWhichQueue into a LINKED_LIST pointer.
  788. //
  789. // Returns: A pointer to one of the 5 settings queues we have.
  790. //
  791. //----------------------------------------------------------------------------
  792. LINKED_LIST *SelectSettingQueue(QUEUENUM dwWhichQueue)
  793. {
  794. switch ( dwWhichQueue ) {
  795. case SETTING_QUEUE_ANSWERS:
  796. return &AnswerFileQueue;
  797. case SETTING_QUEUE_UDF:
  798. return &UdfQueue;
  799. case SETTING_QUEUE_ORIG_ANSWERS:
  800. return &OrigAnswerFileQueue;
  801. case SETTING_QUEUE_ORIG_UDF:
  802. return &OrigUdfQueue;
  803. case SETTING_QUEUE_TXTSETUP_OEM:
  804. return &TxtSetupOemQueue;
  805. default:
  806. AssertMsg(FALSE, "Invalid dwWhichQueue");
  807. }
  808. return NULL;
  809. }