Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

611 lines
13 KiB

  1. /*++
  2. Copyright (c) 1998 Intel Corporation
  3. Module Name:
  4. conio.c
  5. Abstract:
  6. Shell Environment driver
  7. Revision History
  8. --*/
  9. #include "shelle.h"
  10. /*
  11. *
  12. */
  13. #define MAX_HISTORY 20
  14. #define INPUT_LINE_SIGNATURE EFI_SIGNATURE_32('i','s','i','g')
  15. typedef struct {
  16. UINTN Signature;
  17. LIST_ENTRY Link;
  18. CHAR16 Buffer[MAX_CMDLINE];
  19. } INPUT_LINE;
  20. /*
  21. * Globals
  22. */
  23. static BOOLEAN SEnvInsertMode;
  24. static LIST_ENTRY SEnvLineHistory;
  25. static UINTN SEnvNoHistory;
  26. /*
  27. *
  28. */
  29. VOID
  30. SEnvConIoInitDosKey (
  31. VOID
  32. )
  33. {
  34. InitializeListHead (&SEnvLineHistory);
  35. SEnvInsertMode = FALSE;
  36. SEnvNoHistory = 0;
  37. }
  38. /*
  39. * Functions used to access the console interface via a file handle
  40. * Used if the console is not being redirected to a file
  41. */
  42. EFI_STATUS
  43. SEnvConIoOpen (
  44. IN struct _EFI_FILE_HANDLE *File,
  45. OUT struct _EFI_FILE_HANDLE **NewHandle,
  46. IN CHAR16 *FileName,
  47. IN UINT64 OpenMode,
  48. IN UINT64 Attributes
  49. )
  50. {
  51. return EFI_NOT_FOUND;
  52. }
  53. EFI_STATUS
  54. SEnvConIoNop (
  55. IN struct _EFI_FILE_HANDLE *File
  56. )
  57. {
  58. return EFI_SUCCESS;
  59. }
  60. EFI_STATUS
  61. SEnvConIoGetPosition (
  62. IN struct _EFI_FILE_HANDLE *File,
  63. OUT UINT64 *Position
  64. )
  65. {
  66. return EFI_UNSUPPORTED;
  67. }
  68. EFI_STATUS
  69. SEnvConIoSetPosition (
  70. IN struct _EFI_FILE_HANDLE *File,
  71. OUT UINT64 Position
  72. )
  73. {
  74. return EFI_UNSUPPORTED;
  75. }
  76. EFI_STATUS
  77. SEnvConIoGetInfo (
  78. IN struct _EFI_FILE_HANDLE *File,
  79. IN EFI_GUID *InformationType,
  80. IN OUT UINTN *BufferSize,
  81. OUT VOID *Buffer
  82. )
  83. {
  84. return EFI_UNSUPPORTED;
  85. }
  86. EFI_STATUS
  87. SEnvConIoSetInfo (
  88. IN struct _EFI_FILE_HANDLE *File,
  89. IN EFI_GUID *InformationType,
  90. IN UINTN BufferSize,
  91. OUT VOID *Buffer
  92. )
  93. {
  94. return EFI_UNSUPPORTED;
  95. }
  96. EFI_STATUS
  97. SEnvConIoWrite (
  98. IN struct _EFI_FILE_HANDLE *File,
  99. IN OUT UINTN *BufferSize,
  100. IN VOID *Buffer
  101. )
  102. {
  103. Print (L"%.*s", *BufferSize, Buffer);
  104. return EFI_SUCCESS;
  105. }
  106. EFI_STATUS
  107. SEnvErrIoWrite (
  108. IN struct _EFI_FILE_HANDLE *File,
  109. IN OUT UINTN *BufferSize,
  110. IN VOID *Buffer
  111. )
  112. {
  113. IPrint (ST->StdErr, L"%.*s", *BufferSize, Buffer);
  114. return EFI_SUCCESS;
  115. }
  116. EFI_STATUS
  117. SEnvErrIoRead (
  118. IN struct _EFI_FILE_HANDLE *File,
  119. IN OUT UINTN *BufferSize,
  120. IN VOID *Buffer
  121. )
  122. {
  123. return EFI_UNSUPPORTED;
  124. }
  125. VOID
  126. SEnvPrintHistory(
  127. VOID
  128. )
  129. {
  130. LIST_ENTRY *Link;
  131. INPUT_LINE *Line;
  132. UINTN Index;
  133. Print (L"\n");
  134. Index = 0;
  135. for (Link=SEnvLineHistory.Flink; Link != &SEnvLineHistory; Link=Link->Flink) {
  136. Index += 1;
  137. Line = CR(Link, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
  138. Print (L"%2d. %s\n", Index, Line->Buffer);
  139. }
  140. }
  141. EFI_STATUS
  142. SEnvConIoRead (
  143. IN struct _EFI_FILE_HANDLE *File,
  144. IN OUT UINTN *BufferSize,
  145. IN VOID *Buffer
  146. )
  147. {
  148. CHAR16 *Str;
  149. BOOLEAN Done;
  150. UINTN Column, Row;
  151. UINTN Update, Delete;
  152. UINTN Len, StrPos, MaxStr;
  153. UINTN Index;
  154. EFI_INPUT_KEY Key;
  155. SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut;
  156. SIMPLE_INPUT_INTERFACE *ConIn;
  157. INPUT_LINE *NewLine, *LineCmd;
  158. LIST_ENTRY *LinePos, *NewPos;
  159. ConOut = ST->ConOut;
  160. ConIn = ST->ConIn;
  161. Str = Buffer;
  162. if (*BufferSize < sizeof(CHAR16)*2) {
  163. *BufferSize = 0;
  164. return EFI_SUCCESS;
  165. }
  166. /*
  167. * Get input fields location
  168. */
  169. Column = ConOut->Mode->CursorColumn;
  170. Row = ConOut->Mode->CursorRow;
  171. ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &MaxStr, &Index);
  172. /* bugbug: for now wrapping is not handled */
  173. MaxStr = MaxStr - Column;
  174. /* Clip to max cmdline */
  175. if (MaxStr > MAX_CMDLINE) {
  176. MaxStr = MAX_CMDLINE;
  177. }
  178. /* Clip to user's buffer size */
  179. if (MaxStr > (*BufferSize / sizeof(CHAR16)) - 1) {
  180. MaxStr = (*BufferSize / sizeof(CHAR16)) - 1;
  181. }
  182. /*
  183. * Allocate a new key entry
  184. */
  185. NewLine = AllocateZeroPool (sizeof(INPUT_LINE));
  186. if (!NewLine) {
  187. return EFI_OUT_OF_RESOURCES;
  188. }
  189. NewLine->Signature = INPUT_LINE_SIGNATURE;
  190. LinePos = &SEnvLineHistory;
  191. /*
  192. * Set new input
  193. */
  194. Update = 0;
  195. Delete = 0;
  196. NewPos = &SEnvLineHistory;
  197. ZeroMem (Str, MaxStr * sizeof(CHAR16));
  198. Done = FALSE;
  199. do {
  200. /*
  201. * If we have a new position, reset
  202. */
  203. if (NewPos != &SEnvLineHistory) {
  204. LineCmd = CR(NewPos, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
  205. LinePos = NewPos;
  206. NewPos = &SEnvLineHistory;
  207. CopyMem (Str, LineCmd->Buffer, MaxStr * sizeof(CHAR16));
  208. Index = Len; /* Save old len */
  209. Len = StrLen(Str); /* Get new len */
  210. StrPos = Len;
  211. Update = 0; /* draw new input string */
  212. if (Index > Len) {
  213. Delete = Index - Len; /* if old string was longer, blank it */
  214. }
  215. }
  216. /*
  217. * If we need to update the output do so now
  218. */
  219. if (Update != -1) {
  220. PrintAt (Column+Update, Row, L"%s%.*s", Str + Update, Delete, L"");
  221. Len = StrLen (Str);
  222. if (Delete) {
  223. SetMem(Str+Len, Delete * sizeof(CHAR16), 0x00);
  224. }
  225. if (StrPos > Len) {
  226. StrPos = Len;
  227. }
  228. Update = -1;
  229. Delete = 0;
  230. }
  231. /*
  232. * Set the cursor position for this key
  233. */
  234. ConOut->SetCursorPosition (ConOut, Column+StrPos, Row);
  235. /*
  236. * Read the key
  237. */
  238. WaitForSingleEvent(ConIn->WaitForKey, 0);
  239. ConIn->ReadKeyStroke(ConIn, &Key);
  240. switch (Key.UnicodeChar) {
  241. case CHAR_CARRIAGE_RETURN:
  242. /*
  243. * All done, print a newline at the end of the string
  244. */
  245. PrintAt (Column+Len, Row, L"\n");
  246. Done = TRUE;
  247. break;
  248. case CHAR_BACKSPACE:
  249. if (StrPos) {
  250. StrPos -= 1;
  251. Update = StrPos;
  252. Delete = 1;
  253. CopyMem (Str+StrPos, Str+StrPos+1, sizeof(CHAR16) * (Len-StrPos));
  254. }
  255. break;
  256. default:
  257. if (Key.UnicodeChar >= ' ') {
  258. /* If we are at the buffer's end, drop the key */
  259. if (Len == MaxStr-1 &&
  260. (SEnvInsertMode || StrPos == Len)) {
  261. break;
  262. }
  263. if (SEnvInsertMode) {
  264. for (Index=Len; Index > StrPos; Index -= 1) {
  265. Str[Index] = Str[Index-1];
  266. }
  267. }
  268. Str[StrPos] = Key.UnicodeChar;
  269. Update = StrPos;
  270. StrPos += 1;
  271. }
  272. break;
  273. case 0:
  274. switch (Key.ScanCode) {
  275. case SCAN_DELETE:
  276. if (Len) {
  277. Update = StrPos;
  278. Delete = 1;
  279. CopyMem (Str+StrPos, Str+StrPos+1, sizeof(CHAR16) * (Len-StrPos));
  280. }
  281. break;
  282. case SCAN_UP:
  283. NewPos = LinePos->Blink;
  284. if (NewPos == &SEnvLineHistory) {
  285. NewPos = NewPos->Blink;
  286. }
  287. break;
  288. case SCAN_DOWN:
  289. NewPos = LinePos->Flink;
  290. if (NewPos == &SEnvLineHistory) {
  291. NewPos = NewPos->Flink;
  292. }
  293. break;
  294. case SCAN_LEFT:
  295. if (StrPos) {
  296. StrPos -= 1;
  297. }
  298. break;
  299. case SCAN_RIGHT:
  300. if (StrPos < Len) {
  301. StrPos += 1;
  302. }
  303. break;
  304. case SCAN_HOME:
  305. StrPos = 0;
  306. break;
  307. case SCAN_END:
  308. StrPos = Len;
  309. break;
  310. case SCAN_ESC:
  311. Str[0] = 0;
  312. Update = 0;
  313. Delete = Len;
  314. break;
  315. case SCAN_INSERT:
  316. SEnvInsertMode = !SEnvInsertMode;
  317. break;
  318. case SCAN_F7:
  319. SEnvPrintHistory();
  320. *Str = 0;
  321. Done = TRUE;
  322. break;
  323. }
  324. }
  325. } while (!Done);
  326. /*
  327. * Copy the line to the history buffer
  328. */
  329. StrCpy (NewLine->Buffer, Str);
  330. if (Str[0]) {
  331. InsertTailList (&SEnvLineHistory, &NewLine->Link);
  332. SEnvNoHistory += 1;
  333. } else {
  334. FreePool (NewLine);
  335. }
  336. /*
  337. * If there's too much in the history buffer free an entry
  338. */
  339. if (SEnvNoHistory > MAX_HISTORY) {
  340. LineCmd = CR(SEnvLineHistory.Flink, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
  341. RemoveEntryList (&LineCmd->Link);
  342. SEnvNoHistory -= 1;
  343. FreePool (LineCmd);
  344. }
  345. /*
  346. * Return the data to the caller
  347. */
  348. *BufferSize = Len * sizeof(CHAR16);
  349. StrCpy(Buffer, Str);
  350. return EFI_SUCCESS;
  351. }
  352. /*
  353. *
  354. */
  355. EFI_STATUS
  356. SEnvReset (
  357. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  358. IN BOOLEAN ExtendedVerification
  359. )
  360. {
  361. return EFI_SUCCESS;
  362. }
  363. EFI_STATUS
  364. SEnvOutputString (
  365. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  366. IN CHAR16 *String
  367. )
  368. {
  369. EFI_STATUS Status;
  370. ENV_SHELL_REDIR_FILE *Redir;
  371. UINTN Len, Size, WriteSize, Index, Start;
  372. CHAR8 Buffer[100];
  373. CHAR16 UnicodeBuffer[100];
  374. BOOLEAN InvalidChar;
  375. SIMPLE_INPUT_INTERFACE *TextIn = NULL;
  376. SIMPLE_TEXT_OUTPUT_INTERFACE *TextOut = NULL;
  377. Redir = CR(This, ENV_SHELL_REDIR_FILE, Out, ENV_REDIR_SIGNATURE);
  378. if (EFI_ERROR(Redir->WriteError)) {
  379. return(Redir->WriteError);
  380. }
  381. Status = EFI_SUCCESS;
  382. InvalidChar = FALSE;
  383. if (Redir->Ascii) {
  384. Start = 0;
  385. Len = StrLen (String);
  386. while (Len) {
  387. Size = Len > sizeof(Buffer) ? sizeof(Buffer) : Len;
  388. for (Index=0; Index < Size; Index +=1) {
  389. if (String[Start+Index] > 0xff) {
  390. Buffer[Index] = '_';
  391. InvalidChar = TRUE;
  392. } else {
  393. Buffer[Index] = (CHAR8) String[Start+Index];
  394. }
  395. }
  396. WriteSize = Size;
  397. Status = Redir->File->Write (Redir->File, &WriteSize, Buffer);
  398. if (EFI_ERROR(Status)) {
  399. break;
  400. }
  401. Len -= Size;
  402. Start += Size;
  403. }
  404. } else {
  405. Len = StrSize (String) - sizeof(CHAR16);
  406. Status = Redir->File->Write (Redir->File, &Len, String);
  407. }
  408. if (EFI_ERROR(Status)) {
  409. Redir->WriteError = Status;
  410. SEnvBatchGetConsole( &TextIn, &TextOut );
  411. SPrint(UnicodeBuffer,100,L"write error: %r\n\r",Status);
  412. Status = TextOut->OutputString( TextOut, UnicodeBuffer);
  413. }
  414. if (InvalidChar && !EFI_ERROR(Status)) {
  415. Status = EFI_WARN_UNKOWN_GLYPH;
  416. }
  417. return Status;
  418. }
  419. EFI_STATUS
  420. SEnvTestString (
  421. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  422. IN CHAR16 *String
  423. )
  424. {
  425. EFI_STATUS Status;
  426. ENV_SHELL_REDIR_FILE *Redir;
  427. Redir = CR(This, ENV_SHELL_REDIR_FILE, Out, ENV_REDIR_SIGNATURE);
  428. Status = ST->ConOut->TestString(ST->ConOut, String);
  429. if (!EFI_ERROR(Status) && Redir->Ascii) {
  430. while (*String && *String < 0x100) {
  431. String += 1;
  432. }
  433. if (*String > 0xff) {
  434. Status = EFI_UNSUPPORTED;
  435. }
  436. }
  437. return Status;
  438. }
  439. EFI_STATUS
  440. SEnvQueryMode (
  441. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  442. IN UINTN ModeNumber,
  443. OUT UINTN *Columns,
  444. OUT UINTN *Rows
  445. )
  446. {
  447. if (ModeNumber > 0) {
  448. return EFI_INVALID_PARAMETER;
  449. }
  450. *Columns = 0;
  451. *Rows = 0;
  452. return EFI_SUCCESS;
  453. }
  454. EFI_STATUS
  455. SEnvSetMode (
  456. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  457. IN UINTN ModeNumber
  458. )
  459. {
  460. return ModeNumber > 0 ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
  461. }
  462. EFI_STATUS
  463. SEnvSetAttribute (
  464. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  465. IN UINTN Attribute
  466. )
  467. {
  468. This->Mode->Attribute = (UINT32) Attribute;
  469. return EFI_SUCCESS;
  470. }
  471. EFI_STATUS
  472. SEnvClearScreen (
  473. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This
  474. )
  475. {
  476. return EFI_SUCCESS;
  477. }
  478. EFI_STATUS
  479. SEnvSetCursorPosition (
  480. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  481. IN UINTN Column,
  482. IN UINTN Row
  483. )
  484. {
  485. return EFI_UNSUPPORTED;
  486. }
  487. EFI_STATUS
  488. SEnvEnableCursor (
  489. IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
  490. IN BOOLEAN Enable
  491. )
  492. {
  493. This->Mode->CursorVisible = Enable;
  494. return EFI_SUCCESS;
  495. }