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.

2312 lines
48 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. Argument
  5. Abstract:
  6. Argument processing for the MODE utility.
  7. The functions in this file:
  8. 1.- Parse the MODE command line.
  9. 2.- Perform some basic argument validation.
  10. 3.- Make a request packet that will be eventually routed to a
  11. device handler.
  12. Author:
  13. Ramon Juan San Andres (ramonsa) 26-Jun-1991
  14. Notes:
  15. Due to the complexity of the MODE command line, and the fact that
  16. we have to support both the DOS5 syntax (tagged parameters) and
  17. the old DOS syntax (positional parameters), MODE does not use
  18. the standard ULIB argument parsing. MODE does its own parsing
  19. instead.
  20. The mode command-line can take any of the following forms:
  21. MODE [/?]
  22. MODE [device] [/STATUS]
  23. MODE device cp PREPARE=string
  24. MODE device cp REFRESH
  25. MODE device cp SELECT=codepage
  26. MODE device cp [/STATUS]
  27. MODE LPTn[:] [c][,l][,r]]
  28. MODE LPTn[:] [COLS=c] [LINES=l] [RETRY=r]
  29. MODE LPTn[:]=COMm[:]
  30. MODE COMm[:] [b[,p[,d[,s[,r]]]]]
  31. MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s] [RETRY=r]
  32. [to=on|off] [xon=on|off] [odsr=on|off] [octs=on|off]
  33. MODE [c[,l]]
  34. MODE CON[:] [COLS=c] [LINES=l]
  35. MODE CON[:] [RATE=r DELAY=d]
  36. where:
  37. device := LPTn[:] | COMm[:] | CON[:]
  38. cp := CP | CODEPAGE
  39. The argument parsing of MODE does a syntax-directed translation of
  40. the command line into a request packet. The translation is based on
  41. the following language. Note that some terminal symbols (in uppercase)
  42. might be language dependent.
  43. mode := MODE { statusline | lptline | comline | conline | videoline }
  44. statusline := /STA*
  45. lptline := lptdev { lptredir | lptsetold | lptsetnew | lptcp | lptstatus }
  46. lptred := =comdev
  47. lptset := { n[,n][,c] | [COLS=n] [LINES=n] [RETRY=c] }
  48. lptcp := cpstuff
  49. lptstatus := { /STA* | }
  50. comline := comdev { comset | comstatus }
  51. comset := { n[,c[,n[,f[,c]]]] | [BAUD=n] [PARITY=c] [DATA=n] [STOP=f] [RETRY=c] }
  52. [to=on|off] [xon=on|off] [odsr=on|off] [octs=on|off]
  53. comstatus := { /STA* | }
  54. conline := condev { conrc | contyp | concp | constatus }
  55. conrc := [COLS=n] [LINES=n]
  56. contyp := RATE=n DELAY=n
  57. concp := cpstuff
  58. constatus := { /STA* | }
  59. videoline := n[,n]
  60. cpstuff := cp { prepare | refresh | select | cpstatus}
  61. cp := CP | CODEPAGE
  62. prepare := PREPARE=*
  63. refresh := REFRESH
  64. select := SELECT=n
  65. cpstatus := { /STA* | }
  66. comdev := COMn[:]
  67. lptdev := LPTn[:]
  68. condev := CON[:]
  69. n := Integer number
  70. f := floating point number
  71. c := character
  72. The functions in this file parse the language shown above. Most of
  73. the functions have names that correspond to non-terminal symbols in
  74. the language.
  75. There are 3 main functions used for reading the command line:
  76. Match() - This function matches a pattern against whatever
  77. is in the command line at the current position.
  78. Note that this does not advance our current position
  79. within the command line.
  80. If the pattern has a magic character, then the
  81. variables MatchBegin and MatchEnd delimit the
  82. substring of the command line that matched that
  83. magic character.
  84. Advance() - This functions advances our current position within
  85. the command line. The amount by which the position
  86. is advanced is determined by the the last Match().
  87. EndOfInput()- Returns TRUE if the command line has been consumed.
  88. e.g. If the command line has the string "MODE COM1: 1200"
  89. This is what the following sequence would do
  90. Match( "*" ); // TRUE (matches "MODE")
  91. Advance();
  92. //
  93. // Note that Match() does not advance our position
  94. //
  95. MATCH( "LPT" ); // FALSE (no match)
  96. MATCH( "COM#" ); // TRUE (matches "COM" )
  97. //
  98. // At this point, MatchBegin and MatchEnd delimit the
  99. // substring "1"
  100. //
  101. MATCH( "FOO" ); // FALSE (no match)
  102. MATCH( "C*" ); // TRUE (matches "COM1:");
  103. //
  104. // At this point, MatchBegin and MatchEnd delimit the
  105. // substring "OM1:"
  106. //
  107. Advance();
  108. Match( "#" ); // TRUE (matches "1200");
  109. Advance();
  110. EndOfInput(); // TRUE
  111. Revision History:
  112. --*/
  113. #include "mode.hxx"
  114. #include "common.hxx"
  115. #include "lpt.hxx"
  116. #include "com.hxx"
  117. #include "cons.hxx"
  118. extern "C" {
  119. #include <ctype.h>
  120. #include <string.h>
  121. }
  122. //
  123. //Static data
  124. //
  125. PWSTRING CmdLine; // The command line
  126. CHNUM CharIndex; // Index of current character
  127. CHNUM AdvanceIndex; // Index of next parameter
  128. CHNUM ParmIndex; // Index of current parameter
  129. CHNUM MatchBegin; // First index of match
  130. CHNUM MatchEnd; // Last index of match
  131. //
  132. // Patterns.
  133. //
  134. // Most patterns contain terminal symbols. Certain characters in a
  135. // pattern have a magic meaning:
  136. //
  137. // '*' Matches everything up to the end of the parameter (parameters are
  138. // delimited by blank space).
  139. //
  140. // '#' Matches a sequence of digits
  141. //
  142. // '@' Matches a single character
  143. //
  144. // '[' Starts an optional sequence. If the first character in the
  145. // the sequence matches, then all the sequence should match. If
  146. // the first character in the sequence does not match, then the
  147. // sequence is skipped.
  148. //
  149. // ']' End of optional sequence
  150. //
  151. //
  152. //
  153. // Prototypoes
  154. //
  155. PREQUEST_HEADER
  156. LptLine (
  157. );
  158. PREQUEST_HEADER
  159. LptRedir (
  160. IN ULONG DeviceNumber
  161. );
  162. PREQUEST_HEADER
  163. LptSet (
  164. IN ULONG DeviceNumber
  165. );
  166. PREQUEST_HEADER
  167. LptCp (
  168. IN ULONG DeviceNumber
  169. );
  170. PREQUEST_HEADER
  171. ComLine (
  172. );
  173. PREQUEST_HEADER
  174. ComSet (
  175. IN ULONG DeviceNumber
  176. );
  177. PREQUEST_HEADER
  178. ConLine (
  179. );
  180. PREQUEST_HEADER
  181. ConRc (
  182. );
  183. PREQUEST_HEADER
  184. ConTyp (
  185. );
  186. PREQUEST_HEADER
  187. ConCp (
  188. );
  189. PREQUEST_HEADER
  190. VideoLine (
  191. );
  192. PREQUEST_HEADER
  193. CpStuff (
  194. IN DEVICE_TTYPE DeviceType,
  195. IN ULONG DeviceNumber
  196. );
  197. BOOLEAN
  198. AllocateResource(
  199. );
  200. VOID
  201. DeallocateResource(
  202. );
  203. BOOLEAN
  204. Match(
  205. IN PCSTR Pattern
  206. );
  207. BOOLEAN
  208. Match(
  209. IN PCWSTRING Pattern
  210. );
  211. VOID
  212. Advance(
  213. );
  214. BOOLEAN
  215. EndOfInput(
  216. );
  217. PREQUEST_HEADER
  218. MakeRequest(
  219. IN DEVICE_TTYPE DeviceType,
  220. IN LONG DeviceNumber,
  221. IN REQUEST_TYPE RequestType,
  222. IN ULONG Size
  223. );
  224. ULONG
  225. GetNumber(
  226. );
  227. INLINE
  228. BOOLEAN
  229. EndOfInput(
  230. )
  231. /*++
  232. Routine Description:
  233. Finds out if we are at the end of the command line.
  234. Arguments:
  235. None
  236. Return Value:
  237. BOOLEAN - TRUE if at the end of input, FALSE otherwise
  238. --*/
  239. {
  240. return (CharIndex >= CmdLine->QueryChCount());
  241. }
  242. PREQUEST_HEADER
  243. GetRequest(
  244. )
  245. /*++
  246. Routine Description:
  247. Parses the command line and makes a device request.
  248. Arguments:
  249. None.
  250. Return Value:
  251. Pointer to the device request.
  252. Notes:
  253. --*/
  254. {
  255. PREQUEST_HEADER Request = NULL;
  256. DSTRING Switches;
  257. //
  258. // Allocate strings (i.e. patterns ) from the resource
  259. //
  260. //
  261. // Get the command line and parse it
  262. //
  263. if (Switches.Initialize("/-") &&
  264. AllocateResource() &&
  265. CmdLine->Initialize( GetCommandLine() )) {
  266. //
  267. // Before anything else, we look for a help switch somewhere
  268. // in the command line. This kind of stinks, but this is how
  269. // MODE works under DOS, se let's be compatible...
  270. //
  271. CharIndex = 0;
  272. while ( TRUE ) {
  273. //
  274. // Look for a switch
  275. //
  276. CharIndex = CmdLine->Strcspn( &Switches, CharIndex );
  277. if ( CharIndex != INVALID_CHNUM ) {
  278. //
  279. // There is a switch, see if it is the help switch
  280. //
  281. CharIndex++;
  282. if ( Match( "?" )) {
  283. //
  284. // This is a help switch, Display help
  285. //
  286. DisplayMessageAndExit( MODE_MESSAGE_HELP, NULL, EXIT_SUCCESS );
  287. }
  288. } else {
  289. break;
  290. }
  291. }
  292. //
  293. // No help requested, now we can parse the command line. First we
  294. // initialize our indeces.
  295. //
  296. ParmIndex = 0;
  297. CharIndex = 0;
  298. AdvanceIndex = 0;
  299. //
  300. // Match the program name
  301. //
  302. Advance();
  303. Match( "*" );
  304. Advance();
  305. //
  306. // If there are no parameters, or the only parameter is the
  307. // status switch, then this is a request for the status of
  308. // all devices.
  309. //
  310. if ( EndOfInput() ) {
  311. Request = MakeRequest( DEVICE_TYPE_ALL,
  312. ALL_DEVICES,
  313. REQUEST_TYPE_STATUS,
  314. sizeof( REQUEST_HEADER ) );
  315. } else if ( Match( "/STA*" ) ) {
  316. Advance();
  317. if ( !EndOfInput() ) {
  318. ParseError();
  319. }
  320. Request = MakeRequest( DEVICE_TYPE_ALL,
  321. ALL_DEVICES,
  322. REQUEST_TYPE_STATUS,
  323. sizeof( REQUEST_HEADER ) );
  324. } else if ( Match( "LPT#[:]" ) ) {
  325. //
  326. // lptline
  327. //
  328. Request = LptLine();
  329. } else if ( Match( "COM#[:]" ) ) {
  330. //
  331. // comline
  332. //
  333. Request = ComLine();
  334. } else if ( Match( "CON[:]" ) ) {
  335. //
  336. // conline
  337. //
  338. Request = ConLine();
  339. } else if ( Match( "#" ) ) {
  340. //
  341. // videoline
  342. //
  343. Request = VideoLine();
  344. } else {
  345. //
  346. // Parse error
  347. //
  348. ParseError();
  349. }
  350. } else {
  351. DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
  352. }
  353. //
  354. // Deallocate strings from resource
  355. //
  356. DeallocateResource();
  357. //
  358. // Return the request
  359. //
  360. return Request;
  361. }
  362. PREQUEST_HEADER
  363. LptLine (
  364. )
  365. /*++
  366. Routine Description:
  367. Takes care of parsing the lptline non-terminal symbol
  368. Arguments:
  369. None.
  370. Return Value:
  371. Pointer to the device request.
  372. Notes:
  373. --*/
  374. {
  375. PREQUEST_HEADER Request;
  376. ULONG DeviceNumber;
  377. //
  378. // Note that at this point we have matched the lpt device.
  379. // Get the device number;
  380. //
  381. DeviceNumber = GetNumber();
  382. Advance();
  383. if ( EndOfInput() ) {
  384. //
  385. // End redirection
  386. //
  387. Request = MakeRequest( DEVICE_TYPE_LPT,
  388. DeviceNumber,
  389. REQUEST_TYPE_LPT_ENDREDIR,
  390. sizeof( REQUEST_HEADER ) );
  391. } else if ( Match( "/STA*" ) ) {
  392. //
  393. // Status request
  394. //
  395. Request = MakeRequest( DEVICE_TYPE_LPT,
  396. DeviceNumber,
  397. REQUEST_TYPE_STATUS,
  398. sizeof( REQUEST_HEADER ) );
  399. } else if ( Match ( "=" ) ) {
  400. //
  401. // lptredir
  402. //
  403. Request = LptRedir( DeviceNumber );
  404. } else if ( Match( "#" ) || Match( "COLS=#" ) ||
  405. Match( "LINES=#" ) || Match( "RETRY=@" ) ) {
  406. //
  407. // lptset
  408. //
  409. Request = LptSet( DeviceNumber );
  410. } else if ( Match( "CP" ) || Match( "CODEPAGE" ) ) {
  411. //
  412. // lptcp
  413. //
  414. Request = LptCp( DeviceNumber );
  415. } else {
  416. //
  417. // Error
  418. //
  419. ParseError();
  420. }
  421. return Request;
  422. }
  423. PREQUEST_HEADER
  424. LptRedir (
  425. IN ULONG DeviceNumber
  426. )
  427. /*++
  428. Routine Description:
  429. Takes care of parsing the lptredir non-terminal symbol
  430. Arguments:
  431. DeviceNumber - Supplies the device number
  432. Return Value:
  433. Pointer to the device request.
  434. Notes:
  435. --*/
  436. {
  437. PREQUEST_HEADER Request;
  438. PLPT_REQUEST LptRequest;
  439. ULONG ComDevice;
  440. Advance();
  441. //
  442. // Can only redirect to COM devices
  443. //
  444. if ( Match( "COM#[:]" ) ) {
  445. ComDevice = GetNumber();
  446. Request = MakeRequest( DEVICE_TYPE_LPT,
  447. DeviceNumber,
  448. REQUEST_TYPE_LPT_REDIRECT,
  449. sizeof(LPT_REQUEST ) );
  450. LptRequest = (PLPT_REQUEST)Request;
  451. LptRequest->Data.Redirect.DeviceType = DEVICE_TYPE_COM;
  452. LptRequest->Data.Redirect.DeviceNumber = ComDevice;
  453. } else {
  454. //
  455. // Error
  456. //
  457. ParseError();
  458. }
  459. return Request;
  460. }
  461. PREQUEST_HEADER
  462. LptSet (
  463. IN ULONG DeviceNumber
  464. )
  465. /*++
  466. Routine Description:
  467. Takes care of parsing the lptset non-terminal symbol
  468. Arguments:
  469. DeviceNumber - Supplies the device number
  470. Return Value:
  471. Pointer to the device request.
  472. Notes:
  473. --*/
  474. {
  475. PREQUEST_HEADER Request;
  476. PLPT_REQUEST LptRequest;
  477. BOOLEAN SetCols = FALSE;
  478. BOOLEAN SetLines = FALSE;
  479. BOOLEAN SetRetry = FALSE;
  480. ULONG Cols;
  481. ULONG Lines;
  482. WCHAR Retry;
  483. if ( Match( "#" ) ) {
  484. //
  485. // Old syntax, where parameter are positional and comma-delimited.
  486. //
  487. // We will use the following automata for parsing the input
  488. // (eoi = end of input)
  489. //
  490. //
  491. // eoi
  492. // [Cols]------------->[End]
  493. // | ^
  494. // |, |eoi
  495. // v |
  496. // [X]-----------+
  497. // | ^
  498. // | # |eoi
  499. // +-->[Lines]--+
  500. // | | ^
  501. // | |, |
  502. // |<----+ |
  503. // | |
  504. // |, |eoi
  505. // | |
  506. // v |
  507. // [Y]-----------+
  508. // | ^
  509. // | @ |eoi
  510. // +-->[Retry]--+
  511. //
  512. //
  513. Cols = GetNumber();
  514. SetCols = TRUE;
  515. Advance();
  516. //
  517. // X:
  518. //
  519. if ( !Match( "," ) ) {
  520. goto Eoi;
  521. }
  522. Advance();
  523. if ( Match( "#" ) ) {
  524. // n
  525. // Lines
  526. //
  527. Lines = GetNumber();
  528. SetLines = TRUE;
  529. Advance();
  530. }
  531. //
  532. // Y:
  533. //
  534. if ( !Match ( "," ) ) {
  535. goto Eoi;
  536. }
  537. if ( Match( "@" ) ) {
  538. //
  539. // Retry
  540. //
  541. Retry = CmdLine->QueryChAt( MatchBegin );
  542. SetRetry = TRUE;
  543. Advance();
  544. }
  545. Eoi:
  546. if ( !EndOfInput() ) {
  547. //
  548. // Error
  549. //
  550. ParseError();
  551. }
  552. } else {
  553. //
  554. // New syntax, where parameters are tagged. The language assumes
  555. // that all parameters are optional (as long as there is at least
  556. // one present). If some is required, it is up to the Device
  557. // handler to complain latter on.
  558. //
  559. while ( !EndOfInput() ) {
  560. if ( Match( "COLS=#" ) ) {
  561. //
  562. // COLS=
  563. //
  564. Cols = GetNumber();
  565. SetCols = TRUE;
  566. Advance();
  567. } else if ( Match( "LINES=#" ) ) {
  568. //
  569. // LINES=
  570. //
  571. Lines = GetNumber();
  572. SetLines = TRUE;
  573. Advance();
  574. } else if ( Match( "RETRY=@" ) ) {
  575. //
  576. // RETRY=
  577. //
  578. Retry = CmdLine->QueryChAt( MatchBegin );
  579. SetRetry = TRUE;
  580. Advance();
  581. } else {
  582. ParseError();
  583. }
  584. }
  585. }
  586. //
  587. // Now that we parsed all the parameters, we make the request
  588. // packet.
  589. //
  590. Request = MakeRequest( DEVICE_TYPE_LPT,
  591. DeviceNumber,
  592. REQUEST_TYPE_LPT_SETUP,
  593. sizeof(LPT_REQUEST ) );
  594. LptRequest = (PLPT_REQUEST)Request;
  595. LptRequest->Data.Setup.SetCol = SetCols;
  596. LptRequest->Data.Setup.SetLines = SetLines;
  597. LptRequest->Data.Setup.SetRetry = SetRetry;
  598. LptRequest->Data.Setup.Col = Cols;
  599. LptRequest->Data.Setup.Lines = Lines;
  600. LptRequest->Data.Setup.Retry = Retry;
  601. return Request;
  602. }
  603. PREQUEST_HEADER
  604. LptCp (
  605. IN ULONG DeviceNumber
  606. )
  607. /*++
  608. Routine Description:
  609. Takes care of parsing the lptcp non-terminal symbol
  610. Arguments:
  611. DeviceNumber - Supplies the device number
  612. Return Value:
  613. Pointer to the device request.
  614. Notes:
  615. --*/
  616. {
  617. //
  618. // Since this is the same for LPT and CON, we use the same
  619. // function to handle both.
  620. //
  621. return CpStuff( DEVICE_TYPE_LPT, DeviceNumber );
  622. }
  623. PREQUEST_HEADER
  624. ComLine (
  625. )
  626. /*++
  627. Routine Description:
  628. Takes care of parsing the comline non-terminal symbol
  629. Arguments:
  630. None.
  631. Return Value:
  632. Pointer to the device request.
  633. Notes:
  634. --*/
  635. {
  636. PREQUEST_HEADER Request;
  637. ULONG DeviceNumber;
  638. //
  639. // Note that we have already matched the COM device.
  640. // Get the device number;
  641. //
  642. DeviceNumber = GetNumber();
  643. Advance();
  644. if ( Match( "/STA*" ) || EndOfInput() ) {
  645. //
  646. // Status request
  647. //
  648. Request = MakeRequest( DEVICE_TYPE_COM,
  649. DeviceNumber,
  650. REQUEST_TYPE_STATUS,
  651. sizeof( REQUEST_HEADER ) );
  652. } else {
  653. //
  654. // comset
  655. //
  656. Request = ComSet( DeviceNumber );
  657. }
  658. return Request;
  659. }
  660. PREQUEST_HEADER
  661. ComSet (
  662. IN ULONG DeviceNumber
  663. )
  664. /*++
  665. Routine Description:
  666. Takes care of parsing the comset non-terminal symbol
  667. Arguments:
  668. DeviceNumber - Supplies the device number
  669. Return Value:
  670. Pointer to the device request.
  671. Notes:
  672. --*/
  673. {
  674. PREQUEST_HEADER Request;
  675. PCOM_REQUEST ComRequest;
  676. BOOLEAN SetBaud = FALSE;
  677. BOOLEAN SetDataBits = FALSE;
  678. BOOLEAN SetStopBits = FALSE;
  679. BOOLEAN SetParity = FALSE;
  680. BOOLEAN SetRetry = FALSE;
  681. BOOLEAN SetTimeOut = FALSE;
  682. BOOLEAN SetXon = FALSE;
  683. BOOLEAN SetOdsr = FALSE;
  684. BOOLEAN SetIdsr = FALSE;
  685. BOOLEAN SetOcts = FALSE;
  686. BOOLEAN SetDtrControl = FALSE;
  687. BOOLEAN SetRtsControl = FALSE;
  688. ULONG Baud;
  689. ULONG DataBits;
  690. STOPBITS StopBits;
  691. PARITY Parity;
  692. WCHAR Retry;
  693. BOOLEAN TimeOut;
  694. BOOLEAN Xon;
  695. BOOLEAN Odsr;
  696. BOOLEAN Idsr;
  697. BOOLEAN Octs;
  698. DTR_CONTROL DtrControl;
  699. RTS_CONTROL RtsControl;
  700. if ( Match( "#" ) ) {
  701. //
  702. // Old syntax, where parameter are positional and comma-delimited.
  703. //
  704. // We will use the following automata for parsing the input
  705. // (eoi = end of input):
  706. //
  707. // eoi
  708. // [Baud]------------->[End]
  709. // | ^
  710. // |, |eoi
  711. // v |
  712. // [a]-----------+
  713. // | ^
  714. // | @ |eoi
  715. // +-->[Parity]-+
  716. // | | ^
  717. // | |, |
  718. // |<----+ |
  719. // | |
  720. // |, |eoi
  721. // | |
  722. // v |
  723. // [b]-----------+
  724. // | ^
  725. // | # |eoi
  726. // +-->[Data]---+
  727. // | | ^
  728. // | |, |
  729. // |<----+ |
  730. // | |
  731. // |, |eoi
  732. // v |
  733. // [c]-----------+
  734. // | ^
  735. // | # |eoi
  736. // +-->[Stop]---+
  737. //
  738. //
  739. // Assume xon=off
  740. //
  741. SetXon = TRUE;
  742. SetOdsr = TRUE;
  743. SetOcts = TRUE;
  744. SetDtrControl = TRUE;
  745. SetRtsControl = TRUE;
  746. Xon = FALSE;
  747. Odsr = FALSE;
  748. Octs = FALSE;
  749. DtrControl = DTR_ENABLE;
  750. RtsControl = RTS_ENABLE;
  751. Baud = ConvertBaudRate( GetNumber() );
  752. SetBaud = TRUE;
  753. Advance();
  754. //
  755. // A:
  756. //
  757. if ( !Match( "," ) ) {
  758. goto Eoi;
  759. }
  760. Advance();
  761. if ( !Match( "," ) && Match( "@" ) ) {
  762. //
  763. // Parity
  764. //
  765. Parity = ConvertParity( CmdLine->QueryChAt( MatchBegin ) );
  766. SetParity = TRUE;
  767. Advance();
  768. }
  769. //
  770. // B:
  771. //
  772. if ( !Match( "," )) {
  773. goto Eoi;
  774. }
  775. Advance();
  776. if ( Match( "#" )) {
  777. //
  778. // Data bits
  779. //
  780. DataBits = ConvertDataBits( GetNumber() );
  781. SetDataBits = TRUE;
  782. Advance();
  783. }
  784. //
  785. // C:
  786. //
  787. if ( !Match( "," )) {
  788. goto Eoi;
  789. }
  790. Advance();
  791. if ( Match( "1.5" ) ) {
  792. StopBits = COMM_STOPBITS_15;
  793. SetStopBits = TRUE;
  794. Advance();
  795. } else if ( Match( "#" ) ) {
  796. StopBits = ConvertStopBits( GetNumber() );
  797. SetStopBits = TRUE;
  798. Advance();
  799. }
  800. if (!Match( "," )) {
  801. goto Eoi;
  802. }
  803. Advance();
  804. if ( Match( "x" )) {
  805. //
  806. // XON=ON
  807. //
  808. SetXon = TRUE;
  809. SetOdsr = TRUE;
  810. SetOcts = TRUE;
  811. SetDtrControl = TRUE;
  812. SetRtsControl = TRUE;
  813. Xon = TRUE;
  814. Odsr = FALSE;
  815. Octs = FALSE;
  816. DtrControl = DTR_ENABLE;
  817. RtsControl = RTS_ENABLE;
  818. Advance();
  819. } else if ( Match( "p" )) {
  820. //
  821. // Permanent retry - Hardware handshaking
  822. //
  823. SetXon = TRUE;
  824. SetOdsr = TRUE;
  825. SetOcts = TRUE;
  826. SetDtrControl = TRUE;
  827. SetRtsControl = TRUE;
  828. Xon = FALSE;
  829. Odsr = TRUE;
  830. Octs = TRUE;
  831. DtrControl = DTR_HANDSHAKE;
  832. RtsControl = RTS_HANDSHAKE;
  833. Advance();
  834. } else {
  835. //
  836. // XON=OFF
  837. //
  838. SetXon = TRUE;
  839. SetOdsr = TRUE;
  840. SetOcts = TRUE;
  841. SetDtrControl = TRUE;
  842. SetRtsControl = TRUE;
  843. Xon = FALSE;
  844. Odsr = FALSE;
  845. Octs = FALSE;
  846. DtrControl = DTR_ENABLE;
  847. RtsControl = RTS_ENABLE;
  848. }
  849. Eoi:
  850. if ( !EndOfInput() ) {
  851. //
  852. // Error
  853. //
  854. ParseError();
  855. }
  856. } else {
  857. //
  858. // New syntax, where parameters are tagged. The language assumes
  859. // that all parameters are optional (as long as there is at least
  860. // one present). If some is required, it is up to the Device
  861. // handler to complain latter on.
  862. //
  863. while ( !EndOfInput() ) {
  864. if ( Match( "BAUD=#" ) ) {
  865. //
  866. // BAUD=
  867. //
  868. Baud = ConvertBaudRate( GetNumber() );
  869. SetBaud = TRUE;
  870. Advance();
  871. } else if ( Match( "PARITY=@" ) ) {
  872. //
  873. // PARITY=
  874. //
  875. Parity = ConvertParity( CmdLine->QueryChAt( MatchBegin ) );
  876. SetParity = TRUE;
  877. Advance();
  878. } else if ( Match( "DATA=#" ) ) {
  879. //
  880. // DATA=
  881. //
  882. DataBits = ConvertDataBits( GetNumber() );
  883. SetDataBits = TRUE;
  884. Advance();
  885. } else if ( Match( "STOP=1.5" ) ) {
  886. //
  887. // STOP=1.5
  888. //
  889. StopBits = COMM_STOPBITS_15;
  890. SetStopBits = TRUE;
  891. Advance();
  892. } else if ( Match( "STOP=#" ) ) {
  893. //
  894. // STOP=
  895. //
  896. StopBits = ConvertStopBits( GetNumber() );
  897. SetStopBits = TRUE;
  898. Advance();
  899. } else if ( Match( "RETRY=@" ) ) {
  900. //
  901. // RETRY=
  902. //
  903. Retry = ConvertRetry( CmdLine->QueryChAt( MatchBegin ) );
  904. SetRetry = TRUE;
  905. Advance();
  906. } else if ( Match( "TO=ON" ) ) {
  907. //
  908. // TO=ON
  909. //
  910. SetTimeOut = TRUE;
  911. TimeOut = FALSE; // FALSE means finite timeout
  912. Advance();
  913. } else if ( Match( "TO=OFF" ) ) {
  914. //
  915. // TO=OFF
  916. //
  917. SetTimeOut = TRUE;
  918. TimeOut = TRUE; // TRUE means infinite timeout
  919. Advance();
  920. } else if ( Match( "XON=ON" ) ) {
  921. //
  922. // XON=ON
  923. //
  924. SetXon = TRUE;
  925. Xon = TRUE;
  926. Advance();
  927. } else if ( Match( "XON=OFF" ) ) {
  928. //
  929. // XON=OFF
  930. //
  931. SetXon = TRUE;
  932. Xon = FALSE;
  933. Advance();
  934. } else if ( Match( "ODSR=ON" ) ) {
  935. //
  936. // ODSR=ON
  937. //
  938. SetOdsr = TRUE;
  939. Odsr = TRUE;
  940. Advance();
  941. } else if ( Match( "ODSR=OFF" ) ) {
  942. //
  943. // ODSR=OFF
  944. //
  945. SetOdsr = TRUE;
  946. Odsr = FALSE;
  947. Advance();
  948. } else if ( Match( "IDSR=ON" ) ) {
  949. //
  950. // IDSR=ON
  951. //
  952. SetIdsr = TRUE;
  953. Idsr = TRUE;
  954. Advance();
  955. } else if ( Match( "IDSR=OFF" ) ) {
  956. //
  957. // IDSR=OFF
  958. //
  959. SetIdsr = TRUE;
  960. Idsr = FALSE;
  961. Advance();
  962. } else if ( Match( "OCTS=ON" ) ) {
  963. //
  964. // OCS=ON
  965. //
  966. SetOcts = TRUE;
  967. Octs = TRUE;
  968. Advance();
  969. } else if ( Match( "OCTS=OFF" ) ) {
  970. //
  971. // OCS=OFF
  972. //
  973. SetOcts = TRUE;
  974. Octs = FALSE;
  975. Advance();
  976. } else if ( Match( "DTR=*" ) ) {
  977. //
  978. // DTR=
  979. //
  980. DtrControl = ConvertDtrControl( CmdLine, MatchBegin, MatchEnd ) ;
  981. SetDtrControl = TRUE;
  982. Advance();
  983. } else if ( Match( "RTS=*" ) ) {
  984. //
  985. // RTS=
  986. //
  987. RtsControl = ConvertRtsControl( CmdLine, MatchBegin, MatchEnd ) ;
  988. SetRtsControl = TRUE;
  989. Advance();
  990. } else {
  991. ParseError();
  992. }
  993. }
  994. }
  995. //
  996. // Now that parsing is done, we can make the request packet.
  997. //
  998. Request = MakeRequest( DEVICE_TYPE_COM,
  999. DeviceNumber,
  1000. REQUEST_TYPE_COM_SET,
  1001. sizeof(COM_REQUEST ) );
  1002. ComRequest = (PCOM_REQUEST)Request;
  1003. ComRequest->Data.Set.SetBaud = SetBaud;
  1004. ComRequest->Data.Set.SetDataBits = SetDataBits;
  1005. ComRequest->Data.Set.SetStopBits = SetStopBits;
  1006. ComRequest->Data.Set.SetParity = SetParity;
  1007. ComRequest->Data.Set.SetRetry = SetRetry;
  1008. ComRequest->Data.Set.SetTimeOut = SetTimeOut;
  1009. ComRequest->Data.Set.SetXon = SetXon;
  1010. ComRequest->Data.Set.SetOdsr = SetOdsr;
  1011. ComRequest->Data.Set.SetIdsr = SetIdsr;
  1012. ComRequest->Data.Set.SetOcts = SetOcts;
  1013. ComRequest->Data.Set.SetDtrControl = SetDtrControl;
  1014. ComRequest->Data.Set.SetRtsControl = SetRtsControl;
  1015. ComRequest->Data.Set.Baud = Baud;
  1016. ComRequest->Data.Set.DataBits = DataBits;
  1017. ComRequest->Data.Set.StopBits = StopBits;
  1018. ComRequest->Data.Set.Parity = Parity;
  1019. ComRequest->Data.Set.Retry = Retry;
  1020. ComRequest->Data.Set.TimeOut = TimeOut;
  1021. ComRequest->Data.Set.Xon = Xon;
  1022. ComRequest->Data.Set.Odsr = Odsr;
  1023. ComRequest->Data.Set.Idsr = Idsr;
  1024. ComRequest->Data.Set.Octs = Octs;
  1025. ComRequest->Data.Set.DtrControl = DtrControl;
  1026. ComRequest->Data.Set.RtsControl = RtsControl;
  1027. return Request;
  1028. }
  1029. PREQUEST_HEADER
  1030. ConLine (
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. Takes care of parsing ConLine
  1035. Arguments:
  1036. None.
  1037. Return Value:
  1038. Pointer to the device request.
  1039. Notes:
  1040. --*/
  1041. {
  1042. PREQUEST_HEADER Request;
  1043. Advance();
  1044. if ( Match( "/STA*" ) || EndOfInput() ) {
  1045. //
  1046. // Status request
  1047. //
  1048. Request = MakeRequest( DEVICE_TYPE_CON,
  1049. 0,
  1050. REQUEST_TYPE_STATUS,
  1051. sizeof( REQUEST_HEADER ) );
  1052. } else if ( Match( "COLS=#" ) || Match( "LINES=#" ) ) {
  1053. //
  1054. // conrc
  1055. //
  1056. Request = ConRc();
  1057. } else if ( Match( "RATE=#" ) || Match( "DELAY=#" ) ) {
  1058. //
  1059. // contyp
  1060. //
  1061. Request = ConTyp();
  1062. } else if ( Match( "CP" ) || Match( "CODEPAGE" ) ) {
  1063. //
  1064. // concp
  1065. //
  1066. Request = ConCp();
  1067. } else {
  1068. //
  1069. // Error
  1070. //
  1071. ParseError();
  1072. }
  1073. return Request;
  1074. }
  1075. PREQUEST_HEADER
  1076. ConRc (
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. Takes care of parsing the conrc non-terminal
  1081. Arguments:
  1082. None
  1083. Return Value:
  1084. Pointer to the device request.
  1085. Notes:
  1086. --*/
  1087. {
  1088. PREQUEST_HEADER Request;
  1089. PCON_REQUEST ConRequest;
  1090. BOOLEAN SetCol = FALSE;
  1091. BOOLEAN SetLines = FALSE;
  1092. ULONG Col;
  1093. ULONG Lines;
  1094. while ( !EndOfInput() ) {
  1095. if ( Match( "LINES=#" )) {
  1096. //
  1097. // LINES=
  1098. //
  1099. Lines = GetNumber();
  1100. SetLines = TRUE;
  1101. Advance();
  1102. } else if ( Match( "COLS=#" )) {
  1103. //
  1104. // COLS=
  1105. //
  1106. Col = GetNumber();
  1107. SetCol = TRUE;
  1108. Advance();
  1109. } else {
  1110. ParseError();
  1111. }
  1112. }
  1113. //
  1114. // We are done parsing, we make the request packet.
  1115. //
  1116. Request = MakeRequest( DEVICE_TYPE_CON,
  1117. 0,
  1118. REQUEST_TYPE_CON_SET_ROWCOL,
  1119. sizeof(CON_REQUEST ) );
  1120. ConRequest = (PCON_REQUEST)Request;
  1121. ConRequest->Data.RowCol.SetCol = SetCol;
  1122. ConRequest->Data.RowCol.SetLines = SetLines;
  1123. ConRequest->Data.RowCol.Col = Col;
  1124. ConRequest->Data.RowCol.Lines = Lines;
  1125. return Request;
  1126. }
  1127. PREQUEST_HEADER
  1128. ConTyp (
  1129. )
  1130. /*++
  1131. Routine Description:
  1132. Takes care of parsing the contyp non-terminal
  1133. Arguments:
  1134. None
  1135. Return Value:
  1136. Pointer to the device request.
  1137. Notes:
  1138. --*/
  1139. {
  1140. PREQUEST_HEADER Request;
  1141. PCON_REQUEST ConRequest;
  1142. BOOLEAN SetRate = FALSE;
  1143. BOOLEAN SetDelay = FALSE;
  1144. ULONG Rate;
  1145. ULONG Delay;
  1146. //
  1147. // RATE=
  1148. //
  1149. if ( Match( "RATE=#" )) {
  1150. Rate = GetNumber();
  1151. SetRate = TRUE;
  1152. Advance();
  1153. }
  1154. //
  1155. // DELAY=
  1156. //
  1157. if ( Match( "DELAY=#" )) {
  1158. Delay = GetNumber();
  1159. SetDelay = TRUE;
  1160. Advance();
  1161. }
  1162. if ( !EndOfInput() ) {
  1163. //
  1164. // Error
  1165. //
  1166. ParseError();
  1167. }
  1168. //
  1169. // We are don parsing, we make the request packet.
  1170. //
  1171. Request = MakeRequest( DEVICE_TYPE_CON,
  1172. 0,
  1173. REQUEST_TYPE_CON_SET_TYPEMATIC,
  1174. sizeof(CON_REQUEST ) );
  1175. ConRequest = (PCON_REQUEST)Request;
  1176. ConRequest->Data.Typematic.SetRate = SetRate;
  1177. ConRequest->Data.Typematic.SetDelay = SetDelay;
  1178. ConRequest->Data.Typematic.Rate = Rate;
  1179. ConRequest->Data.Typematic.Delay = Delay;
  1180. return Request;
  1181. }
  1182. PREQUEST_HEADER
  1183. ConCp (
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. Takes care of parsing the concp non-terminal symbol
  1188. Arguments:
  1189. None
  1190. Return Value:
  1191. Pointer to the device request.
  1192. Notes:
  1193. --*/
  1194. {
  1195. return CpStuff( DEVICE_TYPE_CON, 0 );
  1196. }
  1197. PREQUEST_HEADER
  1198. VideoLine (
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. Takes care of parsing the videoline non-terminal symbol
  1203. Arguments:
  1204. None.
  1205. Return Value:
  1206. Pointer to the device request.
  1207. Notes:
  1208. --*/
  1209. {
  1210. PREQUEST_HEADER Request;
  1211. PCON_REQUEST ConRequest;
  1212. BOOLEAN SetCol = FALSE;
  1213. BOOLEAN SetLines = FALSE;
  1214. ULONG Col;
  1215. ULONG Lines;
  1216. //
  1217. // This is in the old syntax, where parameter are positional
  1218. // and comma-delimited.
  1219. //
  1220. // We will use the following automata for parsing the input
  1221. // (eoi = end of input):
  1222. //
  1223. // eoi
  1224. // [Cols]--------->[End]
  1225. // | ^
  1226. // |, |
  1227. // v |
  1228. // [ ] |
  1229. // | |
  1230. // |# |
  1231. // | |
  1232. // v eoi |
  1233. // [Lines]-----+
  1234. //
  1235. if ( Match( "#" )) {
  1236. //
  1237. // Cols
  1238. //
  1239. Col = GetNumber();
  1240. SetCol = TRUE;
  1241. Advance();
  1242. }
  1243. if ( Match( "," ) ) {
  1244. Advance();
  1245. if ( Match( "#" )) {
  1246. Lines = GetNumber();
  1247. SetLines = TRUE;
  1248. Advance();
  1249. } else {
  1250. ParseError();
  1251. }
  1252. }
  1253. if ( !EndOfInput() ) {
  1254. //
  1255. // Error
  1256. //
  1257. ParseError();
  1258. }
  1259. //
  1260. // We are done parsing, make the request packet
  1261. //
  1262. Request = MakeRequest( DEVICE_TYPE_CON,
  1263. 0,
  1264. REQUEST_TYPE_CON_SET_ROWCOL,
  1265. sizeof(CON_REQUEST ) );
  1266. ConRequest = (PCON_REQUEST)Request;
  1267. ConRequest->Data.RowCol.SetCol = SetCol;
  1268. ConRequest->Data.RowCol.SetLines = SetLines;
  1269. ConRequest->Data.RowCol.Col = Col;
  1270. ConRequest->Data.RowCol.Lines = Lines;
  1271. return Request;
  1272. }
  1273. PREQUEST_HEADER
  1274. CpStuff (
  1275. IN DEVICE_TTYPE DeviceType,
  1276. IN ULONG DeviceNumber
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. Takes care of parsing the cpstuff non-terminal symbol
  1281. Arguments:
  1282. DeviceType - Supplies device type
  1283. DeviceNumber - Supplies device number
  1284. Return Value:
  1285. Pointer to the device request.
  1286. Notes:
  1287. --*/
  1288. {
  1289. PREQUEST_HEADER Request;
  1290. PCON_REQUEST ConRequest;
  1291. Advance();
  1292. if ( Match( "PREPARE=*" ) ) {
  1293. //
  1294. //
  1295. // PREPARE=
  1296. //
  1297. // This is a No-Op
  1298. //
  1299. Request = MakeRequest( DeviceType,
  1300. DeviceNumber,
  1301. REQUEST_TYPE_CODEPAGE_PREPARE,
  1302. sizeof( REQUEST_HEADER ) );
  1303. } else if ( Match( "SELECT=#" ) ) {
  1304. //
  1305. //
  1306. // SELECT=
  1307. //
  1308. // Note that this relies on the fact that codepage requests
  1309. // are identical for all devices.
  1310. //
  1311. Request = MakeRequest( DeviceType,
  1312. DeviceNumber,
  1313. REQUEST_TYPE_CODEPAGE_SELECT,
  1314. sizeof( CON_REQUEST ) );
  1315. ConRequest = (PCON_REQUEST)Request;
  1316. ConRequest->Data.CpSelect.Codepage = GetNumber();
  1317. } else if ( Match( "/STA*" ) || EndOfInput() ) {
  1318. //
  1319. // /STATUS
  1320. //
  1321. Request = MakeRequest( DeviceType,
  1322. DeviceNumber,
  1323. REQUEST_TYPE_CODEPAGE_STATUS,
  1324. sizeof( REQUEST_HEADER ) );
  1325. } else if ( Match( "REFRESH" ) ) {
  1326. //
  1327. //
  1328. // REFRESH
  1329. //
  1330. // This is a No-Op
  1331. //
  1332. Request = MakeRequest( DeviceType,
  1333. DeviceNumber,
  1334. REQUEST_TYPE_CODEPAGE_REFRESH,
  1335. sizeof( REQUEST_HEADER ) );
  1336. } else {
  1337. ParseError();
  1338. }
  1339. return Request;
  1340. }
  1341. BOOLEAN
  1342. AllocateResource(
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. Allocate strings from the resource
  1347. Arguments:
  1348. None.
  1349. Return Value:
  1350. None
  1351. Notes:
  1352. --*/
  1353. {
  1354. CmdLine = NEW DSTRING;
  1355. return (NULL == CmdLine) ? FALSE : TRUE;
  1356. }
  1357. VOID
  1358. DeallocateResource(
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. Deallocate strings from the resource
  1363. Arguments:
  1364. None.
  1365. Return Value:
  1366. None
  1367. Notes:
  1368. --*/
  1369. {
  1370. DELETE( CmdLine );
  1371. }
  1372. BOOLEAN
  1373. Match(
  1374. IN PCSTR Pattern
  1375. )
  1376. /*++
  1377. Routine Description:
  1378. This function matches a pattern against whatever
  1379. is in the command line at the current position.
  1380. Note that this does not advance our current position
  1381. within the command line.
  1382. If the pattern has a magic character, then the
  1383. variables MatchBegin and MatchEnd delimit the
  1384. substring of the command line that matched that
  1385. magic character.
  1386. Arguments:
  1387. Pattern - Supplies pointer to the pattern to match
  1388. Return Value:
  1389. BOOLEAN - TRUE if the pattern matched, FALSE otherwise
  1390. Notes:
  1391. --*/
  1392. {
  1393. DSTRING PatternString;
  1394. BOOLEAN StatusOk;
  1395. StatusOk = PatternString.Initialize( Pattern );
  1396. DebugAssert( StatusOk );
  1397. if ( StatusOk ) {
  1398. return Match( &PatternString );
  1399. } else {
  1400. DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
  1401. }
  1402. //NOTREACHED
  1403. return StatusOk;
  1404. }
  1405. BOOLEAN
  1406. Match(
  1407. IN PCWSTRING Pattern
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This function matches a pattern against whatever
  1412. is in the command line at the current position.
  1413. Note that this does not advance our current position
  1414. within the command line.
  1415. If the pattern has a magic character, then the
  1416. variables MatchBegin and MatchEnd delimit the
  1417. substring of the command line that matched that
  1418. magic character.
  1419. Arguments:
  1420. Pattern - Supplies pointer to the pattern to match
  1421. Return Value:
  1422. BOOLEAN - TRUE if the pattern matched, FALSE otherwise
  1423. Notes:
  1424. --*/
  1425. {
  1426. CHNUM CmdIndex; // Index within command line
  1427. CHNUM PatternIndex; // Index within pattern
  1428. WCHAR PatternChar; // Character in pattern
  1429. WCHAR CmdChar; // Character in command line;
  1430. DebugPtrAssert( Pattern );
  1431. CmdIndex = CharIndex;
  1432. PatternIndex = 0;
  1433. while ( (PatternChar = Pattern->QueryChAt( PatternIndex )) != INVALID_CHAR ) {
  1434. switch ( PatternChar ) {
  1435. case '#':
  1436. //
  1437. // Match a number
  1438. //
  1439. MatchBegin = CmdIndex;
  1440. MatchEnd = MatchBegin;
  1441. //
  1442. // Get all consecutive digits
  1443. //
  1444. while ( ((CmdChar = CmdLine->QueryChAt( MatchEnd )) != INVALID_CHAR) &&
  1445. isdigit( (char)CmdChar ) ) {
  1446. MatchEnd++;
  1447. }
  1448. MatchEnd--;
  1449. if ( MatchBegin > MatchEnd ) {
  1450. //
  1451. // No number
  1452. //
  1453. return FALSE;
  1454. }
  1455. CmdIndex = MatchEnd + 1;
  1456. PatternIndex++;
  1457. break;
  1458. case '@':
  1459. //
  1460. // Match one character
  1461. //
  1462. if ( CmdIndex >= CmdLine->QueryChCount() ) {
  1463. return FALSE;
  1464. }
  1465. MatchBegin = MatchEnd = CmdIndex;
  1466. CmdIndex++;
  1467. PatternIndex++;
  1468. break;
  1469. case '*':
  1470. //
  1471. // Match everything up to next blank (or end of input)
  1472. //
  1473. MatchBegin = CmdIndex;
  1474. MatchEnd = MatchBegin;
  1475. while ( ( (CmdChar = CmdLine->QueryChAt( MatchEnd )) != INVALID_CHAR ) &&
  1476. ( CmdChar != (WCHAR)' ' ) ) {
  1477. MatchEnd++;
  1478. }
  1479. MatchEnd--;
  1480. CmdIndex = MatchEnd+1;
  1481. PatternIndex++;
  1482. break;
  1483. case '[':
  1484. //
  1485. // Optional sequence
  1486. //
  1487. PatternIndex++;
  1488. PatternChar = Pattern->QueryChAt( PatternIndex );
  1489. CmdChar = CmdLine->QueryChAt( CmdIndex );
  1490. //
  1491. // If the first charcter in the input does not match the
  1492. // first character in the optional sequence, we just
  1493. // skip the optional sequence.
  1494. //
  1495. if ( ( CmdChar == INVALID_CHAR ) ||
  1496. ( CmdChar == ' ') ||
  1497. ( towupper(CmdChar) != towupper(PatternChar) ) ) {
  1498. while ( PatternChar != ']' ) {
  1499. PatternIndex++;
  1500. PatternChar = Pattern->QueryChAt( PatternIndex );
  1501. }
  1502. PatternIndex++;
  1503. } else {
  1504. //
  1505. // Since the first character in the sequence matched, now
  1506. // everything must match.
  1507. //
  1508. while ( PatternChar != ']' ) {
  1509. if ( towupper(PatternChar) != towupper(CmdChar) ) {
  1510. return FALSE;
  1511. }
  1512. CmdIndex++;
  1513. PatternIndex++;
  1514. CmdChar = CmdLine->QueryChAt( CmdIndex );
  1515. PatternChar = Pattern->QueryChAt( PatternIndex );
  1516. }
  1517. PatternIndex++;
  1518. }
  1519. break;
  1520. default:
  1521. //
  1522. // Both characters must match
  1523. //
  1524. CmdChar = CmdLine->QueryChAt( CmdIndex );
  1525. if ( ( CmdChar == INVALID_CHAR ) ||
  1526. ( towupper(CmdChar) != towupper(PatternChar) ) ) {
  1527. return FALSE;
  1528. }
  1529. CmdIndex++;
  1530. PatternIndex++;
  1531. break;
  1532. }
  1533. }
  1534. AdvanceIndex = CmdIndex;
  1535. return TRUE;
  1536. }
  1537. VOID
  1538. Advance(
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. Advances our pointers to the beginning of the next lexeme
  1543. Arguments:
  1544. None
  1545. Return Value:
  1546. None
  1547. --*/
  1548. {
  1549. CharIndex = AdvanceIndex;
  1550. //
  1551. // Skip blank space
  1552. //
  1553. if ( CmdLine->QueryChAt( CharIndex ) == ' ' ) {
  1554. while ( CmdLine->QueryChAt( CharIndex ) == ' ' ) {
  1555. CharIndex++;
  1556. }
  1557. ParmIndex = CharIndex;
  1558. }
  1559. }
  1560. VOID
  1561. ParseError(
  1562. )
  1563. /*++
  1564. Routine Description:
  1565. Display Invalid parameter error message and exits
  1566. Arguments:
  1567. None
  1568. Return Value:
  1569. None
  1570. --*/
  1571. {
  1572. DSTRING Parameter;
  1573. CHNUM ParmEnd;
  1574. //
  1575. // Look for end of parameter
  1576. //
  1577. ParmEnd = CmdLine->Strchr( ' ', ParmIndex );
  1578. Parameter.Initialize( CmdLine,
  1579. ParmIndex,
  1580. (ParmEnd == INVALID_CHNUM) ? TO_END : ParmEnd - ParmIndex );
  1581. DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
  1582. &Parameter,
  1583. (ULONG)EXIT_ERROR );
  1584. }
  1585. PREQUEST_HEADER
  1586. MakeRequest(
  1587. IN DEVICE_TTYPE DeviceType,
  1588. IN LONG DeviceNumber,
  1589. IN REQUEST_TYPE RequestType,
  1590. IN ULONG Size
  1591. )
  1592. /*++
  1593. Routine Description:
  1594. Makes a request and initializes its header.
  1595. Arguments:
  1596. DeviceType - Supplies the type of device
  1597. DeviceNumber - Supplies the device number
  1598. RequestType - Supplies the type of request
  1599. Size - Supplies size of the request packet
  1600. Return Value:
  1601. Pointer to the device request.
  1602. Notes:
  1603. --*/
  1604. {
  1605. PREQUEST_HEADER Request;
  1606. DebugAssert( Size >= sizeof( REQUEST_HEADER )) ;
  1607. Request = (PREQUEST_HEADER)MALLOC( (unsigned int)Size );
  1608. DebugPtrAssert( Request );
  1609. if ( !Request ) {
  1610. DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
  1611. }
  1612. Request->DeviceType = DeviceType;
  1613. Request->DeviceNumber = DeviceNumber;
  1614. Request->DeviceName = NULL;
  1615. Request->RequestType = RequestType;
  1616. return Request;
  1617. }
  1618. ULONG
  1619. GetNumber(
  1620. )
  1621. /*++
  1622. Routine Description:
  1623. Converts the substring delimited by MatchBegin and MatchEnd into
  1624. a number.
  1625. Arguments:
  1626. None
  1627. Return Value:
  1628. ULONG - The matched string converted to a number
  1629. --*/
  1630. {
  1631. LONG Number;
  1632. DebugAssert( MatchEnd >= MatchBegin );
  1633. if ( !CmdLine->QueryNumber( &Number, MatchBegin, (MatchEnd-MatchBegin)+1 ) ) {
  1634. ParseError();
  1635. }
  1636. return (ULONG)Number;
  1637. }