1 /****************************************************************************** 2 * 3 * Module Name: acgetline - local line editing 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "acpi.h" 45 #include "accommon.h" 46 #include "amlcode.h" 47 #include "acparser.h" 48 #include "acdebug.h" 49 50 #include <stdio.h> 51 52 /* 53 * This is an os-independent implementation of line-editing services needed 54 * by the AcpiExec utility. It uses getchar() and putchar() and the existing 55 * history support provided by the AML debugger. It assumes that the terminal 56 * is in the correct line-editing mode such as raw and noecho. The OSL 57 * interface AcpiOsInitialize should do this. AcpiOsTerminate should put the 58 * terminal back into the original mode. 59 */ 60 #define _COMPONENT ACPI_OS_SERVICES 61 ACPI_MODULE_NAME ("acgetline") 62 63 64 /* Local prototypes */ 65 66 static void 67 AcpiAcClearLine ( 68 UINT32 EndOfLine, 69 UINT32 CursorPosition); 70 71 /* Various ASCII constants */ 72 73 #define _ASCII_NUL 0 74 #define _ASCII_BACKSPACE 0x08 75 #define _ASCII_TAB 0x09 76 #define _ASCII_ESCAPE 0x1B 77 #define _ASCII_SPACE 0x20 78 #define _ASCII_LEFT_BRACKET 0x5B 79 #define _ASCII_DEL 0x7F 80 #define _ASCII_UP_ARROW 'A' 81 #define _ASCII_DOWN_ARROW 'B' 82 #define _ASCII_RIGHT_ARROW 'C' 83 #define _ASCII_LEFT_ARROW 'D' 84 #define _ASCII_NEWLINE '\n' 85 86 extern UINT32 AcpiGbl_NextCmdNum; 87 88 /* Erase a single character on the input command line */ 89 90 #define ACPI_CLEAR_CHAR() \ 91 putchar (_ASCII_BACKSPACE); \ 92 putchar (_ASCII_SPACE); \ 93 putchar (_ASCII_BACKSPACE); 94 95 /* Backup cursor by Count positions */ 96 97 #define ACPI_BACKUP_CURSOR(i, Count) \ 98 for (i = 0; i < (Count); i++) \ 99 {putchar (_ASCII_BACKSPACE);} 100 101 102 /****************************************************************************** 103 * 104 * FUNCTION: AcpiAcClearLine 105 * 106 * PARAMETERS: EndOfLine - Current end-of-line index 107 * CursorPosition - Current cursor position within line 108 * 109 * RETURN: None 110 * 111 * DESCRIPTION: Clear the entire command line the hard way, but probably the 112 * most portable. 113 * 114 *****************************************************************************/ 115 116 static void 117 AcpiAcClearLine ( 118 UINT32 EndOfLine, 119 UINT32 CursorPosition) 120 { 121 UINT32 i; 122 123 124 if (CursorPosition < EndOfLine) 125 { 126 /* Clear line from current position to end of line */ 127 128 for (i = 0; i < (EndOfLine - CursorPosition); i++) 129 { 130 putchar (' '); 131 } 132 } 133 134 /* Clear the entire line */ 135 136 for (; EndOfLine > 0; EndOfLine--) 137 { 138 ACPI_CLEAR_CHAR (); 139 } 140 } 141 142 143 /****************************************************************************** 144 * 145 * FUNCTION: AcpiOsGetLine 146 * 147 * PARAMETERS: Buffer - Where to return the command line 148 * BufferLength - Maximum length of Buffer 149 * BytesRead - Where the actual byte count is returned 150 * 151 * RETURN: Status and actual bytes read 152 * 153 * DESCRIPTION: Get the next input line from the terminal. NOTE: terminal 154 * is expected to be in a mode that supports line-editing (raw, 155 * noecho). This function is intended to be very portable. Also, 156 * it uses the history support implemented in the AML debugger. 157 * 158 *****************************************************************************/ 159 160 ACPI_STATUS 161 AcpiOsGetLine ( 162 char *Buffer, 163 UINT32 BufferLength, 164 UINT32 *BytesRead) 165 { 166 char *NextCommand; 167 UINT32 MaxCommandIndex = AcpiGbl_NextCmdNum - 1; 168 UINT32 CurrentCommandIndex = MaxCommandIndex; 169 UINT32 PreviousCommandIndex = MaxCommandIndex; 170 int InputChar; 171 UINT32 CursorPosition = 0; 172 UINT32 EndOfLine = 0; 173 UINT32 i; 174 175 176 /* Always clear the line buffer before we read a new line */ 177 178 memset (Buffer, 0, BufferLength); 179 180 /* 181 * This loop gets one character at a time (except for esc sequences) 182 * until a newline or error is detected. 183 * 184 * Note: Don't attempt to write terminal control ESC sequences, even 185 * though it makes certain things more difficult. 186 */ 187 while (1) 188 { 189 if (EndOfLine >= (BufferLength - 1)) 190 { 191 return (AE_BUFFER_OVERFLOW); 192 } 193 194 InputChar = getchar (); 195 switch (InputChar) 196 { 197 default: /* This is the normal character case */ 198 199 /* Echo the character (at EOL) and copy it to the line buffer */ 200 201 if (EndOfLine == CursorPosition) 202 { 203 putchar (InputChar); 204 Buffer[EndOfLine] = (char) InputChar; 205 206 EndOfLine++; 207 CursorPosition++; 208 Buffer[EndOfLine] = 0; 209 continue; 210 } 211 212 /* Insert character into the middle of the buffer */ 213 214 memmove (&Buffer[CursorPosition + 1], &Buffer[CursorPosition], 215 (EndOfLine - CursorPosition + 1)); 216 217 Buffer [CursorPosition] = (char) InputChar; 218 Buffer [EndOfLine + 1] = 0; 219 220 /* Display the new part of line starting at the new character */ 221 222 fprintf (stdout, "%s", &Buffer[CursorPosition]); 223 224 /* Restore cursor */ 225 226 ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition); 227 CursorPosition++; 228 EndOfLine++; 229 continue; 230 231 case _ASCII_DEL: /* Backspace key */ 232 233 if (!EndOfLine) /* Any characters on the command line? */ 234 { 235 continue; 236 } 237 238 if (EndOfLine == CursorPosition) /* Erase the final character */ 239 { 240 ACPI_CLEAR_CHAR (); 241 EndOfLine--; 242 CursorPosition--; 243 continue; 244 } 245 246 if (!CursorPosition) /* Do not backup beyond start of line */ 247 { 248 continue; 249 } 250 251 /* Remove the character from the line */ 252 253 memmove (&Buffer[CursorPosition - 1], &Buffer[CursorPosition], 254 (EndOfLine - CursorPosition + 1)); 255 256 /* Display the new part of line starting at the new character */ 257 258 putchar (_ASCII_BACKSPACE); 259 fprintf (stdout, "%s ", &Buffer[CursorPosition - 1]); 260 261 /* Restore cursor */ 262 263 ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition + 1); 264 EndOfLine--; 265 if (CursorPosition > 0) 266 { 267 CursorPosition--; 268 } 269 continue; 270 271 case _ASCII_NEWLINE: /* Normal exit case at end of command line */ 272 case _ASCII_NUL: 273 274 /* Return the number of bytes in the command line string */ 275 276 if (BytesRead) 277 { 278 *BytesRead = EndOfLine; 279 } 280 281 /* Echo, terminate string buffer, and exit */ 282 283 putchar (InputChar); 284 Buffer[EndOfLine] = 0; 285 return (AE_OK); 286 287 case _ASCII_TAB: 288 289 /* Ignore */ 290 291 continue; 292 293 case EOF: 294 295 return (AE_ERROR); 296 297 case _ASCII_ESCAPE: 298 299 /* Check for escape sequences of the form "ESC[x" */ 300 301 InputChar = getchar (); 302 if (InputChar != _ASCII_LEFT_BRACKET) 303 { 304 continue; /* Ignore this ESC, does not have the '[' */ 305 } 306 307 /* Get the code following the ESC [ */ 308 309 InputChar = getchar (); /* Backup one character */ 310 switch (InputChar) 311 { 312 case _ASCII_LEFT_ARROW: 313 314 if (CursorPosition > 0) 315 { 316 putchar (_ASCII_BACKSPACE); 317 CursorPosition--; 318 } 319 continue; 320 321 case _ASCII_RIGHT_ARROW: 322 /* 323 * Move one character forward. Do this without sending 324 * ESC sequence to the terminal for max portability. 325 */ 326 if (CursorPosition < EndOfLine) 327 { 328 /* Backup to start of line and print the entire line */ 329 330 ACPI_BACKUP_CURSOR (i, CursorPosition); 331 fprintf (stdout, "%s", Buffer); 332 333 /* Backup to where the cursor should be */ 334 335 CursorPosition++; 336 ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition); 337 } 338 continue; 339 340 case _ASCII_UP_ARROW: 341 342 /* If no commands available or at start of history list, ignore */ 343 344 if (!CurrentCommandIndex) 345 { 346 continue; 347 } 348 349 /* Manage our up/down progress */ 350 351 if (CurrentCommandIndex > PreviousCommandIndex) 352 { 353 CurrentCommandIndex = PreviousCommandIndex; 354 } 355 356 /* Get the historical command from the debugger */ 357 358 NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); 359 if (!NextCommand) 360 { 361 return (AE_ERROR); 362 } 363 364 /* Make this the active command and echo it */ 365 366 AcpiAcClearLine (EndOfLine, CursorPosition); 367 strcpy (Buffer, NextCommand); 368 fprintf (stdout, "%s", Buffer); 369 EndOfLine = CursorPosition = strlen (Buffer); 370 371 PreviousCommandIndex = CurrentCommandIndex; 372 CurrentCommandIndex--; 373 continue; 374 375 case _ASCII_DOWN_ARROW: 376 377 if (!MaxCommandIndex) /* Any commands available? */ 378 { 379 continue; 380 } 381 382 /* Manage our up/down progress */ 383 384 if (CurrentCommandIndex < PreviousCommandIndex) 385 { 386 CurrentCommandIndex = PreviousCommandIndex; 387 } 388 389 /* If we are the end of the history list, output a clear new line */ 390 391 if ((CurrentCommandIndex + 1) > MaxCommandIndex) 392 { 393 AcpiAcClearLine (EndOfLine, CursorPosition); 394 EndOfLine = CursorPosition = 0; 395 PreviousCommandIndex = CurrentCommandIndex; 396 continue; 397 } 398 399 PreviousCommandIndex = CurrentCommandIndex; 400 CurrentCommandIndex++; 401 402 /* Get the historical command from the debugger */ 403 404 NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); 405 if (!NextCommand) 406 { 407 return (AE_ERROR); 408 } 409 410 /* Make this the active command and echo it */ 411 412 AcpiAcClearLine (EndOfLine, CursorPosition); 413 strcpy (Buffer, NextCommand); 414 fprintf (stdout, "%s", Buffer); 415 EndOfLine = CursorPosition = strlen (Buffer); 416 continue; 417 418 case 0x31: 419 case 0x32: 420 case 0x33: 421 case 0x34: 422 case 0x35: 423 case 0x36: 424 /* 425 * Ignore the various keys like insert/delete/home/end, etc. 426 * But we must eat the final character of the ESC sequence. 427 */ 428 InputChar = getchar (); 429 continue; 430 431 default: 432 433 /* Ignore random escape sequences that we don't care about */ 434 435 continue; 436 } 437 continue; 438 } 439 } 440 }