libpayload: Provide interpretation of CMOS data structures
[coreboot.git] / payloads / libpayload / libc / readline.c
1 /*
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
30 /**
31  * @file libc/readline.c
32  * Simple readline implementation
33  */
34
35 #include <libpayload.h>
36
37 static char *readline_buffer;
38 static int readline_bufferlen;
39
40 /**
41  * Read a line from the terminal and return it.
42  *
43  * 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.
49  */
50 char *readline(const char *prompt)
51 {
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);
58                 if (!readline_buffer)
59                         return NULL;
60                 readline_bufferlen = READLINE_BUFFERSIZE;
61                 memset(readline_buffer, 0, readline_bufferlen);
62         }
63
64         buffer = readline_buffer;
65
66         /* 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
146 out:
147         if (current >= readline_bufferlen)
148                 current = readline_bufferlen - 1;
149         buffer[current] = '\0';
150
151         return buffer;
152 }
153
154 /**
155  * 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
161  * the buffer and the function will return the length of the string.
162  *
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.
166  */
167 int getline(char *buffer, int len)
168 {
169         readline_buffer = buffer;
170         readline_bufferlen = len;
171         readline(NULL);
172
173         return strlen(buffer);
174 }