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