mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-20 13:08:31 +00:00
Add an EMACS-like command line editor that can be used wit NSH
This commit is contained in:
parent
551e49dfec
commit
82d71bb439
12 changed files with 1232 additions and 8 deletions
|
|
@ -811,3 +811,10 @@
|
|||
untested conditions (2014-1-21).
|
||||
|
||||
6.34 2014-xx-xx Gregory Nutt <gnutt@nuttx.org>
|
||||
|
||||
* apps/system/cle: Add a EMACS-like command line editor. This CLE,
|
||||
is really more like readline than the NuttX readline is! Not fully
|
||||
fully on initial checkout (2014-02-02).
|
||||
* apps/nshlib: Use of the standard tiney readline (about .25KB) is now
|
||||
an option and can be replaces with the EMACX-like CLE (about 2KB)
|
||||
(2014-02-02).
|
||||
|
|
|
|||
87
include/cle.h
Normal file
87
include/cle.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/****************************************************************************
|
||||
* apps/include/cle.h
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 NuttX 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_INCLUDE_CLE_H
|
||||
#define __APPS_INCLUDE_CLE_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef CONFIG_SYSTEM_CLE
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-Processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle
|
||||
*
|
||||
* Description:
|
||||
* EMACS-like command line editor. This is actually more like readline
|
||||
* than is the NuttX readline!
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int cle(FAR char *line, uint16_t linelen, FILE *instream, FILE *outstream);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_SYSTEM_CLE */
|
||||
#endif /* __APPS_INCLUDE_CLE_H */
|
||||
|
|
@ -6,13 +6,37 @@
|
|||
config NSH_LIBRARY
|
||||
bool "NSH Library"
|
||||
default n
|
||||
select SYSTEM_READLINE
|
||||
---help---
|
||||
Build the NSH support library. This is used, for example, by examples/nsh
|
||||
in order to implement the full NuttShell (NSH).
|
||||
Build the NSH support library. This is used, for example, by
|
||||
examples/nsh in order to implement the full NuttShell (NSH).
|
||||
|
||||
if NSH_LIBRARY
|
||||
|
||||
choice
|
||||
prompt "Command Line Editor"
|
||||
default NSH_READLINE
|
||||
|
||||
config NSH_READLINE
|
||||
bool "Minimal readline()"
|
||||
select SYSTEM_READLINE
|
||||
---help---
|
||||
Selects the minimal implementation of readline(). This minimal
|
||||
implementation provides on backspace for command line editing.
|
||||
|
||||
config NSH_CLE
|
||||
bool "Command Line Editor"
|
||||
select SYSTEM_CLE
|
||||
---help---
|
||||
Selects the more extensive, EMACS-like command line editor.
|
||||
Select this option only if (1) you don't mind a modest increase
|
||||
in the FLASH footprint, and (2) you work with a terminal that
|
||||
support VT100 editing commands.
|
||||
|
||||
Selecting this option will add probably 1.5-2KB to the FLASH
|
||||
footprint.
|
||||
|
||||
endchoice
|
||||
|
||||
config NSH_BUILTIN_APPS
|
||||
bool "Enable built-in applications"
|
||||
default n
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* apps/nshlib/nsh_session.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2011-2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -42,7 +42,11 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <apps/readline.h>
|
||||
#ifdef CONFIG_NSH_CLE
|
||||
# include <apps/cle.h>
|
||||
#else
|
||||
# include <apps/readline.h>
|
||||
#endif
|
||||
|
||||
#include "nsh.h"
|
||||
#include "nsh_console.h"
|
||||
|
|
@ -133,8 +137,13 @@ int nsh_session(FAR struct console_stdio_s *pstate)
|
|||
* or any read failure.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NSH_CLE
|
||||
ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN,
|
||||
INSTREAM(pstate), OUTSTREAM(pstate));
|
||||
#else
|
||||
ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN,
|
||||
INSTREAM(pstate), OUTSTREAM(pstate));
|
||||
#endif
|
||||
if (ret != EOF)
|
||||
{
|
||||
/* Parse process the command */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* apps/nshlib/nsh_stdsession.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2013-2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -42,7 +42,11 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <apps/readline.h>
|
||||
#ifdef CONFIG_NSH_CLE
|
||||
# include <apps/cle.h>
|
||||
#else
|
||||
# include <apps/readline.h>
|
||||
#endif
|
||||
|
||||
#include "nsh.h"
|
||||
#include "nsh_console.h"
|
||||
|
|
@ -124,7 +128,12 @@ int nsh_session(FAR struct console_stdio_s *pstate)
|
|||
* or any read failure.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NSH_CLE
|
||||
ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN,
|
||||
stdin, stdout);
|
||||
#else
|
||||
ret = std_readline(pstate->cn_line, CONFIG_NSH_LINELEN);
|
||||
#endif
|
||||
if (ret != EOF)
|
||||
{
|
||||
/* Parse process the command */
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ menu "USB Monitor"
|
|||
source "$APPSDIR/system/usbmonitor/Kconfig"
|
||||
endmenu
|
||||
|
||||
menu "EMACS-like Command Line Editor"
|
||||
source "$APPSDIR/system/cle/Kconfig"
|
||||
endmenu
|
||||
|
||||
menu "VI Work-Alike Editor"
|
||||
source "$APPSDIR/system/vi/Kconfig"
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ ifeq ($(CONFIG_SYSTEM_USBMSC),y)
|
|||
CONFIGURED_APPS += system/usbmsc
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SYSTEM_CLE),y)
|
||||
CONFIGURED_APPS += system/cle
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SYSTEM_VI),y)
|
||||
CONFIGURED_APPS += system/vi
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
# Sub-directories containing system task
|
||||
|
||||
SUBDIRS = cdcacm composite flash_eraseall free i2c inifile install
|
||||
SUBDIRS = cdcacm cle composite flash_eraseall free i2c inifile install
|
||||
SUBDIRS += nxplayer poweroff ramtest ramtron readline sdcard stackmonitor
|
||||
SUBDIRS += sysinfo usbmonitor usbmsc vi zmodem
|
||||
|
||||
|
|
|
|||
11
system/cle/.gitignore
vendored
Normal file
11
system/cle/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/Make.dep
|
||||
/.depend
|
||||
/.built
|
||||
/*.asm
|
||||
/*.rel
|
||||
/*.lst
|
||||
/*.sym
|
||||
/*.adb
|
||||
/*.lib
|
||||
/*.src
|
||||
/*.obj
|
||||
37
system/cle/Kconfig
Normal file
37
system/cle/Kconfig
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see misc/tools/kconfig-language.txt.
|
||||
#
|
||||
|
||||
config SYSTEM_CLE
|
||||
bool "Tiny VI work-alike command line editor"
|
||||
default n
|
||||
---help---
|
||||
Enable support for NuttX tiny EMACS-like command line editor.
|
||||
|
||||
Omitted features:
|
||||
- No keypad cursor control support
|
||||
- No word oriented operations.
|
||||
|
||||
Assumptions and Limitations:
|
||||
- A VT100 host terminal is assumed.
|
||||
- A fixed width character set (like Courier) is assumed
|
||||
|
||||
Memory Usage: Looks like 1.5-2KB
|
||||
|
||||
if SYSTEM_CLE
|
||||
|
||||
config SYSTEM_CLE_DEBUGLEVEL
|
||||
int "Debug level"
|
||||
default 0
|
||||
range 0 2
|
||||
---help---
|
||||
0=Debug off; 1=Print errors on console; 2=Print debug information
|
||||
on the console.
|
||||
|
||||
Debug output is generated with syslog. The editor works on
|
||||
/dev/console. In order to get both a usable display and also
|
||||
readable debug output, syslog'ing should sent to some device other
|
||||
than /dev/console (which is the default).
|
||||
|
||||
endif # SYSTEM_CLE
|
||||
103
system/cle/Makefile
Normal file
103
system/cle/Makefile
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
############################################################################
|
||||
# apps/system/cle/Makefile
|
||||
#
|
||||
# Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
#
|
||||
# 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 NuttX 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 $(TOPDIR)/.config
|
||||
-include $(TOPDIR)/Make.defs
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
ifeq ($(WINTOOL),y)
|
||||
INCDIROPT = -w
|
||||
endif
|
||||
|
||||
# EMACS-like Command Line Editor (CLE)
|
||||
|
||||
ASRCS =
|
||||
CSRCS = cle.c
|
||||
|
||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||
|
||||
SRCS = $(ASRCS) $(CSRCS)
|
||||
OBJS = $(AOBJS) $(COBJS)
|
||||
|
||||
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
|
||||
BIN = ..\..\libapps$(LIBEXT)
|
||||
else
|
||||
ifeq ($(WINTOOL),y)
|
||||
BIN = ..\\..\\libapps$(LIBEXT)
|
||||
else
|
||||
BIN = ../../libapps$(LIBEXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
ROOTDEPPATH = --dep-path .
|
||||
|
||||
# Common build
|
||||
|
||||
VPATH =
|
||||
|
||||
all: .built
|
||||
.PHONY: context depend clean distclean
|
||||
|
||||
$(AOBJS): %$(OBJEXT): %.S
|
||||
$(call ASSEMBLE, $<, $@)
|
||||
|
||||
$(COBJS): %$(OBJEXT): %.c
|
||||
$(call COMPILE, $<, $@)
|
||||
|
||||
.built: $(OBJS)
|
||||
$(call ARCHIVE, $(BIN), $(OBJS))
|
||||
$(Q) touch .built
|
||||
|
||||
context:
|
||||
|
||||
# Create dependencies
|
||||
|
||||
.depend: Makefile $(SRCS)
|
||||
$(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
|
||||
$(Q) touch $@
|
||||
|
||||
depend: .depend
|
||||
|
||||
clean:
|
||||
$(call DELFILE, .built)
|
||||
$(call CLEAN)
|
||||
|
||||
distclean: clean
|
||||
$(call DELFILE, Make.dep)
|
||||
$(call DELFILE, .depend)
|
||||
|
||||
-include Make.dep
|
||||
|
||||
929
system/cle/cle.c
Normal file
929
system/cle/cle.c
Normal file
|
|
@ -0,0 +1,929 @@
|
|||
/****************************************************************************
|
||||
* apps/system/cle/cle.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 NuttX 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/ascii.h>
|
||||
#include <nuttx/vt100.h>
|
||||
|
||||
#include <apps/cle.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Some environments may return CR as end-of-line, others LF, and others
|
||||
* both. If not specified, the logic here assumes either (but not both) as
|
||||
* the default.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_EOL_IS_CR)
|
||||
# undef CONFIG_EOL_IS_LF
|
||||
# undef CONFIG_EOL_IS_BOTH_CRLF
|
||||
# undef CONFIG_EOL_IS_EITHER_CRLF
|
||||
#elif defined(CONFIG_EOL_IS_LF)
|
||||
# undef CONFIG_EOL_IS_CR
|
||||
# undef CONFIG_EOL_IS_BOTH_CRLF
|
||||
# undef CONFIG_EOL_IS_EITHER_CRLF
|
||||
#elif defined(CONFIG_EOL_IS_BOTH_CRLF)
|
||||
# undef CONFIG_EOL_IS_CR
|
||||
# undef CONFIG_EOL_IS_LF
|
||||
# undef CONFIG_EOL_IS_EITHER_CRLF
|
||||
#elif defined(CONFIG_EOL_IS_EITHER_CRLF)
|
||||
# undef CONFIG_EOL_IS_CR
|
||||
# undef CONFIG_EOL_IS_LF
|
||||
# undef CONFIG_EOL_IS_BOTH_CRLF
|
||||
#else
|
||||
# undef CONFIG_EOL_IS_CR
|
||||
# undef CONFIG_EOL_IS_LF
|
||||
# undef CONFIG_EOL_IS_BOTH_CRLF
|
||||
# define CONFIG_EOL_IS_EITHER_CRLF 1
|
||||
#endif
|
||||
|
||||
/* Control characters */
|
||||
|
||||
#undef CTRL
|
||||
#define CTRL(a) ((a) & 0x1f)
|
||||
|
||||
#define CLE_BEL(cle) cle_putch(cle,CTRL('G'))
|
||||
|
||||
/* Sizes of things */
|
||||
|
||||
#define TABSIZE 8 /* A TAB is eight characters */
|
||||
#define TABMASK 7 /* Mask for TAB alignment */
|
||||
#define NEXT_TAB(p) (((p) + TABSIZE) & ~TABMASK)
|
||||
|
||||
/* Debug */
|
||||
|
||||
#ifndef CONFIG_SYSEM_CLE_DEBUGLEVEL
|
||||
# define CONFIG_SYSEM_CLE_DEBUGLEVEL 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPP_HAVE_VARARGS
|
||||
# if CONFIG_SYSEM_CLE_DEBUGLEVEL > 0
|
||||
# define vidbg(format, arg...) \
|
||||
syslog(EXTRA_FMT format EXTRA_ARG, ##arg)
|
||||
# define vvidbg(format, ap) \
|
||||
vsyslog(format, ap)
|
||||
# else
|
||||
# define vidbg(x...)
|
||||
# define vvidbg(x...)
|
||||
# endif
|
||||
|
||||
# if CONFIG_SYSEM_CLE_DEBUGLEVEL > 1
|
||||
# define vivdbg(format, arg...) \
|
||||
syslog(EXTRA_FMT format EXTRA_ARG, ##arg)
|
||||
# else
|
||||
# define vivdbg(x...)
|
||||
# endif
|
||||
#else
|
||||
# if CONFIG_SYSEM_CLE_DEBUGLEVEL > 0
|
||||
# define vidbg syslog
|
||||
# define vvidbg vsyslog
|
||||
# else
|
||||
# define vidbg (void)
|
||||
# define vvidbg (void)
|
||||
# endif
|
||||
|
||||
# if CONFIG_SYSEM_CLE_DEBUGLEVEL > 1
|
||||
# define vivdbg syslog
|
||||
# else
|
||||
# define vivdbg (void)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
/* VI Key Bindings */
|
||||
|
||||
enum cle_key_e
|
||||
{
|
||||
KEY_BEGINLINE = CTRL('A'), /* Move cursor to start of current line */
|
||||
KEY_LEFT = CTRL('B'), /* Move left one character */
|
||||
KEY_DEL = CTRL('D'), /* Delete a single character at the cursor position*/
|
||||
KEY_ENDLINE = CTRL('E'), /* Move cursor to end of current line */
|
||||
KEY_RIGHT = CTRL('F'), /* Move right one character */
|
||||
KEY_DELLEFT = CTRL('H'), /* Delete character, left (backspace) */
|
||||
KEY_DELEOL = CTRL('K'), /* Delete to the end of the line */
|
||||
KEY_DELLINE = CTRL('U'), /* Delete the entire line */
|
||||
KEY_QUOTE = '\\', /* The next character is quote (use literal value) */
|
||||
};
|
||||
|
||||
/* This structure describes the overall state of the editor */
|
||||
|
||||
struct cle_s
|
||||
{
|
||||
uint16_t curpos; /* Current cursor position */
|
||||
uint16_t cursave; /* Saved cursor position */
|
||||
uint16_t row; /* This is the row that we are editing iun */
|
||||
uint16_t coloffs; /* Left cursor offset */
|
||||
uint16_t linelen; /* Size of the line buffer */
|
||||
uint16_t nchars; /* Size of data in the line buffer */
|
||||
int infd; /* Input file descriptor */
|
||||
int outfd; /* Output file descriptor */
|
||||
FAR char *line; /* Line buffer */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Low-level display and data entry functions */
|
||||
|
||||
static void cle_write(FAR struct cle_s *cle, FAR const char *buffer,
|
||||
uint16_t buflen);
|
||||
static void cle_putch(FAR struct cle_s *cle, char ch);
|
||||
static int cle_getch(FAR struct cle_s *cle);
|
||||
static void cle_cursoron(FAR struct cle_s *cle);
|
||||
static void cle_cursoroff(FAR struct cle_s *cle);
|
||||
static void cle_setcursor(FAR struct cle_s *cle, uint16_t column);
|
||||
static int cle_getcursor(FAR struct cle_s *cle, uint16_t *prow,
|
||||
uint16_t *pcolumn);
|
||||
static void cle_clrtoeol(FAR struct cle_s *cle);
|
||||
|
||||
/* Editor function */
|
||||
|
||||
static bool cle_opentext(FAR struct cle_s *cle, uint16_t pos,
|
||||
uint16_t increment);
|
||||
static void cle_closetext(FAR struct cle_s *cle, uint16_t pos, uint16_t size);
|
||||
static void cle_showtext(FAR struct cle_s *cle);
|
||||
static void cle_insertch(FAR struct cle_s *cle, char ch);
|
||||
static int cle_editloop(FAR struct cle_s *cle);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* VT100 escape sequences */
|
||||
|
||||
static const char g_cursoron[] = VT100_CURSORON;
|
||||
static const char g_cursoroff[] = VT100_CURSOROFF;
|
||||
static const char g_getcursor[] = VT100_GETCURSOR;
|
||||
static const char g_erasetoeol[] = VT100_CLEAREOL;
|
||||
static const char g_attriboff[] = VT100_MODESOFF;
|
||||
static const char g_fmtcursorpos[] = VT100_FMT_CURSORPOS;
|
||||
|
||||
/* Error format strings */
|
||||
|
||||
static const char g_fmtnotvalid[] = "Command not valid";
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Low-level display and data entry functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_write
|
||||
*
|
||||
* Description:
|
||||
* Write a sequence of bytes to the console device (stdout, fd = 1).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_write(FAR struct cle_s *cle, FAR const char *buffer,
|
||||
uint16_t buflen)
|
||||
{
|
||||
ssize_t nwritten;
|
||||
uint16_t nremaining = buflen;
|
||||
|
||||
//vivdbg("buffer=%p buflen=%d\n", buffer, (int)buflen);
|
||||
|
||||
/* Loop until all bytes have been successuflly written (or until a
|
||||
* un-recoverable error is encountered)
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Take the next gulp */
|
||||
|
||||
nwritten = write(cle->outfd, buffer, buflen);
|
||||
|
||||
/* Handle write errors. write() should neve return 0. */
|
||||
|
||||
if (nwritten <= 0)
|
||||
{
|
||||
/* EINTR is not really an error; it simply means that a signal was
|
||||
* received while waiting for write.
|
||||
*/
|
||||
|
||||
int errcode = errno;
|
||||
if (nwritten == 0 || errcode != EINTR)
|
||||
{
|
||||
vidbg("ERROR: write to stdout failed: %d\n", errcode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrement the count of bytes remaining to be sent (to handle the
|
||||
* case of a partial write)
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
nremaining -= nwritten;
|
||||
}
|
||||
}
|
||||
while (nremaining > 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_putch
|
||||
*
|
||||
* Description:
|
||||
* Write a single character to the console device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_putch(FAR struct cle_s *cle, char ch)
|
||||
{
|
||||
cle_write(cle, &ch, 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_getch
|
||||
*
|
||||
* Description:
|
||||
* Get a single character from the console device (stdin, fd = 0).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int cle_getch(FAR struct cle_s *cle)
|
||||
{
|
||||
char buffer;
|
||||
ssize_t nread;
|
||||
|
||||
/* Loop until we successfully read a character (or until an unexpected
|
||||
* error occurs).
|
||||
*/
|
||||
|
||||
do
|
||||
{
|
||||
/* Read one character from the incoming stream */
|
||||
|
||||
nread = read(cle->infd, &buffer, 1);
|
||||
|
||||
/* Check for error or end-of-file. */
|
||||
|
||||
if (nread <= 0)
|
||||
{
|
||||
/* EINTR is not really an error; it simply means that a signal we
|
||||
* received while waiting for input.
|
||||
*/
|
||||
|
||||
int errcode = errno;
|
||||
if (nread == 0 || errcode != EINTR)
|
||||
{
|
||||
vidbg("ERROR: read from stdin failed: %d\n", errcode);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (nread < 1);
|
||||
|
||||
/* On success, return the character that was read */
|
||||
|
||||
vivdbg("Returning: %c[%02x]\n", isprint(buffer) ? buffer : '.', buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_cursoron
|
||||
*
|
||||
* Description:
|
||||
* Turn on the cursor
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_cursoron(FAR struct cle_s *cle)
|
||||
{
|
||||
/* Send the VT100 CURSORON command */
|
||||
|
||||
cle_write(cle, g_cursoron, sizeof(g_cursoron));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_cursoroff
|
||||
*
|
||||
* Description:
|
||||
* Turn off the cursor
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_cursoroff(FAR struct cle_s *cle)
|
||||
{
|
||||
/* Send the VT100 CURSOROFF command */
|
||||
|
||||
cle_write(cle, g_cursoroff, sizeof(g_cursoroff));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_setcursor
|
||||
*
|
||||
* Description:
|
||||
* Move the current cursor position to position (row,col)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_setcursor(FAR struct cle_s *cle, uint16_t column)
|
||||
{
|
||||
char buffer[16];
|
||||
int len;
|
||||
|
||||
vivdbg("row=%d column=%d\n", row, column);
|
||||
|
||||
/* Format the cursor position command. The origin is (1,1). */
|
||||
|
||||
len = snprintf(buffer, 16, g_fmtcursorpos, cle->row, column + cle->coloffs);
|
||||
|
||||
/* Send the VT100 CURSORPOS command */
|
||||
|
||||
cle_write(cle, buffer, len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_getcursor
|
||||
*
|
||||
* Description:
|
||||
* Get the current cursor position.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int cle_getcursor(FAR struct cle_s *cle, FAR uint16_t *prow,
|
||||
FAR uint16_t *pcolumn)
|
||||
{
|
||||
uint32_t row;
|
||||
uint32_t column;
|
||||
int nbad;
|
||||
int ch;
|
||||
|
||||
/* Send the VT100 GETCURSOR command */
|
||||
|
||||
cle_write(cle, g_getcursor, sizeof(g_getcursor));
|
||||
|
||||
/* We expect to get ESCv;hR where v is the row and h is the column */
|
||||
|
||||
nbad = 0;
|
||||
for (;;)
|
||||
{
|
||||
/* Get the next character from the input */
|
||||
|
||||
ch = cle_getch(cle);
|
||||
if (ch == ASCII_ESC)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
else if (++nbad > 3)
|
||||
{
|
||||
/* We are probably talking to a non-VT100 terminal! */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we expect to see a numeric value terminated with ';' */
|
||||
|
||||
row = 0;
|
||||
for (;;)
|
||||
{
|
||||
/* Get the next character from the input */
|
||||
|
||||
ch = cle_getch(cle);
|
||||
if (isdigit(ch))
|
||||
{
|
||||
row = 10*row + (ch - '0');
|
||||
}
|
||||
else if (ch == ';')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we expect to see another numeric value terminated with 'R' */
|
||||
|
||||
column = 0;
|
||||
for (;;)
|
||||
{
|
||||
/* Get the next character from the input */
|
||||
|
||||
ch = cle_getch(cle);
|
||||
if (isdigit(ch))
|
||||
{
|
||||
column = 10*column + (ch - '0');
|
||||
}
|
||||
else if (ch == 'R')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
vivdbg("row=%ld column=%ld\n", row, column);
|
||||
|
||||
/* Make sure that the values are within range */
|
||||
|
||||
if (row <= UINT16_MAX && column <= UINT16_MAX)
|
||||
{
|
||||
*prow = row;
|
||||
*pcolumn = column;
|
||||
return OK;
|
||||
}
|
||||
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_clrtoeol
|
||||
*
|
||||
* Description:
|
||||
* Clear the display from the current cursor position to the end of the
|
||||
* current line.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_clrtoeol(FAR struct cle_s *cle)
|
||||
{
|
||||
/* Send the VT100 ERASETOEOL command */
|
||||
|
||||
cle_write(cle, g_erasetoeol, sizeof(g_erasetoeol));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_opentext
|
||||
*
|
||||
* Description:
|
||||
* Make space for new text of size 'increment' at the specified cursor
|
||||
* position.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool cle_opentext(FAR struct cle_s *cle, uint16_t pos, uint16_t increment)
|
||||
{
|
||||
int i;
|
||||
|
||||
vivdbg("pos=%ld increment=%ld\n", (long)pos, (long)increment);
|
||||
|
||||
/* Check if there is space in the line buffer to open up a region the size
|
||||
* of 'increment'
|
||||
*/
|
||||
|
||||
if (cle->nchars + increment > cle->linelen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Move text to make space for new text of size 'increment' at the current
|
||||
* cursor position
|
||||
*/
|
||||
|
||||
for (i = cle->nchars - 1; i >= pos; i--)
|
||||
{
|
||||
cle->line[i + increment] = cle->line[i];
|
||||
}
|
||||
|
||||
/* Adjust end of file position */
|
||||
|
||||
cle->nchars += increment;
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_closetext
|
||||
*
|
||||
* Description:
|
||||
* Delete a region in the line buffer by copying the end of the line buffer
|
||||
* over the deleted region and adjusting the size of the region.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_closetext(FAR struct cle_s *cle, uint16_t pos, uint16_t size)
|
||||
{
|
||||
int i;
|
||||
|
||||
vivdbg("pos=%ld size=%ld\n", (long)pos, (long)size);
|
||||
|
||||
/* Close up the gap to remove 'size' characters at 'pos' */
|
||||
|
||||
for (i = pos + size; i < cle->nchars; i++)
|
||||
{
|
||||
cle->line[i - size] = cle->line[i];
|
||||
}
|
||||
|
||||
/* Adjust sizes and positions */
|
||||
|
||||
cle->nchars -= size;
|
||||
|
||||
/* Check if the cursor position is beyond the deleted region */
|
||||
|
||||
if (cle->curpos > pos + size)
|
||||
{
|
||||
/* Yes... just subtract the size of the deleted region */
|
||||
|
||||
cle->curpos -= size;
|
||||
}
|
||||
|
||||
/* What if the position is within the deleted region? Set it to the
|
||||
* beginning of the deleted region.
|
||||
*/
|
||||
|
||||
else if (cle->curpos > pos)
|
||||
{
|
||||
cle->curpos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_showtext
|
||||
*
|
||||
* Description:
|
||||
* Update the display based on the last operation. This function is
|
||||
* called at the beginning of the processing loop in Command and Insert
|
||||
* modes (and also in the continuous replace mode).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_showtext(FAR struct cle_s *cle)
|
||||
{
|
||||
uint16_t column;
|
||||
uint16_t tabcol;
|
||||
|
||||
/* Turn off the cursor during the update. */
|
||||
|
||||
cle_cursoroff(cle);
|
||||
|
||||
/* Set the cursor position to the beginning of this row */
|
||||
|
||||
cle_setcursor(cle, 0);
|
||||
cle_clrtoeol(cle);
|
||||
|
||||
/* Loop for each column */
|
||||
|
||||
for (column = 0; column < cle->nchars && column < cle->linelen; column++)
|
||||
{
|
||||
/* Perform TAB expansion */
|
||||
|
||||
if (cle->line[column] == '\t')
|
||||
{
|
||||
tabcol = NEXT_TAB(column);
|
||||
if (tabcol < cle->linelen)
|
||||
{
|
||||
for (; column < tabcol; column++)
|
||||
{
|
||||
cle_putch(cle, ' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Break out of the loop... there is nothing left on the
|
||||
* line but whitespace.
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the normal character to the display */
|
||||
|
||||
else
|
||||
{
|
||||
cle_putch(cle, cle->line[column]);
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn the cursor back on */
|
||||
|
||||
cle_cursoron(cle);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_insertch
|
||||
*
|
||||
* Description:
|
||||
* Insert one character into the line buffer
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void cle_insertch(FAR struct cle_s *cle, char ch)
|
||||
{
|
||||
vivdbg("curpos=%ld ch=%c[%02x]\n", cle->curpos, isprint(ch) ? ch : '.', ch);
|
||||
|
||||
/* Make space in the buffer for the new character */
|
||||
|
||||
if (cle_opentext(cle, cle->curpos, 1))
|
||||
{
|
||||
/* Add the new character to the buffer */
|
||||
|
||||
cle->line[cle->curpos++] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle_editloop
|
||||
*
|
||||
* Description:
|
||||
* Command line editor loop
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int cle_editloop(FAR struct cle_s *cle)
|
||||
{
|
||||
/* Loop while we are in command mode */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int ch;
|
||||
|
||||
/* Make sure that the display reflects the current state */
|
||||
|
||||
cle_showtext(cle);
|
||||
cle_setcursor(cle, cle->curpos);
|
||||
|
||||
/* Get the next character from the input */
|
||||
|
||||
ch = cle_getch(cle);
|
||||
if (ch < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Then handle the character. */
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case KEY_BEGINLINE: /* Move cursor to start of current line */
|
||||
{
|
||||
cle->curpos = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_LEFT: /* Move the cursor left 1 character */
|
||||
{
|
||||
if (cle->curpos > 0)
|
||||
{
|
||||
cle->curpos--;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLE_BEL(cle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_DEL: /* Delete 1 character at the cursor */
|
||||
case ASCII_DEL:
|
||||
{
|
||||
if (cle->curpos < cle->nchars)
|
||||
{
|
||||
cle_closetext(cle, cle->curpos, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLE_BEL(cle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_ENDLINE: /* Move cursor to end of current line */
|
||||
{
|
||||
if (cle->nchars > 0)
|
||||
{
|
||||
cle->curpos = cle->nchars - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLE_BEL(cle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_RIGHT: /* Move the cursor right one character */
|
||||
{
|
||||
if (cle->curpos < cle->nchars)
|
||||
{
|
||||
cle->curpos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLE_BEL(cle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_DELLEFT: /* Delete 1 character before the cursor */
|
||||
//case ASCII_BS:
|
||||
{
|
||||
if (cle->curpos > 0)
|
||||
{
|
||||
cle_closetext(cle, --cle->curpos, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLE_BEL(cle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_DELEOL: /* Delete to the end of the line */
|
||||
{
|
||||
cle->nchars = (cle->nchars > 0 ? cle->curpos + 1 : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_DELLINE: /* Delete to the end of the line */
|
||||
{
|
||||
cle->nchars = 0;
|
||||
cle->curpos = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_QUOTE: /* Quoted character follows */
|
||||
{
|
||||
ch = cle_getch(cle);
|
||||
if (ch < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Insert the next character unconditionally */
|
||||
|
||||
cle_insertch(cle, ch);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Newline terminates editing */
|
||||
|
||||
#if defined(CONFIG_EOL_IS_CR)
|
||||
case '\r': /* CR terminates line */
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
break;
|
||||
|
||||
#elif defined(CONFIG_EOL_IS_BOTH_CRLF)
|
||||
case '\r': /* Wait for the LF */
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EOL_IS_LF) || defined(CONFIG_EOL_IS_BOTH_CRLF)
|
||||
case '\n': /* LF terminates line */
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EOL_IS_EITHER_CRLF
|
||||
case '\r': /* Ether CR or LF terminates line */
|
||||
case '\n':
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
/* Text to insert or unimplemented/invalid keypresses */
|
||||
|
||||
default:
|
||||
{
|
||||
/* Ignore all control characters except for tab and newline */
|
||||
|
||||
if (!iscntrl(ch) || ch == '\t')
|
||||
{
|
||||
/* Insert the filtered character into the buffer */
|
||||
|
||||
cle_insertch(cle, ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLE_BEL(cle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Command line processing
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cle
|
||||
*
|
||||
* Description:
|
||||
* EMACS-like command line editor. This is actually more like readline
|
||||
* than is the NuttX readline!
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int cle(FAR char *line, uint16_t linelen, FILE *instream, FILE *outstream)
|
||||
{
|
||||
FAR struct cle_s cle;
|
||||
uint16_t column;
|
||||
int ret;
|
||||
|
||||
/* Initialize the cle state structure */
|
||||
|
||||
cle.linelen = linelen;
|
||||
cle.line = line;
|
||||
|
||||
/* REVISIT: Non-standard, non-portable */
|
||||
|
||||
cle.infd = instream->fs_fd;
|
||||
cle.outfd = outstream->fs_fd;
|
||||
|
||||
/* Get the current cursor position */
|
||||
|
||||
ret = cle_getcursor(&cle, &cle.row, &column);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Turn the column number into an offset */
|
||||
|
||||
if (column < 1)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cle.coloffs = column - 1;
|
||||
|
||||
/* The editor loop */
|
||||
|
||||
return cle_editloop(&cle);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue