175 lines
4.5 KiB
C
175 lines
4.5 KiB
C
|
/*
|
||
|
* This file is part of the libpayload project.
|
||
|
*
|
||
|
* Copyright (C) 2008 coresystems GmbH
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
* 3. The name of the author may not be used to endorse or promote products
|
||
|
* derived from this software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
|
* SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @file libc/readline.c
|
||
|
* Simple readline implementation
|
||
|
*/
|
||
|
|
||
|
#include <libpayload.h>
|
||
|
|
||
|
static char *readline_buffer;
|
||
|
static int readline_bufferlen;
|
||
|
|
||
|
/**
|
||
|
* Read a line from the terminal and return it.
|
||
|
*
|
||
|
* This readline implementation is rather simple, but it does more than the
|
||
|
* original readline() because it allows us to have a pre-filled buffer.
|
||
|
* To pre-fill the buffer, use the getline() function.
|
||
|
*
|
||
|
* @param prompt A prompt to display on the line.
|
||
|
* @return A pointer to the input string.
|
||
|
*/
|
||
|
char *readline(const char *prompt)
|
||
|
{
|
||
|
char *buffer;
|
||
|
int current, ch, nonspace_seen;
|
||
|
|
||
|
if (!readline_buffer || !readline_bufferlen) {
|
||
|
#define READLINE_BUFFERSIZE 256
|
||
|
readline_buffer = malloc(READLINE_BUFFERSIZE);
|
||
|
if (!readline_buffer)
|
||
|
return NULL;
|
||
|
readline_bufferlen = READLINE_BUFFERSIZE;
|
||
|
memset(readline_buffer, 0, readline_bufferlen);
|
||
|
}
|
||
|
|
||
|
buffer = readline_buffer;
|
||
|
|
||
|
/* print prompt */
|
||
|
if (prompt) {
|
||
|
current = 0;
|
||
|
while (prompt[current]) {
|
||
|
putchar(prompt[current]);
|
||
|
current++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* print existing buffer, if there is one */
|
||
|
current = 0;
|
||
|
while (buffer[current]) {
|
||
|
putchar(buffer[current]);
|
||
|
current++;
|
||
|
}
|
||
|
|
||
|
while (1) {
|
||
|
ch = getchar();
|
||
|
switch (ch) {
|
||
|
case '\r':
|
||
|
case '\n':
|
||
|
/* newline */
|
||
|
putchar('\n');
|
||
|
goto out;
|
||
|
case '\b':
|
||
|
case '\x7f':
|
||
|
/* backspace */
|
||
|
if (current > 0) {
|
||
|
putchar('\b');
|
||
|
putchar(' ');
|
||
|
putchar('\b');
|
||
|
current--;
|
||
|
}
|
||
|
break;
|
||
|
case 'W' & 0x1f: /* CTRL-W */
|
||
|
/* word erase */
|
||
|
nonspace_seen = 0;
|
||
|
while (current) {
|
||
|
if (buffer[current - 1] != ' ')
|
||
|
nonspace_seen = 1;
|
||
|
putchar('\b');
|
||
|
putchar(' ');
|
||
|
putchar('\b');
|
||
|
current--;
|
||
|
if (nonspace_seen && (current < readline_bufferlen - 1)
|
||
|
&& (current > 0) && (buffer[current - 1] == ' '))
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'U' & 0x1f: /* CTRL-U */
|
||
|
/* line erase */
|
||
|
while (current) {
|
||
|
putchar('\b');
|
||
|
putchar(' ');
|
||
|
putchar('\b');
|
||
|
current--;
|
||
|
}
|
||
|
current = 0;
|
||
|
break;
|
||
|
default:
|
||
|
/* all other characters */
|
||
|
|
||
|
/* ignore control characters */
|
||
|
if (ch < 0x20)
|
||
|
break;
|
||
|
|
||
|
/* ignore unprintables */
|
||
|
if (ch >= 0x7f)
|
||
|
break;
|
||
|
|
||
|
if (current + 1 < readline_bufferlen) {
|
||
|
/* print new character */
|
||
|
putchar(ch);
|
||
|
/* and add it to the array */
|
||
|
buffer[current] = ch;
|
||
|
current++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
out:
|
||
|
if (current >= readline_bufferlen)
|
||
|
current = readline_bufferlen - 1;
|
||
|
buffer[current] = '\0';
|
||
|
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read a line from the input and store it in a buffer.
|
||
|
*
|
||
|
* This function allows the user to pass a predefined buffer to readline().
|
||
|
* The buffer may be filled with a default value which will be displayed by
|
||
|
* readline() and can be edited as normal.
|
||
|
* The final input string returned by readline() will be returned in
|
||
|
* the buffer and the function will return the length of the string.
|
||
|
*
|
||
|
* @param buffer Pointer to a buffer to store the line in.
|
||
|
* @param len Length of the buffer.
|
||
|
* @return The final length of the string.
|
||
|
*/
|
||
|
int getline(char *buffer, int len)
|
||
|
{
|
||
|
readline_buffer = buffer;
|
||
|
readline_bufferlen = len;
|
||
|
readline(NULL);
|
||
|
|
||
|
return strlen(buffer);
|
||
|
}
|