kopia lustrzana https://github.com/Hamlib/Hamlib
Merge branch 'readline'
Merging branch 'readline' into master due to no complaints or other feedback. Adds Readline capability for the command prompts in rigctl and rotctl.Hamlib-3.0
commit
61ce272911
1
INSTALL
1
INSTALL
|
@ -251,6 +251,7 @@ enabled with options beginning with '--with-'. At this time these options
|
|||
are:
|
||||
|
||||
--with-xml-support build rigmem with XML support [default=no]
|
||||
--without-readline disable readline in rigctl/rotctl [default=yes]
|
||||
--without-cxx-binding do not build C++ binding and demo [default=yes]
|
||||
--with-perl-binding build perl binding and demo [default=no]
|
||||
--with-perl-inc directory containing perl includes
|
||||
|
|
4
NEWS
4
NEWS
|
@ -27,6 +27,10 @@ Version 3.0
|
|||
* IC-PCR1500/2500 default write_delay to 0, IC-746/756, IC-PCR8500
|
||||
fixes, pcr.c, pcr1500.c: Add DSP support. TNX Paul, KE7ZZ
|
||||
* WinRadio G313 updates. TNX Julian Campbel
|
||||
* Readline editing and history support added to rigctl interactive
|
||||
mode. Implement options for reading and writing history file.
|
||||
* Readline editing and history support added to rotctl interactive
|
||||
mode. Implement options for reading and writing history file.
|
||||
|
||||
Version 1.2.15.3
|
||||
2012-11-01
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Hamlib - (C) Frank Singleton 2000 (vk3fcs@ix.netcom.com)
|
||||
(C) Stephane Fillod 2000-2011
|
||||
(C) The Hamlib Group 2000-2012
|
||||
(C) The Hamlib Group 2000-2013
|
||||
|
||||
Why does Hamlib need beta-testers?
|
||||
==================================
|
||||
|
@ -86,6 +86,7 @@ Optional, but highly recommended for a complete build:
|
|||
* libxml2 devel # xml2-config --version
|
||||
* libgd2 devel # gdlib-config --version
|
||||
* libusb devel # libusb-config --version (not 1.0.0!)
|
||||
* libreadline devel # ver 5.2 or newer
|
||||
* Git for connection to hamlib.git.sourceforge.net
|
||||
|
||||
N.B The libusb package is required for building most of the 'kit' backend.
|
||||
|
@ -315,4 +316,3 @@ Needless to say, patches are also very welcome (see README.developer). :-)
|
|||
|
||||
|
||||
Stephane - F8CFE and The Hamlib Group
|
||||
|
||||
|
|
|
@ -252,6 +252,7 @@ Optional, but highly recommended:
|
|||
* libxml2 devel # xml2-config --version
|
||||
* libgd2 devel # gdlib-config --version
|
||||
* libusb devel # libusb-config --version (not 1.0.0!)
|
||||
* libreadline devel # ver 5.2 or newer
|
||||
|
||||
N.B.: The libusb package is required for building most of the 'kit' backend.
|
||||
The older version is needed, not 1.0.0 or higher. Debian and derivatives
|
||||
|
|
25
configure.ac
25
configure.ac
|
@ -112,7 +112,7 @@ AC_CHECK_HEADERS([errno.h fcntl.h getopt.h limits.h locale.h malloc.h \
|
|||
netdb.h sgtty.h stddef.h termio.h termios.h values.h ws2tcpip.h \
|
||||
arpa/inet.h dev/ppbus/ppbconf.hdev/ppbus/ppi.h \
|
||||
linux/hidraw.h linux/ioctl.h linux/parport.h linux/ppdev.h netinet/in.h \
|
||||
sys/ioccom.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h])
|
||||
sys/ioccom.h sys/ioctl.h sys/param.h sys/socket.h sys/stat.h sys/time.h])
|
||||
|
||||
|
||||
## ------------------------------------ ##
|
||||
|
@ -356,6 +356,28 @@ AC_SUBST([LIBXML2_LIBS])
|
|||
AC_SUBST([LIBXML2_CFLAGS])
|
||||
|
||||
|
||||
dnl Check if readline support in rigctl/rotctl is wanted
|
||||
AC_MSG_CHECKING([whether to use readline in rigctl/rotctl])
|
||||
AC_ARG_WITH([readline],
|
||||
[AS_HELP_STRING([--without-readline],
|
||||
[disable readline in rigctl/rotctl @<:@default=yes@:>@])],
|
||||
[cf_with_readline_support=no],
|
||||
[cf_with_readline_support=yes]
|
||||
)
|
||||
|
||||
AC_MSG_RESULT([$cf_with_readline_support])
|
||||
|
||||
AS_IF([test x"$cf_with_readline_support" != "xno"], [
|
||||
# macros/ax_lib_readline.m4
|
||||
AX_LIB_READLINE
|
||||
])
|
||||
|
||||
AS_IF([test x"$ax_cv_lib_readline" = "xno"], [
|
||||
AC_MSG_WARN([readline support not found, using internal input handling.])
|
||||
cf_with_readline_support=no
|
||||
])
|
||||
|
||||
|
||||
dnl Check if libgd-dev is installed, so we can enable rigmatrix
|
||||
AC_MSG_CHECKING([whether to build HTML rig feature matrix])
|
||||
AC_ARG_ENABLE([html-matrix],
|
||||
|
@ -701,6 +723,7 @@ echo \
|
|||
With TCL binding ${build_tcl}
|
||||
With rigmem XML support ${cf_with_xml_support}
|
||||
With included ltdl ${with_included_ltdl}
|
||||
With Readline support ${cf_with_readline_support}
|
||||
|
||||
Enable HTML rig feature matrix ${cf_enable_html_matrix}
|
||||
Enable WinRadio ${cf_with_winradio}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_lib_readline.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_LIB_READLINE
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Searches for a readline compatible library. If found, defines
|
||||
# `HAVE_LIBREADLINE'. If the found library has the `add_history' function,
|
||||
# sets also `HAVE_READLINE_HISTORY'. Also checks for the locations of the
|
||||
# necessary include files and sets `HAVE_READLINE_H' or
|
||||
# `HAVE_READLINE_READLINE_H' and `HAVE_READLINE_HISTORY_H' or
|
||||
# 'HAVE_HISTORY_H' if the corresponding include files exists.
|
||||
#
|
||||
# The libraries that may be readline compatible are `libedit',
|
||||
# `libeditline' and `libreadline'. Sometimes we need to link a termcap
|
||||
# library for readline to work, this macro tests these cases too by trying
|
||||
# to link with `libtermcap', `libcurses' or `libncurses' before giving up.
|
||||
#
|
||||
# Here is an example of how to use the information provided by this macro
|
||||
# to perform the necessary includes or declarations in a C file:
|
||||
#
|
||||
# #ifdef HAVE_LIBREADLINE
|
||||
# # if defined(HAVE_READLINE_READLINE_H)
|
||||
# # include <readline/readline.h>
|
||||
# # elif defined(HAVE_READLINE_H)
|
||||
# # include <readline.h>
|
||||
# # else /* !defined(HAVE_READLINE_H) */
|
||||
# extern char *readline ();
|
||||
# # endif /* !defined(HAVE_READLINE_H) */
|
||||
# char *cmdline = NULL;
|
||||
# #else /* !defined(HAVE_READLINE_READLINE_H) */
|
||||
# /* no readline */
|
||||
# #endif /* HAVE_LIBREADLINE */
|
||||
#
|
||||
# #ifdef HAVE_READLINE_HISTORY
|
||||
# # if defined(HAVE_READLINE_HISTORY_H)
|
||||
# # include <readline/history.h>
|
||||
# # elif defined(HAVE_HISTORY_H)
|
||||
# # include <history.h>
|
||||
# # else /* !defined(HAVE_HISTORY_H) */
|
||||
# extern void add_history ();
|
||||
# extern int write_history ();
|
||||
# extern int read_history ();
|
||||
# # endif /* defined(HAVE_READLINE_HISTORY_H) */
|
||||
# /* no history */
|
||||
# #endif /* HAVE_READLINE_HISTORY */
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Ville Laurikari <vl@iki.fi>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 6
|
||||
|
||||
AU_ALIAS([VL_LIB_READLINE], [AX_LIB_READLINE])
|
||||
AC_DEFUN([AX_LIB_READLINE], [
|
||||
AC_CACHE_CHECK([for a readline compatible library],
|
||||
ax_cv_lib_readline, [
|
||||
ORIG_LIBS="$LIBS"
|
||||
for readline_lib in readline edit editline; do
|
||||
for termcap_lib in "" termcap curses ncurses; do
|
||||
if test -z "$termcap_lib"; then
|
||||
TRY_LIB="-l$readline_lib"
|
||||
else
|
||||
TRY_LIB="-l$readline_lib -l$termcap_lib"
|
||||
fi
|
||||
LIBS="$ORIG_LIBS $TRY_LIB"
|
||||
AC_TRY_LINK_FUNC(readline, ax_cv_lib_readline="$TRY_LIB")
|
||||
if test -n "$ax_cv_lib_readline"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "$ax_cv_lib_readline"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -z "$ax_cv_lib_readline"; then
|
||||
ax_cv_lib_readline="no"
|
||||
fi
|
||||
LIBS="$ORIG_LIBS"
|
||||
])
|
||||
|
||||
if test "$ax_cv_lib_readline" != "no"; then
|
||||
LIBS="$LIBS $ax_cv_lib_readline"
|
||||
AC_DEFINE(HAVE_LIBREADLINE, 1,
|
||||
[Define if you have a readline compatible library])
|
||||
AC_CHECK_HEADERS(readline.h readline/readline.h)
|
||||
AC_CACHE_CHECK([whether readline supports history],
|
||||
ax_cv_lib_readline_history, [
|
||||
ax_cv_lib_readline_history="no"
|
||||
AC_TRY_LINK_FUNC(add_history, ax_cv_lib_readline_history="yes")
|
||||
])
|
||||
if test "$ax_cv_lib_readline_history" = "yes"; then
|
||||
AC_DEFINE(HAVE_READLINE_HISTORY, 1,
|
||||
[Define if your readline library has \`add_history'])
|
||||
AC_CHECK_HEADERS(history.h readline/history.h)
|
||||
fi
|
||||
fi
|
||||
])dnl
|
|
@ -2,7 +2,7 @@
|
|||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH RIGCTL "1" "January 23, 2013" "Hamlib" "Radio Control Program"
|
||||
.TH RIGCTL "1" "February 20, 2013" "Hamlib" "Radio Control Program"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
|
@ -31,14 +31,14 @@ interactive mode if none are provided on the command line.
|
|||
Keep in mind that \fBHamlib\fP is BETA level software.
|
||||
While a lot of backend libraries lack complete rig support, the basic functions
|
||||
are usually well supported. The API may change without publicized notice,
|
||||
while an advancement of the minor version (e.g. 1.1.x to 1.2.x) indicates such
|
||||
while an advancement of the major version (e.g. 1.x to 3.x) indicates such
|
||||
a change.
|
||||
.PP
|
||||
Please report bugs and provide feedback at the e-mail address given in the
|
||||
REPORTING BUGS section. Patches and code enhancements are also welcome.
|
||||
.SH OPTIONS
|
||||
This program follows the usual GNU command line syntax, with long
|
||||
options starting with two dashes (`-').
|
||||
options starting with two dashes ('-').
|
||||
.PP
|
||||
Here is a summary of the supported options:
|
||||
.TP
|
||||
|
@ -120,7 +120,27 @@ Dump capabilities for the radio defined with -m above and exit.
|
|||
.TP
|
||||
.B \-o, --vfo
|
||||
Set vfo mode, requiring an extra VFO argument in front of each appropriate
|
||||
command. Otherwise, VFO_CURR is assumed when this option is not set.
|
||||
command. Otherwise, 'currVFO' is assumed when this option is not set.
|
||||
.TP
|
||||
.B \-i, --read-history
|
||||
Read previously saved command and argument history from a file
|
||||
(default '~/.rigctl_history') for the current session. Available when
|
||||
\fBrigctl\fP is built with Readline support (see READLINE below).
|
||||
.sp
|
||||
\fBN.B.\fP To read a history file stored in another directory, set the
|
||||
RIGCTL_HIST_DIR environment variable, e.g. 'RIGCTL_HIST_DIR=~/tmp rigctl -i'.
|
||||
When RIGCTL_HIST_DIR is not set, the value of HOME is used.
|
||||
.TP
|
||||
.B \-I, --save-history
|
||||
Write current session and previous session(s), if -i option is given, command and
|
||||
argument history to a file (default '~/.rigctl_history') at the end of the current
|
||||
session. Complete commands with arguments are saved as a single line to be
|
||||
recalled and used or edited. Available when \fBrigctl\fP is built with Readline
|
||||
support (see READLINE below).
|
||||
.sp
|
||||
\fBN.B.\fP To write a history file in another directory, set the RIGCTL_HIST_DIR
|
||||
environment variable, e.g. 'RIGCTL_HIST_DIR=~/tmp rigctl -I'. When RIGCTL_HIST_DIR
|
||||
is not set, the value of HOME is used.
|
||||
.TP
|
||||
.B \-v, --verbose
|
||||
Set verbose mode, cumulative (see DIAGNOSTICS below).
|
||||
|
@ -142,7 +162,10 @@ the operation will fail with a \fBHamlib\fP error code.
|
|||
Commands can be entered either as a single char, or as a long command name.
|
||||
Basically, the commands do not take a dash in front of them on the command
|
||||
line, as the options do. They may be typed in when in interactive mode
|
||||
or provided as argument(s) in command line interface mode.
|
||||
or provided as argument(s) in command line interface mode. In interactive
|
||||
mode commands and their arguments may be entered on a single line:
|
||||
.sp
|
||||
Rig command: M LSB 2400
|
||||
.PP
|
||||
Since most of the \fBHamlib\fP operations have a \fIset\fP and a \fIget\fP
|
||||
method, an upper case letter will be used for \fIset\fP method whereas the
|
||||
|
@ -150,7 +173,7 @@ corresponding lower case letter refers to the \fIget\fP method. Each operation
|
|||
also has a long name; in interactive mode, prepend a backslash to enter a long
|
||||
command name.
|
||||
.sp
|
||||
Example: Use "\\dump_caps" to see what this radio can do.
|
||||
Example: Use '\\dump_caps' to see what this radio and backend support.
|
||||
.PP
|
||||
Please note that the backend for the radio to be controlled, or the radio
|
||||
itself may not support some commands. In that case, the operation will fail
|
||||
|
@ -509,6 +532,45 @@ Connect to a running \fBrigctld\fP with rig model 2 ("NET rigctl") on the
|
|||
local host and specifying the TCP port, setting frequency and mode:
|
||||
.sp
|
||||
$ rigctl -m 2 -r localhost:4532 F 7253500 M LSB 0
|
||||
.SH READLINE
|
||||
If Readline library development files are found at configure time, \fBrigctl\fP
|
||||
will be conditonally built with Readline support for command and argument entry.
|
||||
Readline command key bindings are at their defaults as described in the Readline
|
||||
manual (\fIhttp://cnswww.cns.cwru.edu/php/chet/readline/rluserman.html\fP)
|
||||
although \fBrigctl\fP sets the name 'rigctl' which can be used in Conditional
|
||||
Init Constructs in the Readline Init File ('~/.inputrc' by default) for custom
|
||||
keybindings unique to \fBrigctl\fP.
|
||||
|
||||
Command history is available with Readline support as described in the Readline
|
||||
History manual
|
||||
(\fIhttp://cnswww.cns.cwru.edu/php/chet/readline/history.html#SEC1\fP). Command
|
||||
and argument strings are stored as single lines even when arguments are prompted
|
||||
for input individually. Commands and arguments are not validated and are stored
|
||||
as typed with values separated by a single space.
|
||||
|
||||
Normally session history is not saved, however, use of either of the
|
||||
\fI-i/--read-history\fP or \fI-I/--save-history\fP options when starting
|
||||
\fBrigctl\fP will cause any previously saved history to be read in and/or the
|
||||
current and any previous session history (assuming the -i and -I options are
|
||||
given together) will be written out when \fBrigctl\fP is closed. Each option is
|
||||
mutually exclusive, i.e. either may be given separately or in combination. This
|
||||
is useful to save a set of commands and then read them later but not write the
|
||||
modified history for a consistent set of test commands in interactive mode, for
|
||||
example.
|
||||
|
||||
History is stored in '~/.rigctl_history' by default although the destination
|
||||
directory may be changed by setting the RIGCTL_HIST_DIR environment variable.
|
||||
When RIGCTL_HIST_DIR is unset, the value of the HOME environment variable is
|
||||
used instead. Only the destination directory may be changed at this time.
|
||||
|
||||
If Readline support is not found at configure time the original internal command
|
||||
handler is used. Readline is not used for \fBrigctl\fP commands entered on the
|
||||
command line regardless if Readline support is built in or not.
|
||||
|
||||
\fBN.B.\fP Readline support is not included in the Windows 32 binary builds
|
||||
supplied by the Hamlib Project. Running \fBrigctl\fP on the Windows 32 platform
|
||||
in the 'cmd' shell does give session command line history, however, it is not
|
||||
saved to disk between sessions.
|
||||
.SH DIAGNOSTICS
|
||||
The \fB-v\fP, \fB--verbose\fP option allows different levels of diagnostics
|
||||
to be output to \fBstderr\fP and correspond to -v for BUG, -vv for ERR,
|
||||
|
|
107
tests/rigctl.c
107
tests/rigctl.c
|
@ -34,9 +34,38 @@
|
|||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
# if defined(HAVE_READLINE_READLINE_H)
|
||||
# include <readline/readline.h>
|
||||
# elif defined(HAVE_READLINE_H) /* !defined(HAVE_READLINE_READLINE_H) */
|
||||
# include <readline.h>
|
||||
# else /* !defined(HAVE_READLINE_H) */
|
||||
extern char *readline ();
|
||||
# endif /* HAVE_READLINE_H */
|
||||
#else
|
||||
/* no readline */
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
# include <sys/stat.h>
|
||||
# define HST_SHRT_OPTS "iI"
|
||||
# if defined(HAVE_READLINE_HISTORY_H)
|
||||
# include <readline/history.h>
|
||||
# elif defined(HAVE_HISTORY_H)
|
||||
# include <history.h>
|
||||
# else /* !defined(HAVE_HISTORY_H) */
|
||||
extern void add_history ();
|
||||
extern int write_history ();
|
||||
extern int read_history ();
|
||||
# endif /* defined(HAVE_READLINE_HISTORY_H) */
|
||||
#else
|
||||
/* no history */
|
||||
#define HST_SHRT_OPTS ""
|
||||
#endif /* HAVE_READLINE_HISTORY */
|
||||
|
||||
|
||||
#include <hamlib/rig.h>
|
||||
#include "misc.h"
|
||||
#include "iofunc.h"
|
||||
|
@ -75,6 +104,10 @@ static struct option long_options[] =
|
|||
{"show-conf", 0, 0, 'L'},
|
||||
{"dump-caps", 0, 0, 'u'},
|
||||
{"vfo", 0, 0, 'o'},
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
{"read-history", 0, 0, 'i'},
|
||||
{"save-history", 0, 0, 'I'},
|
||||
#endif
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"version", 0, 0, 'V'},
|
||||
|
@ -83,6 +116,14 @@ static struct option long_options[] =
|
|||
|
||||
#define MAXCONFLEN 128
|
||||
|
||||
/* variable for readline support */
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
static const int have_rl = 1;
|
||||
#else /* no readline */
|
||||
static const int have_rl = 0;
|
||||
#endif
|
||||
|
||||
|
||||
int interactive = 1; /* if no cmd on command line, switch to interactive */
|
||||
int prompt = 1; /* Print prompt in rigctl */
|
||||
int vfo_mode = 0; /* vfo_mode = 0 means target VFO is 'currVFO' */
|
||||
|
@ -100,6 +141,14 @@ int main (int argc, char *argv[])
|
|||
int verbose = 0;
|
||||
int show_conf = 0;
|
||||
int dump_caps_opt = 0;
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
int rd_hist = 0;
|
||||
int sv_hist = 0;
|
||||
const char *hist_dir = NULL;
|
||||
const char hist_file[] = "/.rigctl_history";
|
||||
char *hist_path = NULL;
|
||||
struct stat hist_dir_stat;
|
||||
#endif
|
||||
const char *rig_file=NULL, *ptt_file=NULL, *dcd_file=NULL;
|
||||
ptt_type_t ptt_type = RIG_PTT_NONE;
|
||||
dcd_type_t dcd_type = RIG_DCD_NONE;
|
||||
|
@ -111,7 +160,7 @@ int main (int argc, char *argv[])
|
|||
int c;
|
||||
int option_index = 0;
|
||||
|
||||
c = getopt_long (argc, argv, SHORT_OPTIONS,
|
||||
c = getopt_long (argc, argv, SHORT_OPTIONS HST_SHRT_OPTS,
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
@ -229,6 +278,14 @@ int main (int argc, char *argv[])
|
|||
case 'o':
|
||||
vfo_mode++;
|
||||
break;
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
case 'i':
|
||||
rd_hist++;
|
||||
break;
|
||||
case 'I':
|
||||
sv_hist++;
|
||||
break;
|
||||
#endif
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
@ -327,6 +384,34 @@ int main (int argc, char *argv[])
|
|||
|
||||
exitcode = 0;
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (interactive && prompt && have_rl) {
|
||||
rl_readline_name = "rigctl";
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
using_history(); /* Initialize Readline History */
|
||||
|
||||
if (rd_hist || sv_hist) {
|
||||
if (!(hist_dir = getenv("RIGCTL_HIST_DIR")))
|
||||
hist_dir = getenv("HOME");
|
||||
|
||||
if (((stat(hist_dir, &hist_dir_stat) == -1) && (errno == ENOENT))
|
||||
|| !(S_ISDIR(hist_dir_stat.st_mode))) {
|
||||
fprintf(stderr, "Warning: %s is not a directory!\n", hist_dir);
|
||||
}
|
||||
|
||||
hist_path = (char *)calloc((sizeof(char) * (strlen(hist_dir) + strlen(hist_file) + 1)), sizeof(char));
|
||||
|
||||
strncpy(hist_path, hist_dir, strlen(hist_dir));
|
||||
strncat(hist_path, hist_file, strlen(hist_file));
|
||||
}
|
||||
|
||||
if (rd_hist && hist_path)
|
||||
if (read_history(hist_path) == ENOENT)
|
||||
fprintf(stderr, "Warning: Could not read history from %s\n", hist_path);
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
do {
|
||||
retcode = rigctl_parse(my_rig, stdin, stdout, argv, argc);
|
||||
if (retcode == 2)
|
||||
|
@ -334,6 +419,20 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
while (retcode == 0 || retcode == 2);
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (interactive && prompt && have_rl) {
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (sv_hist && hist_path)
|
||||
if (write_history(hist_path) == ENOENT)
|
||||
fprintf(stderr, "\nWarning: Could not write history to %s\n", hist_path);
|
||||
|
||||
if ((rd_hist || sv_hist) && hist_path) {
|
||||
free(hist_path);
|
||||
hist_path = (char *)NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
rig_close(my_rig); /* close port */
|
||||
rig_cleanup(my_rig); /* if you care about memory */
|
||||
|
||||
|
@ -362,6 +461,10 @@ void usage(void)
|
|||
" -l, --list list all model numbers and exit\n"
|
||||
" -u, --dump-caps dump capabilities and exit\n"
|
||||
" -o, --vfo do not default to VFO_CURR, require extra vfo arg\n"
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
" -i, --read-history read prior interactive session history\n"
|
||||
" -I, --save-history save current interactive session history\n"
|
||||
#endif
|
||||
" -v, --verbose set verbose mode, cumulative\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n\n"
|
||||
|
|
|
@ -36,7 +36,31 @@
|
|||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <getopt.h>
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
# if defined(HAVE_READLINE_READLINE_H)
|
||||
# include <readline/readline.h>
|
||||
# elif defined(HAVE_READLINE_H) /* !defined(HAVE_READLINE_READLINE_H) */
|
||||
# include <readline.h>
|
||||
# else /* !defined(HAVE_READLINE_H) */
|
||||
extern char *readline ();
|
||||
# endif /* HAVE_READLINE_H */
|
||||
#else
|
||||
/* no readline */
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
# if defined(HAVE_READLINE_HISTORY_H)
|
||||
# include <readline/history.h>
|
||||
# elif defined(HAVE_HISTORY_H)
|
||||
# include <history.h>
|
||||
# else /* !defined(HAVE_HISTORY_H) */
|
||||
extern void add_history ();
|
||||
extern int write_history ();
|
||||
extern int read_history ();
|
||||
# endif /* defined(HAVE_READLINE_HISTORY_H) */
|
||||
/* no history */
|
||||
#endif /* HAVE_READLINE_HISTORY */
|
||||
|
||||
|
||||
#include <hamlib/rig.h>
|
||||
#include "misc.h"
|
||||
|
@ -73,6 +97,21 @@ static pthread_mutex_t rig_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||
#define ARG_IN (ARG_IN1|ARG_IN2|ARG_IN3|ARG_IN4)
|
||||
#define ARG_OUT (ARG_OUT1|ARG_OUT2|ARG_OUT3|ARG_OUT4)
|
||||
|
||||
/* variables for readline support */
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
static char *input_line = (char *)NULL;
|
||||
static char *result = (char *)NULL;
|
||||
static char *parsed_input[sizeof(char) * 5];
|
||||
static const int have_rl = 1;
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
static char *rp_hist_buf = (char *)NULL;
|
||||
#endif
|
||||
|
||||
#else /* no readline */
|
||||
static const int have_rl = 0;
|
||||
#endif
|
||||
|
||||
struct test_table {
|
||||
unsigned char cmd;
|
||||
const char *name;
|
||||
|
@ -308,6 +347,35 @@ void hash_delete_all() {
|
|||
}
|
||||
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
/* Frees allocated memory and sets pointers to NULL before calling readline
|
||||
* and then parses the input into space separated tokens.
|
||||
*/
|
||||
static void rp_getline(const char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* free allocated memory and set pointers to NULL */
|
||||
if (input_line) {
|
||||
free(input_line);
|
||||
input_line = (char *)NULL;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result = (char *)NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
parsed_input[i] = NULL;
|
||||
|
||||
/* Action! Returns typed line with newline stripped. */
|
||||
input_line = readline(s);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* TODO: use Lex?
|
||||
*/
|
||||
|
@ -348,6 +416,7 @@ static int scanfc(FILE *fin, const char *format, void *p)
|
|||
|
||||
#define MAXARGSZ 127
|
||||
|
||||
|
||||
extern int interactive;
|
||||
extern int prompt;
|
||||
extern int vfo_mode;
|
||||
|
@ -359,194 +428,603 @@ int rigctl_parse(RIG *my_rig, FILE *fin, FILE *fout, char *argv[], int argc)
|
|||
{
|
||||
int retcode; /* generic return code from functions */
|
||||
unsigned char cmd;
|
||||
struct test_table *cmd_entry;
|
||||
struct test_table *cmd_entry = NULL;
|
||||
|
||||
char arg1[MAXARGSZ+1], *p1;
|
||||
char arg2[MAXARGSZ+1], *p2;
|
||||
char arg3[MAXARGSZ+1], *p3;
|
||||
char arg1[MAXARGSZ+1], *p1 = NULL;
|
||||
char arg2[MAXARGSZ+1], *p2 = NULL;
|
||||
char arg3[MAXARGSZ+1], *p3 = NULL;
|
||||
static int last_was_ret = 1;
|
||||
vfo_t vfo = RIG_VFO_CURR;
|
||||
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "\nRig command: ");
|
||||
/* cmd, internal, rigctld */
|
||||
if (!(interactive && prompt && have_rl)) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "\nRig command: ");
|
||||
|
||||
do {
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
|
||||
/* Extended response protocol requested with leading '+' on command
|
||||
* string--rigctld only!
|
||||
*/
|
||||
if (cmd == '+' && !prompt) {
|
||||
ext_resp = 1;
|
||||
do {
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
} else if (cmd == '+' && prompt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd != '\\' && cmd != '_' && cmd != '#' && ispunct(cmd) && !prompt) {
|
||||
ext_resp = 1;
|
||||
resp_sep = cmd;
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
} else if (cmd != '\\' && cmd != '?' && cmd != '_' && cmd != '#' && ispunct(cmd) && prompt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* command by name */
|
||||
if (cmd == '\\') {
|
||||
unsigned char cmd_name[MAXNAMSIZ], *pcmd = cmd_name;
|
||||
int c_len = MAXNAMSIZ;
|
||||
|
||||
if (scanfc(fin, "%c", pcmd) < 1)
|
||||
return -1;
|
||||
|
||||
while(c_len-- && (isalnum(*pcmd) || *pcmd == '_' ))
|
||||
if (scanfc(fin, "%c", ++pcmd) < 1)
|
||||
/* Extended response protocol requested with leading '+' on command
|
||||
* string--rigctld only!
|
||||
*/
|
||||
if (cmd == '+' && !prompt) {
|
||||
ext_resp = 1;
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
|
||||
*pcmd = '\0';
|
||||
cmd = parse_arg((char *)cmd_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd == 0x0a || cmd == 0x0d) {
|
||||
if (last_was_ret) {
|
||||
if (prompt) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fprintf_flush(fout, "\nRig command: ");
|
||||
}
|
||||
} else if (cmd == '+' && prompt) {
|
||||
return 0;
|
||||
}
|
||||
last_was_ret = 1;
|
||||
|
||||
if (cmd != '\\' && cmd != '_' && cmd != '#' && ispunct(cmd) && !prompt) {
|
||||
ext_resp = 1;
|
||||
resp_sep = cmd;
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
} else if (cmd != '\\' && cmd != '?' && cmd != '_' && cmd != '#' && ispunct(cmd) && prompt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* command by name */
|
||||
if (cmd == '\\') {
|
||||
unsigned char cmd_name[MAXNAMSIZ], *pcmd = cmd_name;
|
||||
int c_len = MAXNAMSIZ;
|
||||
|
||||
if (scanfc(fin, "%c", pcmd) < 1)
|
||||
return -1;
|
||||
|
||||
while(c_len-- && (isalnum(*pcmd) || *pcmd == '_' ))
|
||||
if (scanfc(fin, "%c", ++pcmd) < 1)
|
||||
return -1;
|
||||
|
||||
*pcmd = '\0';
|
||||
cmd = parse_arg((char *)cmd_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd == 0x0a || cmd == 0x0d) {
|
||||
if (last_was_ret) {
|
||||
if (prompt) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fprintf_flush(fout, "\nRig command: ");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
last_was_ret = 1;
|
||||
}
|
||||
} while (cmd == 0x0a || cmd == 0x0d);
|
||||
|
||||
last_was_ret = 0;
|
||||
|
||||
/* comment line */
|
||||
if (cmd == '#') {
|
||||
while( cmd != '\n' && cmd != '\r')
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
} while (cmd == 0x0a || cmd == 0x0d);
|
||||
if (cmd == 'Q' || cmd == 'q')
|
||||
return 1;
|
||||
if (cmd == '?') {
|
||||
usage_rig(fout);
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* parse rest of command line */
|
||||
if (optind >= argc)
|
||||
return 1;
|
||||
if (argv[optind][1] == '\0')
|
||||
cmd = argv[optind][0];
|
||||
else
|
||||
cmd = parse_arg(argv[optind]);
|
||||
optind++;
|
||||
}
|
||||
|
||||
last_was_ret = 0;
|
||||
|
||||
/* comment line */
|
||||
if (cmd == '#') {
|
||||
while( cmd != '\n' && cmd != '\r')
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
cmd_entry = find_cmd_entry(cmd);
|
||||
if (!cmd_entry) {
|
||||
fprintf(stderr, "Command '%c' not found!\n", cmd);
|
||||
return 0;
|
||||
}
|
||||
if (cmd == 'Q' || cmd == 'q')
|
||||
return 1;
|
||||
if (cmd == '?') {
|
||||
|
||||
if (!(cmd_entry->flags & ARG_NOVFO) && vfo_mode) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "VFO: ");
|
||||
if (scanfc(fin, "%s", arg1) < 1)
|
||||
return -1;
|
||||
vfo = rig_parse_vfo(arg1);
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
vfo = rig_parse_vfo(argv[optind++]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((cmd_entry->flags & ARG_IN_LINE) &&
|
||||
(cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
char *nl;
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
if (arg1[0] == 0xa)
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
nl = strchr(arg1, 0xa);
|
||||
if (nl) *nl = '\0'; /* chomp */
|
||||
p1 = arg1[0] == ' ' ? arg1 + 1 : arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
}
|
||||
} else
|
||||
if ((cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (scanfc(fin, "%s", arg1) < 1)
|
||||
return -1;
|
||||
p1 = arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN2) && cmd_entry->arg2) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg2);
|
||||
if (scanfc(fin, "%s", arg2) < 1)
|
||||
return -1;
|
||||
p2 = arg2;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p2 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN3) && cmd_entry->arg3) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg3);
|
||||
if (scanfc(fin, "%s", arg3) < 1)
|
||||
return -1;
|
||||
p3 = arg3;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p3 = argv[optind++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
|
||||
if (interactive && prompt && have_rl) {
|
||||
int j, x;
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
/* Minimum space for 32+1+32+1+128+1+128+1+128+1 = 453 chars, so
|
||||
* allocate 512 chars cleared to zero for safety.
|
||||
*/
|
||||
rp_hist_buf = (char *)calloc(512, sizeof(char));
|
||||
#endif
|
||||
|
||||
rl_instream = fin;
|
||||
rl_outstream = fout;
|
||||
|
||||
rp_getline("\nRig command: ");
|
||||
|
||||
/* EOF (Ctl-D) received on empty input line, bail out gracefully. */
|
||||
if (!input_line) {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Q or q to quit */
|
||||
if (!(strncasecmp(input_line, "q", 1)))
|
||||
return 1;
|
||||
|
||||
/* '?' for help */
|
||||
if (!(strncmp(input_line, "?", 1))) {
|
||||
usage_rig(fout);
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* parse rest of command line */
|
||||
if (optind >= argc)
|
||||
|
||||
/* '#' for comment */
|
||||
if (!(strncmp(input_line, "#", 1)))
|
||||
return 0;
|
||||
|
||||
/* Blank line entered */
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_BUG, "%s: input_line: %s\n", __func__, input_line);
|
||||
|
||||
/* Split input_line on any number of spaces to get the command token
|
||||
* Tabs are intercepted by readline for completion and a newline
|
||||
* causes readline to return the typed text. If more than one
|
||||
* argument is given, it will be parsed out later.
|
||||
*/
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
/* parsed_input stores pointers into input_line where the token strings
|
||||
* start.
|
||||
*/
|
||||
if (result) {
|
||||
parsed_input[0] = result;
|
||||
} else {
|
||||
/* Oops! Invoke GDB!! */
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
if (argv[optind][1] == '\0')
|
||||
cmd = argv[optind][0];
|
||||
else
|
||||
cmd = parse_arg(argv[optind]);
|
||||
optind++;
|
||||
}
|
||||
|
||||
cmd_entry = find_cmd_entry(cmd);
|
||||
if (!cmd_entry) {
|
||||
fprintf(stderr, "Command '%c' not found!\n", cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p1 = p2 = p3 = NULL;
|
||||
if (!(cmd_entry->flags & ARG_NOVFO) && vfo_mode) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "VFO: ");
|
||||
if (scanfc(fin, "%s", arg1) < 1)
|
||||
return -1;
|
||||
vfo = rig_parse_vfo(arg1);
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
vfo = rig_parse_vfo(argv[optind++]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((cmd_entry->flags & ARG_IN_LINE) &&
|
||||
(cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
char *nl;
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
if (arg1[0] == 0xa)
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
nl = strchr(arg1, 0xa);
|
||||
if (nl) *nl = '\0'; /* chomp */
|
||||
p1 = arg1[0] == ' ' ? arg1 + 1 : arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
/* At this point parsed_input contains the typed text of the command
|
||||
* with surrounding space characters removed. If Readline History is
|
||||
* available, copy the command string into a history buffer.
|
||||
*/
|
||||
|
||||
/* Single character command */
|
||||
if ((strlen(parsed_input[0]) == 1) && (*parsed_input[0] != '\\')) {
|
||||
cmd = *parsed_input[0];
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
/* Store what is typed, not validated, for history. */
|
||||
if (rp_hist_buf)
|
||||
strncpy(rp_hist_buf, parsed_input[0], 1);
|
||||
#endif
|
||||
}
|
||||
} else
|
||||
if ((cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (scanfc(fin, "%s", arg1) < 1)
|
||||
return -1;
|
||||
/* Test the command token, parsed_input[0] */
|
||||
else if ((*parsed_input[0] == '\\') && (strlen(parsed_input[0]) > 1)) {
|
||||
char cmd_name[MAXNAMSIZ];
|
||||
|
||||
/* if there is no terminating '\0' character in the source string,
|
||||
* srncpy() doesn't add one even if the supplied length is less
|
||||
* than the destination array. Truncate the source string here.
|
||||
*/
|
||||
if (strlen(parsed_input[0] + 1) >= MAXNAMSIZ)
|
||||
*(parsed_input[0] + MAXNAMSIZ) = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf)
|
||||
strncpy(rp_hist_buf, parsed_input[0], MAXNAMSIZ);
|
||||
#endif
|
||||
/* The starting position of the source string is the first
|
||||
* character past the initial '\'. Using MAXNAMSIZ for the
|
||||
* length leaves enough space for the '\0' string terminator in the
|
||||
* cmd_name array.
|
||||
*/
|
||||
strncpy(cmd_name, parsed_input[0] + 1, MAXNAMSIZ);
|
||||
|
||||
/* Sanity check as valid multiple character commands consist of
|
||||
* alpha-numeric characters and the underscore ('_') character.
|
||||
*/
|
||||
for (j = 0; cmd_name[j] != '\0'; j++) {
|
||||
if (!(isalnum(cmd_name[j]) || cmd_name[j] == '_')) {
|
||||
fprintf(stderr, "Valid multiple character command names contain alpha-numeric characters plus '_'\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = parse_arg(cmd_name);
|
||||
}
|
||||
/* Single '\' entered, prompt again */
|
||||
else if ((*parsed_input[0] == '\\') && (strlen(parsed_input[0]) == 1)) {
|
||||
return 0;
|
||||
}
|
||||
/* Multiple characters but no leading '\' */
|
||||
else {
|
||||
fprintf(stderr, "Precede multiple character command names with '\\'\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd_entry = find_cmd_entry(cmd);
|
||||
if (!cmd_entry) {
|
||||
if (cmd == '\0')
|
||||
fprintf(stderr, "Command '%s' not found!\n", parsed_input[0]);
|
||||
else
|
||||
fprintf(stderr, "Command '%c' not found!\n", cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If vfo_mode is enabled (-o|--vfo) check if already given
|
||||
* or prompt for it.
|
||||
*/
|
||||
if (!(cmd_entry->flags & ARG_NOVFO) && vfo_mode) {
|
||||
/* Check if VFO was given with command. */
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (result) {
|
||||
x = 1;
|
||||
parsed_input[x] = result;
|
||||
}
|
||||
/* Need to prompt if a VFO string was not given. */
|
||||
else {
|
||||
x = 0;
|
||||
rp_getline("VFO: ");
|
||||
|
||||
if (!input_line) {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Blank line entered */
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the first token of input, the rest, if any, will be
|
||||
* used later.
|
||||
*/
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* VFO name tokens are presently quite short. Truncate excessively
|
||||
* long strings.
|
||||
*/
|
||||
if (strlen(parsed_input[x]) >= MAXNAMSIZ)
|
||||
*(parsed_input[x] + (MAXNAMSIZ - 1)) = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXNAMSIZ);
|
||||
}
|
||||
#endif
|
||||
/* Sanity check, VFO names are alpha only. */
|
||||
for (j = 0; j < MAXNAMSIZ && parsed_input[x][j] != '\0'; j++) {
|
||||
if (!(isalpha(parsed_input[x][j]))) {
|
||||
parsed_input[x][j] = '\0';
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
vfo = rig_parse_vfo(parsed_input[x]);
|
||||
|
||||
if (vfo == RIG_VFO_NONE) {
|
||||
fprintf(stderr, "Warning: VFO '%s' unrecognized, using 'currVFO' instead.\n",
|
||||
parsed_input[x]);
|
||||
vfo = RIG_VFO_CURR;
|
||||
}
|
||||
}
|
||||
|
||||
/* \send_cmd, \send_morse */
|
||||
if ((cmd_entry->flags & ARG_IN_LINE) &&
|
||||
(cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
/* Check for a non-existent delimiter so as to not break up
|
||||
* remaining line into separate tokens (spaces OK).
|
||||
*/
|
||||
result = strtok(NULL, "\0");
|
||||
|
||||
if (vfo_mode && result) {
|
||||
x = 2;
|
||||
parsed_input[x] = result;
|
||||
} else if (result) {
|
||||
x = 1;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg1) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg1);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
/* Blank line entered */
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (input_line)
|
||||
parsed_input[x] = input_line;
|
||||
else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The arg1 array size is MAXARGSZ + 1 so truncate it to fit if larger. */
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg1, parsed_input[x]);
|
||||
p1 = arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN2) && cmd_entry->arg2) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg2);
|
||||
if (scanfc(fin, "%s", arg2) < 1)
|
||||
return -1;
|
||||
|
||||
/* Normal argument parsing. */
|
||||
else if ((cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (vfo_mode && result) {
|
||||
x = 2;
|
||||
parsed_input[x] = result;
|
||||
} else if (result) {
|
||||
x = 1;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg1) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg1);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg1, parsed_input[x]);
|
||||
p1 = arg1;
|
||||
}
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN2) && cmd_entry->arg2) {
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (vfo_mode && result) {
|
||||
x = 3;
|
||||
parsed_input[x] = result;
|
||||
} else if (result) {
|
||||
x = 2;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg2) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg2);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg2, parsed_input[x]);
|
||||
p2 = arg2;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p2 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN3) && cmd_entry->arg3) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg3);
|
||||
if (scanfc(fin, "%s", arg3) < 1)
|
||||
return -1;
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN3) && cmd_entry->arg3) {
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (vfo_mode && result) {
|
||||
x = 4;
|
||||
parsed_input[x] = result;
|
||||
} else if (result) {
|
||||
x = 3;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg3) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg3);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg3, parsed_input[x]);
|
||||
p3 = arg3;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p3 = argv[optind++];
|
||||
}
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
add_history(rp_hist_buf);
|
||||
free(rp_hist_buf);
|
||||
rp_hist_buf = (char *)NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
|
||||
/*
|
||||
* mutex locking needed because rigctld is multithreaded
|
||||
* and hamlib is not MT-safe
|
||||
|
@ -645,6 +1123,8 @@ void usage_rig(FILE *fout)
|
|||
else
|
||||
fprintf(fout, ")%*s", nbspaces, " ");
|
||||
}
|
||||
|
||||
fprintf(fout, "\n\nPrepend long command names with '\\', e.g. '\\dump_state'\n");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH ROTCTL "1" "March 1, 2012" "Hamlib" "Rotator Control Program"
|
||||
.TH ROTCTL "1" "February 22, 2013" "Hamlib" "Rotator Control Program"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
|
@ -29,23 +29,23 @@ interactive mode if none are provided on the command line.
|
|||
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
|
||||
.\" respectively.
|
||||
Keep in mind that \fBHamlib\fP is BETA level software.
|
||||
While a lot of backend libraries lack complete rig support, the basic functions
|
||||
While a lot of backend libraries lack complete rotator support, the basic functions
|
||||
are usually well supported. The API may change without publicized notice,
|
||||
while an advancement of the minor version (e.g. 1.1.x to 1.2.x) indicates such
|
||||
while an advancement of the minor version (e.g. 1.x to 3.x) indicates such
|
||||
a change.
|
||||
.PP
|
||||
Please report bugs and provide feedback at the e-mail address given in the
|
||||
REPORTING BUGS section. Patches and code enhancements are also welcome.
|
||||
.SH OPTIONS
|
||||
This program follows the usual GNU command line syntax, with long
|
||||
options starting with two dashes (`-').
|
||||
options starting with two dashes ('-').
|
||||
|
||||
Here is s summary of the supported options:
|
||||
Here is a summary of the supported options:
|
||||
.TP
|
||||
.B \-m, --model=id
|
||||
Select rotator model number. See model list (use 'rotctl -l').
|
||||
.sp
|
||||
NB: \fBrotctl\fP (or third party software) will use rig model 2
|
||||
NB: \fBrotctl\fP (or third party software) will use rotator model 2
|
||||
for NET rotctl (rotctld).
|
||||
.TP
|
||||
.B \-r, --rot-file=device
|
||||
|
@ -86,6 +86,26 @@ Shift-PageDown, or using the scrollbars of a virtual terminal in X or
|
|||
the cmd window in Windows. The output can be piped to 'more' or 'less',
|
||||
e.g. 'rotctl -l | more'.
|
||||
.TP
|
||||
.B \-i, --read-history
|
||||
Read previously saved command and argument history from a file
|
||||
(default '~/.rotctl_history') for the current session. Available when
|
||||
\fBrotctl\fP is built with Readline support (see READLINE below).
|
||||
.sp
|
||||
\fBN.B.\fP To read a history file stored in another directory, set the
|
||||
ROTCTL_HIST_DIR environment variable, e.g. 'ROTCTL_HIST_DIR=~/tmp rotctl -i'.
|
||||
When ROTCTL_HIST_DIR is not set, the value of HOME is used.
|
||||
.TP
|
||||
.B \-I, --save-history
|
||||
Write current session and previous session(s), if -i option is given, command and
|
||||
argument history to a file (default '~/.rotctl_history') at the end of the current
|
||||
session. Complete commands with arguments are saved as a single line to be
|
||||
recalled and used or edited. Available when \fBrotctl\fP is built with Readline
|
||||
support (see READLINE below).
|
||||
.sp
|
||||
\fBN.B.\fP To write a history file in another directory, set the ROTCTL_HIST_DIR
|
||||
environment variable, e.g. 'ROTCTL_HIST_DIR=~/tmp rotctl -I'. When ROTCTL_HIST_DIR
|
||||
is not set, the value of HOME is used.
|
||||
.TP
|
||||
.B \-v, --verbose
|
||||
Set verbose mode, cumulative (see DIAGNOSTICS below).
|
||||
.TP
|
||||
|
@ -106,7 +126,10 @@ the operation will fail with a \fBHamlib\fP error code.
|
|||
Commands can be entered either as a single char, or as a long command name.
|
||||
Basically, the commands do not take a dash in front of them, as
|
||||
the options do. They may be typed in when in interactive mode
|
||||
or provided as argument(s) in command line interface mode.
|
||||
or provided as argument(s) in command line interface mode. In interactive
|
||||
mode commands and their arguments may be entered on a single line:
|
||||
.sp
|
||||
Rotator command: P 123 45
|
||||
.PP
|
||||
Since most of the \fBHamlib\fP operations have a \fIset\fP and a \fIget\fP
|
||||
method, an upper case letter will be used for \fIset\fP method whereas the
|
||||
|
@ -188,8 +211,8 @@ Both are floating point values. The precision of the returned square is
|
|||
controlled by 'Loc Len' which should be an even numbered integer value between
|
||||
2 and 12.
|
||||
.sp
|
||||
For example, "+L -170.000000 -85.000000 12\\n" returns
|
||||
"Locator: AA55AA00AA00\\n".
|
||||
For example, "L -170.000000 -85.000000 12" returns
|
||||
"Locator: AA55AA00AA00".
|
||||
.TP
|
||||
.B l, loc2lonlat 'Locator'
|
||||
Returns 'Longitude' and 'Latitude' in decimal degrees at the approximate
|
||||
|
@ -198,8 +221,8 @@ variables internally, some rounding error occurs). West longitude is
|
|||
expressed as a negative value. South latitude is expressed as a negative
|
||||
value. Locator can be from 2 to 12 characters in length.
|
||||
.sp
|
||||
For example, "+l AA55AA00AA00\\n" returns "Longitude: -169.999983\\nLatitude:
|
||||
-84.999991\\n".
|
||||
For example, "l AA55AA00AA00" returns "Longitude: -169.999983 Latitude:
|
||||
-84.999991".
|
||||
.TP
|
||||
.B D, dms2dec 'Degrees' 'Minutes' 'Seconds' 'S/W'
|
||||
Returns 'Dec Degrees', a signed floating point value.
|
||||
|
@ -258,6 +281,45 @@ Connect to a running \fBrotctld\fP with rotor model 2 ("NET rotctl") on the
|
|||
local host and specifying the TCP port, and querying the position:
|
||||
.sp
|
||||
$ rotctl -m 2 -r localhost:4533 \\get_pos
|
||||
.SH READLINE
|
||||
If Readline library development files are found at configure time, \fBrotctl\fP
|
||||
will be conditonally built with Readline support for command and argument entry.
|
||||
Readline command key bindings are at their defaults as described in the Readline
|
||||
manual (\fIhttp://cnswww.cns.cwru.edu/php/chet/readline/rluserman.html\fP)
|
||||
although \fBrotctl\fP sets the name 'rotctl' which can be used in Conditional
|
||||
Init Constructs in the Readline Init File ('~/.inputrc' by default) for custom
|
||||
keybindings unique to \fBrotctl\fP.
|
||||
|
||||
Command history is available with Readline support as described in the Readline
|
||||
History manual
|
||||
(\fIhttp://cnswww.cns.cwru.edu/php/chet/readline/history.html#SEC1\fP). Command
|
||||
and argument strings are stored as single lines even when arguments are prompted
|
||||
for input individually. Commands and arguments are not validated and are stored
|
||||
as typed with values separated by a single space.
|
||||
|
||||
Normally session history is not saved, however, use of either of the
|
||||
\fI-i/--read-history\fP or \fI-I/--save-history\fP options when starting
|
||||
\fBrotctl\fP will cause any previously saved history to be read in and/or the
|
||||
current and any previous session history (assuming the -i and -I options are
|
||||
given together) will be written out when \fBrotctl\fP is closed. Each option is
|
||||
mutually exclusive, i.e. either may be given separately or in combination. This
|
||||
is useful to save a set of commands and then read them later but not write the
|
||||
modified history for a consistent set of test commands in interactive mode, for
|
||||
example.
|
||||
|
||||
History is stored in '~/.rotctl_history' by default although the destination
|
||||
directory may be changed by setting the ROTCTL_HIST_DIR environment variable.
|
||||
When ROTCTL_HIST_DIR is unset, the value of the HOME environment variable is
|
||||
used instead. Only the destination directory may be changed at this time.
|
||||
|
||||
If Readline support is not found at configure time the original internal command
|
||||
handler is used. Readline is not used for \fBrotctl\fP commands entered on the
|
||||
command line regardless if Readline support is built in or not.
|
||||
|
||||
\fBN.B.\fP Readline support is not included in the Windows 32 binary builds
|
||||
supplied by the Hamlib Project. Running \fBrotctl\fP on the Windows 32 platform
|
||||
in the 'cmd' shell does give session command line history, however, it is not
|
||||
saved to disk between sessions.
|
||||
.SH DIAGNOSTICS
|
||||
The \fB-v\fP, \fB--version\fP option allows different levels of diagnostics
|
||||
to be output to \fBstderr\fP and correspond to -v for BUG, -vv for ERR,
|
||||
|
@ -289,7 +351,7 @@ Written by Stephane Fillod, Nate Bargmann, and the Hamlib Group
|
|||
.SH COPYRIGHT
|
||||
Copyright \(co 2000-2011 Stephane Fillod
|
||||
.br
|
||||
Copyright \(co 2011-2012 Nate Bargmann
|
||||
Copyright \(co 2011-2013 Nate Bargmann
|
||||
.br
|
||||
Copyright \(co 2000-2010 the Hamlib Group
|
||||
.PP
|
||||
|
|
108
tests/rotctl.c
108
tests/rotctl.c
|
@ -33,9 +33,39 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
# if defined(HAVE_READLINE_READLINE_H)
|
||||
# include <readline/readline.h>
|
||||
# elif defined(HAVE_READLINE_H) /* !defined(HAVE_READLINE_READLINE_H) */
|
||||
# include <readline.h>
|
||||
# else /* !defined(HAVE_READLINE_H) */
|
||||
extern char *readline ();
|
||||
# endif /* HAVE_READLINE_H */
|
||||
#else
|
||||
/* no readline */
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
# include <sys/stat.h>
|
||||
# define HST_SHRT_OPTS "iI"
|
||||
# if defined(HAVE_READLINE_HISTORY_H)
|
||||
# include <readline/history.h>
|
||||
# elif defined(HAVE_HISTORY_H)
|
||||
# include <history.h>
|
||||
# else /* !defined(HAVE_HISTORY_H) */
|
||||
extern void add_history ();
|
||||
extern int write_history ();
|
||||
extern int read_history ();
|
||||
# endif /* defined(HAVE_READLINE_HISTORY_H) */
|
||||
#else
|
||||
/* no history */
|
||||
#define HST_SHRT_OPTS ""
|
||||
#endif /* HAVE_READLINE_HISTORY */
|
||||
|
||||
|
||||
#include <hamlib/rotator.h>
|
||||
#include "misc.h"
|
||||
|
||||
|
@ -63,6 +93,10 @@ static struct option long_options[] =
|
|||
{"set-conf", 1, 0, 'C'},
|
||||
{"show-conf",0, 0, 'L'},
|
||||
{"dump-caps",0, 0, 'u'},
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
{"read-history", 0, 0, 'i'},
|
||||
{"save-history", 0, 0, 'I'},
|
||||
#endif
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{"version", 0, 0, 'V'},
|
||||
|
@ -71,6 +105,14 @@ static struct option long_options[] =
|
|||
|
||||
#define MAXCONFLEN 128
|
||||
|
||||
/* variable for readline support */
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
static const int have_rl = 1;
|
||||
#else /* no readline */
|
||||
static const int have_rl = 0;
|
||||
#endif
|
||||
|
||||
|
||||
int interactive = 1; /* if no cmd on command line, switch to interactive */
|
||||
int prompt = 1; /* Print prompt in rotctl */
|
||||
|
||||
|
@ -87,6 +129,14 @@ int main (int argc, char *argv[])
|
|||
int verbose = 0;
|
||||
int show_conf = 0;
|
||||
int dump_caps_opt = 0;
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
int rd_hist = 0;
|
||||
int sv_hist = 0;
|
||||
const char *hist_dir = NULL;
|
||||
const char hist_file[] = "/.rotctl_history";
|
||||
char *hist_path = NULL;
|
||||
struct stat hist_dir_stat;
|
||||
#endif
|
||||
const char *rot_file=NULL;
|
||||
int serial_rate = 0;
|
||||
char conf_parms[MAXCONFLEN] = "";
|
||||
|
@ -95,7 +145,7 @@ int main (int argc, char *argv[])
|
|||
int c;
|
||||
int option_index = 0;
|
||||
|
||||
c = getopt_long (argc, argv, SHORT_OPTIONS,
|
||||
c = getopt_long (argc, argv, SHORT_OPTIONS HST_SHRT_OPTS,
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
@ -147,6 +197,14 @@ int main (int argc, char *argv[])
|
|||
else
|
||||
send_cmd_term = optarg[0];
|
||||
break;
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
case 'i':
|
||||
rd_hist++;
|
||||
break;
|
||||
case 'I':
|
||||
sv_hist++;
|
||||
break;
|
||||
#endif
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
@ -233,6 +291,34 @@ int main (int argc, char *argv[])
|
|||
|
||||
exitcode = 0;
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (interactive && prompt && have_rl) {
|
||||
rl_readline_name = "rotctl";
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
using_history(); /* Initialize Readline History */
|
||||
|
||||
if (rd_hist || sv_hist) {
|
||||
if (!(hist_dir = getenv("ROTCTL_HIST_DIR")))
|
||||
hist_dir = getenv("HOME");
|
||||
|
||||
if (((stat(hist_dir, &hist_dir_stat) == -1) && (errno == ENOENT))
|
||||
|| !(S_ISDIR(hist_dir_stat.st_mode))) {
|
||||
fprintf(stderr, "Warning: %s is not a directory!\n", hist_dir);
|
||||
}
|
||||
|
||||
hist_path = (char *)calloc((sizeof(char) * (strlen(hist_dir) + strlen(hist_file) + 1)), sizeof(char));
|
||||
|
||||
strncpy(hist_path, hist_dir, strlen(hist_dir));
|
||||
strncat(hist_path, hist_file, strlen(hist_file));
|
||||
}
|
||||
|
||||
if (rd_hist && hist_path)
|
||||
if (read_history(hist_path) == ENOENT)
|
||||
fprintf(stderr, "Warning: Could not read history from %s\n", hist_path);
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
do {
|
||||
retcode = rotctl_parse(my_rot, stdin, stdout, argv, argc);
|
||||
if (retcode == 2)
|
||||
|
@ -240,6 +326,20 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
while (retcode == 0 || retcode == 2);
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
if (interactive && prompt && have_rl) {
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (sv_hist && hist_path)
|
||||
if (write_history(hist_path) == ENOENT)
|
||||
fprintf(stderr, "\nWarning: Could not write history to %s\n", hist_path);
|
||||
|
||||
if ((rd_hist || sv_hist) && hist_path) {
|
||||
free(hist_path);
|
||||
hist_path = (char *)NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
rot_close(my_rot); /* close port */
|
||||
rot_cleanup(my_rot); /* if you care about memory */
|
||||
|
||||
|
@ -261,6 +361,10 @@ void usage()
|
|||
" -L, --show-conf list all config parameters\n"
|
||||
" -l, --list list all model numbers and exit\n"
|
||||
" -u, --dump-caps dump capabilities and exit\n"
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
" -i, --read-history read prior interactive session history\n"
|
||||
" -I, --save-history save current interactive session history\n"
|
||||
#endif
|
||||
" -v, --verbose set verbose mode, cumulative\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n\n"
|
||||
|
|
|
@ -33,9 +33,34 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
# if defined(HAVE_READLINE_READLINE_H)
|
||||
# include <readline/readline.h>
|
||||
# elif defined(HAVE_READLINE_H) /* !defined(HAVE_READLINE_READLINE_H) */
|
||||
# include <readline.h>
|
||||
# else /* !defined(HAVE_READLINE_H) */
|
||||
extern char *readline ();
|
||||
# endif /* HAVE_READLINE_H */
|
||||
#else
|
||||
/* no readline */
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
# if defined(HAVE_READLINE_HISTORY_H)
|
||||
# include <readline/history.h>
|
||||
# elif defined(HAVE_HISTORY_H)
|
||||
# include <history.h>
|
||||
# else /* !defined(HAVE_HISTORY_H) */
|
||||
extern void add_history ();
|
||||
extern int write_history ();
|
||||
extern int read_history ();
|
||||
# endif /* defined(HAVE_READLINE_HISTORY_H) */
|
||||
/* no history */
|
||||
#endif /* HAVE_READLINE_HISTORY */
|
||||
|
||||
|
||||
#include <hamlib/rotator.h>
|
||||
#include "serial.h"
|
||||
#include "misc.h"
|
||||
|
@ -70,6 +95,21 @@ static pthread_mutex_t rot_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|||
#define ARG_IN (ARG_IN1|ARG_IN2|ARG_IN3|ARG_IN4)
|
||||
#define ARG_OUT (ARG_OUT1|ARG_OUT2|ARG_OUT3|ARG_OUT4)
|
||||
|
||||
/* variables for readline support */
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
static char *input_line = (char *)NULL;
|
||||
static char *result = (char *)NULL;
|
||||
static char *parsed_input[sizeof(char) * 7];
|
||||
static const int have_rl = 1;
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
static char *rp_hist_buf = (char *)NULL;
|
||||
#endif
|
||||
|
||||
#else /* no readline */
|
||||
static const int have_rl = 0;
|
||||
#endif
|
||||
|
||||
struct test_table {
|
||||
unsigned char cmd;
|
||||
const char *name;
|
||||
|
@ -212,6 +252,38 @@ void hash_delete_all() {
|
|||
}
|
||||
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
/* Frees allocated memory and sets pointers to NULL before calling readline
|
||||
* and then parses the input into space separated tokens.
|
||||
*/
|
||||
static void rp_getline(const char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* free allocated memory and set pointers to NULL */
|
||||
if (input_line) {
|
||||
free(input_line);
|
||||
input_line = (char *)NULL;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result = (char *)NULL;
|
||||
}
|
||||
|
||||
/* cmd, arg1, arg2, arg3, arg4, arg5, arg6
|
||||
* arg5 and arg 6 are currently unused.
|
||||
*/
|
||||
for (i = 0; i < 7; i++)
|
||||
parsed_input[i] = NULL;
|
||||
|
||||
/* Action! Returns typed line with newline stripped. */
|
||||
input_line = readline(s);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* TODO: use Lex?
|
||||
*/
|
||||
|
@ -264,194 +336,564 @@ int rotctl_parse(ROT *my_rot, FILE *fin, FILE *fout, char *argv[], int argc)
|
|||
unsigned char cmd;
|
||||
struct test_table *cmd_entry;
|
||||
|
||||
char arg1[MAXARGSZ + 1], *p1;
|
||||
char arg2[MAXARGSZ + 1], *p2;
|
||||
char arg3[MAXARGSZ + 1], *p3;
|
||||
char arg4[MAXARGSZ + 1], *p4;
|
||||
char *p5, *p6;
|
||||
char arg1[MAXARGSZ + 1], *p1 = NULL;
|
||||
char arg2[MAXARGSZ + 1], *p2 = NULL;
|
||||
char arg3[MAXARGSZ + 1], *p3 = NULL;
|
||||
char arg4[MAXARGSZ + 1], *p4 = NULL;
|
||||
char *p5 = NULL;
|
||||
char *p6 = NULL;
|
||||
static int last_was_ret = 1;
|
||||
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "\nRotator command: ");
|
||||
/* cmd, internal, rotctld */
|
||||
if (!(interactive && prompt && have_rl)) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "\nRotator command: ");
|
||||
|
||||
do {
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
|
||||
/* Extended response protocol requested with leading '+' on command
|
||||
* string--rotctld only!
|
||||
*/
|
||||
if (cmd == '+' && !prompt) {
|
||||
ext_resp = 1;
|
||||
do {
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
} else if (cmd == '+' && prompt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd != '\\' && cmd != '_' && cmd != '#' && ispunct(cmd) && !prompt) {
|
||||
ext_resp = 1;
|
||||
resp_sep = cmd;
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
} else if (cmd != '\\' && cmd != '?' && cmd != '_' && cmd != '#' && ispunct(cmd) && prompt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* command by name */
|
||||
if (cmd == '\\') {
|
||||
unsigned char cmd_name[MAXNAMSIZ], *pcmd = cmd_name;
|
||||
int c_len = MAXNAMSIZ;
|
||||
|
||||
if (scanfc(fin, "%c", pcmd) < 1)
|
||||
return -1;
|
||||
|
||||
while(c_len-- && (isalnum(*pcmd) || *pcmd == '_' ))
|
||||
if (scanfc(fin, "%c", ++pcmd) < 1)
|
||||
/* Extended response protocol requested with leading '+' on command
|
||||
* string--rotctld only!
|
||||
*/
|
||||
if (cmd == '+' && !prompt) {
|
||||
ext_resp = 1;
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
|
||||
*pcmd = '\0';
|
||||
cmd = parse_arg((char *) cmd_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd == 0x0a || cmd == 0x0d) {
|
||||
if (last_was_ret) {
|
||||
if (prompt) {
|
||||
fprintf_flush(fout, "? for help, q to quit.\n");
|
||||
}
|
||||
} else if (cmd == '+' && prompt) {
|
||||
return 0;
|
||||
}
|
||||
last_was_ret = 1;
|
||||
|
||||
if (cmd != '\\' && cmd != '_' && cmd != '#' && ispunct(cmd) && !prompt) {
|
||||
ext_resp = 1;
|
||||
resp_sep = cmd;
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
} else if (cmd != '\\' && cmd != '?' && cmd != '_' && cmd != '#' && ispunct(cmd) && prompt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* command by name */
|
||||
if (cmd == '\\') {
|
||||
unsigned char cmd_name[MAXNAMSIZ], *pcmd = cmd_name;
|
||||
int c_len = MAXNAMSIZ;
|
||||
|
||||
if (scanfc(fin, "%c", pcmd) < 1)
|
||||
return -1;
|
||||
|
||||
while(c_len-- && (isalnum(*pcmd) || *pcmd == '_' ))
|
||||
if (scanfc(fin, "%c", ++pcmd) < 1)
|
||||
return -1;
|
||||
|
||||
*pcmd = '\0';
|
||||
cmd = parse_arg((char *) cmd_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd == 0x0a || cmd == 0x0d) {
|
||||
if (last_was_ret) {
|
||||
if (prompt) {
|
||||
fprintf_flush(fout, "? for help, q to quit.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
last_was_ret = 1;
|
||||
}
|
||||
} while (cmd == 0x0a || cmd == 0x0d);
|
||||
|
||||
last_was_ret = 0;
|
||||
|
||||
/* comment line */
|
||||
if (cmd == '#') {
|
||||
while( cmd != '\n' && cmd != '\r')
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
} while (cmd == 0x0a || cmd == 0x0d);
|
||||
if (cmd == 'Q' || cmd == 'q')
|
||||
return 1;
|
||||
if (cmd == '?') {
|
||||
usage_rot(fout);
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* parse rest of command line */
|
||||
if (optind >= argc)
|
||||
return 1;
|
||||
if (argv[optind][1] == '\0')
|
||||
cmd = argv[optind][0];
|
||||
else
|
||||
cmd = parse_arg(argv[optind]);
|
||||
optind++;
|
||||
}
|
||||
|
||||
last_was_ret = 0;
|
||||
|
||||
/* comment line */
|
||||
if (cmd == '#') {
|
||||
while( cmd != '\n' && cmd != '\r')
|
||||
if (scanfc(fin, "%c", &cmd) < 1)
|
||||
return -1;
|
||||
cmd_entry = find_cmd_entry(cmd);
|
||||
if (!cmd_entry) {
|
||||
fprintf_flush(stderr, "Command '%c' not found!\n", cmd);
|
||||
return 0;
|
||||
}
|
||||
if (cmd == 'Q' || cmd == 'q')
|
||||
|
||||
if ((cmd_entry->flags & ARG_IN_LINE) &&
|
||||
(cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
char *nl;
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
if (arg1[0] == 0xa)
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
nl = strchr(arg1, 0xa);
|
||||
if (nl) *nl = '\0'; /* chomp */
|
||||
p1 = arg1[0]==' '?arg1+1:arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
}
|
||||
} else if ((cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (scanfc(fin, "%s", arg1) < 1)
|
||||
return -1;
|
||||
p1 = arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0]!='?' && (cmd_entry->flags & ARG_IN2) && cmd_entry->arg2) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg2);
|
||||
if (scanfc(fin, "%s", arg2) < 1)
|
||||
return -1;
|
||||
p2 = arg2;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p2 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0]!='?' && (cmd_entry->flags & ARG_IN3) && cmd_entry->arg3) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg3);
|
||||
if (scanfc(fin, "%s", arg3) < 1)
|
||||
return -1;
|
||||
p3 = arg3;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p3 = argv[optind++];
|
||||
}
|
||||
}
|
||||
|
||||
if (p1 && p1[0]!='?' && (cmd_entry->flags & ARG_IN4) && cmd_entry->arg4) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg4);
|
||||
if (scanfc(fin, "%s", arg4) < 1)
|
||||
return -1;
|
||||
p4 = arg4;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p4 = argv[optind++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBREADLINE
|
||||
|
||||
if (interactive && prompt && have_rl) {
|
||||
int j, x;
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
/* Minimum space for 32+1+128+1+128+1+128+1+128+1+128+1+128+1 = 807
|
||||
* chars, so allocate 896 chars cleared to zero for safety.
|
||||
*/
|
||||
rp_hist_buf = (char *)calloc(896, sizeof(char));
|
||||
#endif
|
||||
|
||||
rl_instream = fin;
|
||||
rl_outstream = fout;
|
||||
|
||||
rp_getline("\nRotator command: ");
|
||||
|
||||
/* EOF (Ctl-D) received on empty input line, bail out gracefully. */
|
||||
if (!input_line) {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
if (cmd == '?') {
|
||||
}
|
||||
|
||||
/* Q or q to quit */
|
||||
if (!(strncasecmp(input_line, "q", 1)))
|
||||
return 1;
|
||||
|
||||
/* '?' for help */
|
||||
if (!(strncmp(input_line, "?", 1))) {
|
||||
usage_rot(fout);
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* parse rest of command line */
|
||||
if (optind >= argc)
|
||||
|
||||
/* '#' for comment */
|
||||
if (!(strncmp(input_line, "#", 1)))
|
||||
return 0;
|
||||
|
||||
/* Blank line entered */
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_BUG, "%s: input_line: %s\n", __func__, input_line);
|
||||
|
||||
/* Split input_line on any number of spaces to get the command token
|
||||
* Tabs are intercepted by readline for completion and a newline
|
||||
* causes readline to return the typed text. If more than one
|
||||
* argument is given, it will be parsed out later.
|
||||
*/
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
/* parsed_input stores pointers into input_line where the token strings
|
||||
* start.
|
||||
*/
|
||||
if (result) {
|
||||
parsed_input[0] = result;
|
||||
} else {
|
||||
/* Oops! Invoke GDB!! */
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
if (argv[optind][1] == '\0')
|
||||
cmd = argv[optind][0];
|
||||
else
|
||||
cmd = parse_arg(argv[optind]);
|
||||
optind++;
|
||||
}
|
||||
|
||||
cmd_entry = find_cmd_entry(cmd);
|
||||
if (!cmd_entry) {
|
||||
fprintf_flush(stderr, "Command '%c' not found!\n", cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p1 = p2 = p3 = p4 = p5 = p6 = NULL;
|
||||
|
||||
if ((cmd_entry->flags & ARG_IN_LINE) &&
|
||||
(cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
char *nl;
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
if (arg1[0] == 0xa)
|
||||
if (fgets(arg1, MAXARGSZ, fin) == NULL)
|
||||
return -1;
|
||||
nl = strchr(arg1, 0xa);
|
||||
if (nl) *nl = '\0'; /* chomp */
|
||||
p1 = arg1[0]==' '?arg1+1:arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
}
|
||||
} else if ((cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg1);
|
||||
if (scanfc(fin, "%s", arg1) < 1)
|
||||
return -1;
|
||||
|
||||
/* At this point parsed_input contains the typed text of the command
|
||||
* with surrounding space characters removed. If Readline History is
|
||||
* available, copy the command string into a history buffer.
|
||||
*/
|
||||
|
||||
/* Single character command */
|
||||
if ((strlen(parsed_input[0]) == 1) && (*parsed_input[0] != '\\')) {
|
||||
cmd = *parsed_input[0];
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
/* Store what is typed, not validated, for history. */
|
||||
if (rp_hist_buf)
|
||||
strncpy(rp_hist_buf, parsed_input[0], 1);
|
||||
#endif
|
||||
}
|
||||
/* Test the command token, parsed_input[0] */
|
||||
else if ((*parsed_input[0] == '\\') && (strlen(parsed_input[0]) > 1)) {
|
||||
char cmd_name[MAXNAMSIZ];
|
||||
|
||||
/* if there is no terminating '\0' character in the source string,
|
||||
* srncpy() doesn't add one even if the supplied length is less
|
||||
* than the destination array. Truncate the source string here.
|
||||
*/
|
||||
if (strlen(parsed_input[0] + 1) >= MAXNAMSIZ)
|
||||
*(parsed_input[0] + MAXNAMSIZ) = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf)
|
||||
strncpy(rp_hist_buf, parsed_input[0], MAXNAMSIZ);
|
||||
#endif
|
||||
/* The starting position of the source string is the first
|
||||
* character past the initial '\'. Using MAXNAMSIZ for the
|
||||
* length leaves enough space for the '\0' string terminator in the
|
||||
* cmd_name array.
|
||||
*/
|
||||
strncpy(cmd_name, parsed_input[0] + 1, MAXNAMSIZ);
|
||||
|
||||
/* Sanity check as valid multiple character commands consist of
|
||||
* alpha-numeric characters and the underscore ('_') character.
|
||||
*/
|
||||
for (j = 0; cmd_name[j] != '\0'; j++) {
|
||||
if (!(isalnum(cmd_name[j]) || cmd_name[j] == '_')) {
|
||||
fprintf(stderr, "Valid multiple character command names contain alpha-numeric characters plus '_'\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = parse_arg(cmd_name);
|
||||
}
|
||||
/* Single '\' entered, prompt again */
|
||||
else if ((*parsed_input[0] == '\\') && (strlen(parsed_input[0]) == 1)) {
|
||||
return 0;
|
||||
}
|
||||
/* Multiple characters but no leading '\' */
|
||||
else {
|
||||
fprintf(stderr, "Precede multiple character command names with '\\'\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd_entry = find_cmd_entry(cmd);
|
||||
if (!cmd_entry) {
|
||||
if (cmd == '\0')
|
||||
fprintf(stderr, "Command '%s' not found!\n", parsed_input[0]);
|
||||
else
|
||||
fprintf(stderr, "Command '%c' not found!\n", cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* \send_cmd */
|
||||
if ((cmd_entry->flags & ARG_IN_LINE) &&
|
||||
(cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
/* Check for a non-existent delimiter so as to not break up
|
||||
* remaining line into separate tokens (spaces OK).
|
||||
*/
|
||||
result = strtok(NULL, "\0");
|
||||
|
||||
if (result) {
|
||||
x = 1;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg1) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg1);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
/* Blank line entered */
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (input_line)
|
||||
parsed_input[x] = input_line;
|
||||
else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The arg1 array size is MAXARGSZ + 1 so truncate it to fit if larger. */
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg1, parsed_input[x]);
|
||||
p1 = arg1;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p1 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0]!='?' && (cmd_entry->flags & ARG_IN2) && cmd_entry->arg2) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg2);
|
||||
if (scanfc(fin, "%s", arg2) < 1)
|
||||
return -1;
|
||||
|
||||
/* Normal argument parsing. */
|
||||
else if ((cmd_entry->flags & ARG_IN1) && cmd_entry->arg1) {
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (result) {
|
||||
x = 1;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg1) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg1);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg1, parsed_input[x]);
|
||||
p1 = arg1;
|
||||
}
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN2) && cmd_entry->arg2) {
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (result) {
|
||||
x = 2;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg2) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg2);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg2, parsed_input[x]);
|
||||
p2 = arg2;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p2 = argv[optind++];
|
||||
}
|
||||
}
|
||||
if (p1 && p1[0]!='?' && (cmd_entry->flags & ARG_IN3) && cmd_entry->arg3) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg3);
|
||||
if (scanfc(fin, "%s", arg3) < 1)
|
||||
return -1;
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN3) && cmd_entry->arg3) {
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (result) {
|
||||
x = 3;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg3) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg3);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg3, parsed_input[x]);
|
||||
p3 = arg3;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p3 = argv[optind++];
|
||||
}
|
||||
if (p1 && p1[0] != '?' && (cmd_entry->flags & ARG_IN4) && cmd_entry->arg4) {
|
||||
result = strtok(NULL, " ");
|
||||
|
||||
if (result) {
|
||||
x = 4;
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
x = 0;
|
||||
char pmptstr[(strlen(cmd_entry->arg4) + 3)];
|
||||
|
||||
strcpy(pmptstr, cmd_entry->arg4);
|
||||
strcat(pmptstr, ": ");
|
||||
|
||||
rp_getline(pmptstr);
|
||||
|
||||
if (!(strcmp(input_line, ""))) {
|
||||
fprintf(fout, "? for help, q to quit.\n");
|
||||
fflush(fout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtok(input_line, " ");
|
||||
|
||||
if (result) {
|
||||
parsed_input[x] = result;
|
||||
} else {
|
||||
fprintf_flush(fout, "\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(parsed_input[x]) > MAXARGSZ)
|
||||
parsed_input[x][MAXARGSZ] = '\0';
|
||||
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
strncat(rp_hist_buf, " ", 1);
|
||||
strncat(rp_hist_buf, parsed_input[x], MAXARGSZ);
|
||||
}
|
||||
#endif
|
||||
strcpy(arg4, parsed_input[x]);
|
||||
p4 = arg4;
|
||||
}
|
||||
#ifdef HAVE_READLINE_HISTORY
|
||||
if (rp_hist_buf) {
|
||||
add_history(rp_hist_buf);
|
||||
free(rp_hist_buf);
|
||||
rp_hist_buf = (char *)NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (p1 && p1[0]!='?' && (cmd_entry->flags & ARG_IN4) && cmd_entry->arg4) {
|
||||
if (interactive) {
|
||||
if (prompt)
|
||||
fprintf_flush(fout, "%s: ", cmd_entry->arg4);
|
||||
if (scanfc(fin, "%s", arg4) < 1)
|
||||
return -1;
|
||||
p4 = arg4;
|
||||
} else {
|
||||
if (!argv[optind]) {
|
||||
fprintf(stderr, "Invalid arg for command '%s'\n",
|
||||
cmd_entry->name);
|
||||
exit(1);
|
||||
}
|
||||
p4 = argv[optind++];
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBREADLINE */
|
||||
|
||||
|
||||
/*
|
||||
* mutex locking needed because rigctld is multithreaded
|
||||
* mutex locking needed because rotctld is multithreaded
|
||||
* and hamlib is not MT-safe
|
||||
*/
|
||||
#ifdef HAVE_PTHREAD
|
||||
|
@ -531,7 +973,7 @@ void usage_rot(FILE *fout)
|
|||
{
|
||||
int i, nbspaces;
|
||||
|
||||
fprintf(fout, "Commands (some may not be available for this rig):\n");
|
||||
fprintf(fout, "Commands (some may not be available for this rotator):\n");
|
||||
for (i = 0; test_list[i].cmd != 0; i++) {
|
||||
fprintf(fout, "%c: %-12s(", isprint(test_list[i].cmd) ?
|
||||
test_list[i].cmd : '?', test_list[i].name);
|
||||
|
@ -548,6 +990,8 @@ void usage_rot(FILE *fout)
|
|||
|
||||
fprintf(fout, ")\n");
|
||||
}
|
||||
|
||||
fprintf(fout, "\n\nPrepend long command names with '\\', e.g. '\\dump_state'\n");
|
||||
}
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue