WAD bad interaction between echox and command grouping

Mar 18, 2010
63
1
Consider this TCC v23.00.24 x64 session: (Discussion follows.)
Code:
[C:\Tmp]
> type load.btm && rem BTM script which can show echox funkiness with command grouping
@echo off
setlocal
iff _%1_==__ then
  alias say=echo.
else
  alias say=%1
endiff
iff _%2_==__ then
  alias dowith=cat -
else
  alias dowith=%@unquote[%2]%
endiff
(
  say drop table if exists People;
  say create table People( id, name );
  say insert into People values (1,'Gonzo');
) | dowith
endlocal

[C:\Tmp]
> load && Rem Show the desired output (using echo. to do emits.)
 drop table if exists People;
 create table People( id, name );
 insert into People values (1,'Gonzo');

[C:\Tmp]
> load echox && Rem Show messup with echox doing the emits.
drop table if exists People; &| say create table People( id, name ); &| say insert into People values (1,'Gonzo');
The problem is that the echox internal command is interpreting everything in the command group except for the first echox, plus it is seeing command separators that were never injected except by TCC as part of its command grouping. This behavior violates the separation of functions that we programmers rely upon. I expect that if I invoke echox 3 times, then what is emitted to its output (however it is redirected or not) will be literally what followed on the 3 command tails, each followed by a newline.
 

rconn

Administrator
Staff member
May 14, 2008
11,910
133
WAD - ECHOX is supposed to do exactly that. When you create a command group, you *are* forcing TCC to insert command separators -- that's how command groups work.

The "&|" string is inserted specifically to duplicate a CMD bug in command groups. If you have "Duplicate CMD bugs" enabled, you should turn it off if you want to create TCC-only syntax like this.

What I don't understand is why you would use ECHOX in that case - are you asking for ECHOX's behavior to be changed (unlikely it will be) or is this a feature request for some new command?
 
Mar 18, 2010
63
1
I do not see that there is anything "forced" about the way TCC has implemented command grouping. TCC could have arranged, as some other shells have done, that commands which are grouped for redirection are invoked with just the command tail that was written (by the script author.) What TCC is doing is akin to a textual transformation rather than a parse able to extract individual commands for processing according to the usual command line syntax. (No need to say that CMD.exe led the way, and now TCC must follow.)

Disabling "Duplicate CMD bugs" changes the injected '&|' sequences into '&' characters; That's just as bad.

As for why I would use ECHOX, it is exactly what I need in common scenarios where I am creating input to a program (fed to it via a pipe, usually) which has very different syntax and quoting conventions and rules. The much-reduced code I posted is just a sample. Often, generated SQL has '|' characters and other punctuation which are best left in the form common in that language rather than being quoted and escaped as needed to avoid making (or forcing) TCC do something unwanted.

Using the TEXT ... ENDTEXT facility is attactive, but where I need to get output from several sections emitted to a single stream it gets awkward. For some sections, literal text such as TEXT/ENDTEXT can handle is great, but some other sections may need to emit results of processing within a TCC script, usually reflected in some environment variable values being incorporated. Unfortunately, command grouping is useful only when I am willing to goober up every bit of what is being emitted with TCC-required escapes, quotes, dequotes, etc.

When I use an external echo program in grouped commands, it never sees any '&' or '&|' stuck onto its input. I do not see why ECHOX should be any different. And I cannot see why ECHOX's current behavior has any value with respect to backwards compatibility. (Can you imagine somebody relying on such a quirk?)

I think there is a feature request, here, for something like ECHOX which can be interspersed with ECHO. and which will emit only the command tail it has been given (by the script author.) It would be good if it had a companion that did not emit a newline, or if it had a set of options, such as
Code:
-e => enable C-style escape specifications
-n => omit terminating newline
-- => end of option flags, emit what follows
 
In regards to TEXT/ENDTEXT, maybe "Here-document" would be better;
Code:
@echo off

type <<- endtext
   Shell version = %_4ver
   Command line = %_cmdline
   Command shell name = %_cmdproc
   Command shell filename = %_cmdspec
   User name = %_winuser
   Windows version = %_winver
endtext
To re-direct to a file:
Code:
@echo off

type <<- endtext > thefile.txt
   Shell version = %_4ver
   Command line = %_cmdline
   Command shell name = %_cmdproc
   Command shell filename = %_cmdspec
   User name = %_winuser
   Windows version = %_winver
endtext
Ref: "Here-document" trickery

Joe
 
Mar 18, 2010
63
1
(Re Joe's "Here-document" trick:) That's a nice addition to my TCC bag of tricks.

However, it does not solve the problem of intermixing literal and shell-expanded sections, all going to an uninterrupted output stream. "Here-document" redirection is not going to work in combination with command grouping. I am quite (overly) familiar with the pattern:
echo some stuff > %tempfile%
echo more stuff >> %tempfile%
but it is tedious to write, and prone to leaving temp file litter. Much preferable would be:
(
emit Some stuff to go out without !@##$% interpretation,
echo followed by something needing a TCC %@Whatever[xxx]% rendering.
) | program_not_able_to_accept_multiple_command_streams
 
Another suggestion;
Code:
@echo off

type <<- endtext > clip: | echo %@clip[2]
   Shell version = %_4ver
   Command line = %_cmdline
   Some stuff to go out without !@##$% interpretation
   Command shell name = %_cmdproc
   Command shell filename = %_cmdspec
   User name = %_winuser
   Windows version = %_winver
endtext
Joe
 
May 20, 2008
10,565
78
Syracuse, NY, USA
Another suggestion;
Code:
@echo off

type <<- endtext > clip: | echo %@clip[2]
   Shell version = %_4ver
   Command line = %_cmdline
   Some stuff to go out without !@##$% interpretation
   Command shell name = %_cmdproc
   Command shell filename = %_cmdspec
   User name = %_winuser
   Windows version = %_winver
endtext
Joe
What's it supposed to do? I pasted that into a BTM. Here's what I got the first four times I ran it. Is it at all dependable for you?

Code:
v:\> s.btm
Some stuff to go out without !@##$ interpretation
TCC: (Sys) V:\s.btm [3]  The parameter is incorrect.
 "h:\Temp\endE592.tmp"

v:\> s.btm
**EOC**

v:\> s.btm
Some stuff to go out without !@##$ interpretation

v:\> s.btm
TCC: (Sys) V:\s.btm [3]  The parameter is incorrect.

v:\>
 
On my system, it returns;
Code:
c:\users\jlc\utils>test
Some stuff to go out without !@##$ interpretation

c:\users\jlc\utils>test
Some stuff to go out without !@##$ interpretation

c:\users\jlc\utils>test
Some stuff to go out without !@##$ interpretation

c:\users\jlc\utils>test
Some stuff to go out without !@##$ interpretation
Joe
 
Mar 18, 2010
63
1
Corruption is not necessary to get strange results when letting TCC interpret text which has not been carefully created with that process in mind. (That's why my example had a '%' in it.) Env-var expansion is particularly insidious (when "accidental") because the result depends upon accidents of how the environment has been set previously.