15129044dSC.J. Collier/*-
25129044dSC.J. Collier *   BSD LICENSE
35129044dSC.J. Collier *
45129044dSC.J. Collier *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
55129044dSC.J. Collier *   All rights reserved.
65129044dSC.J. Collier *
75129044dSC.J. Collier *   Redistribution and use in source and binary forms, with or without
85129044dSC.J. Collier *   modification, are permitted provided that the following conditions
95129044dSC.J. Collier *   are met:
105129044dSC.J. Collier *
115129044dSC.J. Collier *     * Redistributions of source code must retain the above copyright
125129044dSC.J. Collier *       notice, this list of conditions and the following disclaimer.
135129044dSC.J. Collier *     * Redistributions in binary form must reproduce the above copyright
145129044dSC.J. Collier *       notice, this list of conditions and the following disclaimer in
155129044dSC.J. Collier *       the documentation and/or other materials provided with the
165129044dSC.J. Collier *       distribution.
175129044dSC.J. Collier *     * Neither the name of Intel Corporation nor the names of its
185129044dSC.J. Collier *       contributors may be used to endorse or promote products derived
195129044dSC.J. Collier *       from this software without specific prior written permission.
205129044dSC.J. Collier *
215129044dSC.J. Collier *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225129044dSC.J. Collier *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
235129044dSC.J. Collier *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
245129044dSC.J. Collier *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
255129044dSC.J. Collier *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
265129044dSC.J. Collier *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
275129044dSC.J. Collier *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
285129044dSC.J. Collier *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
295129044dSC.J. Collier *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
305129044dSC.J. Collier *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
315129044dSC.J. Collier *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
325129044dSC.J. Collier */
335129044dSC.J. Collier
345129044dSC.J. Collier/*
355129044dSC.J. Collier * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
365129044dSC.J. Collier * All rights reserved.
375129044dSC.J. Collier * Redistribution and use in source and binary forms, with or without
385129044dSC.J. Collier * modification, are permitted provided that the following conditions are met:
395129044dSC.J. Collier *
405129044dSC.J. Collier *     * Redistributions of source code must retain the above copyright
415129044dSC.J. Collier *       notice, this list of conditions and the following disclaimer.
425129044dSC.J. Collier *     * Redistributions in binary form must reproduce the above copyright
435129044dSC.J. Collier *       notice, this list of conditions and the following disclaimer in the
445129044dSC.J. Collier *       documentation and/or other materials provided with the distribution.
455129044dSC.J. Collier *     * Neither the name of the University of California, Berkeley nor the
465129044dSC.J. Collier *       names of its contributors may be used to endorse or promote products
475129044dSC.J. Collier *       derived from this software without specific prior written permission.
485129044dSC.J. Collier *
495129044dSC.J. Collier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
505129044dSC.J. Collier * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
515129044dSC.J. Collier * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
525129044dSC.J. Collier * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
535129044dSC.J. Collier * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
545129044dSC.J. Collier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
555129044dSC.J. Collier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
565129044dSC.J. Collier * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
575129044dSC.J. Collier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
585129044dSC.J. Collier * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
595129044dSC.J. Collier */
605129044dSC.J. Collier
615129044dSC.J. Collier#include <stdlib.h>
625129044dSC.J. Collier#include <stdio.h>
635129044dSC.J. Collier#include <stdint.h>
645129044dSC.J. Collier#include <string.h>
655129044dSC.J. Collier#include <stdarg.h>
665129044dSC.J. Collier#include <errno.h>
675129044dSC.J. Collier#include <ctype.h>
685129044dSC.J. Collier
695129044dSC.J. Collier#include "cmdline_cirbuf.h"
705129044dSC.J. Collier#include "cmdline_rdline.h"
715129044dSC.J. Collier
725129044dSC.J. Collierstatic void rdline_puts(struct rdline *rdl, const char *buf);
735129044dSC.J. Collierstatic void rdline_miniprintf(struct rdline *rdl,
745129044dSC.J. Collier			      const char *buf, unsigned int val);
755129044dSC.J. Collier
765129044dSC.J. Collierstatic void rdline_remove_old_history_item(struct rdline *rdl);
775129044dSC.J. Collierstatic void rdline_remove_first_history_item(struct rdline *rdl);
785129044dSC.J. Collierstatic unsigned int rdline_get_history_size(struct rdline *rdl);
795129044dSC.J. Collier
805129044dSC.J. Collier
815129044dSC.J. Collier/* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
825129044dSC.J. Collier * own. */
835129044dSC.J. Collierstatic int
845129044dSC.J. Collierisblank2(char c)
855129044dSC.J. Collier{
865129044dSC.J. Collier	if (c == ' ' ||
875129044dSC.J. Collier	    c == '\t' )
885129044dSC.J. Collier		return 1;
895129044dSC.J. Collier	return 0;
905129044dSC.J. Collier}
915129044dSC.J. Collier
925129044dSC.J. Collierint
935129044dSC.J. Collierrdline_init(struct rdline *rdl,
945129044dSC.J. Collier		 rdline_write_char_t *write_char,
955129044dSC.J. Collier		 rdline_validate_t *validate,
965129044dSC.J. Collier		 rdline_complete_t *complete)
975129044dSC.J. Collier{
985129044dSC.J. Collier	if (!rdl || !write_char || !validate || !complete)
995129044dSC.J. Collier		return -EINVAL;
1005129044dSC.J. Collier	memset(rdl, 0, sizeof(*rdl));
1015129044dSC.J. Collier	rdl->validate = validate;
1025129044dSC.J. Collier	rdl->complete = complete;
1035129044dSC.J. Collier	rdl->write_char = write_char;
1045129044dSC.J. Collier	rdl->status = RDLINE_INIT;
1055129044dSC.J. Collier	return cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
1065129044dSC.J. Collier}
1075129044dSC.J. Collier
1085129044dSC.J. Colliervoid
1095129044dSC.J. Collierrdline_newline(struct rdline *rdl, const char *prompt)
1105129044dSC.J. Collier{
1115129044dSC.J. Collier	unsigned int i;
1125129044dSC.J. Collier
1135129044dSC.J. Collier	if (!rdl || !prompt)
1145129044dSC.J. Collier		return;
1155129044dSC.J. Collier
1165129044dSC.J. Collier	vt100_init(&rdl->vt100);
1175129044dSC.J. Collier	cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
1185129044dSC.J. Collier	cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
1195129044dSC.J. Collier
1205129044dSC.J. Collier	rdl->prompt_size = strnlen(prompt, RDLINE_PROMPT_SIZE-1);
1215129044dSC.J. Collier	if (prompt != rdl->prompt)
1225129044dSC.J. Collier		memcpy(rdl->prompt, prompt, rdl->prompt_size);
1235129044dSC.J. Collier	rdl->prompt[RDLINE_PROMPT_SIZE-1] = '\0';
1245129044dSC.J. Collier
1255129044dSC.J. Collier	for (i=0 ; i<rdl->prompt_size ; i++)
1265129044dSC.J. Collier		rdl->write_char(rdl, rdl->prompt[i]);
1275129044dSC.J. Collier	rdl->status = RDLINE_RUNNING;
1285129044dSC.J. Collier
1295129044dSC.J. Collier	rdl->history_cur_line = -1;
1305129044dSC.J. Collier}
1315129044dSC.J. Collier
1325129044dSC.J. Colliervoid
1335129044dSC.J. Collierrdline_stop(struct rdline *rdl)
1345129044dSC.J. Collier{
1355129044dSC.J. Collier	if (!rdl)
1365129044dSC.J. Collier		return;
1375129044dSC.J. Collier	rdl->status = RDLINE_INIT;
1385129044dSC.J. Collier}
1395129044dSC.J. Collier
1405129044dSC.J. Colliervoid
1415129044dSC.J. Collierrdline_quit(struct rdline *rdl)
1425129044dSC.J. Collier{
1435129044dSC.J. Collier	if (!rdl)
1445129044dSC.J. Collier		return;
1455129044dSC.J. Collier	rdl->status = RDLINE_EXITED;
1465129044dSC.J. Collier}
1475129044dSC.J. Collier
1485129044dSC.J. Colliervoid
1495129044dSC.J. Collierrdline_restart(struct rdline *rdl)
1505129044dSC.J. Collier{
1515129044dSC.J. Collier	if (!rdl)
1525129044dSC.J. Collier		return;
1535129044dSC.J. Collier	rdl->status = RDLINE_RUNNING;
1545129044dSC.J. Collier}
1555129044dSC.J. Collier
1565129044dSC.J. Colliervoid
1575129044dSC.J. Collierrdline_reset(struct rdline *rdl)
1585129044dSC.J. Collier{
1595129044dSC.J. Collier	if (!rdl)
1605129044dSC.J. Collier		return;
1615129044dSC.J. Collier	vt100_init(&rdl->vt100);
1625129044dSC.J. Collier	cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
1635129044dSC.J. Collier	cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
1645129044dSC.J. Collier
1655129044dSC.J. Collier	rdl->status = RDLINE_RUNNING;
1665129044dSC.J. Collier
1675129044dSC.J. Collier	rdl->history_cur_line = -1;
1685129044dSC.J. Collier}
1695129044dSC.J. Collier
1705129044dSC.J. Collierconst char *
1715129044dSC.J. Collierrdline_get_buffer(struct rdline *rdl)
1725129044dSC.J. Collier{
1735129044dSC.J. Collier	if (!rdl)
1745129044dSC.J. Collier		return NULL;
1755129044dSC.J. Collier	unsigned int len_l, len_r;
1765129044dSC.J. Collier	cirbuf_align_left(&rdl->left);
1775129044dSC.J. Collier	cirbuf_align_left(&rdl->right);
1785129044dSC.J. Collier
1795129044dSC.J. Collier	len_l = CIRBUF_GET_LEN(&rdl->left);
1805129044dSC.J. Collier	len_r = CIRBUF_GET_LEN(&rdl->right);
1815129044dSC.J. Collier	memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
1825129044dSC.J. Collier
1835129044dSC.J. Collier	rdl->left_buf[len_l + len_r] = '\n';
1845129044dSC.J. Collier	rdl->left_buf[len_l + len_r + 1] = '\0';
1855129044dSC.J. Collier	return rdl->left_buf;
1865129044dSC.J. Collier}
1875129044dSC.J. Collier
1885129044dSC.J. Collierstatic void
1895129044dSC.J. Collierdisplay_right_buffer(struct rdline *rdl, int force)
1905129044dSC.J. Collier{
1915129044dSC.J. Collier	unsigned int i;
1925129044dSC.J. Collier	char tmp;
1935129044dSC.J. Collier
1945129044dSC.J. Collier	if (!force && CIRBUF_IS_EMPTY(&rdl->right))
1955129044dSC.J. Collier		return;
1965129044dSC.J. Collier
1975129044dSC.J. Collier	rdline_puts(rdl, vt100_clear_right);
1985129044dSC.J. Collier	CIRBUF_FOREACH(&rdl->right, i, tmp) {
1995129044dSC.J. Collier		rdl->write_char(rdl, tmp);
2005129044dSC.J. Collier	}
2015129044dSC.J. Collier	if (!CIRBUF_IS_EMPTY(&rdl->right))
2025129044dSC.J. Collier		rdline_miniprintf(rdl, vt100_multi_left,
2035129044dSC.J. Collier				  CIRBUF_GET_LEN(&rdl->right));
2045129044dSC.J. Collier}
2055129044dSC.J. Collier
2065129044dSC.J. Colliervoid
2075129044dSC.J. Collierrdline_redisplay(struct rdline *rdl)
2085129044dSC.J. Collier{
2095129044dSC.J. Collier	unsigned int i;
2105129044dSC.J. Collier	char tmp;
2115129044dSC.J. Collier
2125129044dSC.J. Collier	if (!rdl)
2135129044dSC.J. Collier		return;
2145129044dSC.J. Collier
2155129044dSC.J. Collier	rdline_puts(rdl, vt100_home);
2165129044dSC.J. Collier	for (i=0 ; i<rdl->prompt_size ; i++)
2175129044dSC.J. Collier		rdl->write_char(rdl, rdl->prompt[i]);
2185129044dSC.J. Collier	CIRBUF_FOREACH(&rdl->left, i, tmp) {
2195129044dSC.J. Collier		rdl->write_char(rdl, tmp);
2205129044dSC.J. Collier	}
2215129044dSC.J. Collier	display_right_buffer(rdl, 1);
2225129044dSC.J. Collier}
2235129044dSC.J. Collier
2245129044dSC.J. Collierint
2255129044dSC.J. Collierrdline_char_in(struct rdline *rdl, char c)
2265129044dSC.J. Collier{
2275129044dSC.J. Collier	unsigned int i;
2285129044dSC.J. Collier	int cmd;
2295129044dSC.J. Collier	char tmp;
2305129044dSC.J. Collier	char *buf;
2315129044dSC.J. Collier
2325129044dSC.J. Collier	if (!rdl)
2335129044dSC.J. Collier		return -EINVAL;
2345129044dSC.J. Collier
2355129044dSC.J. Collier	if (rdl->status == RDLINE_EXITED)
2365129044dSC.J. Collier		return RDLINE_RES_EXITED;
2375129044dSC.J. Collier	if (rdl->status != RDLINE_RUNNING)
2385129044dSC.J. Collier		return RDLINE_RES_NOT_RUNNING;
2395129044dSC.J. Collier
2405129044dSC.J. Collier	cmd = vt100_parser(&rdl->vt100, c);
2415129044dSC.J. Collier	if (cmd == -2)
2425129044dSC.J. Collier		return RDLINE_RES_SUCCESS;
2435129044dSC.J. Collier
2445129044dSC.J. Collier	if (cmd >= 0) {
2455129044dSC.J. Collier		switch (cmd) {
2465129044dSC.J. Collier		/* move caret 1 char to the left */
2475129044dSC.J. Collier		case CMDLINE_KEY_CTRL_B:
2485129044dSC.J. Collier		case CMDLINE_KEY_LEFT_ARR:
2495129044dSC.J. Collier			if (CIRBUF_IS_EMPTY(&rdl->left))
2505129044dSC.J. Collier				break;
2515129044dSC.J. Collier			tmp = cirbuf_get_tail(&rdl->left);
2525129044dSC.J. Collier			cirbuf_del_tail(&rdl->left);
2535129044dSC.J. Collier			cirbuf_add_head(&rdl->right, tmp);
2545129044dSC.J. Collier			rdline_puts(rdl, vt100_left_arr);
2555129044dSC.J. Collier			break;
2565129044dSC.J. Collier
2575129044dSC.J. Collier		/* move caret 1 char to the right */
2585129044dSC.J. Collier		case CMDLINE_KEY_CTRL_F:
2595129044dSC.J. Collier		case CMDLINE_KEY_RIGHT_ARR:
2605129044dSC.J. Collier			if (CIRBUF_IS_EMPTY(&rdl->right))
2615129044dSC.J. Collier				break;
2625129044dSC.J. Collier			tmp = cirbuf_get_head(&rdl->right);
2635129044dSC.J. Collier			cirbuf_del_head(&rdl->right);
2645129044dSC.J. Collier			cirbuf_add_tail(&rdl->left, tmp);
2655129044dSC.J. Collier			rdline_puts(rdl, vt100_right_arr);
2665129044dSC.J. Collier			break;
2675129044dSC.J. Collier
2685129044dSC.J. Collier		/* move caret 1 word to the left */
2695129044dSC.J. Collier		/* keyboard equivalent: Alt+B */
2705129044dSC.J. Collier		case CMDLINE_KEY_WLEFT:
2715129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->left) &&
2725129044dSC.J. Collier			       (tmp = cirbuf_get_tail(&rdl->left)) &&
2735129044dSC.J. Collier			       isblank2(tmp)) {
2745129044dSC.J. Collier				rdline_puts(rdl, vt100_left_arr);
2755129044dSC.J. Collier				cirbuf_del_tail(&rdl->left);
2765129044dSC.J. Collier				cirbuf_add_head(&rdl->right, tmp);
2775129044dSC.J. Collier			}
2785129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->left) &&
2795129044dSC.J. Collier			       (tmp = cirbuf_get_tail(&rdl->left)) &&
2805129044dSC.J. Collier			       !isblank2(tmp)) {
2815129044dSC.J. Collier				rdline_puts(rdl, vt100_left_arr);
2825129044dSC.J. Collier				cirbuf_del_tail(&rdl->left);
2835129044dSC.J. Collier				cirbuf_add_head(&rdl->right, tmp);
2845129044dSC.J. Collier			}
2855129044dSC.J. Collier			break;
2865129044dSC.J. Collier
2875129044dSC.J. Collier		/* move caret 1 word to the right */
2885129044dSC.J. Collier		/* keyboard equivalent: Alt+F */
2895129044dSC.J. Collier		case CMDLINE_KEY_WRIGHT:
2905129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->right) &&
2915129044dSC.J. Collier			       (tmp = cirbuf_get_head(&rdl->right)) &&
2925129044dSC.J. Collier			       isblank2(tmp)) {
2935129044dSC.J. Collier				rdline_puts(rdl, vt100_right_arr);
2945129044dSC.J. Collier				cirbuf_del_head(&rdl->right);
2955129044dSC.J. Collier				cirbuf_add_tail(&rdl->left, tmp);
2965129044dSC.J. Collier			}
2975129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->right) &&
2985129044dSC.J. Collier			       (tmp = cirbuf_get_head(&rdl->right)) &&
2995129044dSC.J. Collier			       !isblank2(tmp)) {
3005129044dSC.J. Collier				rdline_puts(rdl, vt100_right_arr);
3015129044dSC.J. Collier				cirbuf_del_head(&rdl->right);
3025129044dSC.J. Collier				cirbuf_add_tail(&rdl->left, tmp);
3035129044dSC.J. Collier			}
3045129044dSC.J. Collier			break;
3055129044dSC.J. Collier
3065129044dSC.J. Collier		/* move caret to the left */
3075129044dSC.J. Collier		case CMDLINE_KEY_CTRL_A:
3085129044dSC.J. Collier			if (CIRBUF_IS_EMPTY(&rdl->left))
3095129044dSC.J. Collier				break;
3105129044dSC.J. Collier			rdline_miniprintf(rdl, vt100_multi_left,
3115129044dSC.J. Collier						CIRBUF_GET_LEN(&rdl->left));
3125129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->left)) {
3135129044dSC.J. Collier				tmp = cirbuf_get_tail(&rdl->left);
3145129044dSC.J. Collier				cirbuf_del_tail(&rdl->left);
3155129044dSC.J. Collier				cirbuf_add_head(&rdl->right, tmp);
3165129044dSC.J. Collier			}
3175129044dSC.J. Collier			break;
3185129044dSC.J. Collier
3195129044dSC.J. Collier		/* move caret to the right */
3205129044dSC.J. Collier		case CMDLINE_KEY_CTRL_E:
3215129044dSC.J. Collier			if (CIRBUF_IS_EMPTY(&rdl->right))
3225129044dSC.J. Collier				break;
3235129044dSC.J. Collier			rdline_miniprintf(rdl, vt100_multi_right,
3245129044dSC.J. Collier						CIRBUF_GET_LEN(&rdl->right));
3255129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->right)) {
3265129044dSC.J. Collier				tmp = cirbuf_get_head(&rdl->right);
3275129044dSC.J. Collier				cirbuf_del_head(&rdl->right);
3285129044dSC.J. Collier				cirbuf_add_tail(&rdl->left, tmp);
3295129044dSC.J. Collier			}
3305129044dSC.J. Collier			break;
3315129044dSC.J. Collier
3325129044dSC.J. Collier		/* delete 1 char from the left */
3335129044dSC.J. Collier		case CMDLINE_KEY_BKSPACE:
3345129044dSC.J. Collier			if(!cirbuf_del_tail_safe(&rdl->left)) {
3355129044dSC.J. Collier				rdline_puts(rdl, vt100_bs);
3365129044dSC.J. Collier				display_right_buffer(rdl, 1);
3375129044dSC.J. Collier			}
3385129044dSC.J. Collier			break;
3395129044dSC.J. Collier
3405129044dSC.J. Collier		/* delete 1 char from the right */
3415129044dSC.J. Collier		case CMDLINE_KEY_SUPPR:
3425129044dSC.J. Collier		case CMDLINE_KEY_CTRL_D:
3435129044dSC.J. Collier			if (cmd == CMDLINE_KEY_CTRL_D &&
3445129044dSC.J. Collier			    CIRBUF_IS_EMPTY(&rdl->left) &&
3455129044dSC.J. Collier			    CIRBUF_IS_EMPTY(&rdl->right)) {
3465129044dSC.J. Collier				return RDLINE_RES_EOF;
3475129044dSC.J. Collier			}
3485129044dSC.J. Collier			if (!cirbuf_del_head_safe(&rdl->right)) {
3495129044dSC.J. Collier				display_right_buffer(rdl, 1);
3505129044dSC.J. Collier			}
3515129044dSC.J. Collier			break;
3525129044dSC.J. Collier
3535129044dSC.J. Collier		/* delete 1 word from the left */
3545129044dSC.J. Collier		case CMDLINE_KEY_META_BKSPACE:
3555129044dSC.J. Collier		case CMDLINE_KEY_CTRL_W:
3565129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
3575129044dSC.J. Collier				rdline_puts(rdl, vt100_bs);
3585129044dSC.J. Collier				cirbuf_del_tail(&rdl->left);
3595129044dSC.J. Collier			}
3605129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank2(cirbuf_get_tail(&rdl->left))) {
3615129044dSC.J. Collier				rdline_puts(rdl, vt100_bs);
3625129044dSC.J. Collier				cirbuf_del_tail(&rdl->left);
3635129044dSC.J. Collier			}
3645129044dSC.J. Collier			display_right_buffer(rdl, 1);
3655129044dSC.J. Collier			break;
3665129044dSC.J. Collier
3675129044dSC.J. Collier		/* delete 1 word from the right */
3685129044dSC.J. Collier		case CMDLINE_KEY_META_D:
3695129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->right) && isblank2(cirbuf_get_head(&rdl->right)))
3705129044dSC.J. Collier				cirbuf_del_head(&rdl->right);
3715129044dSC.J. Collier			while (! CIRBUF_IS_EMPTY(&rdl->right) && !isblank2(cirbuf_get_head(&rdl->right)))
3725129044dSC.J. Collier				cirbuf_del_head(&rdl->right);
3735129044dSC.J. Collier			display_right_buffer(rdl, 1);
3745129044dSC.J. Collier			break;
3755129044dSC.J. Collier
3765129044dSC.J. Collier		/* set kill buffer to contents on the right side of caret */
3775129044dSC.J. Collier		case CMDLINE_KEY_CTRL_K:
3785129044dSC.J. Collier			cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
3795129044dSC.J. Collier			rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
3805129044dSC.J. Collier			cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
3815129044dSC.J. Collier			rdline_puts(rdl, vt100_clear_right);
3825129044dSC.J. Collier			break;
3835129044dSC.J. Collier
3845129044dSC.J. Collier		/* paste contents of kill buffer to the left side of caret */
3855129044dSC.J. Collier		case CMDLINE_KEY_CTRL_Y:
3865129044dSC.J. Collier			i=0;
3875129044dSC.J. Collier			while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
3885129044dSC.J. Collier			      RDLINE_BUF_SIZE &&
3895129044dSC.J. Collier			      i < rdl->kill_size) {
3905129044dSC.J. Collier				cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
3915129044dSC.J. Collier				rdl->write_char(rdl, rdl->kill_buf[i]);
3925129044dSC.J. Collier				i++;
3935129044dSC.J. Collier			}
3945129044dSC.J. Collier			display_right_buffer(rdl, 0);
3955129044dSC.J. Collier			break;
3965129044dSC.J. Collier
3975129044dSC.J. Collier		/* clear and newline */
3985129044dSC.J. Collier		case CMDLINE_KEY_CTRL_C:
3995129044dSC.J. Collier			rdline_puts(rdl, "\r\n");
4005129044dSC.J. Collier			rdline_newline(rdl, rdl->prompt);
4015129044dSC.J. Collier			break;
4025129044dSC.J. Collier
4035129044dSC.J. Collier		/* redisplay (helps when prompt is lost in other output) */
4045129044dSC.J. Collier		case CMDLINE_KEY_CTRL_L:
4055129044dSC.J. Collier			rdline_redisplay(rdl);
4065129044dSC.J. Collier			break;
4075129044dSC.J. Collier
4085129044dSC.J. Collier		/* autocomplete */
4095129044dSC.J. Collier		case CMDLINE_KEY_TAB:
4105129044dSC.J. Collier		case CMDLINE_KEY_HELP:
4115129044dSC.J. Collier			cirbuf_align_left(&rdl->left);
4125129044dSC.J. Collier			rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
4135129044dSC.J. Collier			if (rdl->complete) {
4145129044dSC.J. Collier				char tmp_buf[BUFSIZ];
4155129044dSC.J. Collier				int complete_state;
4165129044dSC.J. Collier				int ret;
4175129044dSC.J. Collier				unsigned int tmp_size;
4185129044dSC.J. Collier
4195129044dSC.J. Collier				if (cmd == CMDLINE_KEY_TAB)
4205129044dSC.J. Collier					complete_state = 0;
4215129044dSC.J. Collier				else
4225129044dSC.J. Collier					complete_state = -1;
4235129044dSC.J. Collier
4245129044dSC.J. Collier				/* see in parse.h for help on complete() */
4255129044dSC.J. Collier				ret = rdl->complete(rdl, rdl->left_buf,
4265129044dSC.J. Collier						    tmp_buf, sizeof(tmp_buf),
4275129044dSC.J. Collier						    &complete_state);
4285129044dSC.J. Collier				/* no completion or error */
4295129044dSC.J. Collier				if (ret <= 0) {
4305129044dSC.J. Collier					return RDLINE_RES_COMPLETE;
4315129044dSC.J. Collier				}
4325129044dSC.J. Collier
4335129044dSC.J. Collier				tmp_size = strnlen(tmp_buf, sizeof(tmp_buf));
4345129044dSC.J. Collier				/* add chars */
4355129044dSC.J. Collier				if (ret == RDLINE_RES_COMPLETE) {
4365129044dSC.J. Collier					i=0;
4375129044dSC.J. Collier					while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
4385129044dSC.J. Collier					      RDLINE_BUF_SIZE &&
4395129044dSC.J. Collier					      i < tmp_size) {
4405129044dSC.J. Collier						cirbuf_add_tail(&rdl->left, tmp_buf[i]);
4415129044dSC.J. Collier						rdl->write_char(rdl, tmp_buf[i]);
4425129044dSC.J. Collier						i++;
4435129044dSC.J. Collier					}
4445129044dSC.J. Collier					display_right_buffer(rdl, 1);
4455129044dSC.J. Collier					return RDLINE_RES_COMPLETE; /* ?? */
4465129044dSC.J. Collier				}
4475129044dSC.J. Collier
4485129044dSC.J. Collier				/* choice */
4495129044dSC.J. Collier				rdline_puts(rdl, "\r\n");
4505129044dSC.J. Collier				while (ret) {
4515129044dSC.J. Collier					rdl->write_char(rdl, ' ');
4525129044dSC.J. Collier					for (i=0 ; tmp_buf[i] ; i++)
4535129044dSC.J. Collier						rdl->write_char(rdl, tmp_buf[i]);
4545129044dSC.J. Collier					rdline_puts(rdl, "\r\n");
4555129044dSC.J. Collier					ret = rdl->complete(rdl, rdl->left_buf,
4565129044dSC.J. Collier							    tmp_buf, sizeof(tmp_buf),
4575129044dSC.J. Collier							    &complete_state);
4585129044dSC.J. Collier				}
4595129044dSC.J. Collier
4605129044dSC.J. Collier				rdline_redisplay(rdl);
4615129044dSC.J. Collier			}
4625129044dSC.J. Collier			return RDLINE_RES_COMPLETE;
4635129044dSC.J. Collier
4645129044dSC.J. Collier		/* complete buffer */
4655129044dSC.J. Collier		case CMDLINE_KEY_RETURN:
4665129044dSC.J. Collier		case CMDLINE_KEY_RETURN2:
4675129044dSC.J. Collier			rdline_get_buffer(rdl);
4685129044dSC.J. Collier			rdl->status = RDLINE_INIT;
4695129044dSC.J. Collier			rdline_puts(rdl, "\r\n");
4705129044dSC.J. Collier			if (rdl->history_cur_line != -1)
4715129044dSC.J. Collier				rdline_remove_first_history_item(rdl);
4725129044dSC.J. Collier
4735129044dSC.J. Collier			if (rdl->validate)
4745129044dSC.J. Collier				rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
4755129044dSC.J. Collier			/* user may have stopped rdline */
4765129044dSC.J. Collier			if (rdl->status == RDLINE_EXITED)
4775129044dSC.J. Collier				return RDLINE_RES_EXITED;
4785129044dSC.J. Collier			return RDLINE_RES_VALIDATED;
4795129044dSC.J. Collier
4805129044dSC.J. Collier		/* previous element in history */
4815129044dSC.J. Collier		case CMDLINE_KEY_UP_ARR:
4825129044dSC.J. Collier		case CMDLINE_KEY_CTRL_P:
4835129044dSC.J. Collier			if (rdl->history_cur_line == 0) {
4845129044dSC.J. Collier				rdline_remove_first_history_item(rdl);
4855129044dSC.J. Collier			}
4865129044dSC.J. Collier			if (rdl->history_cur_line <= 0) {
4875129044dSC.J. Collier				rdline_add_history(rdl, rdline_get_buffer(rdl));
4885129044dSC.J. Collier				rdl->history_cur_line = 0;
4895129044dSC.J. Collier			}
4905129044dSC.J. Collier
4915129044dSC.J. Collier			buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
4925129044dSC.J. Collier			if (!buf)
4935129044dSC.J. Collier				break;
4945129044dSC.J. Collier
4955129044dSC.J. Collier			rdl->history_cur_line ++;
4965129044dSC.J. Collier			vt100_init(&rdl->vt100);
4975129044dSC.J. Collier			cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
4985129044dSC.J. Collier			cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
4995129044dSC.J. Collier			cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
5005129044dSC.J. Collier			rdline_redisplay(rdl);
5015129044dSC.J. Collier			break;
5025129044dSC.J. Collier
5035129044dSC.J. Collier		/* next element in history */
5045129044dSC.J. Collier		case CMDLINE_KEY_DOWN_ARR:
5055129044dSC.J. Collier		case CMDLINE_KEY_CTRL_N:
5065129044dSC.J. Collier			if (rdl->history_cur_line - 1 < 0)
5075129044dSC.J. Collier				break;
5085129044dSC.J. Collier
5095129044dSC.J. Collier			rdl->history_cur_line --;
5105129044dSC.J. Collier			buf = rdline_get_history_item(rdl, rdl->history_cur_line);
5115129044dSC.J. Collier			if (!buf)
5125129044dSC.J. Collier				break;
5135129044dSC.J. Collier			vt100_init(&rdl->vt100);
5145129044dSC.J. Collier			cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
5155129044dSC.J. Collier			cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
5165129044dSC.J. Collier			cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
5175129044dSC.J. Collier			rdline_redisplay(rdl);
5185129044dSC.J. Collier
5195129044dSC.J. Collier			break;
5205129044dSC.J. Collier
5215129044dSC.J. Collier
5225129044dSC.J. Collier		default:
5235129044dSC.J. Collier			break;
5245129044dSC.J. Collier		}
5255129044dSC.J. Collier
5265129044dSC.J. Collier		return RDLINE_RES_SUCCESS;
5275129044dSC.J. Collier	}
5285129044dSC.J. Collier
5295129044dSC.J. Collier	if (!isprint((int)c))
5305129044dSC.J. Collier		return RDLINE_RES_SUCCESS;
5315129044dSC.J. Collier
5325129044dSC.J. Collier	/* standard chars */
5335129044dSC.J. Collier	if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
5345129044dSC.J. Collier		return RDLINE_RES_SUCCESS;
5355129044dSC.J. Collier
5365129044dSC.J. Collier	if (cirbuf_add_tail_safe(&rdl->left, c))
5375129044dSC.J. Collier		return RDLINE_RES_SUCCESS;
5385129044dSC.J. Collier
5395129044dSC.J. Collier	rdl->write_char(rdl, c);
5405129044dSC.J. Collier	display_right_buffer(rdl, 0);
5415129044dSC.J. Collier
5425129044dSC.J. Collier	return RDLINE_RES_SUCCESS;
5435129044dSC.J. Collier}
5445129044dSC.J. Collier
5455129044dSC.J. Collier
5465129044dSC.J. Collier/* HISTORY */
5475129044dSC.J. Collier
5485129044dSC.J. Collierstatic void
5495129044dSC.J. Collierrdline_remove_old_history_item(struct rdline * rdl)
5505129044dSC.J. Collier{
5515129044dSC.J. Collier	char tmp;
5525129044dSC.J. Collier
5535129044dSC.J. Collier	while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
5545129044dSC.J. Collier		tmp = cirbuf_get_head(&rdl->history);
5555129044dSC.J. Collier		cirbuf_del_head(&rdl->history);
5565129044dSC.J. Collier		if (!tmp)
5575129044dSC.J. Collier			break;
5585129044dSC.J. Collier	}
5595129044dSC.J. Collier}
5605129044dSC.J. Collier
5615129044dSC.J. Collierstatic void
5625129044dSC.J. Collierrdline_remove_first_history_item(struct rdline * rdl)
5635129044dSC.J. Collier{
5645129044dSC.J. Collier	char tmp;
5655129044dSC.J. Collier
5665129044dSC.J. Collier	if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
5675129044dSC.J. Collier		return;
5685129044dSC.J. Collier	}
5695129044dSC.J. Collier	else {
5705129044dSC.J. Collier		cirbuf_del_tail(&rdl->history);
5715129044dSC.J. Collier	}
5725129044dSC.J. Collier
5735129044dSC.J. Collier	while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
5745129044dSC.J. Collier		tmp = cirbuf_get_tail(&rdl->history);
5755129044dSC.J. Collier		if (!tmp)
5765129044dSC.J. Collier			break;
5775129044dSC.J. Collier		cirbuf_del_tail(&rdl->history);
5785129044dSC.J. Collier	}
5795129044dSC.J. Collier}
5805129044dSC.J. Collier
5815129044dSC.J. Collierstatic unsigned int
5825129044dSC.J. Collierrdline_get_history_size(struct rdline * rdl)
5835129044dSC.J. Collier{
5845129044dSC.J. Collier	unsigned int i, tmp, ret=0;
5855129044dSC.J. Collier
5865129044dSC.J. Collier	CIRBUF_FOREACH(&rdl->history, i, tmp) {
5875129044dSC.J. Collier		if (tmp == 0)
5885129044dSC.J. Collier			ret ++;
5895129044dSC.J. Collier	}
5905129044dSC.J. Collier
5915129044dSC.J. Collier	return ret;
5925129044dSC.J. Collier}
5935129044dSC.J. Collier
5945129044dSC.J. Collierchar *
5955129044dSC.J. Collierrdline_get_history_item(struct rdline * rdl, unsigned int idx)
5965129044dSC.J. Collier{
5975129044dSC.J. Collier	unsigned int len, i, tmp;
5985129044dSC.J. Collier
5995129044dSC.J. Collier	if (!rdl)
6005129044dSC.J. Collier		return NULL;
6015129044dSC.J. Collier
6025129044dSC.J. Collier	len = rdline_get_history_size(rdl);
6035129044dSC.J. Collier	if ( idx >= len ) {
6045129044dSC.J. Collier		return NULL;
6055129044dSC.J. Collier	}
6065129044dSC.J. Collier
6075129044dSC.J. Collier	cirbuf_align_left(&rdl->history);
6085129044dSC.J. Collier
6095129044dSC.J. Collier	CIRBUF_FOREACH(&rdl->history, i, tmp) {
6105129044dSC.J. Collier		if ( idx == len - 1) {
6115129044dSC.J. Collier			return rdl->history_buf + i;
6125129044dSC.J. Collier		}
6135129044dSC.J. Collier		if (tmp == 0)
6145129044dSC.J. Collier			len --;
6155129044dSC.J. Collier	}
6165129044dSC.J. Collier
6175129044dSC.J. Collier	return NULL;
6185129044dSC.J. Collier}
6195129044dSC.J. Collier
6205129044dSC.J. Collierint
6215129044dSC.J. Collierrdline_add_history(struct rdline * rdl, const char * buf)
6225129044dSC.J. Collier{
6235129044dSC.J. Collier	unsigned int len, i;
6245129044dSC.J. Collier
6255129044dSC.J. Collier	if (!rdl || !buf)
6265129044dSC.J. Collier		return -EINVAL;
6275129044dSC.J. Collier
6285129044dSC.J. Collier	len = strnlen(buf, RDLINE_BUF_SIZE);
6295129044dSC.J. Collier	for (i=0; i<len ; i++) {
6305129044dSC.J. Collier		if (buf[i] == '\n') {
6315129044dSC.J. Collier			len = i;
6325129044dSC.J. Collier			break;
6335129044dSC.J. Collier		}
6345129044dSC.J. Collier	}
6355129044dSC.J. Collier
6365129044dSC.J. Collier	if ( len >= RDLINE_HISTORY_BUF_SIZE )
6375129044dSC.J. Collier		return -1;
6385129044dSC.J. Collier
6395129044dSC.J. Collier	while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
6405129044dSC.J. Collier		rdline_remove_old_history_item(rdl);
6415129044dSC.J. Collier	}
6425129044dSC.J. Collier
6435129044dSC.J. Collier	cirbuf_add_buf_tail(&rdl->history, buf, len);
6445129044dSC.J. Collier	cirbuf_add_tail(&rdl->history, 0);
6455129044dSC.J. Collier
6465129044dSC.J. Collier	return 0;
6475129044dSC.J. Collier}
6485129044dSC.J. Collier
6495129044dSC.J. Colliervoid
6505129044dSC.J. Collierrdline_clear_history(struct rdline * rdl)
6515129044dSC.J. Collier{
6525129044dSC.J. Collier	if (!rdl)
6535129044dSC.J. Collier		return;
6545129044dSC.J. Collier	cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
6555129044dSC.J. Collier}
6565129044dSC.J. Collier
6575129044dSC.J. Collier
6585129044dSC.J. Collier/* STATIC USEFUL FUNCS */
6595129044dSC.J. Collier
6605129044dSC.J. Collierstatic void
6615129044dSC.J. Collierrdline_puts(struct rdline * rdl, const char * buf)
6625129044dSC.J. Collier{
6635129044dSC.J. Collier	char c;
6645129044dSC.J. Collier	while ( (c = *(buf++)) != '\0' ) {
6655129044dSC.J. Collier		rdl->write_char(rdl, c);
6665129044dSC.J. Collier	}
6675129044dSC.J. Collier}
6685129044dSC.J. Collier
6695129044dSC.J. Collier/* a very very basic printf with one arg and one format 'u' */
6705129044dSC.J. Collierstatic void
6715129044dSC.J. Collierrdline_miniprintf(struct rdline *rdl, const char * buf, unsigned int val)
6725129044dSC.J. Collier{
6735129044dSC.J. Collier	char c, started=0, div=100;
6745129044dSC.J. Collier
6755129044dSC.J. Collier	while ( (c=*(buf++)) ) {
6765129044dSC.J. Collier		if (c != '%') {
6775129044dSC.J. Collier			rdl->write_char(rdl, c);
6785129044dSC.J. Collier			continue;
6795129044dSC.J. Collier		}
6805129044dSC.J. Collier		c = *(buf++);
6815129044dSC.J. Collier		if (c != 'u') {
6825129044dSC.J. Collier			rdl->write_char(rdl, '%');
6835129044dSC.J. Collier			rdl->write_char(rdl, c);
6845129044dSC.J. Collier			continue;
6855129044dSC.J. Collier		}
6865129044dSC.J. Collier		/* val is never more than 255 */
6875129044dSC.J. Collier		while (div) {
6885129044dSC.J. Collier			c = (char)(val / div);
6895129044dSC.J. Collier			if (c || started) {
6905129044dSC.J. Collier				rdl->write_char(rdl, (char)(c+'0'));
6915129044dSC.J. Collier				started = 1;
6925129044dSC.J. Collier			}
6935129044dSC.J. Collier			val %= div;
6945129044dSC.J. Collier			div /= 10;
6955129044dSC.J. Collier		}
6965129044dSC.J. Collier	}
6975129044dSC.J. Collier}
698