1256655Sjkim/****************************************************************************** 2256655Sjkim * 3256655Sjkim * Module Name: acgetline - local line editing 4256655Sjkim * 5256655Sjkim *****************************************************************************/ 6256655Sjkim 7256655Sjkim/* 8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp. 9256655Sjkim * All rights reserved. 10256655Sjkim * 11256655Sjkim * Redistribution and use in source and binary forms, with or without 12256655Sjkim * modification, are permitted provided that the following conditions 13256655Sjkim * are met: 14256655Sjkim * 1. Redistributions of source code must retain the above copyright 15256655Sjkim * notice, this list of conditions, and the following disclaimer, 16256655Sjkim * without modification. 17256655Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18256655Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19256655Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20256655Sjkim * including a substantially similar Disclaimer requirement for further 21256655Sjkim * binary redistribution. 22256655Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23256655Sjkim * of any contributors may be used to endorse or promote products derived 24256655Sjkim * from this software without specific prior written permission. 25256655Sjkim * 26256655Sjkim * Alternatively, this software may be distributed under the terms of the 27256655Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28256655Sjkim * Software Foundation. 29256655Sjkim * 30256655Sjkim * NO WARRANTY 31256655Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32256655Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33256655Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34256655Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35256655Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36256655Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37256655Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38256655Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39256655Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40256655Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41256655Sjkim * POSSIBILITY OF SUCH DAMAGES. 42256655Sjkim */ 43256655Sjkim 44272444Sjkim#include <contrib/dev/acpica/include/acpi.h> 45272444Sjkim#include <contrib/dev/acpica/include/accommon.h> 46272444Sjkim#include <contrib/dev/acpica/include/amlcode.h> 47272444Sjkim#include <contrib/dev/acpica/include/acparser.h> 48272444Sjkim#include <contrib/dev/acpica/include/acdebug.h> 49256655Sjkim 50256655Sjkim#include <stdio.h> 51256655Sjkim 52256655Sjkim/* 53256655Sjkim * This is an os-independent implementation of line-editing services needed 54256655Sjkim * by the AcpiExec utility. It uses getchar() and putchar() and the existing 55256655Sjkim * history support provided by the AML debugger. It assumes that the terminal 56256655Sjkim * is in the correct line-editing mode such as raw and noecho. The OSL 57256655Sjkim * interface AcpiOsInitialize should do this. AcpiOsTerminate should put the 58256655Sjkim * terminal back into the original mode. 59256655Sjkim */ 60256655Sjkim#define _COMPONENT ACPI_OS_SERVICES 61256655Sjkim ACPI_MODULE_NAME ("acgetline") 62256655Sjkim 63256655Sjkim 64256655Sjkim/* Local prototypes */ 65256655Sjkim 66256655Sjkimstatic void 67256655SjkimAcpiAcClearLine ( 68256655Sjkim UINT32 EndOfLine, 69256655Sjkim UINT32 CursorPosition); 70256655Sjkim 71256655Sjkim/* Various ASCII constants */ 72256655Sjkim 73256655Sjkim#define _ASCII_NUL 0 74256655Sjkim#define _ASCII_BACKSPACE 0x08 75256655Sjkim#define _ASCII_TAB 0x09 76256655Sjkim#define _ASCII_ESCAPE 0x1B 77256655Sjkim#define _ASCII_SPACE 0x20 78256655Sjkim#define _ASCII_LEFT_BRACKET 0x5B 79256655Sjkim#define _ASCII_DEL 0x7F 80256655Sjkim#define _ASCII_UP_ARROW 'A' 81256655Sjkim#define _ASCII_DOWN_ARROW 'B' 82256655Sjkim#define _ASCII_RIGHT_ARROW 'C' 83256655Sjkim#define _ASCII_LEFT_ARROW 'D' 84256655Sjkim#define _ASCII_NEWLINE '\n' 85256655Sjkim 86256655Sjkimextern UINT32 AcpiGbl_NextCmdNum; 87256655Sjkim 88256655Sjkim/* Erase a single character on the input command line */ 89256655Sjkim 90256655Sjkim#define ACPI_CLEAR_CHAR() \ 91256655Sjkim putchar (_ASCII_BACKSPACE); \ 92256655Sjkim putchar (_ASCII_SPACE); \ 93256655Sjkim putchar (_ASCII_BACKSPACE); 94256655Sjkim 95256655Sjkim/* Backup cursor by Count positions */ 96256655Sjkim 97256655Sjkim#define ACPI_BACKUP_CURSOR(i, Count) \ 98256655Sjkim for (i = 0; i < (Count); i++) \ 99256655Sjkim {putchar (_ASCII_BACKSPACE);} 100256655Sjkim 101256655Sjkim 102256655Sjkim/****************************************************************************** 103256655Sjkim * 104256655Sjkim * FUNCTION: AcpiAcClearLine 105256655Sjkim * 106256655Sjkim * PARAMETERS: EndOfLine - Current end-of-line index 107256655Sjkim * CursorPosition - Current cursor position within line 108256655Sjkim * 109256655Sjkim * RETURN: None 110256655Sjkim * 111256655Sjkim * DESCRIPTION: Clear the entire command line the hard way, but probably the 112256655Sjkim * most portable. 113256655Sjkim * 114256655Sjkim *****************************************************************************/ 115256655Sjkim 116256655Sjkimstatic void 117256655SjkimAcpiAcClearLine ( 118256655Sjkim UINT32 EndOfLine, 119256655Sjkim UINT32 CursorPosition) 120256655Sjkim{ 121256655Sjkim UINT32 i; 122256655Sjkim 123256655Sjkim 124256655Sjkim if (CursorPosition < EndOfLine) 125256655Sjkim { 126256655Sjkim /* Clear line from current position to end of line */ 127256655Sjkim 128256655Sjkim for (i = 0; i < (EndOfLine - CursorPosition); i++) 129256655Sjkim { 130256655Sjkim putchar (' '); 131256655Sjkim } 132256655Sjkim } 133256655Sjkim 134256655Sjkim /* Clear the entire line */ 135256655Sjkim 136256655Sjkim for (; EndOfLine > 0; EndOfLine--) 137256655Sjkim { 138256655Sjkim ACPI_CLEAR_CHAR (); 139256655Sjkim } 140256655Sjkim} 141256655Sjkim 142256655Sjkim 143256655Sjkim/****************************************************************************** 144256655Sjkim * 145256655Sjkim * FUNCTION: AcpiOsGetLine 146256655Sjkim * 147256655Sjkim * PARAMETERS: Buffer - Where to return the command line 148256655Sjkim * BufferLength - Maximum length of Buffer 149256655Sjkim * BytesRead - Where the actual byte count is returned 150256655Sjkim * 151256655Sjkim * RETURN: Status and actual bytes read 152256655Sjkim * 153256655Sjkim * DESCRIPTION: Get the next input line from the terminal. NOTE: terminal 154256655Sjkim * is expected to be in a mode that supports line-editing (raw, 155256655Sjkim * noecho). This function is intended to be very portable. Also, 156256655Sjkim * it uses the history support implemented in the AML debugger. 157256655Sjkim * 158256655Sjkim *****************************************************************************/ 159256655Sjkim 160256655SjkimACPI_STATUS 161256655SjkimAcpiOsGetLine ( 162256655Sjkim char *Buffer, 163256655Sjkim UINT32 BufferLength, 164256655Sjkim UINT32 *BytesRead) 165256655Sjkim{ 166256655Sjkim char *NextCommand; 167256655Sjkim UINT32 MaxCommandIndex = AcpiGbl_NextCmdNum - 1; 168256655Sjkim UINT32 CurrentCommandIndex = MaxCommandIndex; 169256655Sjkim UINT32 PreviousCommandIndex = MaxCommandIndex; 170256655Sjkim int InputChar; 171256655Sjkim UINT32 CursorPosition = 0; 172256655Sjkim UINT32 EndOfLine = 0; 173256655Sjkim UINT32 i; 174256655Sjkim 175256655Sjkim 176256655Sjkim /* Always clear the line buffer before we read a new line */ 177256655Sjkim 178256655Sjkim memset (Buffer, 0, BufferLength); 179256655Sjkim 180256655Sjkim /* 181256655Sjkim * This loop gets one character at a time (except for esc sequences) 182256655Sjkim * until a newline or error is detected. 183256655Sjkim * 184256655Sjkim * Note: Don't attempt to write terminal control ESC sequences, even 185256655Sjkim * though it makes certain things more difficult. 186256655Sjkim */ 187256655Sjkim while (1) 188256655Sjkim { 189256655Sjkim if (EndOfLine >= (BufferLength - 1)) 190256655Sjkim { 191256655Sjkim return (AE_BUFFER_OVERFLOW); 192256655Sjkim } 193256655Sjkim 194256655Sjkim InputChar = getchar (); 195256655Sjkim switch (InputChar) 196256655Sjkim { 197256655Sjkim default: /* This is the normal character case */ 198256655Sjkim 199256655Sjkim /* Echo the character (at EOL) and copy it to the line buffer */ 200256655Sjkim 201256655Sjkim if (EndOfLine == CursorPosition) 202256655Sjkim { 203256655Sjkim putchar (InputChar); 204256655Sjkim Buffer[EndOfLine] = (char) InputChar; 205256655Sjkim 206256655Sjkim EndOfLine++; 207256655Sjkim CursorPosition++; 208256655Sjkim Buffer[EndOfLine] = 0; 209256655Sjkim continue; 210256655Sjkim } 211256655Sjkim 212256655Sjkim /* Insert character into the middle of the buffer */ 213256655Sjkim 214256655Sjkim memmove (&Buffer[CursorPosition + 1], &Buffer[CursorPosition], 215256655Sjkim (EndOfLine - CursorPosition + 1)); 216256655Sjkim 217256655Sjkim Buffer [CursorPosition] = (char) InputChar; 218256655Sjkim Buffer [EndOfLine + 1] = 0; 219256655Sjkim 220256655Sjkim /* Display the new part of line starting at the new character */ 221256655Sjkim 222256655Sjkim fprintf (stdout, "%s", &Buffer[CursorPosition]); 223256655Sjkim 224256655Sjkim /* Restore cursor */ 225256655Sjkim 226256655Sjkim ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition); 227256655Sjkim CursorPosition++; 228256655Sjkim EndOfLine++; 229256655Sjkim continue; 230256655Sjkim 231256655Sjkim case _ASCII_DEL: /* Backspace key */ 232256655Sjkim 233256655Sjkim if (!EndOfLine) /* Any characters on the command line? */ 234256655Sjkim { 235256655Sjkim continue; 236256655Sjkim } 237256655Sjkim 238256655Sjkim if (EndOfLine == CursorPosition) /* Erase the final character */ 239256655Sjkim { 240256655Sjkim ACPI_CLEAR_CHAR (); 241256655Sjkim EndOfLine--; 242256655Sjkim CursorPosition--; 243256655Sjkim continue; 244256655Sjkim } 245256655Sjkim 246256655Sjkim if (!CursorPosition) /* Do not backup beyond start of line */ 247256655Sjkim { 248256655Sjkim continue; 249256655Sjkim } 250256655Sjkim 251256655Sjkim /* Remove the character from the line */ 252256655Sjkim 253256655Sjkim memmove (&Buffer[CursorPosition - 1], &Buffer[CursorPosition], 254256655Sjkim (EndOfLine - CursorPosition + 1)); 255256655Sjkim 256256655Sjkim /* Display the new part of line starting at the new character */ 257256655Sjkim 258256655Sjkim putchar (_ASCII_BACKSPACE); 259256655Sjkim fprintf (stdout, "%s ", &Buffer[CursorPosition - 1]); 260256655Sjkim 261256655Sjkim /* Restore cursor */ 262256655Sjkim 263256655Sjkim ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition + 1); 264256655Sjkim EndOfLine--; 265306536Sjkim 266256655Sjkim if (CursorPosition > 0) 267256655Sjkim { 268256655Sjkim CursorPosition--; 269256655Sjkim } 270256655Sjkim continue; 271256655Sjkim 272256655Sjkim case _ASCII_NEWLINE: /* Normal exit case at end of command line */ 273256655Sjkim case _ASCII_NUL: 274256655Sjkim 275256655Sjkim /* Return the number of bytes in the command line string */ 276256655Sjkim 277256655Sjkim if (BytesRead) 278256655Sjkim { 279256655Sjkim *BytesRead = EndOfLine; 280256655Sjkim } 281256655Sjkim 282256655Sjkim /* Echo, terminate string buffer, and exit */ 283256655Sjkim 284256655Sjkim putchar (InputChar); 285256655Sjkim Buffer[EndOfLine] = 0; 286256655Sjkim return (AE_OK); 287256655Sjkim 288256655Sjkim case _ASCII_TAB: 289256655Sjkim 290256655Sjkim /* Ignore */ 291256655Sjkim 292256655Sjkim continue; 293256655Sjkim 294256655Sjkim case EOF: 295256655Sjkim 296256655Sjkim return (AE_ERROR); 297256655Sjkim 298256655Sjkim case _ASCII_ESCAPE: 299256655Sjkim 300256655Sjkim /* Check for escape sequences of the form "ESC[x" */ 301256655Sjkim 302256655Sjkim InputChar = getchar (); 303256655Sjkim if (InputChar != _ASCII_LEFT_BRACKET) 304256655Sjkim { 305256655Sjkim continue; /* Ignore this ESC, does not have the '[' */ 306256655Sjkim } 307256655Sjkim 308256655Sjkim /* Get the code following the ESC [ */ 309256655Sjkim 310256655Sjkim InputChar = getchar (); /* Backup one character */ 311256655Sjkim switch (InputChar) 312256655Sjkim { 313256655Sjkim case _ASCII_LEFT_ARROW: 314256655Sjkim 315256655Sjkim if (CursorPosition > 0) 316256655Sjkim { 317256655Sjkim putchar (_ASCII_BACKSPACE); 318256655Sjkim CursorPosition--; 319256655Sjkim } 320256655Sjkim continue; 321256655Sjkim 322256655Sjkim case _ASCII_RIGHT_ARROW: 323256655Sjkim /* 324256655Sjkim * Move one character forward. Do this without sending 325256655Sjkim * ESC sequence to the terminal for max portability. 326256655Sjkim */ 327256655Sjkim if (CursorPosition < EndOfLine) 328256655Sjkim { 329256655Sjkim /* Backup to start of line and print the entire line */ 330256655Sjkim 331256655Sjkim ACPI_BACKUP_CURSOR (i, CursorPosition); 332256655Sjkim fprintf (stdout, "%s", Buffer); 333256655Sjkim 334256655Sjkim /* Backup to where the cursor should be */ 335256655Sjkim 336256655Sjkim CursorPosition++; 337256655Sjkim ACPI_BACKUP_CURSOR (i, EndOfLine - CursorPosition); 338256655Sjkim } 339256655Sjkim continue; 340256655Sjkim 341256655Sjkim case _ASCII_UP_ARROW: 342256655Sjkim 343256655Sjkim /* If no commands available or at start of history list, ignore */ 344256655Sjkim 345256655Sjkim if (!CurrentCommandIndex) 346256655Sjkim { 347256655Sjkim continue; 348256655Sjkim } 349256655Sjkim 350256655Sjkim /* Manage our up/down progress */ 351256655Sjkim 352256655Sjkim if (CurrentCommandIndex > PreviousCommandIndex) 353256655Sjkim { 354256655Sjkim CurrentCommandIndex = PreviousCommandIndex; 355256655Sjkim } 356256655Sjkim 357256655Sjkim /* Get the historical command from the debugger */ 358256655Sjkim 359256655Sjkim NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); 360256655Sjkim if (!NextCommand) 361256655Sjkim { 362256655Sjkim return (AE_ERROR); 363256655Sjkim } 364256655Sjkim 365256655Sjkim /* Make this the active command and echo it */ 366256655Sjkim 367256655Sjkim AcpiAcClearLine (EndOfLine, CursorPosition); 368256655Sjkim strcpy (Buffer, NextCommand); 369256655Sjkim fprintf (stdout, "%s", Buffer); 370256655Sjkim EndOfLine = CursorPosition = strlen (Buffer); 371256655Sjkim 372256655Sjkim PreviousCommandIndex = CurrentCommandIndex; 373256655Sjkim CurrentCommandIndex--; 374256655Sjkim continue; 375256655Sjkim 376256655Sjkim case _ASCII_DOWN_ARROW: 377256655Sjkim 378256655Sjkim if (!MaxCommandIndex) /* Any commands available? */ 379256655Sjkim { 380256655Sjkim continue; 381256655Sjkim } 382256655Sjkim 383256655Sjkim /* Manage our up/down progress */ 384256655Sjkim 385256655Sjkim if (CurrentCommandIndex < PreviousCommandIndex) 386256655Sjkim { 387256655Sjkim CurrentCommandIndex = PreviousCommandIndex; 388256655Sjkim } 389256655Sjkim 390256655Sjkim /* If we are the end of the history list, output a clear new line */ 391256655Sjkim 392256655Sjkim if ((CurrentCommandIndex + 1) > MaxCommandIndex) 393256655Sjkim { 394256655Sjkim AcpiAcClearLine (EndOfLine, CursorPosition); 395256655Sjkim EndOfLine = CursorPosition = 0; 396256655Sjkim PreviousCommandIndex = CurrentCommandIndex; 397256655Sjkim continue; 398256655Sjkim } 399256655Sjkim 400256655Sjkim PreviousCommandIndex = CurrentCommandIndex; 401256655Sjkim CurrentCommandIndex++; 402256655Sjkim 403256655Sjkim /* Get the historical command from the debugger */ 404256655Sjkim 405256655Sjkim NextCommand = AcpiDbGetHistoryByIndex (CurrentCommandIndex); 406256655Sjkim if (!NextCommand) 407256655Sjkim { 408256655Sjkim return (AE_ERROR); 409256655Sjkim } 410256655Sjkim 411256655Sjkim /* Make this the active command and echo it */ 412256655Sjkim 413256655Sjkim AcpiAcClearLine (EndOfLine, CursorPosition); 414256655Sjkim strcpy (Buffer, NextCommand); 415256655Sjkim fprintf (stdout, "%s", Buffer); 416256655Sjkim EndOfLine = CursorPosition = strlen (Buffer); 417256655Sjkim continue; 418256655Sjkim 419256655Sjkim case 0x31: 420256655Sjkim case 0x32: 421256655Sjkim case 0x33: 422256655Sjkim case 0x34: 423256655Sjkim case 0x35: 424256655Sjkim case 0x36: 425256655Sjkim /* 426256655Sjkim * Ignore the various keys like insert/delete/home/end, etc. 427256655Sjkim * But we must eat the final character of the ESC sequence. 428256655Sjkim */ 429256655Sjkim InputChar = getchar (); 430256655Sjkim continue; 431256655Sjkim 432256655Sjkim default: 433256655Sjkim 434256655Sjkim /* Ignore random escape sequences that we don't care about */ 435256655Sjkim 436256655Sjkim continue; 437256655Sjkim } 438256655Sjkim continue; 439256655Sjkim } 440256655Sjkim } 441256655Sjkim} 442