1 /****************************************************************************** 2 * 3 * Module Name: acgetline - local line editing 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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 #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 266 if (CursorPosition > 0) 267 { 268 CursorPosition--; 269 } 270 continue; 271 272 case _ASCII_NEWLINE: /* Normal exit case at end of command line */ 273 case _ASCII_NUL: 274 275 /* Return the number of bytes in the command line string */ 276 277 if (BytesRead) 278 { 279 *BytesRead = EndOfLine; 280 } 281 282 /* Echo, terminate string buffer, and exit */ 283 284 putchar (InputChar); 285 Buffer[EndOfLine] = 0; 286 return (AE_OK); 287 288 case _ASCII_TAB: 289 290 /* Ignore */ 291 292 continue; 293 294 case EOF: 295 296 return (AE_ERROR); 297 298 case _ASCII_ESCAPE: 299 300 /* Check for escape sequences of the form "ESC[x" */ 301 302 InputChar = getchar (); 303 if (InputChar != _ASCII_LEFT_BRACKET) 304 { 305 continue; /* Ignore this ESC, does not have the '[' */ 306 } 307 308 /* Get the code following the ESC [ */ 309 310 InputChar = getchar (); /* Backup one character */ 311 switch (InputChar) 312 { 313 case _ASCII_LEFT_ARROW: 314 315 if (CursorPosition > 0) 316 { 317 putchar (_ASCII_BACKSPACE); 318 CursorPosition--; 319 } 320 continue; 321 322 case _ASCII_RIGHT_ARROW: 323 /* 324 * Move one character forward. Do this without sending 325 * ESC sequence to the terminal for max portability. 326 */ 327 if (CursorPosition < EndOfLine) 328 { 329 /* Backup to start of line and print the entire line */ 330 331 ACPI_BACKUP_CURSOR (i, CursorPosition); 332 fprintf (stdout, "%s", Buffer); 333 334 /* Backup to where the cursor should be */ 335 336 CursorPosition++; 337 ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition); 338 } 339 continue; 340 341 case _ASCII_UP_ARROW: 342 343 /* If no commands available or at start of history list, ignore */ 344 345 if (!CurrentCommandIndex) 346 { 347 continue; 348 } 349 350 /* Manage our up/down progress */ 351 352 if (CurrentCommandIndex > PreviousCommandIndex) 353 { 354 CurrentCommandIndex = PreviousCommandIndex; 355 } 356 357 /* Get the historical command from the debugger */ 358 359 NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); 360 if (!NextCommand) 361 { 362 return (AE_ERROR); 363 } 364 365 /* Make this the active command and echo it */ 366 367 AcpiAcClearLine (EndOfLine, CursorPosition); 368 strcpy (Buffer, NextCommand); 369 fprintf (stdout, "%s", Buffer); 370 EndOfLine = CursorPosition = strlen (Buffer); 371 372 PreviousCommandIndex = CurrentCommandIndex; 373 CurrentCommandIndex--; 374 continue; 375 376 case _ASCII_DOWN_ARROW: 377 378 if (!MaxCommandIndex) /* Any commands available? */ 379 { 380 continue; 381 } 382 383 /* Manage our up/down progress */ 384 385 if (CurrentCommandIndex < PreviousCommandIndex) 386 { 387 CurrentCommandIndex = PreviousCommandIndex; 388 } 389 390 /* If we are the end of the history list, output a clear new line */ 391 392 if ((CurrentCommandIndex + 1) > MaxCommandIndex) 393 { 394 AcpiAcClearLine (EndOfLine, CursorPosition); 395 EndOfLine = CursorPosition = 0; 396 PreviousCommandIndex = CurrentCommandIndex; 397 continue; 398 } 399 400 PreviousCommandIndex = CurrentCommandIndex; 401 CurrentCommandIndex++; 402 403 /* Get the historical command from the debugger */ 404 405 NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); 406 if (!NextCommand) 407 { 408 return (AE_ERROR); 409 } 410 411 /* Make this the active command and echo it */ 412 413 AcpiAcClearLine (EndOfLine, CursorPosition); 414 strcpy (Buffer, NextCommand); 415 fprintf (stdout, "%s", Buffer); 416 EndOfLine = CursorPosition = strlen (Buffer); 417 continue; 418 419 case 0x31: 420 case 0x32: 421 case 0x33: 422 case 0x34: 423 case 0x35: 424 case 0x36: 425 /* 426 * Ignore the various keys like insert/delete/home/end, etc. 427 * But we must eat the final character of the ESC sequence. 428 */ 429 InputChar = getchar (); 430 continue; 431 432 default: 433 434 /* Ignore random escape sequences that we don't care about */ 435 436 continue; 437 } 438 continue; 439 } 440 } 441 } 442