/*
* Command line editing and history
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
#include "list.h"
#include "edit.h"
-#define CMD_BUF_LEN 256
+#define CMD_BUF_LEN 4096
static char cmdbuf[CMD_BUF_LEN];
static int cmdbuf_pos = 0;
static int cmdbuf_len = 0;
+static char currbuf[CMD_BUF_LEN];
+static int currbuf_valid = 0;
+static const char *ps2 = NULL;
+
+#define HISTORY_MAX 100
struct edit_history {
struct dl_list list;
{
int i;
putchar('\r');
- for (i = 0; i < cmdbuf_len + 2; i++)
+ for (i = 0; i < cmdbuf_len + 2 + (ps2 ? (int) os_strlen(ps2) : 0); i++)
putchar(' ');
}
static void history_add(const char *str)
{
- struct edit_history *h, *match = NULL;
- size_t len;
+ struct edit_history *h, *match = NULL, *last = NULL;
+ size_t len, count = 0;
if (str[0] == '\0')
return;
match = h;
break;
}
+ last = h;
+ count++;
}
if (match) {
return;
}
+ if (count >= HISTORY_MAX && last) {
+ dl_list_del(&last->list);
+ os_free(last);
+ }
+
len = os_strlen(str);
h = os_zalloc(sizeof(*h) + len);
if (h == NULL)
static void history_prev(void)
{
- if (history_curr == NULL ||
- history_curr ==
- dl_list_last(&history_list, struct edit_history, list))
+ if (history_curr == NULL)
return;
if (history_curr ==
dl_list_first(&history_list, struct edit_history, list)) {
- cmdbuf[cmdbuf_len] = '\0';
- history_add(cmdbuf);
+ if (!currbuf_valid) {
+ cmdbuf[cmdbuf_len] = '\0';
+ os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1);
+ currbuf_valid = 1;
+ history_use();
+ return;
+ }
}
+ if (history_curr ==
+ dl_list_last(&history_list, struct edit_history, list))
+ return;
+
history_curr = dl_list_entry(history_curr->list.next,
struct edit_history, list);
history_use();
{
if (history_curr == NULL ||
history_curr ==
- dl_list_first(&history_list, struct edit_history, list))
+ dl_list_first(&history_list, struct edit_history, list)) {
+ if (currbuf_valid) {
+ currbuf_valid = 0;
+ edit_clear_line();
+ cmdbuf_len = cmdbuf_pos = os_strlen(currbuf);
+ os_memcpy(cmdbuf, currbuf, cmdbuf_len);
+ edit_redraw();
+ }
return;
+ }
history_curr = dl_list_entry(history_curr->list.prev,
struct edit_history, list);
}
+static void history_read(const char *fname)
+{
+ FILE *f;
+ char buf[CMD_BUF_LEN], *pos;
+
+ f = fopen(fname, "r");
+ if (f == NULL)
+ return;
+
+ while (fgets(buf, CMD_BUF_LEN, f)) {
+ for (pos = buf; *pos; pos++) {
+ if (*pos == '\r' || *pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ }
+ history_add(buf);
+ }
+
+ fclose(f);
+}
+
+
+static void history_write(const char *fname,
+ int (*filter_cb)(void *ctx, const char *cmd))
+{
+ FILE *f;
+ struct edit_history *h;
+
+ f = fopen(fname, "w");
+ if (f == NULL)
+ return;
+
+ dl_list_for_each_reverse(h, &history_list, struct edit_history, list) {
+ if (filter_cb && filter_cb(edit_cb_ctx, h->str))
+ continue;
+ fprintf(f, "%s\n", h->str);
+ }
+
+ fclose(f);
+}
+
+
static void history_debug_dump(void)
{
struct edit_history *h;
printf("\r");
dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
+ if (currbuf_valid)
+ printf("{%s}\n", currbuf);
edit_redraw();
}
static void process_cmd(void)
{
-
+ currbuf_valid = 0;
if (cmdbuf_len == 0) {
- printf("\n> ");
+ printf("\n%s> ", ps2 ? ps2 : "");
fflush(stdout);
return;
}
cmdbuf_pos = 0;
cmdbuf_len = 0;
edit_cmd_cb(edit_cb_ctx, cmdbuf);
- printf("> ");
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
}
int param1 = -1, param2 = -1;
enum edit_key_code ret = EDIT_KEY_NONE;
+ last = '\0';
for (pos = seq; *pos; pos++)
last = *pos;
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file)
+ void *ctx, const char *history_file, const char *ps)
{
+ currbuf[0] = '\0';
dl_list_init(&history_list);
history_curr = NULL;
+ if (history_file)
+ history_read(history_file);
edit_cb_ctx = ctx;
edit_cmd_cb = cmd_cb;
eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
- printf("> ");
+ ps2 = ps;
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
return 0;
int (*filter_cb)(void *ctx, const char *cmd))
{
struct edit_history *h;
+ if (history_file)
+ history_write(history_file, filter_cb);
while ((h = dl_list_first(&history_list, struct edit_history, list))) {
dl_list_del(&h->list);
os_free(h);
}
+ edit_clear_line();
+ putchar('\r');
+ fflush(stdout);
eloop_unregister_read_sock(STDIN_FILENO);
tcsetattr(STDIN_FILENO, TCSANOW, &prevt);
}
{
char tmp;
cmdbuf[cmdbuf_len] = '\0';
- printf("\r> %s", cmdbuf);
+ printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
if (cmdbuf_pos != cmdbuf_len) {
tmp = cmdbuf[cmdbuf_pos];
cmdbuf[cmdbuf_pos] = '\0';
- printf("\r> %s", cmdbuf);
+ printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
cmdbuf[cmdbuf_pos] = tmp;
}
fflush(stdout);