blob: 9387e09149e32c095436475adb1b2caa4caa40d4 [file] [log] [blame]
Stefan Reinaueraddf4432008-08-19 17:48:02 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2008 coresystems GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
Uwe Hermann31538632008-08-31 22:10:35 +000030/**
31 * @file libc/readline.c
32 * Simple readline implementation
Jordan Crouse617120c2008-08-28 23:11:29 +000033 */
34
Stefan Reinaueraddf4432008-08-19 17:48:02 +000035#include <libpayload.h>
36
Uwe Hermann31538632008-08-31 22:10:35 +000037static char *readline_buffer;
Stefan Reinaueraddf4432008-08-19 17:48:02 +000038static int readline_bufferlen;
39
40/**
Uwe Hermann31538632008-08-31 22:10:35 +000041 * Read a line from the terminal and return it.
Jordan Crouse617120c2008-08-28 23:11:29 +000042 *
Uwe Hermann31538632008-08-31 22:10:35 +000043 * This readline implementation is rather simple, but it does more than the
44 * original readline() because it allows us to have a pre-filled buffer.
45 * To pre-fill the buffer, use the getline() function.
46 *
47 * @param prompt A prompt to display on the line.
48 * @return A pointer to the input string.
Stefan Reinaueraddf4432008-08-19 17:48:02 +000049 */
Uwe Hermann31538632008-08-31 22:10:35 +000050char *readline(const char *prompt)
Stefan Reinaueraddf4432008-08-19 17:48:02 +000051{
52 char *buffer;
53 int current, ch, nonspace_seen;
54
55 if (!readline_buffer || !readline_bufferlen) {
56#define READLINE_BUFFERSIZE 256
57 readline_buffer = malloc(READLINE_BUFFERSIZE);
Stefan Reinauer5fe6e232009-07-31 11:39:55 +000058 if (!readline_buffer)
59 return NULL;
Stefan Reinaueraddf4432008-08-19 17:48:02 +000060 readline_bufferlen = READLINE_BUFFERSIZE;
61 memset(readline_buffer, 0, readline_bufferlen);
62 }
63
64 buffer = readline_buffer;
Jordan Crouse617120c2008-08-28 23:11:29 +000065
Stefan Reinaueraddf4432008-08-19 17:48:02 +000066 /* print prompt */
67 if (prompt) {
68 current = 0;
69 while (prompt[current]) {
70 putchar(prompt[current]);
71 current++;
72 }
73 }
74
75 /* print existing buffer, if there is one */
76 current = 0;
77 while (buffer[current]) {
78 putchar(buffer[current]);
79 current++;
80 }
81
82 while (1) {
83 ch = getchar();
84 switch (ch) {
85 case '\r':
86 case '\n':
87 /* newline */
88 putchar('\n');
89 goto out;
90 case '\b':
91 case '\x7f':
92 /* backspace */
93 if (current > 0) {
94 putchar('\b');
95 putchar(' ');
96 putchar('\b');
97 current--;
98 }
99 break;
100 case 'W' & 0x1f: /* CTRL-W */
101 /* word erase */
102 nonspace_seen = 0;
103 while (current) {
104 if (buffer[current - 1] != ' ')
105 nonspace_seen = 1;
106 putchar('\b');
107 putchar(' ');
108 putchar('\b');
109 current--;
110 if (nonspace_seen && (current < readline_bufferlen - 1)
111 && (current > 0) && (buffer[current - 1] == ' '))
112 break;
113 }
114 break;
115 case 'U' & 0x1f: /* CTRL-U */
116 /* line erase */
117 while (current) {
118 putchar('\b');
119 putchar(' ');
120 putchar('\b');
121 current--;
122 }
123 current = 0;
124 break;
125 default:
126 /* all other characters */
127
128 /* ignore control characters */
129 if (ch < 0x20)
130 break;
131
132 /* ignore unprintables */
133 if (ch >= 0x7f)
134 break;
135
136 if (current + 1 < readline_bufferlen) {
137 /* print new character */
138 putchar(ch);
139 /* and add it to the array */
140 buffer[current] = ch;
141 current++;
142 }
143 }
144 }
145
Stefan Reinaueraddf4432008-08-19 17:48:02 +0000146out:
147 if (current >= readline_bufferlen)
148 current = readline_bufferlen - 1;
149 buffer[current] = '\0';
150
151 return buffer;
152}
153
Jordan Crouse617120c2008-08-28 23:11:29 +0000154/**
Uwe Hermann31538632008-08-31 22:10:35 +0000155 * Read a line from the input and store it in a buffer.
156 *
157 * This function allows the user to pass a predefined buffer to readline().
158 * The buffer may be filled with a default value which will be displayed by
159 * readline() and can be edited as normal.
160 * The final input string returned by readline() will be returned in
Jordan Crouse617120c2008-08-28 23:11:29 +0000161 * the buffer and the function will return the length of the string.
Uwe Hermann31538632008-08-31 22:10:35 +0000162 *
163 * @param buffer Pointer to a buffer to store the line in.
164 * @param len Length of the buffer.
165 * @return The final length of the string.
Jordan Crouse617120c2008-08-28 23:11:29 +0000166 */
Stefan Reinaueraddf4432008-08-19 17:48:02 +0000167int getline(char *buffer, int len)
168{
169 readline_buffer = buffer;
170 readline_bufferlen = len;
171 readline(NULL);
Uwe Hermann31538632008-08-31 22:10:35 +0000172
Stefan Reinaueraddf4432008-08-19 17:48:02 +0000173 return strlen(buffer);
174}