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.

381 lines
9.5 KiB

  1. /*/###########################################################################
  2. //**
  3. //** Copyright (C) 1996-97 Intel Corporation. All rights reserved.
  4. //**
  5. //** The information and source code contained herein is the exclusive
  6. //** property of Intel Corporation and may not be disclosed, examined
  7. //** from the company.
  8. //**
  9. *//* ########################################################################### */
  10. #include "EfiShell.h"
  11. #include "doskey.h"
  12. #define isprint(a) ((a) >= ' ')
  13. CHAR16 *DosKeyInsert (DosKey_t *DosKey);
  14. CHAR16 *DosKeyPreviousCurrent (DosKey_t *DosKey);
  15. CHAR16 *DosKeyGetCommandLine (DosKey_t *DosKey);
  16. #define MAX_LINE 256
  17. #define MAX_HISTORY 20
  18. typedef struct {
  19. UINTN Signature;
  20. LIST_ENTRY Link;
  21. CHAR16 Buffer[MAX_LINE];
  22. } INPUT_LINE;
  23. /*
  24. * Globals
  25. */
  26. static BOOLEAN ShellEnvInsertMode;
  27. static LIST_ENTRY *ShellEnvCurrentLine;
  28. static LIST_ENTRY ShellEnvLineHistory;
  29. static UINTN ShellEnvNoHistory;
  30. VOID
  31. DosKeyDelete (
  32. IN OUT DosKey_t *DosKey
  33. )
  34. {
  35. INTN NewEnd;
  36. if (DosKey->Start != DosKey->End) {
  37. NewEnd = (DosKey->End==0)?(MAX_HISTORY-1):(DosKey->End - 1);
  38. if (DosKey->Current == NewEnd) {
  39. DosKey->Current = (DosKey->Current==0)?(MAX_HISTORY-1):(DosKey->Current - 1);
  40. }
  41. DosKey->End = NewEnd;
  42. }
  43. }
  44. CHAR16 *
  45. DosKeyInsert (
  46. IN OUT DosKey_t *DosKey
  47. )
  48. {
  49. INTN Next;
  50. INTN Data;
  51. INTN i;
  52. Data = DosKey->End;
  53. Next = ((DosKey->End + 1) % MAX_HISTORY);
  54. if (DosKey->Start == Next) {
  55. /* Wrap case */
  56. DosKey->Start = ((DosKey->Start + 1) % MAX_HISTORY);
  57. }
  58. DosKey->End = Next;
  59. for (i=0; i<MAX_CMDLINE; i++) {
  60. DosKey->Buffer[Data][i] = '\0';
  61. }
  62. DosKey->Current = Data;
  63. return (&(DosKey->Buffer[Data][0]));
  64. }
  65. CHAR16 *
  66. DosKeyPreviousCurrent (
  67. IN OUT DosKey_t *DosKey
  68. )
  69. {
  70. INTN Next;
  71. Next = (DosKey->Current==0)?(MAX_HISTORY-1):(DosKey->Current - 1);
  72. if (DosKey->Start < DosKey->End) {
  73. if ((Next >= DosKey->Start) && (Next != (MAX_HISTORY-1))) {
  74. DosKey->Current = Next;
  75. }
  76. } else if (DosKey->Start > DosKey->End){
  77. /* Allways a Full Buffer */
  78. if (Next != DosKey->End) {
  79. DosKey->Current = Next;
  80. }
  81. } else {
  82. /* No Data */
  83. }
  84. return (&(DosKey->Buffer[DosKey->Current][0]));
  85. }
  86. CHAR16 *
  87. DosKeyNextCurrent (
  88. IN OUT DosKey_t *DosKey
  89. )
  90. {
  91. INTN Next;
  92. Next = ((DosKey->Current + 1) % MAX_HISTORY);
  93. if (DosKey->Start < DosKey->End) {
  94. if (Next != DosKey->End) {
  95. DosKey->Current = Next;
  96. }
  97. } else if (DosKey->Start > DosKey->End){
  98. /* Allways a Full Buffer */
  99. if (Next != DosKey->Start) {
  100. DosKey->Current = Next;
  101. }
  102. } else {
  103. /* No Data */
  104. }
  105. return (&(DosKey->Buffer[DosKey->Current][0]));
  106. }
  107. VOID
  108. PrintDosKeyBuffer(
  109. IN OUT DosKey_t *DosKey
  110. )
  111. {
  112. INTN i;
  113. INTN Index;
  114. Index = 1;
  115. if (DosKey->Start < DosKey->End) {
  116. for (i = DosKey->End - 1; i >= DosKey->Start; i--) {
  117. if (DosKey->Buffer[i][0] != '\0') {
  118. Print (L"\n%2d:%2d: %s",Index++, i, DosKey->Buffer[i]);
  119. } else {
  120. Print (L"\n :%2d:",i);
  121. }
  122. }
  123. } else if (DosKey->Start > DosKey->End) {
  124. for (i = DosKey->End -1; i >= 0; i--) {
  125. if (DosKey->Buffer[i][0] != '\0') {
  126. Print (L"\n%2d:%2d: %s",Index++, i, DosKey->Buffer[i]);
  127. } else {
  128. Print (L"\n :%2d:",i);
  129. }
  130. }
  131. for (i = (MAX_HISTORY-1); i >= DosKey->Start; i--) {
  132. if (DosKey->Buffer[i][0] != '\0') {
  133. Print(L"\n%2d:%2d: %s",Index++, i, DosKey->Buffer[i]);
  134. } else {
  135. Print(L"\n :%2d:",i);
  136. }
  137. }
  138. } else /* if (DosKey->Start == DosKey->End) */{
  139. }
  140. }
  141. CHAR16 *
  142. ShellEnvReadLine (
  143. DosKeyGetCommandLine (
  144. IN DosKey_t *DosKey
  145. )
  146. {
  147. CHAR16 Str[MAX_CMDLINE];
  148. CHAR16 *CommandLine;
  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. ConOut = ST->ConOut;
  158. ConIn = ST->ConIn;
  159. /*
  160. * Get input fields location
  161. */
  162. Column = ConOut->CursorColumn;
  163. Row = ConOut->CursorRow;
  164. ConOut->QueryMode (ConOut, ConOut->Mode, &MaxStr, &Index);
  165. /* bugbug: for now wrapping is not handled */
  166. MaxStr = MaxStr - Column;
  167. if (MaxStr > MAX_CMDLINE) {
  168. MaxStr = MAX_CMDLINE;
  169. }
  170. /*
  171. * Set new input
  172. */
  173. CommandLine = DosKeyInsert(DosKey);
  174. SetMem(Str, sizeof(Str), 0x00);
  175. Update = 0;
  176. Delete = 0;
  177. Done = FALSE;
  178. do {
  179. /*
  180. * If we need to update the output do so now
  181. */
  182. if (Update != -1) {
  183. PrintAt (Column+Update, Row, L"%s%.*s", Str + Update, Delete, L"");
  184. Len = StrLen (Str);
  185. if (Delete) {
  186. SetMem(Str+Len, Delete * sizeof(CHAR16), 0x00);
  187. }
  188. if (StrPos > Len) {
  189. StrPos = Len;
  190. }
  191. Update = -1;
  192. Delete = 0;
  193. }
  194. /*
  195. * Set the cursor position for this key
  196. */
  197. ConOut->SetCursorPosition (ConOut, Column+StrPos, Row);
  198. /*
  199. * Read the key
  200. */
  201. ConIn->ReadKeyStroke(ConIn, &Key);
  202. switch (Key.UnicodeChar) {
  203. case CHAR_CARRIAGE_RETURN:
  204. /*
  205. * All done, print a newline at the end of the string
  206. */
  207. PrintAt (Column+Len, Row, L"\n");
  208. if (*Str == 0) {
  209. DosKeyDelete(DosKey);
  210. }
  211. Done = TRUE;
  212. break;
  213. case CHAR_BACKSPACE:
  214. if (StrPos) {
  215. StrPos -= 1;
  216. Update = StrPos;
  217. Delete = 1;
  218. CopyMem (Str+StrPos, Str+StrPos+1, sizeof(CHAR16) * (Len-StrPos));
  219. }
  220. break;
  221. default:
  222. if (isprint(Key.UnicodeChar)) {
  223. /* If we are at the buffer's end, drop the key */
  224. if (Len == MaxStr-1 &&
  225. (DosKey->InsertMode || StrPos == Len)) {
  226. break;
  227. }
  228. if (DosKey->InsertMode) {
  229. for (Index=Len; Index > StrPos; Index -= 1) {
  230. Str[Index] = Str[Index-1];
  231. }
  232. }
  233. Str[StrPos] = Key.UnicodeChar;
  234. Update = StrPos;
  235. StrPos += 1;
  236. }
  237. break;
  238. case 0:
  239. switch (Key.ScanCode) {
  240. case SCAN_DELETE:
  241. if (StrLen) {
  242. Update = StrPos;
  243. Delete = 1;
  244. CopyMem (Str+StrPos, Str+StrPos+1, sizeof(CHAR16) * (Len-StrPos));
  245. }
  246. break;
  247. case SCAN_UP:
  248. StrCpy(Str, DosKeyPreviousCurrent(DosKey));
  249. Index = Len; /* Save old len */
  250. Len = StrLen(Str); /* Get new len */
  251. StrPos = Len;
  252. Update = 0; /* draw new input string */
  253. if (Index > Len) {
  254. Delete = Index - Len; /* if old string was longer, blank it */
  255. }
  256. break;
  257. case SCAN_DOWN:
  258. StrCpy(Str, DosKeyNextCurrent(DosKey));
  259. Index = Len; /* Save old len */
  260. Len = StrLen(Str); /* Get new len */
  261. StrPos = Len;
  262. Update = 0; /* draw new input string */
  263. if (Index > Len) {
  264. Delete = Index - Len; /* if old string was longer, blank it */
  265. }
  266. break;
  267. case SCAN_LEFT:
  268. if (StrPos) {
  269. StrPos -= 1;
  270. }
  271. break;
  272. case SCAN_RIGHT:
  273. if (StrPos < Len) {
  274. StrPos += 1;
  275. }
  276. break;
  277. case SCAN_HOME:
  278. StrPos = 0;
  279. break;
  280. case SCAN_END:
  281. StrPos = Len;
  282. break;
  283. case SCAN_ESC:
  284. Str[0] = 0;
  285. Update = 0;
  286. Delete = Len;
  287. break;
  288. case SCAN_INSERT:
  289. DosKey->InsertMode = !DosKey->InsertMode;
  290. break;
  291. case SCAN_F7:
  292. DosKeyDelete(DosKey);
  293. PrintDosKeyBuffer(DosKey);
  294. *Str = 0;
  295. Done = TRUE;
  296. break;
  297. }
  298. }
  299. } while (!Done);
  300. StrCpy (CommandLine, Str);
  301. return (CommandLine);
  302. }
  303. VOID
  304. RemoveFirstCharFromString(
  305. IN OUT CHAR16 *Str
  306. )
  307. {
  308. UINTN Length;
  309. CHAR16 *NewData;
  310. NewData = Str + 1;
  311. Length = StrLen(NewData);
  312. while (Length-- != 0) {
  313. *Str++ = *NewData++;
  314. }
  315. *Str = 0;
  316. }