On Wed, Feb 27, 2002 at 07:03:28PM -0500, Jeremy Doolin wrote:
> Well, hello to all on this list.
> I've been messing around with writing a shell in Common Lisp using
> CLISP. So far I've managed to make pretty good progress. Most of what
> I've done is basic string processing. So here is what my shell can do:
Cool. I have been playing around with something similar.
> -execute commands, change directory, variables, environment variables,
> aliases, configurable prompt, evaluate S-expressions and probably a few
> minor things I can't think of right now.
> And here is what I'd like it to do:
> -pipes, I/O redirection, a complete syntax (it will not be bash syntax),
> and (the hardest part) job control.
> Here is what is wrong with it so far:
> I am using the (execute ..) function for executing commands. Regardless
> if I use this or (run-program ..), my shell is dependent upon another
> shell. This is rather... disgusting. Now, I'm well aware that Lisp is
> not an OS level language. But I've noticed that (cd ..) is implemented
> in CLISP. I can think of no other way this could be implemented than a
> system call to 'chdir'. So perhaps an 'exec' type function could be
> implemented in the same way. A 'fork' command would also be helpful.
You can do these things with the libc bindings. You don't mention
what your OS is, but if you're using Linux or AmigaOs (!) bindings are
supplied. The problem with exec is you need a C definition with the
correct number of args. linux.lisp includes 3 execlp definitions, so
you would be limited to a small number of args. I 'worked around this'
by defining a larger number of execlp's in linux.lisp, and on the lisp
side have a macro construct the call to the correct execlp. It's ugly
and primitive, and your number of args is still limited, so it's
pretty unsatisfactory, even though it works.
For some reason, wait() and waitpid() are not included in linux.lisp.
I asked about this before on clisp-list, but nobody replied. I don't
think fork() is useable without wait() so it's a bit strange. I added
(empty (c-ptr int)))
and it seems to work ok. I also added a definition for waitpid(), but
I think it will need a wrapper.
> Another problem is when I give the shell an S-expression with an error.
> For example, (car "foo"). If this happens, the entire shell exits.
> That's inconvenient. I suppose I could disallow s-expressions, but can
> you imagine how cool it would be to something like:
> (+ 2 $FOO) in the shell? Obviously, expressions like this would
> require me to make my own syntax.
I take it your shell is a program Clisp is running? My approach
was/is to use Clisp directly, and extend it to provide the needed
functionality of a shell. See http://clisp.sourceforge.net/clash.html
I abandoned the idea of a read-macro for entering commands, since
running programs from execlp is simple enough to not need to pamper
the user. You can also define readline functions that insert text
'invisibly', so you can provide the user with the illusion that your
shell has two seperate syntaxes. As an example, I have a readline
function 'clash-run-wait' which wraps whatever the user has typed in
with (runw "....")\n. Where the dots are replaced with the user's
input. #'runw calls a macro which builds the call to the appropriate
execlp call in the linux package. It forks and waits. The upshot is
you can run programs using an identical syntax to Bash, from the
user's point of view.
> So here is what I'm asking:
> First of all, I'd be perfectly willing to implement an exec command in
> CLISP. However, I need to know how 'cd' and 'getenv' were done (and
> where in the source tree). Unless there is another way to do this, of
getenv is in misc.d. But I would advise you to try the libc bindings
first. Good luck :-)
> Second, I'm looking for advice with any of the other problems/issues
> I've described. (like pipes and the bad S-expression problem).
Clisp has pipes, but they use the shell (I think). See,