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.

2700 lines
57 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. parseini.c
  5. Abstract:
  6. This module implements functions to parse a .INI file
  7. Author:
  8. John Vert (jvert) 7-Oct-1993
  9. Revision History:
  10. John Vert (jvert) 7-Oct-1993 - largely lifted from splib\spinf.c
  11. --*/
  12. #include "parseini.h"
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <stdlib.h>
  16. #define SpFree(x)
  17. // what follows was alpar.h
  18. //
  19. // EXPORTED BY THE PARSER AND USED BY BOTH THE PARSER AND
  20. // THE INF HANDLING COMPONENTS
  21. //
  22. // typedefs exported
  23. //
  24. typedef struct _value {
  25. struct _value *pNext;
  26. PCHAR pName;
  27. #ifdef UNICODE
  28. PWCHAR pNameW;
  29. #endif
  30. } VALUE, *PVALUE;
  31. #define NUMBER_OF_INTERNAL_VALUES 10
  32. typedef struct _line {
  33. struct _line *pNext;
  34. PCHAR pName;
  35. PCHAR InternalValues[NUMBER_OF_INTERNAL_VALUES];
  36. #ifdef UNICODE
  37. PWCHAR pNameW;
  38. PWCHAR InternalValuesW[NUMBER_OF_INTERNAL_VALUES];
  39. #endif
  40. PVALUE pFirstExternalValue;
  41. } LINE, *PLINE;
  42. typedef struct _section {
  43. struct _section *pNext;
  44. PCHAR pName;
  45. #ifdef UNICODE
  46. PWCHAR pNameW;
  47. #endif
  48. PLINE pLine;
  49. } SECTION, *PSECTION;
  50. typedef struct _inf {
  51. PSECTION pSection;
  52. } INF, *PINF;
  53. //
  54. // Routines exported
  55. //
  56. PVOID
  57. ParseInfBuffer(
  58. PCHAR INFFile,
  59. PCHAR Buffer,
  60. ULONG Size,
  61. PULONG ErrorLine
  62. );
  63. //
  64. // DEFINES USED FOR THE PARSER INTERNALLY
  65. //
  66. //
  67. // typedefs used
  68. //
  69. typedef enum _tokentype {
  70. TOK_EOF,
  71. TOK_EOL,
  72. TOK_LBRACE,
  73. TOK_RBRACE,
  74. TOK_STRING,
  75. TOK_EQUAL,
  76. TOK_COMMA,
  77. TOK_ERRPARSE,
  78. TOK_ERRNOMEM
  79. } TOKENTYPE, *PTOKENTTYPE;
  80. typedef struct _token {
  81. TOKENTYPE Type;
  82. PCHAR pValue;
  83. } TOKEN, *PTOKEN;
  84. //
  85. // Routine defines
  86. //
  87. ARC_STATUS
  88. SpAppendSection(
  89. IN PCHAR pSectionName
  90. #ifdef UNICODE
  91. , IN PWCHAR pSectionNameW
  92. #endif
  93. );
  94. ARC_STATUS
  95. SpAppendLine(
  96. IN PCHAR pLineKey
  97. #ifdef UNICODE
  98. , IN PWCHAR pLineKeyW
  99. #endif
  100. );
  101. ARC_STATUS
  102. SpAppendValue(
  103. IN PCHAR pValueString
  104. #ifdef UNICODE
  105. , IN PWCHAR pValueStringW
  106. #endif
  107. );
  108. TOKEN
  109. SpGetToken(
  110. IN OUT PCHAR *Stream,
  111. IN PCHAR MaxStream
  112. );
  113. // Global added to provide INF filename for friendly error messages.
  114. PCHAR pchINFName = NULL;
  115. // what follows was alinf.c
  116. //
  117. // Internal Routine Declarations for freeing inf structure members
  118. //
  119. VOID
  120. FreeSectionList (
  121. IN PSECTION pSection
  122. );
  123. VOID
  124. FreeLineList (
  125. IN PLINE pLine
  126. );
  127. VOID
  128. FreeValueList (
  129. IN PVALUE pValue
  130. );
  131. //
  132. // Internal Routine declarations for searching in the INF structures
  133. //
  134. PCHAR
  135. SearchValueInLine(
  136. IN PLINE pLine,
  137. IN ULONG ValueIndex
  138. );
  139. PLINE
  140. SearchLineInSectionByKey(
  141. IN PSECTION pSection,
  142. IN PCHAR Key,
  143. OUT PULONG pOrdinal OPTIONAL
  144. );
  145. PLINE
  146. SearchLineInSectionByIndex(
  147. IN PSECTION pSection,
  148. IN ULONG LineIndex
  149. );
  150. PSECTION
  151. SearchSectionByName(
  152. IN PINF pINF,
  153. IN PCHAR SectionName
  154. );
  155. PCHAR
  156. ProcessForStringSubs(
  157. IN PINF pInf,
  158. IN PCHAR String
  159. );
  160. #ifdef UNICODE
  161. PWCHAR
  162. SearchValueInLineW(
  163. IN PLINE pLine,
  164. IN ULONG ValueIndex
  165. );
  166. PWCHAR
  167. ProcessForStringSubsW(
  168. IN PINF pInf,
  169. IN PWCHAR String
  170. );
  171. #endif
  172. //
  173. // ROUTINE DEFINITIONS
  174. //
  175. PCHAR
  176. SlGetIniValue(
  177. IN PVOID InfHandle,
  178. IN PCHAR SectionName,
  179. IN PCHAR KeyName,
  180. IN PCHAR Default
  181. )
  182. /*++
  183. Routine Description:
  184. Searches an INF handle for a given section/key value.
  185. Arguments:
  186. InfHandle - Supplies a handle returned by SlInitIniFile.
  187. SectionName - Supplies the name of the section to search
  188. KeyName - Supplies the name of the key whose value should be returned.
  189. Default - Supplies the default setting, returned if the specified key
  190. is not found.
  191. Return Value:
  192. Pointer to the value of the key, if the key is found
  193. Default, if the key is not found.
  194. --*/
  195. {
  196. PCHAR Value;
  197. Value = SlGetSectionKeyIndex(InfHandle,
  198. SectionName,
  199. KeyName,
  200. 0);
  201. if (Value==NULL) {
  202. Value = Default;
  203. }
  204. return(Value);
  205. }
  206. #ifdef UNICODE
  207. PWCHAR
  208. SlGetIniValueW(
  209. IN PVOID InfHandle,
  210. IN PCHAR SectionName,
  211. IN PCHAR KeyName,
  212. IN PWCHAR Default
  213. )
  214. /*++
  215. Routine Description:
  216. Searches an INF handle for a given section/key value.
  217. Arguments:
  218. InfHandle - Supplies a handle returned by SlInitIniFile.
  219. SectionName - Supplies the name of the section to search
  220. KeyName - Supplies the name of the key whose value should be returned.
  221. Default - Supplies the default setting, returned if the specified key
  222. is not found.
  223. Return Value:
  224. Pointer to the value of the key, if the key is found
  225. Default, if the key is not found.
  226. --*/
  227. {
  228. PWCHAR Value;
  229. Value = SlGetSectionKeyIndexW(InfHandle,
  230. SectionName,
  231. KeyName,
  232. 0);
  233. if (Value==NULL) {
  234. Value = Default;
  235. }
  236. return(Value);
  237. }
  238. #endif
  239. //
  240. // returns a handle to use for further inf parsing
  241. //
  242. ARC_STATUS
  243. SlInitIniFile(
  244. IN PCHAR DevicePath,
  245. IN ULONG DeviceId,
  246. IN PCHAR INFFile,
  247. OUT PVOID *pINFHandle,
  248. OUT PVOID *pINFBuffer OPTIONAL,
  249. OUT PULONG INFBufferSize OPTIONAL,
  250. OUT PULONG ErrorLine
  251. )
  252. /*++
  253. Routine Description:
  254. Arguments:
  255. Return Value:
  256. --*/
  257. {
  258. ARC_STATUS Status;
  259. ULONG DeviceID,FileID;
  260. PCHAR Buffer;
  261. ULONG Size, SizeRead;
  262. FILE_INFORMATION FileInfo;
  263. ULONG PageCount;
  264. ULONG ActualBase;
  265. *ErrorLine = BL_INF_FILE_ERROR;
  266. //
  267. // If required, open the device
  268. //
  269. if(DevicePath) {
  270. Status = ArcOpen(DevicePath,ArcOpenReadOnly,&DeviceID);
  271. if (Status != ESUCCESS) {
  272. return( Status );
  273. }
  274. } else {
  275. DeviceID = DeviceId;
  276. }
  277. //
  278. // Open the file
  279. //
  280. Status = BlOpen(DeviceID,INFFile,ArcOpenReadOnly,&FileID);
  281. if (Status != ESUCCESS) {
  282. // We report better error messages elsewhere
  283. // SlMessageBox(SL_FILE_LOAD_FAILED,INFFile,Status);
  284. pchINFName = NULL;
  285. goto xx0;
  286. } else {
  287. pchINFName = INFFile;
  288. }
  289. //
  290. // find out size of INF file
  291. //
  292. Status = BlGetFileInformation(FileID, &FileInfo);
  293. if (Status != ESUCCESS) {
  294. BlClose(FileID);
  295. goto xx0;
  296. }
  297. Size = FileInfo.EndingAddress.LowPart;
  298. //
  299. // Allocate a descriptor large enough to hold the entire file.
  300. // On x86 this has an unfortunate tendency to slam txtsetup.sif
  301. // into a free block at 1MB, which means the kernel can't be
  302. // loaded (it's linked for 0x100000 without relocations).
  303. // On x86 this has an unfortunate tendency to slam txtsetup.sif
  304. // into a free block at 1MB, which means the kernel can't be
  305. // loaded (it's linked for 0x100000 without relocations).
  306. //
  307. // (tedm) we're also seeing a similar problem on alphas now
  308. // because txtsetup.sif has grown too large, so this code has been
  309. // made non-conditional.
  310. //
  311. {
  312. PageCount = (ULONG)(ROUND_TO_PAGES(Size) >> PAGE_SHIFT);
  313. Status = BlAllocateDescriptor(LoaderOsloaderHeap,
  314. 0,
  315. PageCount,
  316. &ActualBase);
  317. }
  318. if (Status != ESUCCESS) {
  319. BlClose(FileID);
  320. goto xx0;
  321. }
  322. Buffer = (PCHAR)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
  323. //
  324. // read the file in
  325. //
  326. Status = BlRead(FileID, Buffer, Size, &SizeRead);
  327. if (Status != ESUCCESS) {
  328. BlClose(FileID);
  329. goto xx0;
  330. }
  331. if ( pINFBuffer != NULL ) {
  332. *pINFBuffer = Buffer;
  333. *INFBufferSize = SizeRead;
  334. }
  335. //
  336. // parse the file
  337. //
  338. if((*pINFHandle = ParseInfBuffer(INFFile, Buffer, SizeRead, ErrorLine)) == (PVOID)NULL) {
  339. Status = EBADF;
  340. } else {
  341. Status = ESUCCESS;
  342. }
  343. //
  344. // Clean up and return
  345. //
  346. BlClose(FileID);
  347. xx0:
  348. if(DevicePath) {
  349. ArcClose(DeviceID);
  350. }
  351. return( Status );
  352. }
  353. //
  354. // frees an INF Buffer
  355. //
  356. ARC_STATUS
  357. SpFreeINFBuffer (
  358. IN PVOID INFHandle
  359. )
  360. /*++
  361. Routine Description:
  362. Arguments:
  363. Return Value:
  364. --*/
  365. {
  366. PINF pINF;
  367. //
  368. // Valid INF Handle?
  369. //
  370. if (INFHandle == (PVOID)NULL) {
  371. return ESUCCESS;
  372. }
  373. //
  374. // cast the buffer into an INF structure
  375. //
  376. pINF = (PINF)INFHandle;
  377. FreeSectionList(pINF->pSection);
  378. //
  379. // free the inf structure too
  380. //
  381. SpFree(pINF);
  382. return( ESUCCESS );
  383. }
  384. VOID
  385. FreeSectionList (
  386. IN PSECTION pSection
  387. )
  388. /*++
  389. Routine Description:
  390. Arguments:
  391. Return Value:
  392. --*/
  393. {
  394. PSECTION Next;
  395. while(pSection) {
  396. Next = pSection->pNext;
  397. FreeLineList(pSection->pLine);
  398. if(pSection->pName) {
  399. SpFree(pSection->pName);
  400. }
  401. #ifdef UNICODE
  402. if(pSection->pNameW) {
  403. SpFree(pSection->pNameW);
  404. }
  405. #endif
  406. SpFree(pSection);
  407. pSection = Next;
  408. }
  409. }
  410. VOID
  411. FreeLineList (
  412. IN PLINE pLine
  413. )
  414. /*++
  415. Routine Description:
  416. Arguments:
  417. Return Value:
  418. --*/
  419. {
  420. PLINE Next;
  421. while(pLine) {
  422. Next = pLine->pNext;
  423. FreeValueList(pLine->pFirstExternalValue);
  424. if(pLine->pName) {
  425. SpFree(pLine->pName);
  426. }
  427. #ifdef UNICODE
  428. if(pLine->pNameW) {
  429. SpFree(pLine->pNameW);
  430. }
  431. #endif
  432. SpFree(pLine);
  433. pLine = Next;
  434. }
  435. }
  436. VOID
  437. FreeValueList (
  438. IN PVALUE pValue
  439. )
  440. /*++
  441. Routine Description:
  442. Arguments:
  443. Return Value:
  444. --*/
  445. {
  446. PVALUE Next;
  447. while(pValue) {
  448. Next = pValue->pNext;
  449. if(pValue->pName) {
  450. SpFree(pValue->pName);
  451. }
  452. #ifdef UNICODE
  453. if(pValue->pNameW) {
  454. SpFree(pValue->pNameW);
  455. }
  456. #endif
  457. SpFree(pValue);
  458. pValue = Next;
  459. }
  460. }
  461. //
  462. // searches for the existance of a particular section
  463. //
  464. BOOLEAN
  465. SpSearchINFSection (
  466. IN PVOID INFHandle,
  467. IN PCHAR SectionName
  468. )
  469. /*++
  470. Routine Description:
  471. Arguments:
  472. Return Value:
  473. --*/
  474. {
  475. PSECTION pSection;
  476. //
  477. // if search for section fails return false
  478. //
  479. if ((pSection = SearchSectionByName(
  480. (PINF)INFHandle,
  481. SectionName
  482. )) == (PSECTION)NULL) {
  483. return( FALSE );
  484. }
  485. //
  486. // else return true
  487. //
  488. return( TRUE );
  489. }
  490. //
  491. // given section name, line number and index return the value.
  492. //
  493. PCHAR
  494. SlGetSectionLineIndex (
  495. IN PVOID INFHandle,
  496. IN PCHAR SectionName,
  497. IN ULONG LineIndex,
  498. IN ULONG ValueIndex
  499. )
  500. /*++
  501. Routine Description:
  502. Arguments:
  503. Return Value:
  504. --*/
  505. {
  506. PSECTION pSection;
  507. PLINE pLine;
  508. PCHAR pName;
  509. if((pSection = SearchSectionByName(
  510. (PINF)INFHandle,
  511. SectionName
  512. ))
  513. == (PSECTION)NULL)
  514. return((PCHAR)NULL);
  515. if((pLine = SearchLineInSectionByIndex(
  516. pSection,
  517. LineIndex
  518. ))
  519. == (PLINE)NULL)
  520. return((PCHAR)NULL);
  521. if((pName = SearchValueInLine(
  522. pLine,
  523. ValueIndex
  524. ))
  525. == (PCHAR)NULL)
  526. return((PCHAR)NULL);
  527. return(ProcessForStringSubs(INFHandle,pName));
  528. }
  529. #ifdef UNICODE
  530. //
  531. // given section name, line number and index return the value.
  532. //
  533. PWCHAR
  534. SlGetSectionLineIndexW (
  535. IN PVOID INFHandle,
  536. IN PCHAR SectionName,
  537. IN ULONG LineIndex,
  538. IN ULONG ValueIndex
  539. )
  540. /*++
  541. Routine Description:
  542. Arguments:
  543. Return Value:
  544. --*/
  545. {
  546. PSECTION pSection;
  547. PLINE pLine;
  548. PWCHAR pName;
  549. if((pSection = SearchSectionByName(
  550. (PINF)INFHandle,
  551. SectionName
  552. ))
  553. == (PSECTION)NULL)
  554. return((PWCHAR)NULL);
  555. if((pLine = SearchLineInSectionByIndex(
  556. pSection,
  557. LineIndex
  558. ))
  559. == (PLINE)NULL)
  560. return((PWCHAR)NULL);
  561. if((pName = SearchValueInLineW(
  562. pLine,
  563. ValueIndex
  564. ))
  565. == (PWCHAR)NULL)
  566. return((PWCHAR)NULL);
  567. return(ProcessForStringSubsW(INFHandle,pName));
  568. }
  569. #endif
  570. BOOLEAN
  571. SpGetSectionKeyExists (
  572. IN PVOID INFHandle,
  573. IN PCHAR SectionName,
  574. IN PCHAR Key
  575. )
  576. /*++
  577. Routine Description:
  578. Arguments:
  579. Return Value:
  580. --*/
  581. {
  582. PSECTION pSection;
  583. if((pSection = SearchSectionByName(
  584. (PINF)INFHandle,
  585. SectionName
  586. ))
  587. == (PSECTION)NULL) {
  588. return( FALSE );
  589. }
  590. if (SearchLineInSectionByKey(pSection, Key, NULL) == (PLINE)NULL) {
  591. return( FALSE );
  592. }
  593. return( TRUE );
  594. }
  595. PCHAR
  596. SlGetKeyName(
  597. IN PVOID INFHandle,
  598. IN PCHAR SectionName,
  599. IN ULONG LineIndex
  600. )
  601. {
  602. PSECTION pSection;
  603. PLINE pLine;
  604. pSection = SearchSectionByName((PINF)INFHandle,SectionName);
  605. if(pSection == NULL) {
  606. return(NULL);
  607. }
  608. pLine = SearchLineInSectionByIndex(pSection,LineIndex);
  609. if(pLine == NULL) {
  610. return(NULL);
  611. }
  612. return(pLine->pName);
  613. }
  614. #ifdef UNICODE
  615. PWCHAR
  616. SlGetKeyNameW(
  617. IN PVOID INFHandle,
  618. IN PCHAR SectionName,
  619. IN ULONG LineIndex
  620. )
  621. {
  622. PSECTION pSection;
  623. PLINE pLine;
  624. pSection = SearchSectionByName((PINF)INFHandle,SectionName);
  625. if(pSection == NULL) {
  626. return(NULL);
  627. }
  628. pLine = SearchLineInSectionByIndex(pSection,LineIndex);
  629. if(pLine == NULL) {
  630. return(NULL);
  631. }
  632. return(pLine->pNameW);
  633. }
  634. #endif
  635. //
  636. // given section name and key, return (0-based) ordinal for this entry
  637. // (returns -1 on error)
  638. //
  639. ULONG
  640. SlGetSectionKeyOrdinal(
  641. IN PVOID INFHandle,
  642. IN PCHAR SectionName,
  643. IN PCHAR Key
  644. )
  645. {
  646. PSECTION pSection;
  647. PLINE pLine;
  648. ULONG Ordinal;
  649. pSection = SearchSectionByName(
  650. (PINF)INFHandle,
  651. SectionName
  652. );
  653. pLine = SearchLineInSectionByKey(
  654. pSection,
  655. Key,
  656. &Ordinal
  657. );
  658. if(pLine == (PLINE)NULL) {
  659. return BL_INF_FILE_ERROR;
  660. } else {
  661. return Ordinal;
  662. }
  663. }
  664. //
  665. // given section name, key and index return the value
  666. //
  667. PCHAR
  668. SlGetSectionKeyIndex (
  669. IN PVOID INFHandle,
  670. IN PCHAR SectionName,
  671. IN PCHAR Key,
  672. IN ULONG ValueIndex
  673. )
  674. /*++
  675. Routine Description:
  676. Arguments:
  677. Return Value:
  678. --*/
  679. {
  680. PSECTION pSection;
  681. PLINE pLine;
  682. PCHAR pName;
  683. if((pSection = SearchSectionByName(
  684. (PINF)INFHandle,
  685. SectionName
  686. ))
  687. == (PSECTION)NULL)
  688. return((PCHAR)NULL);
  689. if((pLine = SearchLineInSectionByKey(
  690. pSection,
  691. Key,
  692. NULL
  693. ))
  694. == (PLINE)NULL)
  695. return((PCHAR)NULL);
  696. if((pName = SearchValueInLine(
  697. pLine,
  698. ValueIndex
  699. ))
  700. == (PCHAR)NULL)
  701. return((PCHAR)NULL);
  702. return(ProcessForStringSubs(INFHandle,pName));
  703. }
  704. #ifdef UNICODE
  705. //
  706. // given section name, key and index return the value
  707. //
  708. PWCHAR
  709. SlGetSectionKeyIndexW (
  710. IN PVOID INFHandle,
  711. IN PCHAR SectionName,
  712. IN PCHAR Key,
  713. IN ULONG ValueIndex
  714. )
  715. /*++
  716. Routine Description:
  717. Arguments:
  718. Return Value:
  719. --*/
  720. {
  721. PSECTION pSection;
  722. PLINE pLine;
  723. PWCHAR pName;
  724. if((pSection = SearchSectionByName(
  725. (PINF)INFHandle,
  726. SectionName
  727. ))
  728. == (PSECTION)NULL)
  729. return((PWCHAR)NULL);
  730. if((pLine = SearchLineInSectionByKey(
  731. pSection,
  732. Key,
  733. NULL
  734. ))
  735. == (PLINE)NULL)
  736. return((PWCHAR)NULL);
  737. if((pName = SearchValueInLineW(
  738. pLine,
  739. ValueIndex
  740. ))
  741. == (PWCHAR)NULL)
  742. return((PWCHAR)NULL);
  743. return(ProcessForStringSubsW(INFHandle,pName));
  744. }
  745. #endif
  746. ULONG
  747. SlCountLinesInSection(
  748. IN PVOID INFHandle,
  749. IN PCHAR SectionName
  750. )
  751. {
  752. PSECTION pSection;
  753. PLINE pLine;
  754. ULONG Count;
  755. if((pSection = SearchSectionByName((PINF)INFHandle,SectionName)) == NULL) {
  756. return(BL_INF_FILE_ERROR);
  757. }
  758. for(pLine = pSection->pLine, Count = 0;
  759. pLine;
  760. pLine = pLine->pNext, Count++
  761. );
  762. return(Count);
  763. }
  764. PCHAR
  765. SearchValueInLine(
  766. IN PLINE pLine,
  767. IN ULONG ValueIndex
  768. )
  769. /*++
  770. Routine Description:
  771. Arguments:
  772. Return Value:
  773. --*/
  774. {
  775. PVALUE pValue;
  776. ULONG i;
  777. if (pLine == (PLINE)NULL)
  778. return ((PCHAR)NULL);
  779. if (ValueIndex < NUMBER_OF_INTERNAL_VALUES) {
  780. return pLine->InternalValues[ValueIndex];
  781. }
  782. pValue = pLine->pFirstExternalValue;
  783. for (i = NUMBER_OF_INTERNAL_VALUES;
  784. i < ValueIndex && ((pValue = pValue->pNext) != (PVALUE)NULL);
  785. i++)
  786. ;
  787. return (PCHAR)((pValue != NULL) ? pValue->pName : NULL);
  788. }
  789. #ifdef UNICODE
  790. PWCHAR
  791. SearchValueInLineW(
  792. IN PLINE pLine,
  793. IN ULONG ValueIndex
  794. )
  795. /*++
  796. Routine Description:
  797. Arguments:
  798. Return Value:
  799. --*/
  800. {
  801. PVALUE pValue;
  802. ULONG i;
  803. if (pLine == (PLINE)NULL)
  804. return ((PWCHAR)NULL);
  805. if (ValueIndex < NUMBER_OF_INTERNAL_VALUES) {
  806. return pLine->InternalValuesW[ValueIndex];
  807. }
  808. pValue = pLine->pFirstExternalValue;
  809. for (i = NUMBER_OF_INTERNAL_VALUES;
  810. i < ValueIndex && ((pValue = pValue->pNext) != (PVALUE)NULL);
  811. i++)
  812. ;
  813. return (PWCHAR)((pValue != NULL) ? pValue->pNameW : NULL);
  814. }
  815. #endif
  816. PLINE
  817. SearchLineInSectionByKey(
  818. IN PSECTION pSection,
  819. IN PCHAR Key,
  820. OUT PULONG pOrdinal OPTIONAL
  821. )
  822. /*++
  823. Routine Description:
  824. Arguments:
  825. Return Value:
  826. --*/
  827. {
  828. PLINE pLine;
  829. ULONG LineOrdinal;
  830. if (pSection == (PSECTION)NULL || Key == (PCHAR)NULL) {
  831. return ((PLINE)NULL);
  832. }
  833. pLine = pSection->pLine;
  834. LineOrdinal = 0;
  835. while ((pLine != (PLINE)NULL) && (pLine->pName == NULL || _stricmp(pLine->pName, Key))) {
  836. pLine = pLine->pNext;
  837. LineOrdinal++;
  838. }
  839. if(pLine && pOrdinal) {
  840. *pOrdinal = LineOrdinal;
  841. }
  842. return pLine;
  843. }
  844. PLINE
  845. SearchLineInSectionByIndex(
  846. IN PSECTION pSection,
  847. IN ULONG LineIndex
  848. )
  849. /*++
  850. Routine Description:
  851. Arguments:
  852. Return Value:
  853. --*/
  854. {
  855. PLINE pLine;
  856. ULONG i;
  857. //
  858. // Validate the parameters passed in
  859. //
  860. if (pSection == (PSECTION)NULL) {
  861. return ((PLINE)NULL);
  862. }
  863. //
  864. // find the start of the line list in the section passed in
  865. //
  866. pLine = pSection->pLine;
  867. //
  868. // traverse down the current line list to the LineIndex th line
  869. //
  870. for (i = 0; i < LineIndex && ((pLine = pLine->pNext) != (PLINE)NULL); i++) {
  871. ;
  872. }
  873. //
  874. // return the Line found
  875. //
  876. return pLine;
  877. }
  878. PSECTION
  879. SearchSectionByName(
  880. IN PINF pINF,
  881. IN PCHAR SectionName
  882. )
  883. /*++
  884. Routine Description:
  885. Arguments:
  886. Return Value:
  887. --*/
  888. {
  889. PSECTION pSection;
  890. //
  891. // validate the parameters passed in
  892. //
  893. if (pINF == (PINF)NULL || SectionName == (PCHAR)NULL) {
  894. return ((PSECTION)NULL);
  895. }
  896. //
  897. // find the section list
  898. //
  899. pSection = pINF->pSection;
  900. //
  901. // traverse down the section list searching each section for the section
  902. // name mentioned
  903. //
  904. while ((pSection != (PSECTION)NULL) && _stricmp(pSection->pName, SectionName)) {
  905. pSection = pSection->pNext;
  906. }
  907. //
  908. // return the section at which we stopped (either NULL or the section
  909. // which was found
  910. //
  911. return pSection;
  912. }
  913. PCHAR
  914. ProcessForStringSubs(
  915. IN PINF pInf,
  916. IN PCHAR String
  917. )
  918. {
  919. unsigned Len;
  920. PCHAR ReturnString;
  921. PSECTION pSection;
  922. PLINE pLine;
  923. //
  924. // Assume no substitution necessary.
  925. //
  926. ReturnString = String;
  927. //
  928. // If it starts and ends with % then look it up in the
  929. // strings section. Note the initial check before doing a
  930. // strlen, to preserve performance in the 99% case where
  931. // there is no substitution.
  932. //
  933. if((String[0] == '%') && ((Len = (ULONG)strlen(String)) > 2) && (String[Len-1] == '%')) {
  934. for(pSection = pInf->pSection; pSection; pSection=pSection->pNext) {
  935. if(pSection->pName && !_stricmp(pSection->pName,"Strings")) {
  936. break;
  937. }
  938. }
  939. if(pSection) {
  940. for(pLine = pSection->pLine; pLine; pLine=pLine->pNext) {
  941. if(pLine->pName
  942. && !_strnicmp(pLine->pName,String+1,Len-2)
  943. && (pLine->pName[Len-2] == 0))
  944. {
  945. break;
  946. }
  947. }
  948. if(pLine && pLine->InternalValues[0]) {
  949. ReturnString = pLine->InternalValues[0];
  950. }
  951. }
  952. }
  953. return(ReturnString);
  954. }
  955. #ifdef UNICODE
  956. PWCHAR
  957. ProcessForStringSubsW(
  958. IN PINF pInf,
  959. IN PWCHAR String
  960. )
  961. {
  962. unsigned Len;
  963. PWCHAR ReturnString;
  964. PSECTION pSection;
  965. PLINE pLine;
  966. //
  967. // Assume no substitution necessary.
  968. //
  969. ReturnString = String;
  970. //
  971. // If it starts and ends with % then look it up in the
  972. // strings section. Note the initial check before doing a
  973. // strlen, to preserve performance in the 99% case where
  974. // there is no substitution.
  975. //
  976. if((String[0] == L'%') && ((Len = (ULONG)wcslen(String)) > 2) && (String[Len-1] == L'%')) {
  977. for(pSection = pInf->pSection; pSection; pSection=pSection->pNext) {
  978. if(pSection->pName && !_stricmp(pSection->pName,"Strings")) {
  979. break;
  980. }
  981. }
  982. if(pSection) {
  983. for(pLine = pSection->pLine; pLine; pLine=pLine->pNext) {
  984. if(pLine->pName
  985. && !_tcsnicmp(pLine->pNameW,String+1,Len-2)
  986. && (pLine->pName[Len-2] == 0))
  987. {
  988. break;
  989. }
  990. }
  991. if(pLine && pLine->InternalValuesW[0]) {
  992. ReturnString = pLine->InternalValuesW[0];
  993. }
  994. }
  995. }
  996. return(ReturnString);
  997. }
  998. #endif
  999. // what follows was alparse.c
  1000. //
  1001. // Globals used to make building the lists easier
  1002. //
  1003. PINF pINF;
  1004. PSECTION pSectionRecord;
  1005. PLINE pLineRecord;
  1006. PVALUE pValueRecord;
  1007. PCHAR * pInternalValue;
  1008. PCHAR * pLastInternalValue;
  1009. #ifdef UNICODE
  1010. PWCHAR * pInternalValueW;
  1011. PWCHAR * pLastInternalValueW;
  1012. #endif
  1013. //
  1014. // Globals used by the token parser
  1015. //
  1016. // string terminators are the whitespace characters (isspace: space, tab,
  1017. // linefeed, formfeed, vertical tab, carriage return) or the chars given below
  1018. CHAR StringTerminators[] = "[]=,\t \"\n\f\v\r";
  1019. PCHAR QStringTerminators = StringTerminators+6;
  1020. PCHAR EmptyValue;
  1021. #define STRING_HEAP_SIZE 1024
  1022. ULONG_PTR StringHeapFree = 0;
  1023. ULONG_PTR StringHeapLimit = 0;
  1024. #if 0 && DBG
  1025. #define HEAP_SIZE(_size) (((_size) + BL_GRANULARITY - 1) & ~(BL_GRANULARITY - 1))
  1026. #define MAX(_a,_b) (((_a) > (_b)) ? (_a) : (_b))
  1027. #define MIN(_a,_b) (((_a) < (_b)) ? (_a) : (_b))
  1028. ULONG nStrings = 0;
  1029. ULONG maxString = 0;
  1030. ULONG bytesStrings = 0;
  1031. ULONG wasteStrings = 0;
  1032. ULONG stringsWithNLength[12] = {0};
  1033. VOID
  1034. GetStatistics (
  1035. PINF pINF
  1036. )
  1037. {
  1038. ULONG nSections = 0;
  1039. ULONG nLines = 0;
  1040. ULONG nValues = 0;
  1041. ULONG maxLinesPerSection = 0;
  1042. ULONG maxValuesPerLine = 0;
  1043. ULONG maxValuesPerSection = 0;
  1044. ULONG bytesSections = 0;
  1045. ULONG bytesLines = 0;
  1046. ULONG bytesValues = 0;
  1047. ULONG sectionsWithNLines[12] = {0};
  1048. ULONG linesWithNValues[12] = {0};
  1049. ULONG sectionsWithNValues[12] = {0};
  1050. ULONG linesThisSection;
  1051. ULONG valuesThisLine;
  1052. ULONG valuesThisSection;
  1053. PSECTION section;
  1054. PLINE line;
  1055. PVALUE value;
  1056. ULONG i;
  1057. section = pINF->pSection;
  1058. while ( section != NULL ) {
  1059. nSections++;
  1060. bytesSections += HEAP_SIZE(sizeof(SECTION));
  1061. linesThisSection = 0;
  1062. valuesThisSection = 0;
  1063. line = section->pLine;
  1064. while ( line != NULL ) {
  1065. linesThisSection++;
  1066. bytesLines += HEAP_SIZE(sizeof(LINE));
  1067. valuesThisLine = 0;
  1068. for ( i = 0; i < NUMBER_OF_INTERNAL_VALUES; i++ ) {
  1069. if ( line->InternalValues[i] != NULL ) {
  1070. valuesThisLine++;
  1071. }
  1072. }
  1073. value = line->pFirstExternalValue;
  1074. while ( value != NULL ) {
  1075. valuesThisLine++;
  1076. bytesValues += HEAP_SIZE(sizeof(VALUE));
  1077. value = value->pNext;
  1078. }
  1079. nValues += valuesThisLine;
  1080. valuesThisSection += valuesThisLine;
  1081. maxValuesPerLine = MAX(maxValuesPerLine, valuesThisLine);
  1082. linesWithNValues[MIN(valuesThisLine,11)]++;
  1083. line = line->pNext;
  1084. }
  1085. nLines += linesThisSection;
  1086. maxLinesPerSection = MAX(maxLinesPerSection, linesThisSection);
  1087. sectionsWithNLines[MIN(linesThisSection,11)]++;
  1088. maxValuesPerSection = MAX(maxValuesPerSection, valuesThisSection);
  1089. sectionsWithNValues[MIN(valuesThisSection,11)]++;
  1090. section = section->pNext;
  1091. }
  1092. DbgPrint( "Number of sections = %d\n", nSections );
  1093. DbgPrint( "Bytes in sections = %d\n", bytesSections );
  1094. DbgPrint( "\n" );
  1095. DbgPrint( "Number of lines = %d\n", nLines );
  1096. DbgPrint( "Bytes in lines = %d\n", bytesLines );
  1097. DbgPrint( "\n" );
  1098. DbgPrint( "Number of values = %d\n", nValues );
  1099. DbgPrint( "Bytes in values = %d\n", bytesValues );
  1100. DbgPrint( "\n" );
  1101. DbgPrint( "Max lines/section = %d\n", maxLinesPerSection );
  1102. DbgPrint( "Max values/line = %d\n", maxValuesPerLine );
  1103. DbgPrint( "Max values/section = %d\n", maxValuesPerSection );
  1104. DbgPrint( "\n" );
  1105. DbgPrint( "Number of strings = %d\n", nStrings );
  1106. DbgPrint( "Bytes in strings = %d\n", bytesStrings );
  1107. DbgPrint( "Wasted bytes in strings = %d\n", wasteStrings + (StringHeapLimit - StringHeapFree) );
  1108. DbgPrint( "Longest string = %d\n", maxString );
  1109. DbgPrint( "\n" );
  1110. DbgPrint( "Sections with N lines =" );
  1111. for ( i = 0; i < 12; i++ ) {
  1112. DbgPrint( " %5d", sectionsWithNLines[i] );
  1113. }
  1114. DbgPrint( "\n" );
  1115. DbgPrint( "Sections with N values =" );
  1116. for ( i = 0; i < 12; i++ ) {
  1117. DbgPrint( " %5d", sectionsWithNValues[i] );
  1118. }
  1119. DbgPrint( "\n" );
  1120. DbgPrint( "Lines with N values =" );
  1121. for ( i = 0; i < 12; i++ ) {
  1122. DbgPrint( " %5d", linesWithNValues[i] );
  1123. }
  1124. DbgPrint( "\n" );
  1125. DbgPrint( "String with length N =" );
  1126. for ( i = 0; i < 12; i++ ) {
  1127. DbgPrint( " %5d", stringsWithNLength[i] );
  1128. }
  1129. DbgPrint( "\n" );
  1130. DbgBreakPoint();
  1131. }
  1132. #endif // DBG
  1133. //
  1134. // Main parser routine
  1135. //
  1136. PVOID
  1137. ParseInfBuffer(
  1138. PCHAR INFFile,
  1139. PCHAR Buffer,
  1140. ULONG Size,
  1141. PULONG ErrorLine
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. Given a character buffer containing the INF file, this routine parses
  1146. the INF into an internal form with Section records, Line records and
  1147. Value records.
  1148. Arguments:
  1149. Buffer - contains to ptr to a buffer containing the INF file
  1150. Size - contains the size of the buffer.
  1151. ErrorLine - if a parse error occurs, this variable receives the line
  1152. number of the line containing the error.
  1153. Return Value:
  1154. PVOID - INF handle ptr to be used in subsequent INF calls.
  1155. --*/
  1156. {
  1157. PCHAR Stream, MaxStream, pchSectionName = NULL, pchValue = NULL;
  1158. ULONG State, InfLine;
  1159. TOKEN Token;
  1160. BOOLEAN Done;
  1161. BOOLEAN Error;
  1162. ARC_STATUS ErrorCode = ESUCCESS;
  1163. //
  1164. // Initialise the globals
  1165. //
  1166. pINF = (PINF)NULL;
  1167. pSectionRecord = (PSECTION)NULL;
  1168. pLineRecord = (PLINE)NULL;
  1169. pValueRecord = (PVALUE)NULL;
  1170. pInternalValue = NULL;
  1171. pLastInternalValue = NULL;
  1172. #ifdef UNICODE
  1173. pInternalValueW = NULL;
  1174. pLastInternalValueW = NULL;
  1175. #endif
  1176. //
  1177. // Need EmptyValue to point at a nul character
  1178. //
  1179. EmptyValue = StringTerminators + strlen(StringTerminators);
  1180. //
  1181. // Get INF record
  1182. //
  1183. if ((pINF = (PINF)BlAllocateHeap(sizeof(INF))) == NULL) {
  1184. SlNoMemoryError();
  1185. return NULL;
  1186. }
  1187. pINF->pSection = NULL;
  1188. //
  1189. // Set initial state
  1190. //
  1191. State = 1;
  1192. InfLine = 1;
  1193. Stream = Buffer;
  1194. MaxStream = Buffer + Size;
  1195. Done = FALSE;
  1196. Error = FALSE;
  1197. //
  1198. // Enter token processing loop
  1199. //
  1200. while (!Done) {
  1201. Token = SpGetToken(&Stream, MaxStream);
  1202. switch (State) {
  1203. //
  1204. // STATE1: Start of file, this state remains till first
  1205. // section is found
  1206. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_LBRACE
  1207. case 1:
  1208. switch (Token.Type) {
  1209. case TOK_EOL:
  1210. break;
  1211. case TOK_EOF:
  1212. Done = TRUE;
  1213. break;
  1214. case TOK_LBRACE:
  1215. State = 2;
  1216. break;
  1217. default:
  1218. Error = Done = TRUE;
  1219. ErrorCode = EINVAL;
  1220. SlBadInfLineError(InfLine, INFFile);
  1221. break;
  1222. }
  1223. break;
  1224. //
  1225. // STATE 2: Section LBRACE has been received, expecting STRING
  1226. //
  1227. // Valid Tokens: TOK_STRING
  1228. //
  1229. case 2:
  1230. switch (Token.Type) {
  1231. case TOK_STRING:
  1232. State = 3;
  1233. pchSectionName = Token.pValue;
  1234. break;
  1235. default:
  1236. Error = Done = TRUE;
  1237. ErrorCode = EINVAL;
  1238. SlBadInfLineError(InfLine, INFFile);
  1239. break;
  1240. }
  1241. break;
  1242. //
  1243. // STATE 3: Section Name received, expecting RBRACE
  1244. //
  1245. // Valid Tokens: TOK_RBRACE
  1246. //
  1247. case 3:
  1248. switch (Token.Type) {
  1249. case TOK_RBRACE:
  1250. State = 4;
  1251. break;
  1252. default:
  1253. Error = Done = TRUE;
  1254. ErrorCode = EINVAL;
  1255. SlBadInfLineError(InfLine, INFFile);
  1256. break;
  1257. }
  1258. break;
  1259. //
  1260. // STATE 4: Section Definition Complete, expecting EOL
  1261. //
  1262. // Valid Tokens: TOK_EOL, TOK_EOF
  1263. //
  1264. case 4:
  1265. switch (Token.Type) {
  1266. case TOK_EOL:
  1267. if ((ErrorCode = SpAppendSection(
  1268. pchSectionName
  1269. #ifdef UNICODE
  1270. ,SlCopyStringAW(pchSectionName)
  1271. #endif
  1272. )) != ESUCCESS) {
  1273. Error = Done = TRUE;
  1274. } else {
  1275. pchSectionName = NULL;
  1276. State = 5;
  1277. }
  1278. break;
  1279. case TOK_EOF:
  1280. if ((ErrorCode = SpAppendSection(
  1281. pchSectionName
  1282. #ifdef UNICODE
  1283. ,SlCopyStringAW(pchSectionName)
  1284. #endif
  1285. )) != ESUCCESS)
  1286. Error = Done = TRUE;
  1287. else {
  1288. pchSectionName = NULL;
  1289. Done = TRUE;
  1290. }
  1291. break;
  1292. default:
  1293. Error = Done = TRUE;
  1294. ErrorCode = EINVAL;
  1295. break;
  1296. }
  1297. break;
  1298. //
  1299. // STATE 5: Expecting Section Lines
  1300. //
  1301. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_STRING, TOK_LBRACE
  1302. //
  1303. case 5:
  1304. switch (Token.Type) {
  1305. case TOK_EOL:
  1306. break;
  1307. case TOK_EOF:
  1308. Done = TRUE;
  1309. break;
  1310. case TOK_STRING:
  1311. pchValue = Token.pValue;
  1312. State = 6;
  1313. break;
  1314. case TOK_LBRACE:
  1315. State = 2;
  1316. break;
  1317. default:
  1318. Error = Done = TRUE;
  1319. ErrorCode = EINVAL;
  1320. SlBadInfLineError(InfLine, INFFile);
  1321. break;
  1322. }
  1323. break;
  1324. //
  1325. // STATE 6: String returned, not sure whether it is key or value
  1326. //
  1327. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA, TOK_EQUAL
  1328. //
  1329. case 6:
  1330. switch (Token.Type) {
  1331. case TOK_EOL:
  1332. if ( (ErrorCode = SpAppendLine(
  1333. NULL
  1334. #ifdef UNICODE
  1335. ,NULL
  1336. #endif
  1337. )) != ESUCCESS ||
  1338. (ErrorCode = SpAppendValue(
  1339. pchValue
  1340. #ifdef UNICODE
  1341. ,SlCopyStringAW(pchValue)
  1342. #endif
  1343. )) !=ESUCCESS )
  1344. Error = Done = TRUE;
  1345. else {
  1346. pchValue = NULL;
  1347. State = 5;
  1348. }
  1349. break;
  1350. case TOK_EOF:
  1351. if ( (ErrorCode = SpAppendLine(
  1352. NULL
  1353. #ifdef UNICODE
  1354. ,NULL
  1355. #endif
  1356. )) != ESUCCESS ||
  1357. (ErrorCode = SpAppendValue(
  1358. pchValue
  1359. #ifdef UNICODE
  1360. ,SlCopyStringAW(pchValue)
  1361. #endif
  1362. )) !=ESUCCESS )
  1363. Error = Done = TRUE;
  1364. else {
  1365. pchValue = NULL;
  1366. Done = TRUE;
  1367. }
  1368. break;
  1369. case TOK_COMMA:
  1370. if ( (ErrorCode = SpAppendLine(
  1371. NULL
  1372. #ifdef UNICODE
  1373. ,NULL
  1374. #endif
  1375. )) != ESUCCESS ||
  1376. (ErrorCode = SpAppendValue(
  1377. pchValue
  1378. #ifdef UNICODE
  1379. ,SlCopyStringAW(pchValue)
  1380. #endif
  1381. )) !=ESUCCESS )
  1382. Error = Done = TRUE;
  1383. else {
  1384. pchValue = NULL;
  1385. State = 7;
  1386. }
  1387. break;
  1388. case TOK_EQUAL:
  1389. if ( (ErrorCode = SpAppendLine(
  1390. pchValue
  1391. #ifdef UNICODE
  1392. ,SlCopyStringAW(pchValue)
  1393. #endif
  1394. )) !=ESUCCESS)
  1395. Error = Done = TRUE;
  1396. else {
  1397. pchValue = NULL;
  1398. State = 8;
  1399. }
  1400. break;
  1401. default:
  1402. Error = Done = TRUE;
  1403. ErrorCode = EINVAL;
  1404. SlBadInfLineError(InfLine, INFFile);
  1405. break;
  1406. }
  1407. break;
  1408. //
  1409. // STATE 7: Comma received, Expecting another string
  1410. //
  1411. // Valid Tokens: TOK_STRING TOK_COMMA
  1412. // A comma means we have an empty value.
  1413. //
  1414. case 7:
  1415. switch (Token.Type) {
  1416. case TOK_COMMA:
  1417. Token.pValue = EmptyValue;
  1418. if ((ErrorCode = SpAppendValue(
  1419. Token.pValue
  1420. #ifdef UNICODE
  1421. ,SlCopyStringAW(Token.pValue)
  1422. #endif
  1423. )) != ESUCCESS) {
  1424. Error = Done = TRUE;
  1425. }
  1426. //
  1427. // State stays at 7 because we are expecting a string
  1428. //
  1429. break;
  1430. case TOK_STRING:
  1431. if ((ErrorCode = SpAppendValue(
  1432. Token.pValue
  1433. #ifdef UNICODE
  1434. ,SlCopyStringAW(Token.pValue)
  1435. #endif
  1436. )) != ESUCCESS)
  1437. Error = Done = TRUE;
  1438. else
  1439. State = 9;
  1440. break;
  1441. case TOK_EOL:
  1442. case TOK_EOF:
  1443. Token.pValue = EmptyValue;
  1444. if ((ErrorCode = SpAppendValue(
  1445. Token.pValue
  1446. #ifdef UNICODE
  1447. ,SlCopyStringAW(Token.pValue)
  1448. #endif
  1449. )) != ESUCCESS)
  1450. Error = Done = TRUE;
  1451. else
  1452. State = 9;
  1453. break;
  1454. default:
  1455. Error = Done = TRUE;
  1456. ErrorCode = EINVAL;
  1457. SlBadInfLineError(InfLine, INFFile);
  1458. break;
  1459. }
  1460. break;
  1461. //
  1462. // STATE 8: Equal received, Expecting another string
  1463. // If none, assume there is a single empty string on the RHS
  1464. //
  1465. // Valid Tokens: TOK_STRING, TOK_EOL, TOK_EOF
  1466. //
  1467. case 8:
  1468. switch (Token.Type) {
  1469. case TOK_EOF:
  1470. Token.pValue = EmptyValue;
  1471. if((ErrorCode = SpAppendValue(
  1472. Token.pValue
  1473. #ifdef UNICODE
  1474. ,SlCopyStringAW(Token.pValue)
  1475. #endif
  1476. )) != ESUCCESS) {
  1477. Error = TRUE;
  1478. }
  1479. Done = TRUE;
  1480. break;
  1481. case TOK_EOL:
  1482. Token.pValue = EmptyValue;
  1483. if((ErrorCode = SpAppendValue(
  1484. Token.pValue
  1485. #ifdef UNICODE
  1486. ,SlCopyStringAW(Token.pValue)
  1487. #endif
  1488. )) != ESUCCESS) {
  1489. Error = TRUE;
  1490. Done = TRUE;
  1491. } else {
  1492. State = 5;
  1493. }
  1494. break;
  1495. case TOK_STRING:
  1496. if ((ErrorCode = SpAppendValue(
  1497. Token.pValue
  1498. #ifdef UNICODE
  1499. ,SlCopyStringAW(Token.pValue)
  1500. #endif
  1501. )) != ESUCCESS)
  1502. Error = Done = TRUE;
  1503. else
  1504. State = 9;
  1505. break;
  1506. default:
  1507. Error = Done = TRUE;
  1508. ErrorCode = EINVAL;
  1509. SlBadInfLineError(InfLine, INFFile);
  1510. break;
  1511. }
  1512. break;
  1513. //
  1514. // STATE 9: String received after equal, value string
  1515. //
  1516. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  1517. //
  1518. case 9:
  1519. switch (Token.Type) {
  1520. case TOK_EOL:
  1521. State = 5;
  1522. break;
  1523. case TOK_EOF:
  1524. Done = TRUE;
  1525. break;
  1526. case TOK_COMMA:
  1527. State = 7;
  1528. break;
  1529. default:
  1530. Error = Done = TRUE;
  1531. ErrorCode = EINVAL;
  1532. SlBadInfLineError(InfLine, INFFile);
  1533. break;
  1534. }
  1535. break;
  1536. //
  1537. // STATE 10: Value string definitely received
  1538. //
  1539. // Valid Tokens: TOK_EOL, TOK_EOF, TOK_COMMA
  1540. //
  1541. case 10:
  1542. switch (Token.Type) {
  1543. case TOK_EOL:
  1544. State =5;
  1545. break;
  1546. case TOK_EOF:
  1547. Done = TRUE;
  1548. break;
  1549. case TOK_COMMA:
  1550. State = 7;
  1551. break;
  1552. default:
  1553. Error = Done = TRUE;
  1554. ErrorCode = EINVAL;
  1555. SlBadInfLineError(InfLine, INFFile);
  1556. break;
  1557. }
  1558. break;
  1559. default:
  1560. Error = Done = TRUE;
  1561. ErrorCode = EINVAL;
  1562. break;
  1563. } // end switch(State)
  1564. if (Error) {
  1565. switch (ErrorCode) {
  1566. case EINVAL:
  1567. *ErrorLine = InfLine;
  1568. break;
  1569. case ENOMEM:
  1570. SlBadInfLineError(InfLine, INFFile);
  1571. break;
  1572. default:
  1573. break;
  1574. }
  1575. ErrorCode = SpFreeINFBuffer((PVOID)pINF);
  1576. if (pchSectionName != (PCHAR)NULL) {
  1577. SpFree(pchSectionName);
  1578. }
  1579. if (pchValue != (PCHAR)NULL) {
  1580. SpFree(pchValue);
  1581. }
  1582. pINF = (PINF)NULL;
  1583. }
  1584. else {
  1585. //
  1586. // Keep track of line numbers so that we can display Errors
  1587. //
  1588. if (Token.Type == TOK_EOL)
  1589. InfLine++;
  1590. }
  1591. } // End while
  1592. #if 0 && DBG
  1593. GetStatistics(pINF);
  1594. #endif
  1595. return((PVOID)pINF);
  1596. }
  1597. ARC_STATUS
  1598. SpAppendSection(
  1599. IN PCHAR pSectionName
  1600. #ifdef UNICODE
  1601. , IN PWCHAR pSectionNameW
  1602. #endif
  1603. )
  1604. /*++
  1605. Routine Description:
  1606. This appends a new section to the section list in the current INF.
  1607. All further lines and values pertain to this new section, so it resets
  1608. the line list and value lists too.
  1609. Arguments:
  1610. pSectionName - Name of the new section. ( [SectionName] )
  1611. Return Value:
  1612. ESUCCESS - if successful.
  1613. ENOMEM - if memory allocation failed.
  1614. EINVAL - if invalid parameters passed in or the INF buffer not
  1615. initialised
  1616. --*/
  1617. {
  1618. PSECTION pNewSection;
  1619. //
  1620. // Check to see if INF initialised and the parameter passed in is valid
  1621. //
  1622. if (pINF == (PINF)NULL || pSectionName == (PCHAR)NULL) {
  1623. if(pchINFName) {
  1624. SlFriendlyError(
  1625. EINVAL,
  1626. pchINFName,
  1627. __LINE__,
  1628. __FILE__
  1629. );
  1630. } else {
  1631. SlError(EINVAL);
  1632. }
  1633. return EINVAL;
  1634. }
  1635. //
  1636. // See if we already have a section by this name. If so we want
  1637. // to merge sections.
  1638. //
  1639. for(pNewSection=pINF->pSection; pNewSection; pNewSection=pNewSection->pNext) {
  1640. if(pNewSection->pName && !_stricmp(pNewSection->pName,pSectionName)) {
  1641. break;
  1642. }
  1643. }
  1644. if(pNewSection) {
  1645. //
  1646. // Set pLineRecord to point to the list line currently in the section.
  1647. //
  1648. for(pLineRecord = pNewSection->pLine;
  1649. pLineRecord && pLineRecord->pNext;
  1650. pLineRecord = pLineRecord->pNext)
  1651. ;
  1652. } else {
  1653. //
  1654. // Allocate memory for the new section
  1655. //
  1656. if ((pNewSection = (PSECTION)BlAllocateHeap(sizeof(SECTION))) == (PSECTION)NULL) {
  1657. SlNoMemoryError();
  1658. return ENOMEM;
  1659. }
  1660. //
  1661. // initialise the new section
  1662. //
  1663. pNewSection->pNext = NULL;
  1664. pNewSection->pLine = NULL;
  1665. pNewSection->pName = pSectionName;
  1666. #ifdef UNICODE
  1667. pNewSection->pNameW = pSectionNameW;
  1668. #endif
  1669. //
  1670. // link it in
  1671. //
  1672. pNewSection->pNext = pINF->pSection;
  1673. pINF->pSection = pNewSection;
  1674. //
  1675. // reset the current line record
  1676. //
  1677. pLineRecord = NULL;
  1678. }
  1679. pSectionRecord = pNewSection;
  1680. pValueRecord = NULL;
  1681. pInternalValue = NULL;
  1682. pLastInternalValue = NULL;
  1683. #ifdef UNICODE
  1684. pInternalValueW = NULL;
  1685. pLastInternalValueW = NULL;
  1686. #endif
  1687. return ESUCCESS;
  1688. }
  1689. ARC_STATUS
  1690. SpAppendLine(
  1691. IN PCHAR pLineKey
  1692. #ifdef UNICODE
  1693. , IN PWCHAR pLineKeyW
  1694. #endif
  1695. )
  1696. /*++
  1697. Routine Description:
  1698. This appends a new line to the line list in the current section.
  1699. All further values pertain to this new line, so it resets
  1700. the value list too.
  1701. Arguments:
  1702. pLineKey - Key to be used for the current line, this could be NULL.
  1703. Return Value:
  1704. ESUCCESS - if successful.
  1705. ENOMEM - if memory allocation failed.
  1706. EINVAL - if invalid parameters passed in or current section not
  1707. initialised
  1708. --*/
  1709. {
  1710. PLINE pNewLine;
  1711. ULONG i;
  1712. //
  1713. // Check to see if current section initialised
  1714. //
  1715. if (pSectionRecord == (PSECTION)NULL) {
  1716. if(pchINFName) {
  1717. SlFriendlyError(
  1718. EINVAL,
  1719. pchINFName,
  1720. __LINE__,
  1721. __FILE__
  1722. );
  1723. } else {
  1724. SlError(EINVAL);
  1725. }
  1726. return EINVAL;
  1727. }
  1728. //
  1729. // Allocate memory for the new Line
  1730. //
  1731. if ((pNewLine = (PLINE)BlAllocateHeap(sizeof(LINE))) == (PLINE)NULL) {
  1732. SlNoMemoryError();
  1733. return ENOMEM;
  1734. }
  1735. //
  1736. // Link it in
  1737. //
  1738. pNewLine->pNext = (PLINE)NULL;
  1739. for ( i = 0; i < NUMBER_OF_INTERNAL_VALUES; i++ ) {
  1740. pNewLine->InternalValues[i] = NULL;
  1741. #ifdef UNICODE
  1742. pNewLine->InternalValuesW[i] = NULL;
  1743. #endif
  1744. }
  1745. pNewLine->pFirstExternalValue = (PVALUE)NULL;
  1746. pNewLine->pName = pLineKey;
  1747. #ifdef UNICODE
  1748. pNewLine->pNameW = pLineKeyW;
  1749. #endif
  1750. if (pLineRecord == (PLINE)NULL) {
  1751. pSectionRecord->pLine = pNewLine;
  1752. }
  1753. else {
  1754. pLineRecord->pNext = pNewLine;
  1755. }
  1756. pLineRecord = pNewLine;
  1757. //
  1758. // Reset the current value record
  1759. //
  1760. pValueRecord = (PVALUE)NULL;
  1761. pInternalValue = &pNewLine->InternalValues[0];
  1762. pLastInternalValue = &pNewLine->InternalValues[NUMBER_OF_INTERNAL_VALUES];
  1763. #ifdef UNICODE
  1764. pInternalValueW = &pNewLine->InternalValuesW[0];
  1765. pLastInternalValueW = &pNewLine->InternalValuesW[NUMBER_OF_INTERNAL_VALUES];
  1766. #endif
  1767. return ESUCCESS;
  1768. }
  1769. ARC_STATUS
  1770. SpAppendValue(
  1771. IN PCHAR pValueString
  1772. #ifdef UNICODE
  1773. , IN PWCHAR pValueStringW
  1774. #endif
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. This appends a new value to the value list in the current line.
  1779. Arguments:
  1780. pValueString - The value string to be added.
  1781. Return Value:
  1782. ESUCCESS - if successful.
  1783. ENOMEM - if memory allocation failed.
  1784. EINVAL - if invalid parameters passed in or current line not
  1785. initialised.
  1786. --*/
  1787. {
  1788. PVALUE pNewValue;
  1789. //
  1790. // Check to see if current line record has been initialised and
  1791. // the parameter passed in is valid
  1792. //
  1793. if (pLineRecord == (PLINE)NULL || pValueString == (PCHAR)NULL) {
  1794. if(pchINFName) {
  1795. SlFriendlyError(
  1796. EINVAL,
  1797. pchINFName,
  1798. __LINE__,
  1799. __FILE__
  1800. );
  1801. } else {
  1802. SlError(EINVAL);
  1803. }
  1804. return EINVAL;
  1805. }
  1806. if (pInternalValue != NULL) {
  1807. *pInternalValue++ = pValueString;
  1808. if (pInternalValue >= pLastInternalValue) {
  1809. pInternalValue = NULL;
  1810. }
  1811. #ifdef UNICODE
  1812. *pInternalValueW++ = pValueStringW;
  1813. if (pInternalValueW >= pLastInternalValueW) {
  1814. pInternalValueW = NULL;
  1815. }
  1816. #endif
  1817. return ESUCCESS;
  1818. }
  1819. //
  1820. // Allocate memory for the new value record
  1821. //
  1822. if ((pNewValue = (PVALUE)BlAllocateHeap(sizeof(VALUE))) == (PVALUE)NULL) {
  1823. SlNoMemoryError();
  1824. return ENOMEM;
  1825. }
  1826. //
  1827. // Link it in.
  1828. //
  1829. pNewValue->pNext = (PVALUE)NULL;
  1830. pNewValue->pName = pValueString;
  1831. #ifdef UNICODE
  1832. pNewValue->pNameW = pValueStringW;
  1833. #endif
  1834. if (pValueRecord == (PVALUE)NULL)
  1835. pLineRecord->pFirstExternalValue = pNewValue;
  1836. else
  1837. pValueRecord->pNext = pNewValue;
  1838. pValueRecord = pNewValue;
  1839. return ESUCCESS;
  1840. }
  1841. PVOID
  1842. SpAllocateStringHeap (
  1843. IN ULONG Size
  1844. )
  1845. /*++
  1846. Routine Description:
  1847. This routine allocates memory from the OS loader heap.
  1848. Arguments:
  1849. Size - Supplies the size of block required in bytes.
  1850. Return Value:
  1851. If a free block of memory of the specified size is available, then
  1852. the address of the block is returned. Otherwise, NULL is returned.
  1853. --*/
  1854. {
  1855. PVOID HeapBlock;
  1856. ULONG_PTR Block;
  1857. if (Size >= STRING_HEAP_SIZE) {
  1858. return BlAllocateHeap(Size);
  1859. }
  1860. if ((StringHeapFree + Size) >= StringHeapLimit) {
  1861. #if 0 && DBG
  1862. wasteStrings += (StringHeapLimit - StringHeapFree);
  1863. #endif
  1864. HeapBlock = BlAllocateHeap( STRING_HEAP_SIZE );
  1865. if ( HeapBlock == NULL ) {
  1866. return NULL;
  1867. }
  1868. StringHeapFree = (ULONG_PTR)HeapBlock;
  1869. StringHeapLimit = StringHeapFree + STRING_HEAP_SIZE;
  1870. }
  1871. Block = StringHeapFree;
  1872. StringHeapFree += Size;
  1873. #if 0 && DBG
  1874. nStrings++;
  1875. bytesStrings += Size;
  1876. stringsWithNLength[MIN(Size,11)]++;
  1877. maxString = MAX(maxString, Size);
  1878. #endif
  1879. return (PVOID)Block;
  1880. }
  1881. TOKEN
  1882. SpGetToken(
  1883. IN OUT PCHAR *Stream,
  1884. IN PCHAR MaxStream
  1885. )
  1886. /*++
  1887. Routine Description:
  1888. This function returns the Next token from the configuration stream.
  1889. Arguments:
  1890. Stream - Supplies the address of the configuration stream. Returns
  1891. the address of where to start looking for tokens within the
  1892. stream.
  1893. MaxStream - Supplies the address of the last character in the stream.
  1894. Return Value:
  1895. TOKEN - Returns the next token
  1896. --*/
  1897. {
  1898. PCHAR pch, pchStart, pchNew;
  1899. ULONG Length;
  1900. TOKEN Token;
  1901. //
  1902. // Skip whitespace (except for eol)
  1903. //
  1904. pch = *Stream;
  1905. while (pch < MaxStream && *pch != '\n' && isspace(*pch))
  1906. pch++;
  1907. //
  1908. // Check for comments and remove them
  1909. //
  1910. if (pch < MaxStream &&
  1911. ((*pch == '#') ||
  1912. (*pch == ';') ||
  1913. (*pch == '/' && pch+1 < MaxStream && *(pch+1) =='/')))
  1914. while (pch < MaxStream && *pch != '\n')
  1915. pch++;
  1916. //
  1917. // Check to see if EOF has been reached, set the token to the right
  1918. // value
  1919. //
  1920. if ((pch >= MaxStream) || (*pch == 26)) {
  1921. *Stream = pch;
  1922. Token.Type = TOK_EOF;
  1923. Token.pValue = NULL;
  1924. return Token;
  1925. }
  1926. switch (*pch) {
  1927. case '[' :
  1928. pch++;
  1929. Token.Type = TOK_LBRACE;
  1930. Token.pValue = NULL;
  1931. break;
  1932. case ']' :
  1933. pch++;
  1934. Token.Type = TOK_RBRACE;
  1935. Token.pValue = NULL;
  1936. break;
  1937. case '=' :
  1938. pch++;
  1939. Token.Type = TOK_EQUAL;
  1940. Token.pValue = NULL;
  1941. break;
  1942. case ',' :
  1943. pch++;
  1944. Token.Type = TOK_COMMA;
  1945. Token.pValue = NULL;
  1946. break;
  1947. case '\n' :
  1948. pch++;
  1949. Token.Type = TOK_EOL;
  1950. Token.pValue = NULL;
  1951. break;
  1952. case '\"':
  1953. pch++;
  1954. //
  1955. // determine quoted string
  1956. //
  1957. pchStart = pch;
  1958. while (pch < MaxStream && (strchr(QStringTerminators,*pch) == NULL)) {
  1959. pch++;
  1960. }
  1961. if (pch >=MaxStream || *pch != '\"') {
  1962. Token.Type = TOK_ERRPARSE;
  1963. Token.pValue = NULL;
  1964. } else {
  1965. //
  1966. // We require a quoted string to end with a double-quote.
  1967. // (If the string ended with anything else, the if() above
  1968. // would not have let us into the else clause.) The quote
  1969. // character is irrelevent, however, and can be overwritten.
  1970. // So we'll save some heap and use the string in-place.
  1971. // No need to make a copy.
  1972. //
  1973. // Note that this alters the image of txtsetup.sif we pass
  1974. // to setupdd.sys. Thus the inf parser in setupdd.sys must
  1975. // be able to treat a nul character as if it were a terminating
  1976. // double quote.
  1977. //
  1978. *pch++ = 0;
  1979. Token.Type = TOK_STRING;
  1980. Token.pValue = pchStart;
  1981. }
  1982. break;
  1983. default:
  1984. //
  1985. // determine regular string
  1986. //
  1987. pchStart = pch;
  1988. while (pch < MaxStream && (strchr(StringTerminators,*pch) == NULL)) {
  1989. pch++;
  1990. }
  1991. if (pch == pchStart) {
  1992. pch++;
  1993. Token.Type = TOK_ERRPARSE;
  1994. Token.pValue = NULL;
  1995. }
  1996. else {
  1997. Length = (ULONG)(pch - pchStart);
  1998. if ((pchNew = SpAllocateStringHeap(Length + 1)) == NULL) {
  1999. Token.Type = TOK_ERRNOMEM;
  2000. Token.pValue = NULL;
  2001. }
  2002. else {
  2003. strncpy(pchNew, pchStart, Length);
  2004. pchNew[Length] = 0;
  2005. Token.Type = TOK_STRING;
  2006. Token.pValue = pchNew;
  2007. }
  2008. }
  2009. break;
  2010. }
  2011. *Stream = pch;
  2012. return (Token);
  2013. }
  2014. PCHAR
  2015. SlSearchSection(
  2016. IN PCHAR SectionName,
  2017. IN PCHAR TargetName
  2018. )
  2019. /*++
  2020. Routine Description:
  2021. Searches a section in the INF file to match a name from the ARC identifier
  2022. with the canonical shortname.
  2023. If a string starts with *, then use strstr to find it in the node's id
  2024. string, else use stricmp.
  2025. [Map.Computer]
  2026. msjazz_up = *Jazz
  2027. desksta1_up = "DESKTECH-ARCStation I"
  2028. pica61_up = "PICA-61"
  2029. duo_mp = *Duo
  2030. [Map.Computer]
  2031. DECjensen = "DEC-20Jensen"
  2032. DECjensen = "DEC-10Jensen"
  2033. Arguments:
  2034. SectionName - Supplies the name of the section ("Map.Computer")
  2035. TargetName - Supplies the ARC string to be matched ("DEC-20Jensen")
  2036. Return Value:
  2037. NULL - No match was found.
  2038. PCHAR - Pointer to the canonical shortname of the device.
  2039. --*/
  2040. {
  2041. ULONG i;
  2042. PCHAR SearchName;
  2043. //
  2044. // Enumerate the entries in the section. If the 0 value
  2045. // begins with a *, then see if the system name contains the string that
  2046. // follows. Otherwise, do a case-insensitive compare on the name.
  2047. //
  2048. for (i=0;;i++) {
  2049. SearchName = SlGetSectionLineIndex(InfFile,
  2050. SectionName,
  2051. i,
  2052. 0);
  2053. if (SearchName==NULL) {
  2054. //
  2055. // we have enumerated the entire section without finding a match,
  2056. // return failure.
  2057. //
  2058. return(NULL);
  2059. }
  2060. if (SearchName[0]=='*') {
  2061. if (strstr(TargetName,SearchName+1) != 0) {
  2062. //
  2063. // we have a match
  2064. //
  2065. break;
  2066. }
  2067. } else {
  2068. if (_stricmp(TargetName, SearchName) == 0) {
  2069. //
  2070. // we have a match
  2071. //
  2072. break;
  2073. }
  2074. }
  2075. }
  2076. //
  2077. // i is the index into the section of the short machine name
  2078. //
  2079. return(SlGetKeyName(InfFile,
  2080. SectionName,
  2081. i));
  2082. }