/ payloads / libpayload / libc / readline.c
readline.c
  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   */
 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   */
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  }