/* $NetBSD: prompt.c,v 1.5 2019/01/09 03:28:31 christos Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by UCHIYAMA Yasushi.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>
#include <sys/param.h>
#include <machine/bfs.h>
#include "cmd.h"
#include "local.h"
#define LOG_SIZE 2048
#define LOG_MASK (LOG_SIZE - 1)
uint8_t __log[LOG_SIZE];
int __log_cnt;
#define CMDBUF_HISTORY_MAX 8
#define PROMPT ">> "
struct cmd_buf {
char buf[CMDBUF_SIZE];
int cur, min, max;
} __cmd_buf[CMDBUF_HISTORY_MAX];
struct cmd_buf *__cmd;
int __cur_cmd;
void prompt_reset(void);
void prompt_input(int);
extern void __putchar(int);
void
prompt(void)
{
int c;
prompt_reset();
while (/*CONSTCOND*/1)
if ((c = getchar()) != 0)
prompt_input(c);
/* NOTREACHED */
}
void
prompt_input(int c)
{
int i;
switch (c) {
case 32 ... 127:
__cmd->buf[__cmd->cur] = c;
__cmd->cur = (__cmd->cur >= CMDBUF_SIZE - 1) ? __cmd->cur :
__cmd->cur + 1;
if (__cmd->cur >= __cmd->max)
__cmd->max = __cmd->cur;
putchar(c);
break;
case '\r':
putchar('\n');
if (__cmd->max > 0) {
cmd_exec(__cmd->buf);
prompt_reset();
} else {
printf(PROMPT);
}
break;
case '\b':
if (__cmd->cur > 0) {
__cmd->buf[--__cmd->cur] = 0;
putchar(c);
}
break;
case 1: /* Ctrl a */
__cmd->cur = __cmd->min;
putchar('\r');
printf("%s", PROMPT);
break;
case 5: /* Ctrl e */
__cmd->cur = __cmd->max;
goto redraw;
case 2: /* Ctrl b */
if (__cmd->cur == __cmd->min)
return;
__cmd->cur--;
putchar(c);
break;
case 6: /* Ctrl f */
if (__cmd->cur == __cmd->max)
return;
__cmd->cur++;
putchar(c);
break;
case 4: /* Ctrl d */
if (__cmd->cur == __cmd->max)
return;
for (i = __cmd->cur; i < __cmd->max; i++)
__cmd->buf[i] = __cmd->buf[i + 1];
__cmd->buf[i] = '\0';
__cmd->max--;
goto redraw;
case 11: /* Ctrl k */
for (i = __cmd->cur; i < __cmd->max; i++) {
__cmd->buf[i] = 0;
__cmd->max = __cmd->cur;
}
putchar(c);
break;
case 14: /* Ctrl n */
__cur_cmd = (__cur_cmd + 1) & 0x7;
goto history_redraw;
case 16: /* Ctrl p */
__cur_cmd = (__cur_cmd - 1) & 0x7;
history_redraw:
__cmd = &__cmd_buf[__cur_cmd];
__cmd->cur = __cmd->max;
case 12: /* Ctrl l */
redraw:
putchar('\r');
putchar(11);
printf("%s%s", PROMPT, __cmd->buf);
break;
}
}
void
prompt_reset(void)
{
__cur_cmd = (__cur_cmd + 1) & 0x7;
__cmd = &__cmd_buf[__cur_cmd];
memset(__cmd, 0, sizeof *__cmd);
printf(PROMPT);
}
bool
prompt_yesno(int interactive)
{
int i;
if (!interactive)
return true;
/* block until user input */
while (/*CONSTCOND*/1) {
if ((i = getchar()) == 0)
continue;
if (i == 'N' || i == 'n')
return false;
if (i == 'Y' || i == 'y')
return true;
}
}
void
putchar(int c)
{
__putchar(c);
__log[__log_cnt++] = c;
__log_cnt &= LOG_MASK;
}
int
cmd_log_save(int argc, char *argp[], int interactive)
{
struct bfs *bfs;
if (bfs_init(&bfs) != 0) {
printf("no BFS partition.\n");
return 1;
}
if (bfs_file_write(bfs, "boot.log", __log, LOG_SIZE) != 0)
printf("BFS write failed.\n");
bfs_fini(bfs);
return 0;
}