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