I really don't want to be dismissive of what is clearly a large amount of work that you've put in, but I do need to ask: why not use zsh? To the best of my knowledge, zsh can do everything tcsh can.
I used tcsh for a long time, because it's the default on FreeBSD and FreeBSD was the first Unix system I seriously used. I forgot what exactly the motivation was to look at zsh – I think I was using something very hacky to work around functions for the umpteempth time and just had enough – but overal I'm very happy I (finally) did. I had quite a bespoke tcshrc file, and the only thing I've missed was noclobber=(notempty), but that's since been added to zsh (at my request). And it has so many useful features.
For fun and learning, as well as because I'm much of a retro fan. Csh emerged as a superset of the PWB shell. If one have a look at the
early Csh and
PWB shell codes, they can tell they're similar. William Joy haven't taken these keywords and defines from nowhere. I think he meant to reproduce an open-source version of the PWB shell. The similarity is even clearer by the fact they share issues (e.g:
if is troublesome on pipes and redirections). Tcsh and Csh are the only shells to date resembling the forgotten V6 and PWB shells.
While some people have bad views on Csh and Tcsh, for me, was and is enjoyable. It does lack a couple of features found in Bourne-compatible shells, but I found it better than Bourne-compatible shells. There always exist a workaround for a particular goal. E.g: source and goto make a great combination for functions.
Code:
#!/bin/tcsh -f
if ( ! "$?main" ) then
if ( ! "$?0" ) then
echo You may only run this script by explicitly calling its file.
exit -1
endif
set -r main = "$0"
alias function 'source "$main" \!*'
exit ( { function myfunc 32 } )
endif
if >& /dev/null ( ! { goto "$1" } ) then
echo Function "$1" not set.
exit -1
endif
goto "$1" ; shift
myfunc:
set myrand
set myrand[1] = "`grep -a -o "\''[\\!-~]'\'" /dev/urandom | head -"\"'$1'\""`"
set myrand[1] = "$myrand[1]:ags/ //"
echo "$myrand[1]"
Note how I use goto in the if statement. In sub-shells, goto may seek labels, but may not transfer and resume execution. Some will see and take this as a clear failure; others, like myself, may see it as
a feature for telling whether a label exists or not. Makes no sense for transferring and resuming execution, since wouldn't evaluate the exit status. It's only meant for jumps, not for evaluating procedures.
Also, note how I escape characters in a command substitution. I've read some complaints regarding escaping in quotes and command substitution nesting are impossible. Both claims are false. Csh and Tcsh only support escaping off quotes, be single or double. It's an exception for exclamation marks (I don't get why), which are used for history substitution, though. Escaping and command substitution nesting aren't impossible, but are ugly and tricky.
This, along with others' complaints, is the motivation and inspiration behind implementing functions and other features. I've about ten branches implementing new features. I've ideas I haven't put in construction yet, such as file descriptor handling and independent stderr redirection. These, and others, are yet to come, hopefully.
By the way,
that "Read files into a variable." idea evolved better, allowing pipes and different variable names, resembling Bourne-compatible shells better.
The "Tell whether stdin is empty." idea was approved.