[PATCH 2/2] shell: Add an editor to the shell.
Chris Johns
chrisj at rtems.org
Sat Oct 4 05:14:04 UTC 2014
This is a small (21K on sparc) editor that provides some powerful
features useful when a file needs editing on an embedded
board. No need for copy off, edit, copy back
---
cpukit/libmisc/Makefile.am | 2 +-
cpukit/libmisc/shell/main_edit.c | 2255 ++++++++++++++++++++++++++++++++++++
cpukit/libmisc/shell/shellconfig.h | 6 +
3 files changed, 2262 insertions(+), 1 deletion(-)
create mode 100644 cpukit/libmisc/shell/main_edit.c
diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am
index 820a838..2f41ffa 100644
--- a/cpukit/libmisc/Makefile.am
+++ b/cpukit/libmisc/Makefile.am
@@ -109,7 +109,7 @@ libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \
shell/main_time.c shell/main_mknod.c \
shell/main_setenv.c shell/main_getenv.c shell/main_unsetenv.c \
shell/main_mkrfs.c shell/main_debugrfs.c shell/main_df.c \
- shell/main_lsof.c \
+ shell/main_lsof.c shell/main_edit.c \
shell/main_blkstats.c \
shell/shell-wait-for-input.c
diff --git a/cpukit/libmisc/shell/main_edit.c b/cpukit/libmisc/shell/main_edit.c
new file mode 100644
index 0000000..3097eeb
--- /dev/null
+++ b/cpukit/libmisc/shell/main_edit.c
@@ -0,0 +1,2255 @@
+//
+// edit.c
+//
+// Text editor
+//
+// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
+//
+// 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.
+// 3. Neither the name of the project nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#ifdef SANOS
+#include <os.h>
+#endif
+
+#ifdef __rtems__
+#include <rtems.h>
+#include <rtems/shell.h>
+#endif
+
+#if defined(__linux__) || defined(__rtems__)
+#include <sys/ioctl.h>
+#include <termios.h>
+#define O_BINARY 0
+static int linux_console;
+#endif
+
+#define MINEXTEND 32768
+#define LINEBUF_EXTRA 32
+
+#ifndef TABSIZE
+#define TABSIZE 8
+#endif
+
+#ifndef INDENT
+#define INDENT " "
+#endif
+
+#define CLRSCR "\033[0J\x1b[H\x1b[J"
+#define CLREOL "\033[K"
+#define GOTOXY "\033[%d;%dH"
+#define RESET_COLOR "\033[0m"
+
+#ifdef COLOR
+#define TEXT_COLOR "\033[44m\033[37m\033[1m"
+#define SELECT_COLOR "\033[47m\033[37m\033[1m"
+#define STATUS_COLOR "\033[0m\033[47m\033[30m"
+#else
+#define TEXT_COLOR "\033[0m"
+#define SELECT_COLOR "\033[7m\033[1m"
+#define STATUS_COLOR "\033[1m\033[7m"
+#endif
+
+//
+// Key codes
+//
+
+#define KEY_BACKSPACE 0x101
+#define KEY_ESC 0x102
+#define KEY_INS 0x103
+#define KEY_DEL 0x104
+#define KEY_LEFT 0x105
+#define KEY_RIGHT 0x106
+#define KEY_UP 0x107
+#define KEY_DOWN 0x108
+#define KEY_HOME 0x109
+#define KEY_END 0x10A
+#define KEY_ENTER 0x10B
+#define KEY_TAB 0x10C
+#define KEY_PGUP 0x10D
+#define KEY_PGDN 0x10E
+
+#define KEY_CTRL_LEFT 0x10F
+#define KEY_CTRL_RIGHT 0x110
+#define KEY_CTRL_UP 0x111
+#define KEY_CTRL_DOWN 0x112
+#define KEY_CTRL_HOME 0x113
+#define KEY_CTRL_END 0x114
+#define KEY_CTRL_TAB 0x115
+
+#define KEY_SHIFT_LEFT 0x116
+#define KEY_SHIFT_RIGHT 0x117
+#define KEY_SHIFT_UP 0x118
+#define KEY_SHIFT_DOWN 0x119
+#define KEY_SHIFT_PGUP 0x11A
+#define KEY_SHIFT_PGDN 0x11B
+#define KEY_SHIFT_HOME 0x11C
+#define KEY_SHIFT_END 0x11D
+#define KEY_SHIFT_TAB 0x11E
+
+#define KEY_SHIFT_CTRL_LEFT 0x11F
+#define KEY_SHIFT_CTRL_RIGHT 0x120
+#define KEY_SHIFT_CTRL_UP 0x121
+#define KEY_SHIFT_CTRL_DOWN 0x122
+#define KEY_SHIFT_CTRL_HOME 0x123
+#define KEY_SHIFT_CTRL_END 0x124
+
+#define KEY_F1 0x125
+#define KEY_F2 0x126
+#define KEY_F3 0x127
+#define KEY_F4 0x128
+#define KEY_F5 0x129
+#define KEY_F6 0x12a
+#define KEY_F7 0x12b
+#define KEY_F8 0x12c
+#define KEY_F9 0x12d
+#define KEY_F10 0x12e
+
+#define KEY_UNKNOWN 0xFFF
+
+#define ctrl(c) ((c) - 0x60)
+
+//
+// Editor data block
+//
+// Structure of split buffer:
+//
+// +------------------+------------------+------------------+
+// | text before gap | gap | text after gap |
+// +------------------+------------------+------------------+
+// ^ ^ ^ ^
+// | | | |
+// start gap rest end
+//
+
+struct env;
+
+struct undo {
+ int pos; // Editor position
+ int erased; // Size of erased contents
+ int inserted; // Size of inserted contents
+ unsigned char *undobuf; // Erased contents for undo
+ unsigned char *redobuf; // Inserted contents for redo
+ struct undo *next; // Next undo buffer
+ struct undo *prev; // Previous undo buffer
+};
+
+struct editor {
+ unsigned char *start; // Start of text buffer
+ unsigned char *gap; // Start of gap
+ unsigned char *rest; // End of gap
+ unsigned char *end; // End of text buffer
+
+ int toppos; // Text position for current top screen line
+ int topline; // Line number for top of screen
+ int margin; // Position for leftmost column on screen
+
+ int linepos; // Text position for current line
+ int line; // Current document line
+ int col; // Current document column
+ int lastcol; // Remembered column from last horizontal navigation
+ int anchor; // Anchor position for selection
+
+ struct undo *undohead; // Start of undo buffer list
+ struct undo *undotail; // End of undo buffer list
+ struct undo *undo; // Undo/redo boundary
+
+ int refresh; // Flag to trigger screen redraw
+ int lineupdate; // Flag to trigger redraw of current line
+ int dirty; // Dirty flag is set when the editor buffer has been changed
+
+ int newfile; // File is a new file
+ int permissions; // File permissions
+
+ int selecting; // Selecting active in the edtor.
+
+ struct env *env; // Reference to global editor environment
+ struct editor *next; // Next editor
+ struct editor *prev; // Previous editor
+
+ char filename[FILENAME_MAX];
+};
+
+struct env {
+ struct editor *current; // Current editor
+
+ unsigned char *clipboard; // Clipboard
+ int clipsize; // Clipboard size
+
+ unsigned char *search; // Search text
+ unsigned char *linebuf; // Scratch buffer
+
+ int cols; // Console columns
+ int lines; // Console lines
+
+ int untitled; // Counter for untitled files
+};
+
+/*
+ * This is a hack to allow a simple way to inspect the keys to
+ * add extar decoding. It is not multi-user safe.
+ */
+#define KEY_HISTORY 1
+#if KEY_HISTORY
+int key_history[32];
+size_t key_history_in;
+#endif
+
+//
+// Editor buffer functions
+//
+
+static void clear_undo(struct editor *ed) {
+ struct undo *undo = ed->undohead;
+ while (undo) {
+ struct undo *next = undo->next;
+ free(undo->undobuf);
+ free(undo->redobuf);
+ free(undo);
+ undo = next;
+ }
+ ed->undohead = ed->undotail = ed->undo = NULL;
+}
+
+static void reset_undo(struct editor *ed) {
+ while (ed->undotail != ed->undo) {
+ struct undo *undo = ed->undotail;
+ if (!undo) {
+ ed->undohead = NULL;
+ ed->undotail = NULL;
+ break;
+ }
+ ed->undotail = undo->prev;
+ if (undo->prev) undo->prev->next = NULL;
+ free(undo->undobuf);
+ free(undo->redobuf);
+ free(undo);
+ }
+ ed->undo = ed->undotail;
+}
+
+static struct editor *create_editor(struct env *env) {
+ struct editor *ed = (struct editor *) malloc(sizeof(struct editor));
+ memset(ed, 0, sizeof(struct editor));
+ if (env->current) {
+ ed->next = env->current->next;
+ ed->prev = env->current;
+ env->current->next->prev = ed;
+ env->current->next = ed;
+ } else {
+ ed->next = ed->prev = ed;
+ }
+ ed->env = env;
+ env->current = ed;
+ return ed;
+}
+
+static void delete_editor(struct editor *ed) {
+ if (ed->next == ed) {
+ ed->env->current = NULL;
+ } else {
+ ed->env->current = ed->prev;
+ }
+ ed->next->prev = ed->prev;
+ ed->prev->next = ed->next;
+ if (ed->start) free(ed->start);
+ clear_undo(ed);
+ free(ed);
+}
+
+static struct editor *find_editor(struct env *env, char *filename) {
+ char fn[FILENAME_MAX];
+ struct editor *ed = env->current;
+ struct editor *start = ed;
+
+ if (!realpath(filename, fn)) strcpy(fn, filename);
+
+ do {
+ if (strcmp(fn, ed->filename) == 0) return ed;
+ ed = ed->next;
+ } while (ed != start);
+ return NULL;
+}
+
+static int new_file(struct editor *ed, char *filename) {
+ if (*filename) {
+ strcpy(ed->filename, filename);
+ } else {
+ sprintf(ed->filename, "Untitled-%d", ++ed->env->untitled);
+ ed->newfile = 1;
+ }
+ ed->permissions = 0644;
+
+ ed->start = (unsigned char *) malloc(MINEXTEND);
+ if (!ed->start) return -1;
+#ifdef DEBUG
+ memset(ed->start, 0, MINEXTEND);
+#endif
+
+ ed->gap = ed->start;
+ ed->rest = ed->end = ed->gap + MINEXTEND;
+ ed->anchor = -1;
+
+ return 0;
+}
+
+static int load_file(struct editor *ed, char *filename) {
+ struct stat statbuf;
+ int length;
+ int f;
+
+ if (!realpath(filename, ed->filename)) return -1;
+ f = open(ed->filename, O_RDONLY | O_BINARY);
+ if (f < 0) return -1;
+
+ if (fstat(f, &statbuf) < 0) goto err;
+ length = statbuf.st_size;
+ ed->permissions = statbuf.st_mode & 0777;
+
+ ed->start = (unsigned char *) malloc(length + MINEXTEND);
+ if (!ed->start) goto err;
+#ifdef DEBUG
+ memset(ed->start, 0, length + MINEXTEND);
+#endif
+ if (read(f, ed->start, length) != length) goto err;
+
+ ed->gap = ed->start + length;
+ ed->rest = ed->end = ed->gap + MINEXTEND;
+ ed->anchor = -1;
+
+ close(f);
+ return 0;
+
+err:
+ close(f);
+ if (ed->start) {
+ free(ed->start);
+ ed->start = NULL;
+ }
+ return -1;
+}
+
+static int save_file(struct editor *ed) {
+ int f;
+
+ f = open(ed->filename, O_CREAT | O_TRUNC | O_WRONLY, ed->permissions);
+ if (f < 0) return -1;
+
+ if (write(f, ed->start, ed->gap - ed->start) != ed->gap - ed->start) goto err;
+ if (write(f, ed->rest, ed->end - ed->rest) != ed->end - ed->rest) goto err;
+
+ close(f);
+ ed->dirty = 0;
+ clear_undo(ed);
+ return 0;
+
+err:
+ close(f);
+ return -1;
+}
+
+static int text_length(struct editor *ed) {
+ return (ed->gap - ed->start) + (ed->end - ed->rest);
+}
+
+static unsigned char *text_ptr(struct editor *ed, int pos) {
+ unsigned char *p = ed->start + pos;
+ if (p >= ed->gap) p += (ed->rest - ed->gap);
+ return p;
+}
+
+static void move_gap(struct editor *ed, int pos, int minsize) {
+ int gapsize = ed->rest - ed->gap;
+ unsigned char *p = text_ptr(ed, pos);
+ if (minsize < 0) minsize = 0;
+
+ if (minsize <= gapsize) {
+ if (p != ed->rest) {
+ if (p < ed->gap) {
+ memmove(p + gapsize, p, ed->gap - p);
+ } else {
+ memmove(ed->gap, ed->rest, p - ed->rest);
+ }
+ ed->gap = ed->start + pos;
+ ed->rest = ed->gap + gapsize;
+ }
+ } else {
+ int newsize;
+ unsigned char *start;
+ unsigned char *gap;
+ unsigned char *rest;
+ unsigned char *end;
+
+ if (gapsize + MINEXTEND > minsize) minsize = gapsize + MINEXTEND;
+ newsize = (ed->end - ed->start) - gapsize + minsize;
+ start = (unsigned char *) malloc(newsize); // TODO check for out of memory
+ gap = start + pos;
+ rest = gap + minsize;
+ end = start + newsize;
+
+ if (p < ed->gap) {
+ memcpy(start, ed->start, pos);
+ memcpy(rest, p, ed->gap - p);
+ memcpy(end - (ed->end - ed->rest), ed->rest, ed->end - ed->rest);
+ } else {
+ memcpy(start, ed->start, ed->gap - ed->start);
+ memcpy(start + (ed->gap - ed->start), ed->rest, p - ed->rest);
+ memcpy(rest, p, ed->end - p);
+ }
+
+ free(ed->start);
+ ed->start = start;
+ ed->gap = gap;
+ ed->rest = rest;
+ ed->end = end;
+ }
+
+#ifdef DEBUG
+ memset(ed->gap, 0, ed->rest - ed->gap);
+#endif
+}
+
+static void close_gap(struct editor *ed) {
+ int len = text_length(ed);
+ move_gap(ed, len, 1);
+ ed->start[len] = 0;
+}
+
+static int get(struct editor *ed, int pos) {
+ unsigned char *p = text_ptr(ed, pos);
+ if (p >= ed->end) return -1;
+ return *p;
+}
+
+static int compare(struct editor *ed, unsigned char *buf, int pos, int len) {
+ unsigned char *bufptr = buf;
+ unsigned char *p = ed->start + pos;
+ if (p >= ed->gap) p += (ed->rest - ed->gap);
+
+ while (len > 0) {
+ if (p == ed->end) return 0;
+ if (*bufptr++ != *p) return 0;
+ len--;
+ if (++p == ed->gap) p = ed->rest;
+ }
+
+ return 1;
+}
+
+static int copy(struct editor *ed, unsigned char *buf, int pos, int len) {
+ unsigned char *bufptr = buf;
+ unsigned char *p = ed->start + pos;
+ if (p >= ed->gap) p += (ed->rest - ed->gap);
+
+ while (len > 0) {
+ if (p == ed->end) break;
+ *bufptr++ = *p;
+ len--;
+ if (++p == ed->gap) p = ed->rest;
+ }
+
+ return bufptr - buf;
+}
+
+static void replace(struct editor *ed, int pos, int len, unsigned char *buf, int bufsize, int doundo) {
+ unsigned char *p;
+ struct undo *undo;
+
+ // Store undo information
+ if (doundo) {
+ reset_undo(ed);
+ undo = ed->undotail;
+ if (undo && len == 0 && bufsize == 1 && undo->erased == 0 && pos == undo->pos + undo->inserted) {
+ // Insert character at end of current redo buffer
+ undo->redobuf = realloc(undo->redobuf, undo->inserted + 1);
+ undo->redobuf[undo->inserted] = *buf;
+ undo->inserted++;
+ } else if (undo && len == 1 && bufsize == 0 && undo->inserted == 0 && pos == undo->pos) {
+ // Erase character at end of current undo buffer
+ undo->undobuf = realloc(undo->undobuf, undo->erased + 1);
+ undo->undobuf[undo->erased] = get(ed, pos);
+ undo->erased++;
+ } else if (undo && len == 1 && bufsize == 0 && undo->inserted == 0 && pos == undo->pos - 1) {
+ // Erase character at beginning of current undo buffer
+ undo->pos--;
+ undo->undobuf = realloc(undo->undobuf, undo->erased + 1);
+ memmove(undo->undobuf + 1, undo->undobuf, undo->erased);
+ undo->undobuf[0] = get(ed, pos);
+ undo->erased++;
+ } else {
+ // Create new undo buffer
+ undo = (struct undo *) malloc(sizeof(struct undo));
+ if (ed->undotail) ed->undotail->next = undo;
+ undo->prev = ed->undotail;
+ undo->next = NULL;
+ ed->undotail = ed->undo = undo;
+ if (!ed->undohead) ed->undohead = undo;
+
+ undo->pos = pos;
+ undo->erased = len;
+ undo->inserted = bufsize;
+ undo->undobuf = undo->redobuf = NULL;
+ if (len > 0) {
+ undo->undobuf = malloc(len);
+ copy(ed, undo->undobuf, pos, len);
+ }
+ if (bufsize > 0) {
+ undo->redobuf = malloc(bufsize);
+ memcpy(undo->redobuf, buf, bufsize);
+ }
+ }
+ }
+
+ p = ed->start + pos;
+ if (bufsize == 0 && p <= ed->gap && p + len >= ed->gap) {
+ // Handle deletions at the edges of the gap
+ ed->rest += len - (ed->gap - p);
+ ed->gap = p;
+ } else {
+ // Move the gap
+ move_gap(ed, pos + len, bufsize - len);
+
+ // Replace contents
+ memcpy(ed->start + pos, buf, bufsize);
+ ed->gap = ed->start + pos + bufsize;
+ }
+
+ // Mark buffer as dirty
+ ed->dirty = 1;
+}
+
+static void insert(struct editor *ed, int pos, unsigned char *buf, int bufsize) {
+ replace(ed, pos, 0, buf, bufsize, 1);
+}
+
+static void erase(struct editor *ed, int pos, int len) {
+ replace(ed, pos, len, NULL, 0, 1);
+}
+
+//
+// Navigation functions
+//
+
+static int line_length(struct editor *ed, int linepos) {
+ int pos = linepos;
+ while (1) {
+ int ch = get(ed, pos);
+ if (ch < 0 || ch == '\n' || ch == '\r') break;
+ pos++;
+ }
+
+ return pos - linepos;
+}
+
+static int line_start(struct editor *ed, int pos) {
+ while (1) {
+ if (pos == 0) break;
+ if (get(ed, pos - 1) == '\n') break;
+ pos--;
+ }
+
+ return pos;
+}
+
+static int next_line(struct editor *ed, int pos) {
+ while (1) {
+ int ch = get(ed, pos);
+ if (ch < 0) return -1;
+ pos++;
+ if (ch == '\n') return pos;
+ }
+}
+
+static int prev_line(struct editor *ed, int pos) {
+ if (pos == 0) return -1;
+
+ while (pos > 0) {
+ int ch = get(ed, --pos);
+ if (ch == '\n') break;
+ }
+
+ while (pos > 0) {
+ int ch = get(ed, --pos);
+ if (ch == '\n') return pos + 1;
+ }
+
+ return 0;
+}
+
+static int column(struct editor *ed, int linepos, int col) {
+ unsigned char *p = text_ptr(ed, linepos);
+ int c = 0;
+ while (col > 0) {
+ if (p == ed->end) break;
+ if (*p == '\t') {
+ int spaces = TABSIZE - c % TABSIZE;
+ c += spaces;
+ } else {
+ c++;
+ }
+ col--;
+ if (++p == ed->gap) p = ed->rest;
+ }
+ return c;
+}
+
+static void moveto(struct editor *ed, int pos, int center) {
+ int scroll = 0;
+ for (;;) {
+ int cur = ed->linepos + ed->col;
+ if (pos < cur) {
+ if (pos >= ed->linepos) {
+ ed->col = pos - ed->linepos;
+ } else {
+ ed->col = 0;
+ ed->linepos = prev_line(ed, ed->linepos);
+ ed->line--;
+
+ if (ed->topline > ed->line) {
+ ed->toppos = ed->linepos;
+ ed->topline--;
+ ed->refresh = 1;
+ scroll = 1;
+ }
+ }
+ } else if (pos > cur) {
+ int next = next_line(ed, ed->linepos);
+ if (next == -1) {
+ ed->col = line_length(ed, ed->linepos);
+ break;
+ } else if (pos < next) {
+ ed->col = pos - ed->linepos;
+ } else {
+ ed->col = 0;
+ ed->linepos = next;
+ ed->line++;
+
+ if (ed->line >= ed->topline + ed->env->lines) {
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ ed->refresh = 1;
+ scroll = 1;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (scroll && center) {
+ int tl = ed->line - ed->env->lines / 2;
+ if (tl < 0) tl = 0;
+ for (;;) {
+ if (ed->topline > tl) {
+ ed->toppos = prev_line(ed, ed->toppos);
+ ed->topline--;
+ } else if (ed->topline < tl) {
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ } else {
+ break;
+ }
+ }
+ }
+}
+
+//
+// Text selection
+//
+
+static int get_selection(struct editor *ed, int *start, int *end) {
+ if (ed->anchor == -1) {
+ *start = *end = -1;
+ return 0;
+ } else {
+ int pos = ed->linepos + ed->col;
+ if (pos == ed->anchor) {
+ *start = *end = -1;
+ return 0;
+ } else if (pos < ed->anchor) {
+ *start = pos;
+ *end = ed->anchor;
+ } else {
+ *start = ed->anchor;
+ *end = pos;
+ }
+ }
+ return 1;
+}
+
+static int get_selected_text(struct editor *ed, char *buffer, int size) {
+ int selstart, selend, len;
+
+ if (!get_selection(ed, &selstart, &selend)) return 0;
+ len = selend - selstart;
+ if (len >= size) return 0;
+ copy(ed, (unsigned char*) buffer, selstart, len);
+ buffer[len] = 0;
+ return len;
+}
+
+static void update_selection(struct editor *ed, int select) {
+ if (select) {
+ if (ed->anchor == -1) ed->anchor = ed->linepos + ed->col;
+ ed->refresh = 1;
+ } else {
+ if (ed->anchor != -1) ed->refresh = 1;
+ ed->anchor = -1;
+ }
+}
+
+static int erase_selection(struct editor *ed) {
+ int selstart, selend;
+
+ if (!get_selection(ed, &selstart, &selend)) return 0;
+ moveto(ed, selstart, 0);
+ erase(ed, selstart, selend - selstart);
+ ed->anchor = -1;
+ ed->refresh = 1;
+ return 1;
+}
+
+static void select_all(struct editor *ed) {
+ ed->anchor = 0;
+ ed->refresh = 1;
+ moveto(ed, text_length(ed), 0);
+}
+
+//
+// Screen functions
+//
+
+static void get_console_size(struct env *env) {
+#ifdef __linux__
+ struct winsize ws;
+ ioctl(0, TIOCGWINSZ, &ws);
+ env->cols = ws.ws_col;
+ env->lines = ws.ws_row - 1;
+#elif defined(__rtems__)
+ env->cols = 80;
+ env->lines = 25;
+#else
+ struct term *term = gettib()->proc->term;
+ env->cols = term->cols;
+ env->lines = term->lines - 1;
+#endif
+ env->linebuf = realloc(env->linebuf, env->cols + LINEBUF_EXTRA);
+}
+
+static void outch(char c) {
+ putchar(c);
+}
+
+static void outbuf(unsigned char *buf, int len) {
+ fwrite(buf, 1, len, stdout);
+}
+
+static void outstr(char *str) {
+ fputs(str, stdout);
+}
+
+static void clear_screen() {
+ outstr(CLRSCR);
+}
+
+static void gotoxy(int col, int line) {
+ char buf[32];
+
+ sprintf(buf, GOTOXY, line + 1, col + 1);
+ outstr(buf);
+}
+
+//
+// Keyboard functions
+//
+
+static void get_modifier_keys(int *shift, int *ctrl) {
+ *shift = *ctrl = 0;
+#ifdef __linux__
+ if (linux_console) {
+ char modifiers = 6;
+ if (ioctl(0, TIOCLINUX, &modifiers) >= 0) {
+ if (modifiers & 1) *shift = 1;
+ if (modifiers & 4) *ctrl = 1;
+ }
+ }
+#endif
+}
+
+static int getachar()
+{
+ int ch = getchar();
+#if KEY_HISTORY
+ if (key_history_in < sizeof(key_history)) {
+ key_history[key_history_in++] = ch;
+ } else {
+ memmove(&key_history[0], &key_history[1], sizeof(key_history) - sizeof(key_history[0]));
+ key_history[key_history_in - 1] = ch;
+ }
+#endif
+ return ch;
+}
+
+static int getkey() {
+ int ch, shift, ctrl;
+
+ ch = getachar();
+ if (ch < 0) return ch;
+
+ switch (ch) {
+ case 0x08: return KEY_BACKSPACE;
+ case 0x09:
+ get_modifier_keys(&shift, &ctrl);
+ if (shift) return KEY_SHIFT_TAB;
+ if (ctrl) return KEY_CTRL_TAB;
+ return KEY_TAB;
+#ifdef SANOS
+ case 0x0D: return gettib()->proc->term->type == TERM_CONSOLE ? KEY_ENTER : KEY_UNKNOWN;
+ case 0x0A: return gettib()->proc->term->type != TERM_CONSOLE ? KEY_ENTER : KEY_UNKNOWN;
+#else
+ case 0x0D: return KEY_ENTER;
+ case 0x0A: return KEY_ENTER;
+#endif
+ case 0x1B:
+ ch = getachar();
+ switch (ch) {
+ case 0x1B: return KEY_ESC;
+ case 0x4F:
+ ch = getachar();
+ switch (ch) {
+ case 0x46: return KEY_END;
+ case 0x48: return KEY_HOME;
+ case 0x50: return KEY_F1;
+ case 0x51: return KEY_F2;
+ case 0x52: return KEY_F3;
+ case 0x53: return KEY_F4;
+ case 0x54: return KEY_F5;
+ default: return KEY_UNKNOWN;
+ }
+ break;
+
+ case 0x5B:
+ get_modifier_keys(&shift, &ctrl);
+ ch = getachar();
+ if (ch == 0x31) {
+ ch = getachar();
+ switch (ch) {
+ case 0x35:
+ return getachar() == 0x7E ? KEY_F5 : KEY_UNKNOWN;
+ case 0x37:
+ return getachar() == 0x7E ? KEY_F6 : KEY_UNKNOWN;
+ case 0x3B:
+ ch = getachar();
+ if (ch == 0x7E) return KEY_F7;
+ if (ch == 0x32) shift = 1;
+ if (ch == 0x35) ctrl = 1;
+ if (ch == 0x36) shift = ctrl = 1;
+ ch = getachar();
+ break;
+ case 0x39:
+ return getachar() == 0x7E ? KEY_F8 : KEY_UNKNOWN;
+ case 0x7E:
+ if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
+ if (shift) return KEY_SHIFT_HOME;
+ if (ctrl) return KEY_CTRL_HOME;
+ return KEY_HOME;
+ default:
+ return KEY_UNKNOWN;
+ }
+ }
+
+ switch (ch) {
+ case 0x31:
+ ch = getachar();
+ if (ch != 0x7E) return KEY_UNKNOWN;
+ if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
+ if (shift) return KEY_SHIFT_HOME;
+ if (ctrl) return KEY_CTRL_HOME;
+ return KEY_HOME;
+ case 0x32:
+ ch = getachar();
+ switch (ch) {
+ case 0x30: ch = getachar(); return KEY_F9;
+ case 0x31: ch = getachar(); return KEY_F10;
+ case 0x7E: return KEY_INS;
+ default: break;
+ }
+ return KEY_UNKNOWN;
+ case 0x33: return getachar() == 0x7E ? KEY_DEL : KEY_UNKNOWN;
+ case 0x34:
+ if (getachar() != 0x7E) return KEY_UNKNOWN;
+ if (shift && ctrl) return KEY_SHIFT_CTRL_END;
+ if (shift) return KEY_SHIFT_END;
+ if (ctrl) return KEY_CTRL_END;
+ return KEY_END;
+ case 0x35:
+ if (getachar() != 0x7E) return KEY_UNKNOWN;
+ if (shift) return KEY_SHIFT_PGUP;
+ return KEY_PGUP;
+ case 0x36:
+ if (getachar() != 0x7E) return KEY_UNKNOWN;
+ if (shift) return KEY_SHIFT_PGDN;
+ return KEY_PGDN;
+ case 0x41:
+ if (shift && ctrl) return KEY_SHIFT_CTRL_UP;
+ if (shift) return KEY_SHIFT_UP;
+ if (ctrl) return KEY_CTRL_UP;
+ return KEY_UP;
+ case 0x42:
+ if (shift && ctrl) return KEY_SHIFT_CTRL_DOWN;
+ if (shift) return KEY_SHIFT_DOWN;
+ if (ctrl) return KEY_CTRL_DOWN;
+ return KEY_DOWN;
+ case 0x43:
+ if (shift && ctrl) return KEY_SHIFT_CTRL_RIGHT;
+ if (shift) return KEY_SHIFT_RIGHT;
+ if (ctrl) return KEY_CTRL_RIGHT;
+ return KEY_RIGHT;
+ case 0x44:
+ if (shift && ctrl) return KEY_SHIFT_CTRL_LEFT;
+ if (shift) return KEY_SHIFT_LEFT;
+ if (ctrl) return KEY_CTRL_LEFT;
+ return KEY_LEFT;
+ case 0x46:
+ if (shift && ctrl) return KEY_SHIFT_CTRL_END;
+ if (shift) return KEY_SHIFT_END;
+ if (ctrl) return KEY_CTRL_END;
+ return KEY_END;
+ case 0x48:
+ if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
+ if (shift) return KEY_SHIFT_HOME;
+ if (ctrl) return KEY_CTRL_HOME;
+ return KEY_HOME;
+ case 0x5A:
+ return KEY_SHIFT_TAB;
+ case 0x5B:
+ ch = getachar();
+ switch (ch) {
+ case 0x41: return KEY_F1;
+ case 0x43: return KEY_F3;
+ case 0x45: return KEY_F5;
+ }
+ return KEY_UNKNOWN;
+
+ default: return KEY_UNKNOWN;
+ }
+ break;
+
+ default: return KEY_UNKNOWN;
+ }
+ break;
+
+ case 0x00:
+ case 0xE0:
+ ch = getachar();
+ switch (ch) {
+ case 0x0F: return KEY_SHIFT_TAB;
+ case 0x3B: return KEY_F1;
+ case 0x3D: return KEY_F3;
+ case 0x3F: return KEY_F5;
+ case 0x47: return KEY_HOME;
+ case 0x48: return KEY_UP;
+ case 0x49: return KEY_PGUP;
+ case 0x4B: return KEY_LEFT;
+ case 0x4D: return KEY_RIGHT;
+ case 0x4F: return KEY_END;
+ case 0x50: return KEY_DOWN;
+ case 0x51: return KEY_PGDN;
+ case 0x52: return KEY_INS;
+ case 0x53: return KEY_DEL;
+ case 0x73: return KEY_CTRL_LEFT;
+ case 0x74: return KEY_CTRL_RIGHT;
+ case 0x75: return KEY_CTRL_END;
+ case 0x77: return KEY_CTRL_HOME;
+ case 0x8D: return KEY_CTRL_UP;
+ case 0x91: return KEY_CTRL_DOWN;
+ case 0x94: return KEY_CTRL_TAB;
+ case 0xB8: return KEY_SHIFT_UP;
+ case 0xB7: return KEY_SHIFT_HOME;
+ case 0xBF: return KEY_SHIFT_END;
+ case 0xB9: return KEY_SHIFT_PGUP;
+ case 0xBB: return KEY_SHIFT_LEFT;
+ case 0xBD: return KEY_SHIFT_RIGHT;
+ case 0xC0: return KEY_SHIFT_DOWN;
+ case 0xC1: return KEY_SHIFT_PGDN;
+ case 0xDB: return KEY_SHIFT_CTRL_LEFT;
+ case 0xDD: return KEY_SHIFT_CTRL_RIGHT;
+ case 0xD8: return KEY_SHIFT_CTRL_UP;
+ case 0xE0: return KEY_SHIFT_CTRL_DOWN;
+ case 0xD7: return KEY_SHIFT_CTRL_HOME;
+ case 0xDF: return KEY_SHIFT_CTRL_END;
+
+ default: return KEY_UNKNOWN;
+ }
+ break;
+
+ case 0x7F: return KEY_BACKSPACE;
+
+ default: return ch;
+ }
+}
+
+static int prompt(struct editor *ed, char *msg, int selection) {
+ int maxlen, len, ch;
+ char *buf = (char*) ed->env->linebuf;
+
+ gotoxy(0, ed->env->lines);
+ outstr(STATUS_COLOR);
+ outstr(msg);
+ outstr(CLREOL);
+
+ len = 0;
+ maxlen = ed->env->cols - strlen(msg) - 1;
+ if (selection) {
+ len = get_selected_text(ed, buf, maxlen);
+ outbuf((unsigned char*) buf, len);
+ }
+
+ for (;;) {
+ fflush(stdout);
+ ch = getkey();
+ if (ch == KEY_ESC) {
+ return 0;
+ } else if (ch == KEY_ENTER) {
+ buf[len] = 0;
+ return len > 0;
+ } else if (ch == KEY_BACKSPACE) {
+ if (len > 0) {
+ outstr("\b \b");
+ len--;
+ }
+ } else if (ch >= ' ' && ch < 0x100 && len < maxlen) {
+ outch(ch);
+ buf[len++] = ch;
+ }
+ }
+}
+
+static int ask() {
+ int ch = getachar();
+ return ch == 'y' || ch == 'Y';
+}
+
+//
+// Display functions
+//
+
+static void display_message(struct editor *ed, char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ gotoxy(0, ed->env->lines);
+ outstr(STATUS_COLOR);
+ vprintf(fmt, args);
+ outstr(CLREOL TEXT_COLOR);
+ fflush(stdout);
+ va_end(args);
+}
+
+static void draw_full_statusline(struct editor *ed) {
+ struct env *env = ed->env;
+ int namewidth = env->cols - 29;
+ gotoxy(0, env->lines);
+ sprintf((char*) env->linebuf, STATUS_COLOR "%*.*sF1=Help %c%c Ln %-6dCol %-4d" CLREOL TEXT_COLOR, -namewidth, namewidth, ed->filename, ed->selecting ? '+' : ' ', ed->dirty ? '*' : ' ', ed->line + 1, column(ed, ed->linepos, ed->col) + 1);
+ outstr((char*) env->linebuf);
+}
+
+static void draw_statusline(struct editor *ed) {
+ gotoxy(ed->env->cols - 20, ed->env->lines);
+ sprintf((char*) ed->env->linebuf, STATUS_COLOR "%c Ln %-6dCol %-4d" CLREOL TEXT_COLOR, ed->dirty ? '*' : ' ', ed->line + 1, column(ed, ed->linepos, ed->col) + 1);
+ outstr((char*) ed->env->linebuf);
+}
+
+static void display_line(struct editor *ed, int pos, int fullline) {
+ int hilite = 0;
+ int col = 0;
+ int margin = ed->margin;
+ int maxcol = ed->env->cols + margin;
+ unsigned char *bufptr = ed->env->linebuf;
+ unsigned char *p = text_ptr(ed, pos);
+ int selstart, selend, ch;
+ char *s;
+
+ get_selection(ed, &selstart, &selend);
+ while (col < maxcol) {
+ if (margin == 0) {
+ if (!hilite && pos >= selstart && pos < selend) {
+ for (s = SELECT_COLOR; *s; s++) *bufptr++ = *s;
+ hilite = 1;
+ } else if (hilite && pos >= selend) {
+ for (s = TEXT_COLOR; *s; s++) *bufptr++ = *s;
+ hilite = 0;
+ }
+ }
+
+ if (p == ed->end) break;
+ ch = *p;
+ if (ch == '\r' || ch == '\n') break;
+
+ if (ch == '\t') {
+ int spaces = TABSIZE - col % TABSIZE;
+ while (spaces > 0 && col < maxcol) {
+ if (margin > 0) {
+ margin--;
+ } else {
+ *bufptr++ = ' ';
+ }
+ col++;
+ spaces--;
+ }
+ } else {
+ if (margin > 0) {
+ margin--;
+ } else {
+ *bufptr++ = ch;
+ }
+ col++;
+ }
+
+ if (++p == ed->gap) p = ed->rest;
+ pos++;
+ }
+
+#if defined(__linux__)
+ if (hilite) {
+ while (col < maxcol) {
+ *bufptr++ = ' ';
+ col++;
+ }
+ } else {
+ if (col == margin) *bufptr++ = ' ';
+ }
+#endif
+
+ if (col < maxcol) {
+ for (s = CLREOL; *s; s++) *bufptr++ = *s;
+ if (fullline) {
+ memcpy(bufptr, "\r\n", 2);
+ bufptr += 2;
+ }
+ }
+
+ if (hilite) {
+ for (s = TEXT_COLOR; *s; s++) *bufptr++ = *s;
+ }
+
+ outbuf(ed->env->linebuf, bufptr - ed->env->linebuf);
+}
+
+static void update_line(struct editor *ed) {
+ gotoxy(0, ed->line - ed->topline);
+ display_line(ed, ed->linepos, 0);
+}
+
+static void draw_screen(struct editor *ed) {
+ int pos;
+ int i;
+
+ gotoxy(0, 0);
+ outstr(TEXT_COLOR);
+ pos = ed->toppos;
+ for (i = 0; i < ed->env->lines; i++) {
+ if (pos < 0) {
+ outstr(CLREOL "\r\n");
+ } else {
+ display_line(ed, pos, 1);
+ pos = next_line(ed, pos);
+ }
+ }
+}
+
+static void position_cursor(struct editor *ed) {
+ int col = column(ed, ed->linepos, ed->col);
+ gotoxy(col - ed->margin, ed->line - ed->topline);
+}
+
+//
+// Cursor movement
+//
+
+static void adjust(struct editor *ed) {
+ int col;
+ int ll = line_length(ed, ed->linepos);
+ ed->col = ed->lastcol;
+ if (ed->col > ll) ed->col = ll;
+
+ col = column(ed, ed->linepos, ed->col);
+ while (col < ed->margin) {
+ ed->margin -= 4;
+ if (ed->margin < 0) ed->margin = 0;
+ ed->refresh = 1;
+ }
+
+ while (col - ed->margin >= ed->env->cols) {
+ ed->margin += 4;
+ ed->refresh = 1;
+ }
+}
+
+static void select_toggle(struct editor *ed) {
+ ed->selecting = ed->selecting ? 0 : 1;
+ update_selection(ed, ed->selecting);
+ adjust(ed);
+}
+
+static void up(struct editor *ed, int select) {
+ int newpos;
+
+ update_selection(ed, select);
+
+ newpos = prev_line(ed, ed->linepos);
+ if (newpos < 0) return;
+
+ ed->linepos = newpos;
+ ed->line--;
+ if (ed->line < ed->topline) {
+ ed->toppos = ed->linepos;
+ ed->topline = ed->line;
+ ed->refresh = 1;
+ }
+
+ adjust(ed);
+}
+
+static void down(struct editor *ed, int select) {
+ int newpos;
+
+ update_selection(ed, select);
+
+ newpos = next_line(ed, ed->linepos);
+ if (newpos < 0) return;
+
+ ed->linepos = newpos;
+ ed->line++;
+
+ if (ed->line >= ed->topline + ed->env->lines) {
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ ed->refresh = 1;
+ }
+
+ adjust(ed);
+}
+
+static void left(struct editor *ed, int select) {
+ update_selection(ed, select);
+ if (ed->col > 0) {
+ ed->col--;
+ } else {
+ int newpos = prev_line(ed, ed->linepos);
+ if (newpos < 0) return;
+
+ ed->col = line_length(ed, newpos);
+ ed->linepos = newpos;
+ ed->line--;
+ if (ed->line < ed->topline) {
+ ed->toppos = ed->linepos;
+ ed->topline = ed->line;
+ ed->refresh = 1;
+ }
+ }
+
+ ed->lastcol = ed->col;
+ adjust(ed);
+}
+
+static void right(struct editor *ed, int select) {
+ update_selection(ed, select);
+ if (ed->col < line_length(ed, ed->linepos)) {
+ ed->col++;
+ } else {
+ int newpos = next_line(ed, ed->linepos);
+ if (newpos < 0) return;
+
+ ed->col = 0;
+ ed->linepos = newpos;
+ ed->line++;
+
+ if (ed->line >= ed->topline + ed->env->lines) {
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ ed->refresh = 1;
+ }
+ }
+
+ ed->lastcol = ed->col;
+ adjust(ed);
+}
+
+static int wordchar(int ch) {
+ return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
+}
+
+static void wordleft(struct editor *ed, int select) {
+ int pos, phase;
+
+ update_selection(ed, select);
+ pos = ed->linepos + ed->col;
+ phase = 0;
+ while (pos > 0) {
+ int ch = get(ed, pos - 1);
+ if (phase == 0) {
+ if (wordchar(ch)) phase = 1;
+ } else {
+ if (!wordchar(ch)) break;
+ }
+
+ pos--;
+ if (pos < ed->linepos) {
+ ed->linepos = prev_line(ed, ed->linepos);
+ ed->line--;
+ ed->refresh = 1;
+ }
+ }
+ ed->col = pos - ed->linepos;
+ if (ed->line < ed->topline) {
+ ed->toppos = ed->linepos;
+ ed->topline = ed->line;
+ }
+
+ ed->lastcol = ed->col;
+ adjust(ed);
+}
+
+static void wordright(struct editor *ed, int select) {
+ int pos, end, phase, next;
+
+ update_selection(ed, select);
+ pos = ed->linepos + ed->col;
+ end = text_length(ed);
+ next = next_line(ed, ed->linepos);
+ phase = 0;
+ while (pos < end) {
+ int ch = get(ed, pos);
+ if (phase == 0) {
+ if (wordchar(ch)) phase = 1;
+ } else {
+ if (!wordchar(ch)) break;
+ }
+
+ pos++;
+ if (pos == next) {
+ ed->linepos = next;
+ next = next_line(ed, ed->linepos);
+ ed->line++;
+ ed->refresh = 1;
+ }
+ }
+ ed->col = pos - ed->linepos;
+ if (ed->line >= ed->topline + ed->env->lines) {
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ }
+
+ ed->lastcol = ed->col;
+ adjust(ed);
+}
+
+static void home(struct editor *ed, int select) {
+ update_selection(ed, select);
+ ed->col = ed->lastcol = 0;
+ adjust(ed);
+}
+
+static void end(struct editor *ed, int select) {
+ update_selection(ed, select);
+ ed->col = ed->lastcol = line_length(ed, ed->linepos);
+ adjust(ed);
+}
+
+static void top(struct editor *ed, int select) {
+ update_selection(ed, select);
+ ed->toppos = ed->topline = ed->margin = 0;
+ ed->linepos = ed->line = ed->col = ed->lastcol = 0;
+ ed->refresh = 1;
+}
+
+static void bottom(struct editor *ed, int select) {
+ update_selection(ed, select);
+ for (;;) {
+ int newpos = next_line(ed, ed->linepos);
+ if (newpos < 0) break;
+
+ ed->linepos = newpos;
+ ed->line++;
+
+ if (ed->line >= ed->topline + ed->env->lines) {
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ ed->refresh = 1;
+ }
+ }
+ ed->col = ed->lastcol = line_length(ed, ed->linepos);
+ adjust(ed);
+}
+
+static void pageup(struct editor *ed, int select) {
+ int i;
+
+ update_selection(ed, select);
+ if (ed->line < ed->env->lines) {
+ ed->linepos = ed->toppos = 0;
+ ed->line = ed->topline = 0;
+ } else {
+ for (i = 0; i < ed->env->lines; i++) {
+ int newpos = prev_line(ed, ed->linepos);
+ if (newpos < 0) return;
+
+ ed->linepos = newpos;
+ ed->line--;
+
+ if (ed->topline > 0) {
+ ed->toppos = prev_line(ed, ed->toppos);
+ ed->topline--;
+ }
+ }
+ }
+
+ ed->refresh = 1;
+ adjust(ed);
+}
+
+static void pagedown(struct editor *ed, int select) {
+ int i;
+
+ update_selection(ed, select);
+ for (i = 0; i < ed->env->lines; i++) {
+ int newpos = next_line(ed, ed->linepos);
+ if (newpos < 0) break;
+
+ ed->linepos = newpos;
+ ed->line++;
+
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ }
+
+ ed->refresh = 1;
+ adjust(ed);
+}
+
+//
+// Text editing
+//
+
+static void insert_char(struct editor *ed, unsigned char ch) {
+ erase_selection(ed);
+ insert(ed, ed->linepos + ed->col, &ch, 1);
+ ed->col++;
+ ed->lastcol = ed->col;
+ adjust(ed);
+ if (!ed->refresh) ed->lineupdate = 1;
+}
+
+static void newline(struct editor *ed) {
+ int p;
+ unsigned char ch;
+
+ erase_selection(ed);
+#if defined(__linux__) || defined(__rtems__)
+ insert(ed, ed->linepos + ed->col, (unsigned char*) "\n", 1);
+#else
+ insert(ed, ed->linepos + ed->col, "\r\n", 2);
+#endif
+ ed->col = ed->lastcol = 0;
+ ed->line++;
+ p = ed->linepos;
+ ed->linepos = next_line(ed, ed->linepos);
+ for (;;) {
+ ch = get(ed, p++);
+ if (ch == ' ' || ch == '\t') {
+ insert(ed, ed->linepos + ed->col, &ch, 1);
+ ed->col++;
+ } else {
+ break;
+ }
+ }
+ ed->lastcol = ed->col;
+
+ ed->refresh = 1;
+
+ if (ed->line >= ed->topline + ed->env->lines) {
+ ed->toppos = next_line(ed, ed->toppos);
+ ed->topline++;
+ ed->refresh = 1;
+ }
+
+ adjust(ed);
+}
+
+static void backspace(struct editor *ed) {
+ if (erase_selection(ed)) return;
+ if (ed->linepos + ed->col == 0) return;
+ if (ed->col == 0) {
+ int pos = ed->linepos;
+ erase(ed, --pos, 1);
+ if (get(ed, pos - 1) == '\r') erase(ed, --pos, 1);
+
+ ed->line--;
+ ed->linepos = line_start(ed, pos);
+ ed->col = pos - ed->linepos;
+ ed->refresh = 1;
+
+ if (ed->line < ed->topline) {
+ ed->toppos = ed->linepos;
+ ed->topline = ed->line;
+ }
+ } else {
+ ed->col--;
+ erase(ed, ed->linepos + ed->col, 1);
+ ed->lineupdate = 1;
+ }
+
+ ed->lastcol = ed->col;
+ adjust(ed);
+}
+
+static void del(struct editor *ed) {
+ int pos, ch;
+
+ if (erase_selection(ed)) return;
+ pos = ed->linepos + ed->col;
+ ch = get(ed, pos);
+ if (ch < 0) return;
+
+ erase(ed, pos, 1);
+ if (ch == '\r') {
+ ch = get(ed, pos);
+ if (ch == '\n') erase(ed, pos, 1);
+ }
+
+ if (ch == '\n') {
+ ed->refresh = 1;
+ } else {
+ ed->lineupdate = 1;
+ }
+}
+
+static void indent(struct editor *ed, unsigned char *indentation) {
+ int start, end, i, lines, toplines, newline, ch;
+ unsigned char *buffer, *p;
+ int buflen;
+ int width = strlen((const char*) indentation);
+ int pos = ed->linepos + ed->col;
+
+ if (!get_selection(ed, &start, &end)) {
+ insert_char(ed, '\t');
+ return;
+ }
+
+ lines = 0;
+ toplines = 0;
+ newline = 1;
+ for (i = start; i < end; i++) {
+ if (i == ed->toppos) toplines = lines;
+ if (newline) {
+ lines++;
+ newline = 0;
+ }
+ if (get(ed, i) == '\n') newline = 1;
+ }
+ buflen = end - start + lines * width;
+ buffer = malloc(buflen);
+ if (!buffer) return;
+
+ newline = 1;
+ p = buffer;
+ for (i = start; i < end; i++) {
+ if (newline) {
+ memcpy(p, indentation, width);
+ p += width;
+ newline = 0;
+ }
+ ch = get(ed, i);
+ *p++ = ch;
+ if (ch == '\n') newline = 1;
+ }
+
+ replace(ed, start, end - start, buffer, buflen, 1);
+ free(buffer);
+
+ if (ed->anchor < pos) {
+ pos += width * lines;
+ } else {
+ ed->anchor += width * lines;
+ }
+
+ ed->toppos += width * toplines;
+ ed->linepos = line_start(ed, pos);
+ ed->col = ed->lastcol = pos - ed->linepos;
+
+ adjust(ed);
+ ed->refresh = 1;
+}
+
+static void unindent(struct editor *ed, unsigned char *indentation) {
+ int start, end, i, newline, ch, shrinkage, topofs;
+ unsigned char *buffer, *p;
+ int width = strlen((const char*) indentation);
+ int pos = ed->linepos + ed->col;
+
+ if (!get_selection(ed, &start, &end)) return;
+
+ buffer = malloc(end - start);
+ if (!buffer) return;
+
+ newline = 1;
+ p = buffer;
+ i = start;
+ shrinkage = 0;
+ topofs = 0;
+ while (i < end) {
+ if (newline) {
+ newline = 0;
+ if (compare(ed, indentation, i, width)) {
+ i += width;
+ shrinkage += width;
+ if (i < ed->toppos) topofs -= width;
+ continue;
+ }
+ }
+ ch = get(ed, i++);
+ *p++ = ch;
+ if (ch == '\n') newline = 1;
+ }
+
+ if (!shrinkage) {
+ free(buffer);
+ return;
+ }
+
+ replace(ed, start, end - start, buffer, p - buffer, 1);
+ free(buffer);
+
+ if (ed->anchor < pos) {
+ pos -= shrinkage;
+ } else {
+ ed->anchor -= shrinkage;
+ }
+
+ ed->toppos += topofs;
+ ed->linepos = line_start(ed, pos);
+ ed->col = ed->lastcol = pos - ed->linepos;
+
+ ed->refresh = 1;
+ adjust(ed);
+}
+
+static void undo(struct editor *ed) {
+ if (!ed->undo) return;
+ moveto(ed, ed->undo->pos, 0);
+ replace(ed, ed->undo->pos, ed->undo->inserted, ed->undo->undobuf, ed->undo->erased, 0);
+ ed->undo = ed->undo->prev;
+ if (!ed->undo) ed->dirty = 0;
+ ed->anchor = -1;
+ ed->lastcol = ed->col;
+ ed->refresh = 1;
+}
+
+static void redo(struct editor *ed) {
+ if (ed->undo) {
+ if (!ed->undo->next) return;
+ ed->undo = ed->undo->next;
+ } else {
+ if (!ed->undohead) return;
+ ed->undo = ed->undohead;
+ }
+ replace(ed, ed->undo->pos, ed->undo->erased, ed->undo->redobuf, ed->undo->inserted, 0);
+ moveto(ed, ed->undo->pos, 0);
+ ed->dirty = 1;
+ ed->anchor = -1;
+ ed->lastcol = ed->col;
+ ed->refresh = 1;
+}
+
+//
+// Clipboard
+//
+
+static void copy_selection(struct editor *ed) {
+ int selstart, selend;
+
+ if (!get_selection(ed, &selstart, &selend)) return;
+ ed->env->clipsize = selend - selstart;
+ ed->env->clipboard = (unsigned char *) realloc(ed->env->clipboard, ed->env->clipsize);
+ if (!ed->env->clipboard) return;
+ copy(ed, ed->env->clipboard, selstart, ed->env->clipsize);
+ select_toggle(ed);
+}
+
+static void cut_selection(struct editor *ed) {
+ copy_selection(ed);
+ erase_selection(ed);
+ select_toggle(ed);
+}
+
+static void paste_selection(struct editor *ed) {
+ erase_selection(ed);
+ insert(ed, ed->linepos + ed->col, ed->env->clipboard, ed->env->clipsize);
+ moveto(ed, ed->linepos + ed->col + ed->env->clipsize, 0);
+ ed->refresh = 1;
+}
+
+//
+// Editor Commands
+//
+
+static void open_editor(struct editor *ed) {
+ int rc;
+ char *filename;
+ struct env *env = ed->env;
+
+ if (!prompt(ed, "Open file: ", 1)) {
+ ed->refresh = 1;
+ return;
+ }
+ filename = (char*) ed->env->linebuf;
+
+ ed = find_editor(ed->env, filename);
+ if (ed) {
+ env->current = ed;
+ } else {
+ ed = create_editor(env);
+ rc = load_file(ed, filename);
+ if (rc < 0) {
+ display_message(ed, "Error %d opening %s (%s)", errno, filename, strerror(errno));
+ sleep(5);
+ delete_editor(ed);
+ ed = env->current;
+ }
+ }
+ ed->refresh = 1;
+}
+
+static void new_editor(struct editor *ed) {
+ ed = create_editor(ed->env);
+ new_file(ed, "");
+ ed->refresh = 1;
+}
+
+static void read_from_stdin(struct editor *ed) {
+ char buffer[512];
+ int n, pos;
+
+ pos = 0;
+ while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
+ insert(ed, pos, (unsigned char*) buffer, n);
+ pos += n;
+ }
+ strcpy(ed->filename, "<stdin>");
+ ed->newfile = 1;
+ ed->dirty = 0;
+}
+
+static void save_editor(struct editor *ed) {
+ int rc;
+
+ if (!ed->dirty && !ed->newfile) return;
+
+ if (ed->newfile) {
+ if (!prompt(ed, "Save as: ", 1)) {
+ ed->refresh = 1;
+ return;
+ }
+
+ if (access((const char*) ed->env->linebuf, F_OK) == 0) {
+ display_message(ed, "Overwrite %s (y/n)? ", ed->env->linebuf);
+ if (!ask()) {
+ ed->refresh = 1;
+ return;
+ }
+ }
+ strcpy(ed->filename, (const char*) ed->env->linebuf);
+ ed->newfile = 0;
+ }
+
+ rc = save_file(ed);
+ if (rc < 0) {
+ display_message(ed, "Error %d saving document (%s)", errno, strerror(errno));
+ sleep(5);
+ }
+
+ ed->refresh = 1;
+}
+
+static void close_editor(struct editor *ed) {
+ struct env *env = ed->env;
+
+ if (ed->dirty) {
+ display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
+ if (!ask()) {
+ ed->refresh = 1;
+ return;
+ }
+ }
+
+ delete_editor(ed);
+
+ ed = env->current;
+ if (!ed) {
+ ed = create_editor(env);
+ new_file(ed, "");
+ }
+ ed->refresh = 1;
+}
+
+static void pipe_command(struct editor *ed) {
+#ifdef __rtems__
+ display_message(ed, "Not supported");
+ sleep(3);
+#else
+ FILE *f;
+ char buffer[512];
+ int n;
+ int pos;
+
+ if (!prompt(ed, "Command: ", 1)) {
+ ed->refresh = 1;
+ return;
+ }
+
+#ifdef SANOS
+ f = popen(ed->env->linebuf, "r2");
+#else
+ f = popen(ed->env->linebuf, "r");
+#endif
+ if (!f) {
+ display_message(ed, "Error %d running command (%s)", errno, strerror(errno));
+ sleep(5);
+ } else {
+ erase_selection(ed);
+ pos = ed->linepos + ed->col;
+ while ((n = fread(buffer, 1, sizeof(buffer), f)) > 0) {
+ insert(ed, pos, buffer, n);
+ pos += n;
+ }
+ moveto(ed, pos, 0);
+ pclose(f);
+ }
+ ed->refresh = 1;
+#endif
+}
+
+static void find_text(struct editor *ed, int next) {
+ int slen;
+
+ if (!next) {
+ if (!prompt(ed, "Find: ", 1)) {
+ ed->refresh = 1;
+ return;
+ }
+ if (ed->env->search) free(ed->env->search);
+ ed->env->search = (unsigned char*) strdup((const char*) ed->env->linebuf);
+ }
+
+ if (!ed->env->search) return;
+ slen = strlen((const char*) ed->env->search);
+ if (slen > 0) {
+ unsigned char *match;
+
+ close_gap(ed);
+ match = (unsigned char*) strstr((char*) ed->start + ed->linepos + ed->col, (char*) ed->env->search);
+ if (match != NULL) {
+ int pos = match - ed->start;
+ ed->anchor = pos;
+ moveto(ed, pos + slen, 1);
+ } else {
+ outch('\007');
+ }
+ }
+ ed->refresh = 1;
+}
+
+static void goto_line(struct editor *ed) {
+ int lineno, l, pos;
+
+ ed->anchor = -1;
+ if (prompt(ed, "Goto line: ", 1)) {
+ lineno = atoi((char*) ed->env->linebuf);
+ if (lineno > 0) {
+ pos = 0;
+ for (l = 0; l < lineno - 1; l++) {
+ pos = next_line(ed, pos);
+ if (pos < 0) break;
+ }
+ } else {
+ pos = -1;
+ }
+
+ if (pos >= 0) {
+ moveto(ed, pos, 1);
+ } else {
+ outch('\007');
+ }
+ }
+ ed->refresh = 1;
+}
+
+struct editor *next_file(struct editor *ed) {
+ ed = ed->env->current = ed->next;
+ ed->refresh = 1;
+ return ed;
+}
+
+static void jump_to_editor(struct editor *ed) {
+ struct env *env = ed->env;
+ char filename[FILENAME_MAX];
+ int lineno = 0;
+
+ if (!get_selected_text(ed, filename, FILENAME_MAX)) {
+ int pos = ed->linepos + ed->col;
+ char *p = filename;
+ int left = FILENAME_MAX - 1;
+ while (left > 0) {
+ int ch = get(ed, pos);
+ if (ch < 0) break;
+ if (strchr("!@\"'#%&()[]{}*?+:;\r\n\t ", ch)) break;
+ *p++ = ch;
+ left--;
+ pos++;
+ }
+ *p = 0;
+
+ if (get(ed, pos) == ':') {
+ pos++;
+ for (;;) {
+ int ch = get(ed, pos);
+ if (ch < 0) break;
+ if (ch >= '0' && ch <= '9') {
+ lineno = lineno * 10 + (ch - '0');
+ } else {
+ break;
+ }
+ pos++;
+ }
+ }
+ }
+ if (!*filename) return;
+
+ ed = find_editor(env, filename);
+ if (ed) {
+ env->current = ed;
+ } else {
+ ed = create_editor(env);
+ if (load_file(ed, filename) < 0) {
+ outch('\007');
+ delete_editor(ed);
+ ed = env->current;
+ }
+ }
+
+ if (lineno > 0) {
+ int pos = 0;
+ while (--lineno > 0) {
+ pos = next_line(ed, pos);
+ if (pos < 0) break;
+ }
+ if (pos >= 0) moveto(ed, pos, 1);
+ }
+
+ ed->refresh = 1;
+}
+
+static void redraw_screen(struct editor *ed) {
+ get_console_size(ed->env);
+ draw_screen(ed);
+}
+
+static int quit(struct env *env) {
+ struct editor *ed = env->current;
+ struct editor *start = ed;
+
+ do {
+ if (ed->dirty) {
+ display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
+ if (!ask()) return 0;
+ }
+ ed = ed->next;
+ } while (ed != start);
+
+ return 1;
+}
+
+static void help(struct editor *ed) {
+ gotoxy(0, 0);
+ clear_screen();
+ outstr("Editor Command Summary\r\n");
+ outstr("======================\r\n\r\n");
+ outstr("<up> Move one line up (*) Ctrl+N New editor\r\n");
+ outstr("<down> Move one line down (*) Ctrl+O Open file\r\n");
+ outstr("<left> Move one character left (*) Ctrl+S Save file\r\n");
+ outstr("<right> Move one character right (*) Ctrl+W Close file\r\n");
+ outstr("<pgup> Move one page up (*) Ctrl+Q Quit\r\n");
+ outstr("<pgdn> Move one page down (*) Ctrl+P Pipe command\r\n");
+ outstr("Ctrl+<left> Move to previous word (*) Ctrl+A Select all\r\n");
+ outstr("Ctrl+<right> Move to next word (*) Ctrl+C Copy selection to clipboard\r\n");
+ outstr("<home> Move to start of line (*) Ctrl+X Cut selection to clipboard\r\n");
+ outstr("<end> Move to end of line (*) Ctrl+V Paste from clipboard\r\n");
+ outstr("Ctrl+<home> Move to start of file (*) Ctrl+Z Undo\r\n");
+ outstr("Ctrl+<end> Move to end of file (*) Ctrl+R Redo\r\n");
+ outstr("<backspace> Delete previous character Ctrl+F Find text\r\n");
+ outstr("<delete> Delete current character Ctrl+G Find next\r\n");
+ outstr("Ctrl+<tab> Next editor Ctrl+L Goto line\r\n");
+ outstr("<tab> Indent selection F1 Help\r\n");
+ outstr("Shift+<tab> Unindent selection F3 Navigate to file\r\n");
+ outstr(" F5 Redraw screen\r\n");
+ outstr("\r\n(*) Extends selection if combined with Shift");
+ outstr("\r\nPress any key to continue...");
+ fflush(stdout);
+
+ getkey();
+ draw_screen(ed);
+ draw_full_statusline(ed);
+}
+
+//
+// Editor
+//
+
+static void edit(struct editor *ed) {
+ int done = 0;
+ int key;
+
+ ed->refresh = 1;
+ while (!done) {
+ if (ed->refresh) {
+ draw_screen(ed);
+ draw_full_statusline(ed);
+ ed->refresh = 0;
+ ed->lineupdate = 0;
+ } else if (ed->lineupdate) {
+ update_line(ed);
+ ed->lineupdate = 0;
+ draw_statusline(ed);
+ } else {
+ draw_statusline(ed);
+ }
+
+ position_cursor(ed);
+ fflush(stdout);
+ key = getkey();
+
+ if (key >= ' ' && key <= 0x7F) {
+#ifdef LESS
+ switch (key) {
+ case 'q': done = 1; break;
+ case '/': find_text(ed, 0); break;
+ }
+#else
+ insert_char(ed, (unsigned char) key);
+#endif
+ } else {
+ switch (key) {
+ case KEY_F1: help(ed); break;
+ case KEY_F2: select_toggle(ed); break;
+ case KEY_F3: jump_to_editor(ed); ed = ed->env->current; break;
+ case KEY_F5: redraw_screen(ed); break;
+ case KEY_F9: save_editor(ed); break;
+ case KEY_F10: done = 1; break;
+
+#if defined(__linux__) || defined(__rtems__)
+ case ctrl('y'): help(ed); break;
+ case ctrl('t'): top(ed, 0); break;
+ case ctrl('b'): bottom(ed, 0); break;
+#endif
+
+ case KEY_UP: up(ed, ed->selecting); break;
+ case KEY_DOWN: down(ed, ed->selecting); break;
+ case KEY_LEFT: left(ed, ed->selecting); break;
+ case KEY_RIGHT: right(ed, ed->selecting); break;
+ case KEY_HOME: home(ed, ed->selecting); break;
+ case KEY_END: end(ed, ed->selecting); break;
+ case KEY_PGUP: pageup(ed, ed->selecting); break;
+ case KEY_PGDN: pagedown(ed, ed->selecting); break;
+
+ case KEY_CTRL_RIGHT: wordright(ed, ed->selecting); break;
+ case KEY_CTRL_LEFT: wordleft(ed, ed->selecting); break;
+ case KEY_CTRL_HOME: top(ed, ed->selecting); break;
+ case KEY_CTRL_END: bottom(ed, ed->selecting); break;
+
+#if SHIFT_SELECT
+ case KEY_SHIFT_UP: up(ed, 1); break;
+ case KEY_SHIFT_DOWN: down(ed, 1); break;
+ case KEY_SHIFT_LEFT: left(ed, 1); break;
+ case KEY_SHIFT_RIGHT: right(ed, 1); break;
+ case KEY_SHIFT_PGUP: pageup(ed, 1); break;
+ case KEY_SHIFT_PGDN: pagedown(ed, 1); break;
+ case KEY_SHIFT_HOME: home(ed, 1); break;
+ case KEY_SHIFT_END: end(ed, 1); break;
+
+ case KEY_SHIFT_CTRL_RIGHT: wordright(ed, 1); break;
+ case KEY_SHIFT_CTRL_LEFT: wordleft(ed, 1); break;
+ case KEY_SHIFT_CTRL_HOME: top(ed, 1); break;
+ case KEY_SHIFT_CTRL_END: bottom(ed, 1); break;
+#endif
+
+ case KEY_CTRL_TAB: ed = next_file(ed); break;
+
+ case ctrl('e'): select_toggle(ed); break;
+ case ctrl('a'): select_all(ed); break;
+ case ctrl('c'): copy_selection(ed); break;
+ case ctrl('f'): find_text(ed, 0); break;
+ case ctrl('l'): goto_line(ed); break;
+ case ctrl('g'): find_text(ed, 1); break;
+ case ctrl('q'): done = 1; break;
+#ifdef LESS
+ case KEY_ESC: done = 1; break;
+#else
+ case KEY_TAB: indent(ed, (unsigned char*) INDENT); break;
+ case KEY_SHIFT_TAB: unindent(ed, (unsigned char*) INDENT); break;
+
+ case KEY_ENTER: newline(ed); break;
+ case KEY_BACKSPACE: backspace(ed); break;
+ case KEY_DEL: del(ed); break;
+ case ctrl('x'): cut_selection(ed); break;
+ case ctrl('z'): undo(ed); break;
+ case ctrl('r'): redo(ed); break;
+ case ctrl('v'): paste_selection(ed); break;
+ case ctrl('o'): open_editor(ed); ed = ed->env->current; break;
+ case ctrl('n'): new_editor(ed); ed = ed->env->current; break;
+ case ctrl('s'): save_editor(ed); break;
+ case ctrl('p'): pipe_command(ed); break;
+#endif
+ case ctrl('w'): close_editor(ed); ed = ed->env->current; break;
+ }
+ }
+ }
+}
+
+//
+// main
+//
+
+int rtems_shell_main_edit(int argc, char *argv[]) {
+ struct env env;
+ int rc;
+ int i;
+ sigset_t blocked_sigmask, orig_sigmask;
+#if defined(__linux__) || defined(__rtems__)
+ struct termios tio;
+ struct termios orig_tio;
+#endif
+#ifdef SANOS
+ struct term *term;
+#endif
+
+ memset(&env, 0, sizeof(env));
+ for (i = 1; i < argc; i++) {
+ struct editor *ed = create_editor(&env);
+ rc = load_file(ed, argv[i]);
+ if (rc < 0 && errno == ENOENT) rc = new_file(ed, argv[i]);
+ if (rc < 0) {
+ perror(argv[i]);
+ return 0;
+ }
+ }
+ if (env.current == NULL) {
+ struct editor *ed = create_editor(&env);
+ if (isatty(fileno(stdin))) {
+ new_file(ed, "");
+ } else {
+ read_from_stdin(ed);
+ }
+ }
+ env.current = env.current->next;
+
+#ifdef SANOS
+ term = gettib()->proc->term;
+ if (fdin != term->ttyin) dup2(term->ttyin, fdin);
+ if (fdout != term->ttyout) dup2(term->ttyout, fdout);
+#elif !defined(__rtems__)
+ if (!isatty(fileno(stdin))) {
+ if (!freopen("/dev/tty", "r", stdin)) perror("/dev/tty");
+ }
+#endif
+
+ setvbuf(stdout, NULL, 0, 8192);
+
+#if defined(__linux__) || defined(__rtems__)
+ tcgetattr(0, &orig_tio);
+#if !defined(__rtems__)
+ cfmakeraw(&tio);
+ tcsetattr(0, TCSANOW, &tio);
+#endif
+ if (getenv("TERM") && strcmp(getenv("TERM"), "linux") == 0) {
+ linux_console = 1;
+ } else {
+ outstr(CLRSCR);
+ outstr("\033[3 q"); // xterm
+ outstr("\033]50;CursorShape=2\a"); // KDE
+ }
+#endif
+
+ get_console_size(&env);
+
+ sigemptyset(&blocked_sigmask);
+ sigaddset(&blocked_sigmask, SIGINT);
+ sigaddset(&blocked_sigmask, SIGTSTP);
+ sigaddset(&blocked_sigmask, SIGABRT);
+ sigprocmask(SIG_BLOCK, &blocked_sigmask, &orig_sigmask);
+
+ for (;;) {
+ if (!env.current) break;
+ edit(env.current);
+ if (quit(&env)) break;
+ }
+
+ gotoxy(0, env.lines + 1);
+ outstr(RESET_COLOR CLREOL);
+#if defined(__linux__) || defined(__rtems__)
+ tcsetattr(0, TCSANOW, &orig_tio);
+#endif
+
+ while (env.current) delete_editor(env.current);
+
+ if (env.clipboard) free(env.clipboard);
+ if (env.search) free(env.search);
+ if (env.linebuf) free(env.linebuf);
+
+ setbuf(stdout, NULL);
+ sigprocmask(SIG_SETMASK, &orig_sigmask, NULL);
+
+ return 0;
+}
+
+rtems_shell_cmd_t rtems_shell_EDIT_Command = {
+ "edit", /* name */
+ "edit [file ...]", /* usage */
+ "files", /* topic */
+ rtems_shell_main_edit, /* command */
+ NULL, /* alias */
+ NULL /* next */
+};
diff --git a/cpukit/libmisc/shell/shellconfig.h b/cpukit/libmisc/shell/shellconfig.h
index eacfac2..3776952 100644
--- a/cpukit/libmisc/shell/shellconfig.h
+++ b/cpukit/libmisc/shell/shellconfig.h
@@ -39,6 +39,7 @@ extern rtems_shell_cmd_t rtems_shell_MMOVE_Command;
extern rtems_shell_cmd_t rtems_shell_JOEL_Command;
extern rtems_shell_cmd_t rtems_shell_DATE_Command;
extern rtems_shell_cmd_t rtems_shell_ECHO_Command;
+extern rtems_shell_cmd_t rtems_shell_EDIT_Command;
extern rtems_shell_cmd_t rtems_shell_SLEEP_Command;
extern rtems_shell_cmd_t rtems_shell_ID_Command;
extern rtems_shell_cmd_t rtems_shell_TTY_Command;
@@ -175,6 +176,11 @@ extern rtems_shell_alias_t *rtems_shell_Initial_aliases[];
&rtems_shell_ECHO_Command,
#endif
#if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \
+ !defined(CONFIGURE_SHELL_NO_COMMAND_EDIT)) || \
+ defined(CONFIGURE_SHELL_COMMAND_EDIT)
+ &rtems_shell_EDIT_Command,
+ #endif
+ #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \
!defined(CONFIGURE_SHELL_NO_COMMAND_SLEEP)) || \
defined(CONFIGURE_SHELL_COMMAND_SLEEP)
&rtems_shell_SLEEP_Command,
--
1.9.3 (Apple Git-50)
More information about the devel
mailing list