Skip to content

Commit

Permalink
halcmd: support line extends with backslash (\)
Browse files Browse the repository at this point in the history
Line continuation using trailing backslash:
1) Adapt halcmd_main.c for scripted & interactive usage
2) Update twopass.tcl to concatenate extended lines
3) Add backslash examples in tests/loadrt.1
4) Update halcmd.1 man page

Notes:
a) The tcl "source" cmd substitutes a trailing '\' with
   a single ' ',  so in twopass.tcl, detect a
   trailing '\' in a .tcl file and line extend
b) haltcl uses the tclreadline package with dubious
   support for prompt2 handling
  • Loading branch information
dngarrett committed Feb 16, 2019
1 parent 60ecbbb commit 0e515b9
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 23 deletions.
4 changes: 4 additions & 0 deletions docs/man/man1/halcmd.1
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ halcmd \fB\-i\fR flag. They have the following formats:
\fB[SECTION]VAR\fR followed by end-of-line or whitespace
.IP
\fB[SECTION](VAR)\fR
.SH LINE CONTINUATION
The backslash character (\fB\\\fR) may be used to indicate the line
is extended to the next line. The backslash character must be the
last character before the newline.
.SH EXAMPLES
.SH HISTORY
.SH BUGS
Expand Down
59 changes: 51 additions & 8 deletions src/hal/utils/halcmd_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ static void print_help_general(int showR);
static int release_HAL_mutex(void);
static int propose_completion(char *all, char *fragment, int start);

static char *prompt = "";
static char *prompt = "";
static char *prompt_script = "%%\n";
static char *prompt_interactive = "halcmd: ";
static char *prompt_continue = "halcmd+: ";

#define MAX_EXTEND_LINES 20

/***********************************************************************
* LOCAL FUNCTION DEFINITIONS *
Expand Down Expand Up @@ -223,9 +227,9 @@ int main(int argc, char **argv)

if (srcfile && isatty(fileno(srcfile))) {
if (scriptmode) {
prompt = "%%\n";
prompt = prompt_script;
} else {
prompt = "halcmd: ";
prompt = prompt_interactive;
}
}

Expand All @@ -249,15 +253,53 @@ int main(int argc, char **argv)
}
}
} else {
int extend_ct = 0; // extend lines with backslash (\)
/* read command line(s) from 'srcfile' */
while (get_input(srcfile, raw_buf, MAX_CMD_LEN)) {
char *tokens[MAX_TOK+1];
char eline [(LINELEN + 2) * (MAX_EXTEND_LINES + 1)];
char *elineptr;
char *elinenext;
int newLinePos;

halcmd_set_linenumber(linenumber++);

newLinePos = (int)strlen(raw_buf) - 1; // interactive
if (raw_buf[newLinePos] == '\n') { newLinePos--; } // tty

if (newLinePos > 0 && raw_buf[newLinePos] == '\\') { // backslash
raw_buf[newLinePos] = 0;
newLinePos++;
if (!extend_ct) { //first extend
if (prompt == prompt_interactive) prompt = prompt_continue;
elineptr = eline;
strncpy(elineptr,raw_buf,strlen(raw_buf));
elinenext = elineptr + strlen(raw_buf);
} else { // subsequent extends
strncpy(elinenext,raw_buf,newLinePos);
elinenext = elinenext + strlen(raw_buf);
}
*elinenext = 0;
extend_ct++;
continue; // get next line to extend
} else { // no backslash
if (extend_ct) { // extend finished
strncpy(elinenext,raw_buf,strlen(raw_buf));
*(eline+strlen(eline)+0)='\n';
elinenext = elinenext + strlen(raw_buf);
*elinenext = 0;
elineptr = eline;
}
}
if (!extend_ct) { elineptr = (char*)raw_buf; }
extend_ct = 0;
if (prompt == prompt_continue) { prompt = prompt_interactive; }

/* remove comments, do var substitution, and tokenise */
retval = halcmd_preprocess_line(raw_buf, tokens);
if(echo_mode) {
halcmd_echo("%s\n", raw_buf);
}
retval = halcmd_preprocess_line(elineptr, tokens);
if(echo_mode) {
halcmd_echo("%s\n", eline);
}
if (retval == 0) {
/* the "quit" command is not handled by parse_line() */
if ( ( strcasecmp(tokens[0],"quit") == 0 ) ||
Expand All @@ -281,7 +323,8 @@ int main(int argc, char **argv)
/* exit from loop */
break;
}
}
} //while get_input()
extend_ct=0;
}
/* all done */
halcmd_shutdown();
Expand Down
81 changes: 68 additions & 13 deletions tcl/twopass.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -378,17 +378,23 @@ proc ::tp::prep_the_files {} {
set f $foundfile

# convert to a temporary tcl file if necessary
set suffix [filesuffix $f]
switch -exact $suffix {
tcl {
switch -exact [file extension $f] {
.tcl {
# handle .tcl files with trailing backslash
set has_backslash ""
catch {set has_backslash [exec grep {\\$} $f]} msg
if {"$has_backslash" != ""} {
set ::TP($f,tmp) /tmp/tmp_[file tail $f]
set f [handle_tcl_with_backslash $f $::TP($f,tmp)]
}
if {[llength $f_argv]} {
set f "$f $f_argv" ;# optional args
}
lappend ::TP(runfiles) $f
verbose "tclfile: $f"
}
hal {
set ::TP($f,tmp) /tmp/[file tail $f].tmp
.hal {
set ::TP($f,tmp) /tmp/tmp_[file tail $f]
set converted_file [hal_to_tcl $f $::TP($f,tmp)]
if {"$converted_file" == ""} {
puts "twopass:Sourcing $f WITHOUT twopass processing"
Expand All @@ -400,12 +406,51 @@ proc ::tp::prep_the_files {} {
}
}
default {return -code error \
"prep_the_files:unknown file type <$suffix>"}
"prep_the_files:unknown file type <$f>"}
}
}
}
} ;# prep_the_files

proc ::tp::handle_tcl_with_backslash {ifile ofile} {
if [catch {set fdin [open $ifile r]
set fdout [open $ofile w]
} msg
] {
puts "twopass: Error: $msg"
exit 1
}
puts $fdout "# temporary tcl file generated by twopass.tcl"
set lno 0
while 1 {
if [eof $fdin] break
incr lno
set theline [gets $fdin]
set line [string trim $theline]
if {"$line" == ""} continue

# handle .tcl files extended with backslash:
if {[string range $line end end] == "\\"} {
set line [string replace $line end end] ;# rm trailing backslash
if [info exists extend] {
set extend "${extend}$line" ;# subsequent extends
} else {
set extend "$line" ;# first extend
}
continue ;# get next line
} else {
if [info exists extend] {
set line "${extend}$line"
}
}
catch {unset extend}
puts $fdout "$line"
}
close $fdin
close $fdout
return $ofile
} ;# handle_tcl_with_backslash

proc ::tp::hal_to_tcl {ifile ofile} {
# When hal files are specified with HAL:HALFILE,
# try to make them work (preferred way is use tcl files).
Expand Down Expand Up @@ -436,6 +481,22 @@ proc ::tp::hal_to_tcl {ifile ofile} {
set line [string trim $theline]
if {"$line" == ""} continue

# handle .hal files extended with backslash:
if {[string range $line end end] == "\\"} {
set line [string replace $line end end] ;# rm trailing backslash
if [info exists extend] {
set extend "${extend}$line" ;# subsequent extends
} else {
set extend "$line" ;# first extend
}
continue ;# get next line
} else {
if [info exists extend] {
set line "${extend}$line"
}
}
catch {unset extend}

# find *.hal files excluded from twopass processing:
set tmpline [string map -nocase {" " ""} $line]
set tmpline [string tolower $tmpline]
Expand Down Expand Up @@ -522,7 +583,7 @@ proc ::tp::source_the_files {} {
foreach file_plus_args $::TP(runfiles) {
catch {unset ::argv}
set f [lindex $file_plus_args 0]
if {[filesuffix $f] == "tcl"} {
if {[file extension $f] == ".tcl"} {
# note: ::argv supplies the file_plus_args to the sourced file
# ::argv0 is not set to maintain compatibility with
# the way the linuxcnc script uses haltcl to use tcl files
Expand All @@ -546,12 +607,6 @@ proc ::tp::source_the_files {} {
}
} ;# source_the_files

proc ::tp::filesuffix {f} {
set dot [string last . $f]
if {$dot < 0} {return -code error "filesuffix: no suffix <$f>"}
return [string range $f [expr 1 + $dot ] end]
} ;# filesuffix

proc ::tp::load_the_modules {} {
if ![info exists ::TP(modules)] {
# no modules unlikely, but can occur in testing
Expand Down
4 changes: 2 additions & 2 deletions tests/loadrt.1/expected
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
and2.0 m.q m.r or2.0 or2.1 or2.2
and2.0.in0 and2.0.in1 and2.0.out and2.0.time m.q.in0 m.q.in1 m.q.out m.q.sel m.q.time m.r.in0 m.r.in1 m.r.out m.r.sel m.r.time or2.0.in0 or2.0.in1 or2.0.out or2.0.time or2.1.in0 or2.1.in1 or2.1.out or2.1.time or2.2.in0 or2.2.in1 or2.2.out or2.2.time
and2.0 d1 d2 d3 l1 l2 m.q m.r or2.0 or2.1 or2.2 xor2.0 xor2.1
and2.0.in0 and2.0.in1 and2.0.out and2.0.time d1.in d1.out d1.time d2.in d2.out d2.time d3.in d3.out d3.time l1.and l1.in-00 l1.in-01 l1.time l2.in-00 l2.in-01 l2.in-02 l2.or l2.time m.q.in0 m.q.in1 m.q.out m.q.sel m.q.time m.r.in0 m.r.in1 m.r.out m.r.sel m.r.time or2.0.in0 or2.0.in1 or2.0.out or2.0.time or2.1.in0 or2.1.in1 or2.1.out or2.1.time or2.2.in0 or2.2.in1 or2.2.out or2.2.time xor2.0.in0 xor2.0.in1 xor2.0.out xor2.0.time xor2.1.in0 xor2.1.in1 xor2.1.out xor2.1.time
13 changes: 13 additions & 0 deletions tests/loadrt.1/test.hal
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
loadrt and2 # default count of 1 still works
loadrt mux2 names=m.q,m.r # new names= works
loadrt or2 count=3 # count= still works

# backslash line extend:
loadrt xor2 \
count=2

loadrt ddt names=d1\
,d2\
,d3

loadrt logic \
names=l1,l2 \
personality=0x102,0x203

list funct
list pin

0 comments on commit 0e515b9

Please sign in to comment.