home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / ssh-1.7 / part01 next >
Encoding:
Text File  |  1993-04-15  |  101.0 KB  |  4,119 lines

  1. Newsgroups: comp.sources.unix
  2. From: Steve Baker (ice@judy.indstate.edu)
  3. Subject: v26i167: ssh - Steve's SHell (a small csh-like shell), V1.7, Part01/04
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: Steve Baker (ice@judy.indstate.edu)
  8. Posting-Number: Volume 26, Issue 167
  9. Archive-Name: ssh-1.7/part01
  10.  
  11.   This is ssh V1.7, a unix shell, written over the period of some 2 years on
  12. and off by Steve Baker with help from Thomas Moore who wrote the wildcarding
  13. routines for this shell.
  14.  
  15.   This shell is public domain and may be copied and distributed and further
  16. developed under the guidelines set forth in the file COPYING.  Further
  17. development and modifications to the shell are strongly encouraged.
  18.  
  19.   Ssh sports these features among others:
  20.  
  21.   1. Job control (&, &!, jobs, fg, bg, stop)
  22.   2. String, numeric and null variables w/ variable protection.
  23.   3. Recursive string variable insertion.
  24.   4. Advanced alias argument placement. (%- %+ %% %n %n-m).
  25.   5. Logical assignments for abbreviated paths and files.
  26.   6. Advanced wild card support (~*?[^-]{^})
  27.   7. Advanced redirection and piping
  28.      (< <% <<% > >% >> >>% >! >!% >>! >>!% >& >&% >>& >>&% | |! |&)
  29.   8. C like expressions w/ the full set of C operators, including
  30.      pre/post incrementing/deincrementing.
  31.   9. Shell history save file (w/ auto set history size).
  32.  10. Secondary password support
  33.  11. Advanced key macro support w/ gold key support
  34.  12. Command line editing
  35.  13. Status line support
  36.  14. New mail check
  37.  15. Idle timeout
  38.  16. Structured scripting language.
  39.  17. 50+ builtin commands.
  40.  
  41.   This shell has been compiled and tested on the following machines (future
  42. developers, please add machines that you have tested it on to this list):
  43.  
  44.   A Sequent symmetry system running Dynix V3.2.0
  45.   A Tatung Sun clone running SunOS V4.1.1
  46.   A Sun running SunOS V4.1.1
  47.   A NeXT running NeXTStep V3.0
  48.   A DECstation running Ultrix 4.2A
  49.   A 486 PC running BSDI BSD/386 V1.0
  50.  
  51.   It is unlikely that all bugs have been worked out, but hopefully it's a
  52. fairly solid little shell.  If problems do arise while trying to compile
  53. this program, by all means contact me and I will attempt to help you (and
  54. perhaps release a fixed version).  I am sure that this program will not
  55. compile on all machines.
  56.  
  57.     Steve Baker (ice@judy.indstate.edu)
  58.     Thomas Moore (dark@judy.indstate.edu)
  59.     1600 S. Center St. Apt #1
  60.     Terre Haute, IN 47802
  61.  
  62. #! /bin/sh
  63. # This is a shell archive.  Remove anything before this line, then unpack
  64. # it by saving it into a file and typing "sh file".  To overwrite existing
  65. # files, type "sh file -c".  You can also feed this as standard input via
  66. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  67. # will see the following message at the end:
  68. #        "End of archive 1 (of 4)."
  69. # Contents:  COPYING DISTRIBUTION INSTALLING MANIFEST MODS Makefile
  70. #   NOTES README alias.c assign.c cmds.h file.c init.c key.c parse.c
  71. #   scripts shell.c shell.h stat.c wc.c
  72. # Wrapped by vixie@gw.home.vix.com on Thu Apr 15 22:49:00 1993
  73. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  74. if test -f 'COPYING' -a "${1}" != "-c" ; then 
  75.   echo shar: Will not clobber existing file \"'COPYING'\"
  76. else
  77. echo shar: Extracting \"'COPYING'\" \(1419 characters\)
  78. sed "s/^X//" >'COPYING' <<'END_OF_FILE'
  79. X                    -= COPYING =-
  80. X
  81. X
  82. This software is provided as is without any express or implied warranties,
  83. including, without limitation, the implied warranties of merchantability
  84. and fitness for a particular purpose.
  85. X
  86. The authors of this software and any unnamed third parties, including, but
  87. not limited to those who redistribute and/or modify the source for their own
  88. means, are not liable for any damages, including but not limited to the
  89. loss of data and/or productivity, arising out of the use of this software.
  90. X
  91. This software may be copied freely with the limitation that the attached
  92. copyright notice in each source file remain and that Steve Baker and Thomas
  93. Moore be recognized as the originating authors of the software.  This code
  94. may be modified and redistributed with only the limitation that the above
  95. copyright notices are maintained, and the author of the modifications
  96. appends his name (and e-mail address if applicable), version number and a
  97. record of his modifications in the file ``MODS'' to be distributed with the
  98. the source.  The manual should be updated to reflect any "noticeable"
  99. changes in the shell or it's behavior.  And remember to update the version
  100. builtin command.
  101. X
  102. Code may be extracted from the shell and used in your own programs with the
  103. limitation that the source is documented as having been extracted, where it
  104. was extracted from and the original author of the source if applicable.
  105. END_OF_FILE
  106. if test 1419 -ne `wc -c <'COPYING'`; then
  107.     echo shar: \"'COPYING'\" unpacked with wrong size!
  108. fi
  109. # end of 'COPYING'
  110. fi
  111. if test -f 'DISTRIBUTION' -a "${1}" != "-c" ; then 
  112.   echo shar: Will not clobber existing file \"'DISTRIBUTION'\"
  113. else
  114. echo shar: Extracting \"'DISTRIBUTION'\" \(276 characters\)
  115. sed "s/^X//" >'DISTRIBUTION' <<'END_OF_FILE'
  116. This is the archive for the Ssh shell version 1.7.  It should include the
  117. following files:
  118. X
  119. COPYING
  120. DISTRIBUTION
  121. INSTALLING
  122. MODS
  123. Makefile
  124. NOTES
  125. README
  126. alias.c
  127. assign.c
  128. cmds.h
  129. eval.c
  130. exe.c
  131. file.c
  132. init.c
  133. key.c
  134. parse.c
  135. scripts/*
  136. shcmds.c
  137. shell.c
  138. shell.h
  139. ssh.1
  140. stat.c
  141. vars.c
  142. wc.c
  143. END_OF_FILE
  144. if test 276 -ne `wc -c <'DISTRIBUTION'`; then
  145.     echo shar: \"'DISTRIBUTION'\" unpacked with wrong size!
  146. fi
  147. # end of 'DISTRIBUTION'
  148. fi
  149. if test -f 'INSTALLING' -a "${1}" != "-c" ; then 
  150.   echo shar: Will not clobber existing file \"'INSTALLING'\"
  151. else
  152. echo shar: Extracting \"'INSTALLING'\" \(1126 characters\)
  153. sed "s/^X//" >'INSTALLING' <<'END_OF_FILE'
  154. X                INSTALLING SSH
  155. X
  156. Since SSH is a fairly simply archive, installing it should be a snap. Just
  157. do the following:
  158. X
  159. X1. Compile it - Do whatever it takes.  If this involves dancing around in a
  160. X   circle for 5 minutes, then do it.  Actually typing `make', may be much
  161. X   easier however.
  162. X
  163. X2. Put the resulting binary in a bin directory somewhere. /usr/local/bin is
  164. X   a good place to put it.  You'll probably need your Sys-admin to help out
  165. X   with this and the next three steps.  If he doesn't care for low-life
  166. X   peons like you, then sacrifices of live pizza might be called for.
  167. X
  168. X3. Make an entry in /etc/shells for ssh.  Again you'll probably need the big
  169. X   guy to help out.
  170. X
  171. X4. Install a .sshrc file in /usr/etc (or if you changed shell.h, then to
  172. X   whatever path you changed it to, perhaps /usr/local/etc?).  This is the
  173. X   system startup file for ssh.  It will _always_ be sourced by ssh no
  174. X   matter what.
  175. X
  176. X5. Install the manual in /usr/man/manl/ or /usr/man/man1/, or wherever the
  177. X   sys admin wants it.
  178. X
  179. X6. Install your ssh .login and .sshrc files in your home directory and
  180. X   change your shell to ssh.
  181. X
  182. X7. Enjoy...
  183. X
  184. END_OF_FILE
  185. if test 1126 -ne `wc -c <'INSTALLING'`; then
  186.     echo shar: \"'INSTALLING'\" unpacked with wrong size!
  187. fi
  188. # end of 'INSTALLING'
  189. fi
  190. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  191.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  192. else
  193. echo shar: Extracting \"'MANIFEST'\" \(889 characters\)
  194. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  195. X   File Name        Archive #    Description
  196. X-----------------------------------------------------------
  197. X COPYING                    1    
  198. X DISTRIBUTION               1    
  199. X INSTALLING                 1    
  200. X MANIFEST                   1    This shipping list
  201. X MODS                       1    
  202. X Makefile                   1    
  203. X NOTES                      1    
  204. X README                     1    
  205. X alias.c                    1    
  206. X assign.c                   1    
  207. X cmds.h                     1    
  208. X eval.c                     2    
  209. X exe.c                      2    
  210. X file.c                     1    
  211. X init.c                     1    
  212. X key.c                      1    
  213. X parse.c                    1    
  214. X scripts                    1    
  215. X shcmds.c                   3    
  216. X shell.c                    1    
  217. X shell.h                    1    
  218. X ssh.1                      4    
  219. X stat.c                     1    
  220. X vars.c                     2    
  221. X wc.c                       1    
  222. END_OF_FILE
  223. if test 889 -ne `wc -c <'MANIFEST'`; then
  224.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  225. fi
  226. # end of 'MANIFEST'
  227. fi
  228. if test -f 'MODS' -a "${1}" != "-c" ; then 
  229.   echo shar: Will not clobber existing file \"'MODS'\"
  230. else
  231. echo shar: Extracting \"'MODS'\" \(123 characters\)
  232. sed "s/^X//" >'MODS' <<'END_OF_FILE'
  233. Steve Baker (ice@judy.indstate.edu) and
  234. Thomas Moore (dark@judy.indstate.edu)
  235. Ssh V1.7
  236. Ssh in its original incarnation...
  237. X
  238. END_OF_FILE
  239. if test 123 -ne `wc -c <'MODS'`; then
  240.     echo shar: \"'MODS'\" unpacked with wrong size!
  241. fi
  242. # end of 'MODS'
  243. fi
  244. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  245.   echo shar: Will not clobber existing file \"'Makefile'\"
  246. else
  247. echo shar: Extracting \"'Makefile'\" \(2050 characters\)
  248. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  249. X# $Copyright:    $
  250. X# Copyright (c) 1991,1992,1993 by Steve Baker
  251. X# All rights reserved
  252. X#  
  253. X# This software is provided as is without any express or implied
  254. X# warranties, including, without limitation, the implied warranties
  255. X# of merchantability and fitness for a particular purpose.
  256. X#
  257. X#
  258. X# K&R compilers only for now:
  259. X# Making this program ANSI would be a good project for someone eh?
  260. X
  261. CC = cc
  262. X
  263. X#  Add these defines if required:
  264. X#    -DCANNOT_ALLOCA        - Set it anyway
  265. X#    -DNOSETENV        - For OS's with no setenv function like NeXT's
  266. X#    -DBSD4            - obvious
  267. X
  268. X#CFLAGS = -O0 -s -DCANNOT_ALLOCA
  269. CFLAGS = -g -DCANNOT_ALLOCA -DBSD4
  270. X#CFLAGS = -g -DCANNOT_ALLOCA -DNOSETENV
  271. X#CFLAGS = -g -DDEBUG -DCANNOT_ALLOCA
  272. X
  273. ARCHIVE = Makefile ssh.1 NOTES COPYING README MODS DISTRIBUTION INSTALLING \
  274. X      alias.c assign.c init.c key.c parse.c exe.c shcmds.c stat.c \
  275. X      shell.c wc.c vars.c eval.c file.c shell.h cmds.h scripts
  276. X
  277. OFILES = alias.o assign.o init.o key.o parse.o exe.o shcmds.o stat.o \
  278. X      shell.o wc.o vars.o eval.o file.o
  279. X
  280. LFILES = alias.c assign.c init.c key.c parse.c exe.c shcmds.c stat.c \
  281. X     shell.c wc.c vars.c eval.c file.c
  282. X
  283. X# These files are for debugging, you don't have these, so don't worry about
  284. X# it.
  285. X# mem/mem.o mem/smem.o mem/malloc.o
  286. X
  287. LIBS = -ltermcap
  288. X
  289. X# shells initial destination location and name before installing.
  290. DEST = ssh
  291. X
  292. X# Shells final destination.
  293. BINDEST = /usr/local/bin/ssh
  294. X
  295. X# manuals destination:
  296. MANFILE = ssh.1
  297. MAN = ssh.man
  298. MANDEST = /usr/man/man1/ssh.1
  299. X
  300. X# Archive filenames for lha and tar format.
  301. LHAFILE = ssh.v1.7.lha
  302. TARFILE = ssh.v1.7.tar
  303. X
  304. all:    ssh man
  305. X
  306. X
  307. ssh:    $(OFILES)
  308. X    $(CC) $(CFLAGS) -o $(DEST) $(OFILES) $(LIBS)
  309. X
  310. X
  311. man:
  312. X    nroff -man $(MANFILE) > $(MAN)
  313. X
  314. X
  315. install:
  316. X    cp $(DEST) $(BINDEST)
  317. X    cp $(MAN) $(MANDEST)
  318. X
  319. X
  320. clean:
  321. X    rm -f $(OFILES) $(DEST) $(MAN)
  322. X
  323. X
  324. X#
  325. X#
  326. X
  327. X$(OFILES):    shell.h
  328. X
  329. X
  330. X# Run lint on the bugger...
  331. lint:
  332. X    lint -v $(LFILES)
  333. X
  334. X
  335. X# Make the tar file...
  336. tar:
  337. X    tar cf $(TARFILE) $(ARCHIVE)
  338. X    compress $(TARFILE)
  339. X
  340. X# Make the LHA file...
  341. lha:
  342. X    lha cv $(LHAFILE) $(ARCHIVE)
  343. X
  344. X# Make silly shar files...
  345. shar:
  346. X    makekit -s60k $(ARCHIVE)
  347. END_OF_FILE
  348. if test 2050 -ne `wc -c <'Makefile'`; then
  349.     echo shar: \"'Makefile'\" unpacked with wrong size!
  350. fi
  351. # end of 'Makefile'
  352. fi
  353. if test -f 'NOTES' -a "${1}" != "-c" ; then 
  354.   echo shar: Will not clobber existing file \"'NOTES'\"
  355. else
  356. echo shar: Extracting \"'NOTES'\" \(6845 characters\)
  357. sed "s/^X//" >'NOTES' <<'END_OF_FILE'
  358. X                    -= NOTES TO PROGRAMMERS/HACKERS =-
  359. X
  360. Wishing to see the shell developed and not die a quick and dirty death, I
  361. submit some pointers to would be developers:
  362. X
  363. Status switches can easily be added in `stat.c' by adding new entries in
  364. the switch statement. Shell builtins are defined in the files `shcmds.c',
  365. X`alias.c', `vars.c', `assign.c' and `file.c'.  They are defined much like
  366. a C-program in and of themselves, with the number of arguments, the argument
  367. array and the input and output descriptors being passed to the function. Use
  368. of the global variables is not recommended unless you are knowledgeable in the
  369. operation of the shell.  Care should be taken with the use of the global
  370. variables `buf' and `path', as many of ssh's functions use them.
  371. X
  372. To add builtins, a define should be added to the enum in `cmds.h' and the
  373. NUM_CMDS should be incremented. Also an entry in the command list found at
  374. the start of `parse.c' needs to be inserted in the correct alphabetic
  375. location, then a case statement in shcmds.c which will allow the new command
  376. function to be invoked. One should be able to gleam the calling mechanisms
  377. from the given functions. Someone may want to take the time to remove the
  378. switch altogether and simply put the address of the function to call in the
  379. table in `parse.c' and remove the need for the defines and switch all
  380. together.  If I only had the time, I'd re-write the whole damn thing.
  381. X
  382. Anyways, for the wretched undergrad with too much time on his hands, here's
  383. a rundown of files and functions in brief:
  384. X
  385. alias.c
  386. X    All of the alias stuff, including the alias and unalias commands.
  387. X
  388. assign.c
  389. X    All of the assign stuff, including the assign and unassign commands.
  390. X
  391. eval.c
  392. X    The expression parser and tokenizer.  Needs to have the order of
  393. X    precedence of operators made the same as with C.  The parser is
  394. X    recursive decent and pretty easy to follow.  Might also want to
  395. X    integrate getnext() into the evaluator.
  396. X
  397. exe.c
  398. X    Where all the fun stuff happens. This is where shell redirection,
  399. X    piping, and execution happens.  It's a major chunk of the real
  400. X    shell.  I don't think this stuff could be improved dramatically.
  401. X
  402. file.c
  403. X    This is where all the file commands are defined.
  404. X
  405. init.c
  406. X    All the initialization functions.
  407. X
  408. key.c
  409. X    The command line input routines.  Serious improvement possible
  410. X    here.  Too much time is wasted checking if a key belongs to a macro
  411. X    in my humble opinion.  Just typing shouldn't eat up so much CPU
  412. X    time.  A hash table lookup perhaps?
  413. X
  414. parse.c
  415. X    Functions to split up a line into little words the shell can deal
  416. X    with. Command strings `...` are parsed and executed here as well.
  417. X
  418. shcmds.c
  419. X    The builtin-invoker and most of the builtin commands are defined
  420. X    here.
  421. X
  422. shell.c
  423. X    The other big chunk of the real shell. Command line args are parsed
  424. X    here. Sourcing and command execution is overseen here as well as
  425. X    the all-important SIGCHLD handler.
  426. X
  427. stat.c
  428. X    The routines to parse the status switches.
  429. X
  430. vars.c
  431. X    The routines to parse variables and the set and unset commands.
  432. X
  433. wc.c
  434. X    Toms wildcard routines, these are fine, don't touch them unless you
  435. X    know what you are doing.  Lots of useful routines in here if you
  436. X    can figure out how to extract them.  Feel free to import them into
  437. X    your own programs, but remember to give credit where credit is due.
  438. X
  439. cmds.h
  440. X    Defines for all the commands.
  441. X
  442. shell.h
  443. X    Pretty much all the structures that the shell uses are defined
  444. X    here.  Not all of them, but a good lot of 'em.
  445. X
  446. X
  447. Here's a few things I think that should be done straight away:
  448. X
  449. Tokenize everything and keep it that way until it's time to execute the
  450. command.  Would cut down tremendously on the number of strlen()'s and
  451. strcmp()'s done (profile it sometime, you'll be amazed!). Or maybe just
  452. figure out how to malloc less.  Exe.c is about the only file I feel is
  453. truly optimized in the scope of the current shell, although I think I
  454. could probably remove mallocing in exe.c altogether.  Even simple
  455. tokenization (like remembering that a word is really a string, but have the
  456. quotes stripped off already, this would eliminate quite a few mallocs when it
  457. comes time to execute the command).
  458. X
  459. key.c could stand to be re-written entirely, but keep the macro support
  460. similar to what it is, I don't like the idea of making your shell emulate
  461. emacs or vi, for crying out loud, you don't need a freaking editor built
  462. into your shell, it just makes the shell much larger for very little gain.
  463. Besides, I don't think emacs or vi is as intuitive as my macro setup.
  464. X
  465. Speed and size are essential.  A special printf should be made for the
  466. shell.  I don't need all the features of printf, just %s, %d and %c.
  467. XFormatting options can be gotten around.  Many printf's can probably be
  468. exchanged for puts()'s and fputs()'s.
  469. X
  470. Some alias behavior needs to be fixed with reguards to alias substitution
  471. of words in a pipeline while enclosed in parens.  It shouldn't do it.  By
  472. the same token, perhaps it would be best to recursive alias parse, like csh.
  473. X
  474. The variable stuff could stand to be made more "robust" and the set command
  475. should be made to set individual words in a string var and maybe even
  476. individual characters.  Should probably figure out a way to keep the
  477. recursive stuff from recursing too much.  Perhaps a maximum of 10-20 levels
  478. of recursion.
  479. X
  480. The command substitution (`...`) needs to be moved out of the split-line()
  481. function and into it's own section, so that it will work properly in shell
  482. scripts without a lot of paren and eval hokus-pokus.  Also since shell level
  483. pipes are a reality in this final version, the way `...` works should
  484. probably be made more along those lines. i.e. remove `...` altogether and
  485. make something like:
  486. X
  487. X    pwd >% xx &! set wd = $<% xx
  488. X
  489. Where $<% places the output of pwd on the command line for the set command.
  490. Which I would think would be far less kludgy and certainly would work in a
  491. script file. As far as I'm concerned, I don't care about csh compatibility
  492. anymore.  You can do more in ssh...
  493. X
  494. The secondary password support is far to easily circumvented on machines
  495. with ftp access.  Should be encrypted at least.  Perhaps the secondary
  496. password could be put in a root write only file with a setuid program to
  497. set the password, like passwd works.  Could be made fairly simply.  A
  498. secondary password is perhaps pointless anyway.
  499. X
  500. Amazing as it may seem, I'm not entirely unhappy with the shell as it is,
  501. in fact I'm fairly pleased with it. One is just never really done with these
  502. projects you know, and who knows, maybe somehow I'll manage to find a way to
  503. update all of this stuff myself.
  504. X
  505. Well, if you have questions and/or ideas, by all means drop me a line. I can
  506. be reached for the time being at ice@judy.indstate.edu... If I've moved on
  507. try contacting dark@judy.indstate.edu.  If all else fails figure it out
  508. yourself.
  509. X
  510. Have fun!
  511. X
  512. X                            - Steve Baker
  513. END_OF_FILE
  514. if test 6845 -ne `wc -c <'NOTES'`; then
  515.     echo shar: \"'NOTES'\" unpacked with wrong size!
  516. fi
  517. # end of 'NOTES'
  518. fi
  519. if test -f 'README' -a "${1}" != "-c" ; then 
  520.   echo shar: Will not clobber existing file \"'README'\"
  521. else
  522. echo shar: Extracting \"'README'\" \(2337 characters\)
  523. sed "s/^X//" >'README' <<'END_OF_FILE'
  524. X  This is ssh V1.7, a unix shell, written over the period of some 2 years on
  525. and off by Steve Baker with help from Thomas Moore who wrote the wildcarding
  526. routines for this shell.
  527. X
  528. X  This shell is public domain and may be copied and distributed and further
  529. developed under the guidelines set forth in the file COPYING.  Further
  530. development and modifications to the shell are strongly encouraged.
  531. X
  532. X  Ssh sports these features among others:
  533. X
  534. X  1. Job control (&, &!, jobs, fg, bg, stop)
  535. X  2. String, numeric and null variables w/ variable protection.
  536. X  3. Recursive string variable insertion.
  537. X  4. Advanced alias argument placement. (%- %+ %% %n %n-m).
  538. X  5. Logical assignments for abbreviated paths and files.
  539. X  6. Advanced wild card support (~*?[^-]{^})
  540. X  7. Advanced redirection and piping
  541. X     (< <% <<% > >% >> >>% >! >!% >>! >>!% >& >&% >>& >>&% | |! |&)
  542. X  8. C like expressions w/ the full set of C operators, including
  543. X     pre/post incrementing/deincrementing.
  544. X  9. Shell history save file (w/ auto set history size).
  545. X 10. Secondary password support
  546. X 11. Advanced key macro support w/ gold key support
  547. X 12. Command line editing
  548. X 13. Status line support
  549. X 14. New mail check
  550. X 15. Idle timeout
  551. X 16. Structured scripting language.
  552. X 17. 50+ builtin commands.
  553. X
  554. X  This shell has been compiled and tested on the following machines (future
  555. developers, please add machines that you have tested it on to this list):
  556. X
  557. X  A Sequent symmetry system running Dynix V3.2.0
  558. X  A Tatung Sun clone running SunOS V4.1.1
  559. X  A Sun running SunOS V4.1.1
  560. X  A NeXT running NeXTStep V3.0
  561. X  A DECstation running Ultrix 4.2A
  562. X  A 486 PC running BSDI BSD/386 V1.0
  563. X
  564. X  It is unlikely that all bugs have been worked out, but hopefully it's a
  565. fairly solid little shell.  If problems do arise while trying to compile
  566. this program, by all means contact me and I will attempt to help you (and
  567. perhaps release a fixed version).  I am sure that this program will not
  568. compile on all machines.
  569. X
  570. X  If you like ssh, and feel it in your heart to help out a starving
  571. programmer, please show your appreciation by sending a small donation to:
  572. X
  573. X  Steve Baker
  574. X  1600 S. Center St. Apt #1
  575. X  Terre Haute, IN 47802
  576. X
  577. X  You are under no obligation to send a donation, but by doing so, your
  578. kindness will be remembered... (no telling what that may mean... =)
  579. X
  580. X  Enjoy!
  581. X
  582. X                            - Steve Baker
  583. END_OF_FILE
  584. if test 2337 -ne `wc -c <'README'`; then
  585.     echo shar: \"'README'\" unpacked with wrong size!
  586. fi
  587. # end of 'README'
  588. fi
  589. if test -f 'alias.c' -a "${1}" != "-c" ; then 
  590.   echo shar: Will not clobber existing file \"'alias.c'\"
  591. else
  592. echo shar: Extracting \"'alias.c'\" \(7501 characters\)
  593. sed "s/^X//" >'alias.c' <<'END_OF_FILE'
  594. X/* $Copyright:    $
  595. X * Copyright (c) 1991,1992,1993 by Steve Baker
  596. X * All rights reserved
  597. X *  
  598. X * This software is provided as is without any express or implied
  599. X * warranties, including, without limitation, the implied warranties
  600. X * of merchantability and fitness for a particular purpose.
  601. X */
  602. X#include "shell.h"
  603. X
  604. extern struct _alias *alias[128];
  605. extern char buf[1025], path[1025];
  606. extern int a,b,c,d;
  607. X
  608. char ***parse_alias(), **exchange_alias(), **evalwrd(), *sub_parse();
  609. struct _alias *find_alias();
  610. X
  611. char ***parse_alias(arg)
  612. char ***arg;
  613. X{
  614. X  int i;
  615. X
  616. X  for(i=0;arg[i];i++)
  617. X    arg[i] = (char **)exchange_alias(arg[i]);
  618. X
  619. X  return arg;
  620. X}
  621. X
  622. char **exchange_alias(arg)
  623. char **arg;
  624. X{
  625. X  int twd,wrd,nt,i,j,max;
  626. X  char **tmp, **ptmp, **etmp, *flg, used;
  627. X  struct _alias *ALIAS;
  628. X
  629. X  tmp = (char **)calloc(nt = 5,sizeof(char *));
  630. X
  631. X  twd = wrd = 0;
  632. X  while(arg[wrd]) {
  633. X    ALIAS = find_alias(arg[wrd]);
  634. X
  635. X    if (!ALIAS) {
  636. X      while(arg[wrd] && arg[wrd][0] != '|') {
  637. X    if (twd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 5));
  638. X    tmp[twd++] = arg[wrd++];
  639. X      }
  640. X      if (!arg[wrd]) continue;
  641. X      /* we got a | if we got this far */
  642. X      if (twd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 5));
  643. X      tmp[twd++] = arg[wrd++];
  644. X      continue;
  645. X    }
  646. X    /* Our word was an alias, now we have to build up a subwordlist. */
  647. X    i = wrd;
  648. X    while (arg[wrd] && arg[wrd][0] != '|') wrd++;
  649. X    ptmp = (char **)calloc((wrd-i)+1, sizeof(char *));
  650. X    for(j=0;j<(wrd-i);j++) ptmp[j] = arg[j+i];
  651. X    ptmp[j] = NULL;
  652. X
  653. X    /*
  654. X     * got our subwordlist, now we make a flag list.  This should be done
  655. X     * in a binary fashion.  Use bits instead of whole bytes.
  656. X     */
  657. X    flg = (char *)malloc(j+1);
  658. X    bzero(flg,j+1);
  659. X    flg[j] = -1;
  660. X    max = j;
  661. X    used = FALSE;
  662. X
  663. X    /* Now we evaluate our alias, one word at a time */
  664. X    for(i=0;ALIAS->wrd[i];i++) {
  665. X      etmp = (char **)evalwrd(ALIAS->wrd[i],ptmp,flg,max,&used);
  666. X      if (!etmp) continue;
  667. X      for(j=0;etmp[j];j++) {
  668. X    if (twd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 5));
  669. X    tmp[twd++] = etmp[j];
  670. X      }
  671. X      free(etmp);
  672. X    }
  673. X
  674. X/* check if any args used, if not tack them on to the end of the word list */
  675. X
  676. X    if (!used) {    /* no args used */
  677. X      for(i=1;ptmp[i];i++) {
  678. X    if (twd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 5));
  679. X    tmp[twd++] = ptmp[i];
  680. X      }
  681. X      free(ptmp[0]);
  682. X    } else for(i=0;ptmp[i];i++) free(ptmp[i]);
  683. X    free(ptmp);
  684. X    free(flg);
  685. X    if (arg[wrd] && arg[wrd][0] == '|') {
  686. X      if (twd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 5));
  687. X      tmp[twd++] = arg[wrd++];
  688. X    }
  689. X  }
  690. X  if (twd == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 1));
  691. X  tmp[twd] = NULL;
  692. X  free(arg);
  693. X  return (char **)tmp;
  694. X}
  695. X
  696. X
  697. char **evalwrd(pat,arg,flg,max,used)
  698. char *pat, **arg, *flg, *used;
  699. int max;
  700. X{
  701. X  char **tmp, **sav, *s, c;
  702. X  int n,m,i,j,nt,bp,pos;
  703. X
  704. X  pos = bp = 0;
  705. X  tmp = (char **)malloc(sizeof(char *) * (nt = 2));
  706. X
  707. X  while(*pat) {
  708. X    switch(*pat++) {
  709. X      case '%':
  710. X        if (*pat == '-' || *pat == '+' || *pat == '%' || isdigit(*pat)) {
  711. X      c = *pat;
  712. X      if (isdigit(c)) {
  713. X        s = pat;
  714. X        while(isdigit(*pat)) pat++;
  715. X        m = n = atoi(s);
  716. X        if (n >= max) m = max - 1;
  717. X        if (*pat == '-' && isdigit(*(pat+1))) {
  718. X          s = ++pat;
  719. X          while(isdigit(*pat)) pat++;
  720. X          m = atoi(s);
  721. X          if (m < n) {
  722. X            i = n;
  723. X        n = m;
  724. X        m = i;
  725. X          }
  726. X          if (m >= max) m = max - 1;
  727. X        }
  728. X        pat--;
  729. X      } else {
  730. X        n = 1;
  731. X        m = max - 1;
  732. X      }
  733. X      buf[bp++] = 0;
  734. X      s = (char *)strcpy((char *)malloc(bp),buf);
  735. X      pat++;
  736. X      sav = evalwrd(pat,arg,flg,max,used);
  737. X      if (sav) {
  738. X        for(i=n;i <= m;i++) {
  739. X          if ((c == '-' && flg[i]) || (c == '+' && !flg[i])) continue;
  740. X          for(j=0;sav[j];j++) {
  741. X        if (pos == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 5));
  742. X        tmp[pos] = (char *)malloc(bp+strlen(arg[i])+strlen(sav[j]));
  743. X        sprintf(tmp[pos++],"%s%s%s",s,arg[i],sav[j]);
  744. X        }
  745. X          flg[i] = TRUE;
  746. X        }
  747. X        free_list(sav);  
  748. X      } else {
  749. X        for(i=n;i <= m;i++) {
  750. X          if ((c == '-' && flg[i]) || (c == '+' && !flg[i])) continue;
  751. X          if (pos == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 5));
  752. X          tmp[pos] = (char *)malloc(bp+strlen(arg[i]));
  753. X          sprintf(tmp[pos++],"%s%s",s,arg[i]);
  754. X          flg[i] = TRUE;
  755. X        }
  756. X      }
  757. X      free(s);
  758. X      *used = TRUE;
  759. X      if (pos == nt) tmp = (char **)realloc(tmp,sizeof(char *) * (nt += 1));
  760. X      tmp[pos] = NULL;
  761. X      return tmp;
  762. X    } else if (*pat == '#') {
  763. X      buf[bp] = 0;
  764. X      sprintf(buf,"%s%d",buf,max);
  765. X      bp = strlen(buf);
  766. X      pat++;
  767. X    } else buf[bp++] = '%';
  768. X    break;
  769. X      case '\\':
  770. X    if (*pat) {
  771. X      buf[bp++] = *pat++;
  772. X      break;
  773. X    }
  774. X    continue;
  775. X      default:
  776. X    buf[bp++] = *(pat-1);
  777. X    break;
  778. X    }
  779. X  }
  780. X  if (!bp) {
  781. X    free(tmp);
  782. X    return NULL;
  783. X  }
  784. X  buf[bp++] = 0;
  785. X  tmp[0] = (char *)strcpy((char *)malloc(bp),buf);
  786. X  tmp[1] = NULL;
  787. X  return (char **)tmp;
  788. X}
  789. X
  790. X
  791. ALIAS(n,arg,in,out,err)
  792. int n;
  793. char **arg;
  794. XFILE *in,*out,*err;
  795. X{
  796. X  char *tmp, **wrd;
  797. X  struct _alias *t;
  798. X
  799. X  if (n == 1) {
  800. X    for(a=0;a<128;a++) {
  801. X      t = alias[a];
  802. X      while(t != NULL) {
  803. X    fprt(out,t->cmd);
  804. X    putc('\t',out);
  805. X    tmp = (char *)string(t->wrd);
  806. X    fprt(out,tmp);
  807. X    putc('\n',out);
  808. X    free(tmp);
  809. X    t = t->nxt;
  810. X      }
  811. X    }
  812. X    return 0;
  813. X  }
  814. X  if (n == 2) {
  815. X    if (isregex(arg[1])) {
  816. X      for(a=0;a<128;a++) {
  817. X    t = alias[a];
  818. X    while(t != NULL) {
  819. X      if (patmatch(t->cmd,arg[1])) {
  820. X        fprt(out,t->cmd);
  821. X        putc('\t',out);
  822. X        tmp = (char *)string(t->wrd);
  823. X        fprt(out,tmp);
  824. X        putc('\n',out);
  825. X        free(tmp);
  826. X      }
  827. X      t = t->nxt;
  828. X    }
  829. X      }
  830. X    } else {
  831. X      if (!(t = find_alias(arg[1]))) return 1;
  832. X      fprt(out,t->cmd);
  833. X      putc('\t',out);
  834. X      tmp = (char *)string(t->wrd);
  835. X      fprt(out,tmp);
  836. X      putc('\n',out);
  837. X      free(tmp);
  838. X    }
  839. X    return 0;
  840. X  }
  841. X  tmp = (char *)malloc(strlen(arg[1])+1);
  842. X  strcpy(tmp,arg[1]);
  843. X  wrd = (char **)calloc(n-1,sizeof(char *));
  844. X  for(a=2;arg[a];a++) {
  845. X    wrd[a-2] = (char *)malloc(strlen(arg[a])+1);
  846. X    strcpy(wrd[a-2],arg[a]);
  847. X  }
  848. X  wrd[a-2] = NULL;
  849. X  add_alias(tmp,wrd);
  850. X  return 0;
  851. X}
  852. X
  853. UNALIAS(n,arg,in,out,err)
  854. int n;
  855. char **arg;
  856. XFILE *in,*out,*err;
  857. X{
  858. X  struct _alias *t;
  859. X
  860. X  if (n == 1) return 0;
  861. X  for(a=1;arg[a];a++) {
  862. X    if (isregex(arg[a])) {
  863. X      for(b=0;b<128;b++) {
  864. X    t = alias[b];
  865. X    while(t != NULL) {
  866. X      if (patmatch(t->cmd,arg[a])) remove_alias(t->cmd);
  867. X      t = t->nxt;
  868. X    }
  869. X      }
  870. X    } else remove_alias(arg[a]);
  871. X  }
  872. X  return 0;
  873. X}
  874. X
  875. X
  876. struct _alias *find_alias(pat)
  877. char *pat;
  878. X{
  879. X  char i,hf = *pat & 127;
  880. X  struct _alias *p;
  881. X
  882. X  p = alias[hf];
  883. X
  884. X  while(p) {
  885. X    if (!(i = strcmp(pat,p->cmd))) return p;
  886. X    if (i < 0) return NULL;
  887. X    p = p->nxt;
  888. X  }
  889. X  return NULL;
  890. X}
  891. X
  892. remove_alias(pat)
  893. char *pat;
  894. X{
  895. X  char i, hf = *pat & 127;
  896. X  struct _alias *p = alias[hf], *s;
  897. X
  898. X  s = p;
  899. X  while(p) {
  900. X    if (!(i = strcmp(pat,p->cmd))) {
  901. X      if (p == alias[hf]) alias[hf] = p->nxt;
  902. X      else s->nxt = p->nxt;
  903. X      free_list(p->wrd);
  904. X      free(p->cmd);
  905. X      free(p);
  906. X      return TRUE;
  907. X    }
  908. X    if (i < 0) return FALSE;
  909. X    s = p;
  910. X    p = p->nxt;
  911. X  }
  912. X  return FALSE;
  913. X}
  914. X
  915. add_alias(cmd,wrd)
  916. char *cmd, **wrd;
  917. X{
  918. X  char i, hf = *cmd & 127;
  919. X  struct _alias *p = alias[hf], *s, *t;
  920. X
  921. X  s = p;
  922. X  while(p) {
  923. X    if (!(i = strcmp(cmd,p->cmd))) {
  924. X      free(cmd);
  925. X      free_list(p->wrd);
  926. X      p->wrd = wrd;
  927. X      return 0;
  928. X    }
  929. X    if (i < 0) break;
  930. X    s = p;
  931. X    p = p->nxt;
  932. X  }
  933. X  t = (struct _alias *)malloc(sizeof(struct _alias));
  934. X  t->cmd = cmd;
  935. X  t->wrd = wrd;
  936. X  t->nxt = p;
  937. X  if (p == alias[hf] && s == alias[hf]) alias[hf] = t;
  938. X  else s->nxt = t;
  939. X  return 0;
  940. X}
  941. END_OF_FILE
  942. if test 7501 -ne `wc -c <'alias.c'`; then
  943.     echo shar: \"'alias.c'\" unpacked with wrong size!
  944. fi
  945. # end of 'alias.c'
  946. fi
  947. if test -f 'assign.c' -a "${1}" != "-c" ; then 
  948.   echo shar: Will not clobber existing file \"'assign.c'\"
  949. else
  950. echo shar: Extracting \"'assign.c'\" \(3669 characters\)
  951. sed "s/^X//" >'assign.c' <<'END_OF_FILE'
  952. X/* $Copyright:    $
  953. X * Copyright (c) 1991,1992,1993 by Steve Baker
  954. X * All rights reserved
  955. X *  
  956. X * This software is provided as is without any express or implied
  957. X * warranties, including, without limitation, the implied warranties
  958. X * of merchantability and fitness for a particular purpose.
  959. X */
  960. X
  961. X#include "shell.h"
  962. X
  963. X#define hash(x)    (isalpha(x)? (x & 31) + 10 : isdigit(x)? x - '0' : x == '_' ? 10 : -1)
  964. X
  965. struct _assign {
  966. X  char *name;
  967. X  char *path;
  968. X  struct _assign *next;
  969. X} *assign[37];
  970. X
  971. char *malloc(), *strcpy(), *evalassign(), **eval_assigns();
  972. extern char buf[1025],path[1025];
  973. extern int a,b,c,d;
  974. X
  975. char ***parse_assigns(arg)
  976. char ***arg;
  977. X{
  978. X  int i;
  979. X
  980. X  for(i=0;arg[i];i++)
  981. X    arg[i] = eval_assigns(arg[i]);
  982. X
  983. X  return arg;
  984. X}
  985. X
  986. char **eval_assigns(arg)
  987. char **arg;
  988. X{
  989. X  int i,n = 0;
  990. X
  991. X  for(i=0;arg[i];i++) {
  992. X    if (*arg[i] == '(' && !arg[i][1]) n++;
  993. X    if (*arg[i] == ')' && !arg[i][1]) n -= (n?1:0);
  994. X    if (!n) arg[i] = evalassign(arg[i]);
  995. X  }
  996. X  return arg;
  997. X}
  998. X
  999. char *evalassign(w)
  1000. char *w;
  1001. X{
  1002. X  int i;
  1003. X  char *p, *s = w, *tmp;
  1004. X  struct _assign *ptr;
  1005. X
  1006. X  if (*w == '\'' || *w == '"') return w;
  1007. X
  1008. X  if (!(p = (char *)index(w,':'))) return w;
  1009. X  for(i=0;w < p;i++) buf[i] = *w++;
  1010. X  buf[i] = 0;
  1011. X  w++;
  1012. X  ptr = assign[hash(*buf)];
  1013. X  while (ptr) {
  1014. X    if (!strcmp(ptr->name,buf)) break;
  1015. X    ptr = ptr->next;
  1016. X  }
  1017. X  if (!ptr) return s;
  1018. X  tmp = strcpy((char *)malloc(strlen(ptr->path)+strlen(w)+1),ptr->path);
  1019. X  strcat(tmp,w);
  1020. X  free(s);
  1021. X  return tmp;
  1022. X}
  1023. X
  1024. ASSIGN(n,arg,fout,ferr)
  1025. int n;
  1026. char **arg;
  1027. XFILE *fout,*ferr;
  1028. X{
  1029. X  struct _assign *p, *t, *s;
  1030. X  struct stat st;
  1031. X
  1032. X  if (n == 1) {
  1033. X    for(a=0;a<37;a++) {
  1034. X      p = assign[a];
  1035. X      while (p != NULL) {
  1036. X    fprintf(fout,"%s:\t%s\n",p->name,p->path);
  1037. X    p = p->next;
  1038. X      }
  1039. X    }
  1040. X    return 0;
  1041. X  }
  1042. X  if (n == 2) {
  1043. X    if ((a = hash(*arg[1])) < 0) return 1;
  1044. X    p = assign[a];
  1045. X    while (p != NULL) {
  1046. X      if (!strcmp(p->name,arg[1])) {
  1047. X    fprintf(fout,"%s:\t%s\n",p->name,p->path);
  1048. X    return 0;
  1049. X      }
  1050. X      p = p->next;
  1051. X    }
  1052. X    return 0;
  1053. X  }
  1054. X
  1055. X  if (n > 3) {
  1056. X    fprintf(ferr,"assign: too many arguments.\n");
  1057. X    return 1;
  1058. X  }
  1059. X  if (!(a = strlen(arg[1])) || !(b = strlen(arg[2]))) {
  1060. X    fprintf(ferr,"assign: invalid null assignment.\n");
  1061. X    return 1;
  1062. X  }
  1063. X  if (a > 80) {
  1064. X    fprintf(ferr,"assign: assignment name too long.\n");
  1065. X    return 1;
  1066. X  }
  1067. X  if (arg[1][a-1] == ':') arg[1][--a] = 0;
  1068. X  for(d=0;arg[1][d];d++)
  1069. X    if (hash(arg[1][d]) < 0) {
  1070. X      fprintf(ferr,"assign: illegal assignment name %s.\n",arg[1]);
  1071. X      return 1;
  1072. X    }
  1073. X
  1074. X  t = (struct _assign *)malloc(sizeof(struct _assign));
  1075. X  t->name = strcpy(malloc(strlen(arg[1])+1),arg[1]);
  1076. X  stat(arg[2],&st);
  1077. X  if ((st.st_mode & S_IFMT) == S_IFDIR && arg[2][b-1] != '/') {
  1078. X    t->path = strcpy(malloc(strlen(arg[2])+2),arg[2]);
  1079. X    strcat(t->path,"/");
  1080. X  } else t->path = strcpy(malloc(strlen(arg[2])+1),arg[2]);
  1081. X
  1082. X  s = p =  assign[b = hash(*arg[1])];
  1083. X  while(p) {
  1084. X    if (!(a=strcmp(p->name,t->name))) {
  1085. X      free(p->path);
  1086. X      p->path = t->path;
  1087. X      free(t->name);
  1088. X      free(t);
  1089. X      return 0;
  1090. X    }
  1091. X    if (a < 0) break;
  1092. X    s = p;
  1093. X    p = p->next;
  1094. X  }
  1095. X  t->next = p;
  1096. X  if (p == assign[b] && s == assign[b]) assign[b] = t;
  1097. X  else s->next = t;
  1098. X  return 0;  
  1099. X}
  1100. X
  1101. UNASSIGN(n,arg,fout,ferr)
  1102. int n;
  1103. char **arg;
  1104. XFILE *fout,*ferr;
  1105. X{
  1106. X  struct _assign *p, *s;
  1107. X  if (n == 1) {
  1108. X    fprintf(ferr,"unassign: not enough arguments.\n");
  1109. X    return 1;
  1110. X  }
  1111. X  for(a=1;arg[a];a++) {
  1112. X    s = p = assign[c = hash(*arg[a])];
  1113. X    while (p) {
  1114. X      if (!(b = strcmp(p->name,arg[a]))) {
  1115. X    if (s == assign[c]) assign[c] = p->next;
  1116. X    else s->next = p->next;
  1117. X    free(p->name);
  1118. X    free(p->path);
  1119. X    free(p);
  1120. X    break;
  1121. X      }
  1122. X      if (b < 0) break;
  1123. X      s = p;
  1124. X      p = p->next;
  1125. X    }
  1126. X  }
  1127. X  return 0;
  1128. X}
  1129. END_OF_FILE
  1130. if test 3669 -ne `wc -c <'assign.c'`; then
  1131.     echo shar: \"'assign.c'\" unpacked with wrong size!
  1132. fi
  1133. # end of 'assign.c'
  1134. fi
  1135. if test -f 'cmds.h' -a "${1}" != "-c" ; then 
  1136.   echo shar: Will not clobber existing file \"'cmds.h'\"
  1137. else
  1138. echo shar: Extracting \"'cmds.h'\" \(1013 characters\)
  1139. sed "s/^X//" >'cmds.h' <<'END_OF_FILE'
  1140. X/* $Copyright:    $
  1141. X * Copyright (c) 1991,1992,1993 by Steve Baker
  1142. X * All rights reserved
  1143. X *  
  1144. X * This software is provided as is without any express or implied
  1145. X * warranties, including, without limitation, the implied warranties
  1146. X * of merchantability and fitness for a particular purpose.
  1147. X */
  1148. enum {
  1149. X  CMD_CD = 1, CMD_ALIAS, CMD_SET, CMD_KEY, CMD_LIMIT, CMD_UNALIAS, CMD_UNSET,
  1150. X  CMD_UNKEY, CMD_UNLIMIT, CMD_UMASK, CMD_HISTORY, CMD_JOBS, CMD_LOGOUT,
  1151. X  CMD_EXIT, CMD_FG, CMD_BG, CMD_SOURCE, CMD_STOP, CMD_SETENV, CMD_UNSETENV,
  1152. X  CMD_VERSION, CMD_IF, CMD_ELSE, CMD_ENDIF, CMD_INPUT, CMD_LOGIN, CMD_SECHO,
  1153. X  CMD_WHILE, CMD_WEND, CMD_REPEAT, CMD_UNTIL, CMD_BREAK, CMD_CONTINUE,
  1154. X  CMD_LABEL, CMD_GOTO, CMD_INC, CMD_DEC, CMD_EVAL, CMD_EXEC, CMD_FOREACH,
  1155. X  CMD_ENDFOR, CMD_FOR, CMD_NEXT, CMD_SWITCH, CMD_ENDSW, CMD_USAGE, CMD_INTR,
  1156. X  CMD_TERM, CMD_PROTECT, CMD_ASSIGN, CMD_UNASSIGN, CMD_SHIFT, CMD_SOPEN,
  1157. X  CMD_SCLOSE, CMD_SREAD, CMD_SWRITE, CMD_SSEEK
  1158. X};
  1159. X
  1160. X#define MAX_CMD        57
  1161. X
  1162. struct command {
  1163. X  char *cmd;
  1164. X  char val;
  1165. X};
  1166. END_OF_FILE
  1167. if test 1013 -ne `wc -c <'cmds.h'`; then
  1168.     echo shar: \"'cmds.h'\" unpacked with wrong size!
  1169. fi
  1170. # end of 'cmds.h'
  1171. fi
  1172. if test -f 'file.c' -a "${1}" != "-c" ; then 
  1173.   echo shar: Will not clobber existing file \"'file.c'\"
  1174. else
  1175. echo shar: Extracting \"'file.c'\" \(8413 characters\)
  1176. sed "s/^X//" >'file.c' <<'END_OF_FILE'
  1177. X/* $Copyright:    $
  1178. X * Copyright (c) 1991,1992,1993 by Steve Baker
  1179. X * All rights reserved
  1180. X *  
  1181. X * This software is provided as is without any express or implied
  1182. X * warranties, including, without limitation, the implied warranties
  1183. X * of merchantability and fitness for a particular purpose.
  1184. X */
  1185. X#include "shell.h"
  1186. X#include <fcntl.h>
  1187. X
  1188. X#define MAX_FILES    10
  1189. X
  1190. extern char buf[1024],path[1024];
  1191. X
  1192. struct _FILES FILES[MAX_FILES];
  1193. X
  1194. X/* sopen
  1195. X * sopen <desc>
  1196. X * sopen <desc> <file> <mode> [<mode> .. <mode>]
  1197. X *    modes:
  1198. X *    READ        reading
  1199. X *    WRITE        writing
  1200. X *    APPEND        appended to file
  1201. X *    TRUNCATE    truncate on open
  1202. X *    PIPE        Open a pipe descriptor for READ and WRITE.
  1203. X */
  1204. SOPEN(n,arg,fout,ferr)
  1205. int n;
  1206. char **arg;
  1207. XFILE *fout, *ferr;
  1208. X{
  1209. X  static char *fmts[] = {"READ","WRITE","APPEND","TRUNCATE","PIPE",0};
  1210. X  char i,j, p = -1;
  1211. X  int fmt, pd[2];
  1212. X
  1213. X  if (n == 1) {
  1214. X    for(i=0;i<MAX_FILES;i++) {
  1215. X      if (FILES[i].name)
  1216. X        fprintf(fout,"%s [%s] is open for %s%s%s.\n",FILES[i].name,FILES[i].file,FILES[i].read?"reading":"",(FILES[i].read && FILES[i].write)?" and ":"",FILES[i].write?"writing":"");
  1217. X    }
  1218. X    return 0;
  1219. X  }
  1220. X  if (n == 2) {
  1221. X    for(i=0;i<MAX_FILES;i++) {
  1222. X      if (FILES[i].name && !strcmp(arg[1],FILES[i].name)) {
  1223. X        fprintf(fout,"%s [%s] is open for %s%s%s.\n",FILES[i].name,FILES[i].file,FILES[i].read?"reading":"",FILES[i].read && FILES[i].write?" and ":"",FILES[i].write?"writing":"");
  1224. X    return 0;
  1225. X      }
  1226. X    }
  1227. X    return 0;
  1228. X  }
  1229. X  for(i=0;i<MAX_FILES;i++) {
  1230. X    if (FILES[i].name && !strcmp(arg[1],FILES[i].name)) {
  1231. X      fprintf(ferr,"sopen: descriptor %s already references file %s.\n",FILES[i].name,FILES[i].file);
  1232. X      return 1;
  1233. X    }
  1234. X    if (p < 0 && !FILES[i].name) p = i;
  1235. X  }
  1236. X  if (p < 0) {
  1237. X    fprintf(ferr,"sopen: file descriptor table full.\n");
  1238. X    return 1;
  1239. X  }
  1240. X  FILES[p].pread = FILES[p].pwrite = 0;
  1241. X  FILES[p].ispipe = FILES[p].pipe = FILES[p].read = FILES[p].write = 0;
  1242. X  fmt = O_CREAT;
  1243. X  if (n > 3) {
  1244. X    for(i=3;i<n;i++) {
  1245. X      for(j=0;fmts[j];j++)
  1246. X    if (!strcmp(fmts[j],arg[i])) break;
  1247. X      if (fmts[j]) {
  1248. X    switch(j) {
  1249. X      case 0:
  1250. X        if (FILES[p].write) {
  1251. X          fmt &= ~O_WRONLY;
  1252. X          fmt |= O_RDWR;
  1253. X        } else fmt |= O_RDONLY;
  1254. X        FILES[p].read = 1;    
  1255. X        break;
  1256. X      case 1:
  1257. X        if (FILES[p].read) {
  1258. X          fmt &= ~O_RDONLY;
  1259. X          fmt |= O_RDWR;
  1260. X        } else fmt |= O_WRONLY;
  1261. X        FILES[p].write = 1;
  1262. X        break;
  1263. X      case 2:
  1264. X        fmt |= O_APPEND;
  1265. X        FILES[p].write = 1;
  1266. X        break;
  1267. X      case 3:
  1268. X        fmt |= O_TRUNC;
  1269. X        FILES[p].write = 1;
  1270. X        break;
  1271. X      case 4:
  1272. X        FILES[p].ispipe = 1;
  1273. X        break;
  1274. X    }
  1275. X      }
  1276. X    }
  1277. X  } else {
  1278. X    fmt |= O_RDONLY;
  1279. X    FILES[p].read = 1;
  1280. X  }
  1281. X  if (FILES[p].ispipe) {
  1282. X    FILES[p].read = FILES[p].write = 1;
  1283. X    if (pipe(pd) < 0) {
  1284. X      fprintf(ferr,"sopen: error opening pipe %s.\n",arg[1]);
  1285. X      return 1;
  1286. X    }
  1287. X    FILES[p].pipe = pd[0];
  1288. X    FILES[p].desc = pd[1];
  1289. X    fcntl(FILES[p].pipe,F_SETFD,1);
  1290. X  } else if ((FILES[p].desc = open(arg[2],fmt,0777)) < 0) {
  1291. X    fprintf(ferr,"sopen: error opening file %s for %s.\n",arg[3],FILES[p].read?"reading":"writing");
  1292. X    return 1;
  1293. X  }
  1294. X  fcntl(FILES[p].desc,F_SETFD,1);
  1295. X  FILES[p].name = SCOPY(arg[1]);
  1296. X  FILES[p].file = SCOPY(arg[2]);
  1297. X  return 0;
  1298. X}
  1299. X
  1300. X/*
  1301. X * sclose <desc> [<desc> ... <desc>]
  1302. X */
  1303. SCLOSE(n,arg,ferr)
  1304. int n;
  1305. char **arg;
  1306. XFILE *ferr;
  1307. X{
  1308. X  int i,j;
  1309. X
  1310. X  if (n < 2) {
  1311. X    fprintf(ferr,"sclose: missing file descriptor specification.\n");
  1312. X    return 1;
  1313. X  }
  1314. X  for(i=1;i<n;i++) {
  1315. X    for(j=0;j<MAX_FILES;j++)
  1316. X      if (!strcmp(FILES[j].name,arg[i])) break;
  1317. X    if (j < MAX_FILES) {
  1318. X      if (FILES[j].pipe) close(FILES[j].pipe);
  1319. X      close(FILES[j].desc);
  1320. X      free(FILES[j].name);
  1321. X      FILES[j].name = NULL;
  1322. X      free(FILES[j].file);
  1323. X    } else {
  1324. X      fprintf(ferr,"sclose: invalid file descriptor '%s'.\n",arg[i]);
  1325. X    }
  1326. X  }
  1327. X  return 0;
  1328. X}
  1329. X
  1330. X/* sseek <desc> <mode> <expression>
  1331. X * mode:
  1332. X *   INCR
  1333. X *   SET
  1334. X *   XTND
  1335. X */
  1336. X
  1337. SSEEK(n,arg,ferr)
  1338. int n;
  1339. char **arg;
  1340. XFILE *ferr;
  1341. X{
  1342. X  static char *modes[] = {"INCR","SET","XTND",0};
  1343. X  char *ex;
  1344. X  BYTE f;
  1345. X  int i,mode;
  1346. X  long pos,rpos;
  1347. X
  1348. X  if (n < 4) {
  1349. X    fprintf(ferr,"sseek: Not enough arguments.\n");
  1350. X    return 1;
  1351. X  }
  1352. X
  1353. X  for(f=0;f<MAX_FILES;f++)
  1354. X    if (!strcmp(arg[1],FILES[f].name)) break;
  1355. X
  1356. X  if (f == MAX_FILES) {
  1357. X    fprintf(ferr,"sseek: %s not a valid open file descriptor.\n",arg[1]);
  1358. X    return 1;
  1359. X  }
  1360. X  if (FILES[f].ispipe) {
  1361. X    fprintf(ferr,"sseek: seeks not allowed on pipes.\n");
  1362. X    return 1;
  1363. X  }
  1364. X  for(i=0;modes[i];i++)
  1365. X    if (!strcmp(modes[i],arg[2])) break;
  1366. X
  1367. X  if (!modes[i]) {
  1368. X    fprintf(ferr,"sseek: invalid seek operation '%s'.\n",arg[2]);
  1369. X    return 1;
  1370. X  }
  1371. X  if (!i) mode = L_INCR;
  1372. X  else if (i == 1) mode = L_SET;
  1373. X  else mode = L_XTND;
  1374. X  ex = (char *)grab(arg,3,NULL,&i);
  1375. X  if (!ex) {
  1376. X    fprintf(ferr,"sseek: expected expression.\n");
  1377. X    return 1;
  1378. X  }
  1379. X  pos = expr(ex);
  1380. X  free(ex);
  1381. X  rpos = lseek(FILES[f].desc,pos,mode);
  1382. X  makenvar("filepos",rpos);
  1383. X  return 0;
  1384. X}
  1385. X
  1386. X/*
  1387. X * swrite <desc> [-n] <data>
  1388. X */
  1389. X
  1390. SWRITE(n,arg,ferr)
  1391. int n;
  1392. char **arg;
  1393. XFILE *ferr;
  1394. X{
  1395. X  BYTE f,b,flg = FALSE;
  1396. X  int i;
  1397. X  char *res;
  1398. X
  1399. X  if (n < 3) {
  1400. X    fprintf(ferr,"swrite: Not enough arguments.\n");
  1401. X    return 1;
  1402. X  }
  1403. X  for(f=0;f<MAX_FILES;f++)
  1404. X    if (!strcmp(FILES[f].name,arg[1])) break;
  1405. X  if (f == MAX_FILES) {
  1406. X    fprintf(ferr,"swrite: unknown file descriptor '%s'.\n",arg[1]);
  1407. X    return 1;
  1408. X  }
  1409. X  if (!FILES[f].write) {
  1410. X    fprintf(ferr,"swrite: '%s' not open for writing.  Operation aborted.\n",FILES[f].name);
  1411. X    return 1;
  1412. X  }
  1413. X  if (FILES[f].ispipe && FILES[f].read && FILES[f].write) {
  1414. X    FILES[f].read = 0;
  1415. X    close(FILES[f].pipe);
  1416. X    FILES[f].pipe = 0;
  1417. X  }
  1418. X  for(b=TRUE,i=2;i<n;i++) {
  1419. X    if (arg[i][0] == '-' && arg[i][1] == 'n' && !arg[i][2]) b = FALSE;
  1420. X    else {
  1421. X      res = (char *)pline(arg[i],1023,1023);
  1422. X      if (flg) {
  1423. X    if (write(FILES[f].desc," ",1) < 0) {
  1424. X      fprintf(stderr,"swrite: Error writing to file %s [%s].\n",FILES[f].name,FILES[f].file);
  1425. X      return 1;
  1426. X    }
  1427. X      }
  1428. X      if (write(FILES[f].desc,res,strlen(res)) < 0) {
  1429. X    fprintf(stderr,"swrite: Error writing to file %s [%s].\n",FILES[f].name,FILES[f].file);
  1430. X    return 1;
  1431. X      } else flg = TRUE;
  1432. X    }
  1433. X  }
  1434. X  if (b) if (write(FILES[f].desc,"\n",1) < 0) {
  1435. X    fprintf(stderr,"swrite: Error writing to file %s [%s].\n",FILES[f].name,FILES[f].file);
  1436. X    return 1;
  1437. X  }
  1438. X  return 0;
  1439. X}
  1440. X
  1441. X/*
  1442. X * sread <desc> [-c] [-l] [-w] [-bn] <var>
  1443. X *  -l    Read in a line.
  1444. X *  -w    Read in a line, breaking it up into words.
  1445. X *  -c    Read in a character.
  1446. X *  -bn    Read in n characters.
  1447. X */
  1448. SREAD(n,arg,ferr)
  1449. int n;
  1450. char **arg;
  1451. XFILE *ferr;
  1452. X{
  1453. X  BYTE f, mode = 0;
  1454. X  WORD i, j, k, res;
  1455. X
  1456. X  if (n < 3) {
  1457. X    fprintf(ferr,"read: not enough arguments.\n");
  1458. X    return 1;
  1459. X  }
  1460. X  for(f=0;f<MAX_FILES;f++)
  1461. X    if (!strcmp(arg[1],FILES[f].name)) break;
  1462. X  if (f == MAX_FILES) {
  1463. X    fprintf(ferr,"sread: invalid file descriptor '%s'.\n",arg[1]);
  1464. X    return 1;
  1465. X  }
  1466. X  if (!FILES[f].read) {
  1467. X    fprintf(ferr,"sread: '%s' not open for reading.  Operation aborted.\n",FILES[f].name);
  1468. X    return 1;
  1469. X  }
  1470. X  if (FILES[f].ispipe && FILES[f].write && FILES[f].read) {
  1471. X    FILES[f].write = 0;
  1472. X    close(FILES[f].desc);
  1473. X    FILES[f].desc = FILES[f].pipe;
  1474. X    FILES[f].pipe = 0;
  1475. X  }
  1476. X
  1477. X  for(i=2;i<n;i++) {
  1478. X    if (arg[i][0] == '-') {
  1479. X      switch(arg[i][1]) {
  1480. X    case 'l':
  1481. X      mode = 0;
  1482. X      break;
  1483. X    case 'w':
  1484. X      mode = 1;
  1485. X      break;
  1486. X    case 'c':
  1487. X      mode = 2;
  1488. X      break;
  1489. X    case 'b':
  1490. X      mode = 3;
  1491. X      k = atoi(arg[i]+2);
  1492. X      break;
  1493. X    default:
  1494. X      fprintf(stderr,"sread: '%s' invalid option.\n",arg[i]);
  1495. X      return 1;
  1496. X      }
  1497. X      continue;
  1498. X    }
  1499. X    switch(mode) {
  1500. X      case 0:
  1501. X      case 1:
  1502. X    for(j=0;;j++) {
  1503. X      if ((res = read(FILES[f].desc,buf+j,1)) < 0) {
  1504. X        fprintf(ferr,"sread: error reading from %s [%s].\n",FILES[f].name,FILES[f].file);
  1505. X        return 1;
  1506. X      }
  1507. X      if (!res) {
  1508. X        buf[j] = 0;
  1509. X        makeset(arg[i],buf);
  1510. X        makeset("EOF",FILES[f].name);
  1511. X        return 0;
  1512. X      }
  1513. X      if (buf[j] == '\n') break;
  1514. X    }
  1515. X    buf[j] = 0;
  1516. X    if (mode) makewset(arg[i],buf);
  1517. X    else makeset(arg[i],buf);
  1518. X    break;
  1519. X      case 2:
  1520. X    if ((res = read(FILES[f].desc,buf,1)) < 0) {
  1521. X      fprintf(ferr,"sread: error reading from %s [%s].\n",FILES[f].name,FILES[f].file);
  1522. X      return 1;
  1523. X    }
  1524. X    if (!res) {
  1525. X      makeset("EOF",FILES[f].name);
  1526. X      return 0;
  1527. X    }
  1528. X    buf[1] = 0;
  1529. X    makeset(arg[i],buf);
  1530. X    break;
  1531. X      case 3:
  1532. X    if (read(FILES[f].desc,buf,k) < 0) {
  1533. X      fprintf(ferr,"sread: error reading from %s [%s].\n",FILES[f].name,FILES[f].file);
  1534. X      return 1;
  1535. X    }
  1536. X    if (!res) {
  1537. X      makeset("EOF",FILES[f].name);
  1538. X      return 0;
  1539. X    }
  1540. X    buf[k] = 0;
  1541. X    makeset(arg[i],buf);
  1542. X    break;
  1543. X    }
  1544. X  }
  1545. X  return 0;
  1546. X}
  1547. END_OF_FILE
  1548. if test 8413 -ne `wc -c <'file.c'`; then
  1549.     echo shar: \"'file.c'\" unpacked with wrong size!
  1550. fi
  1551. # end of 'file.c'
  1552. fi
  1553. if test -f 'init.c' -a "${1}" != "-c" ; then 
  1554.   echo shar: Will not clobber existing file \"'init.c'\"
  1555. else
  1556. echo shar: Extracting \"'init.c'\" \(4644 characters\)
  1557. sed "s/^X//" >'init.c' <<'END_OF_FILE'
  1558. X/* $Copyright:    $
  1559. X * Copyright (c) 1991,1992,1993 by Steve Baker
  1560. X * All rights reserved
  1561. X *  
  1562. X * This software is provided as is without any express or implied
  1563. X * warranties, including, without limitation, the implied warranties
  1564. X * of merchantability and fitness for a particular purpose.
  1565. X */
  1566. X#include "shell.h"
  1567. X#include <utmp.h>
  1568. X#include <pwd.h>
  1569. X#include <sgtty.h>
  1570. X
  1571. extern char **PATH;
  1572. extern struct proc_tab *proc;
  1573. extern int max_ent,_pgrp;
  1574. extern char **history;
  1575. extern int _maxhist;
  1576. extern char *_prompt,*_home,*_mbox, *getenv();
  1577. extern char _loginshell, _echo, _verbose, _willecho, _willverbose;
  1578. extern char *_term[11];
  1579. extern char *_kbuf[MAX_GLVL], _kmax[MAX_GLVL];
  1580. extern struct _alias *alias[128];
  1581. extern struct custom_keys **keys[MAX_GLVL];
  1582. struct _setvar *sets[37], *statvar;
  1583. struct sgttyb OTTY;
  1584. struct sgttyb STTY;
  1585. X
  1586. extern char *gettime();
  1587. struct _setvar *makeset(), *makenvar(), *add_var();
  1588. X
  1589. extern char buf[1025], path[1025];
  1590. X
  1591. X
  1592. init()
  1593. X{
  1594. X  int i,j,k;
  1595. X  char *tmp;
  1596. X  struct utmp utmp;
  1597. X  struct passwd *pwd;
  1598. X  struct _setvar *VAR;
  1599. X
  1600. X  i = NTTYDISC;
  1601. X  ioctl(TTY,TIOCSETD,&i);
  1602. X
  1603. X  for(i=0;i<128;i++) alias[i] = NULL;
  1604. X  proc = (struct proc_tab *)calloc(10, sizeof(struct proc_tab));
  1605. X  for(i=0;i<10;i++) proc[i].pid = 0;
  1606. X  max_ent = 10;
  1607. X  history = (char **)calloc(_maxhist, sizeof(char *));
  1608. X  makenvar("history",30);
  1609. X  makenvar("pid",getpid());
  1610. X  if (getuid()) makeset("prompt","> ");
  1611. X  else makeset("prompt","# ");
  1612. X
  1613. X  _kmax[0] = 0;
  1614. X  _kbuf[0] = (char *)malloc(1);
  1615. X  _kbuf[0][0] = 0;
  1616. X
  1617. X  makeset("cwd",getwd(path));
  1618. X  statvar = makenvar("status",0);
  1619. X  statvar->protect = 1;
  1620. X
  1621. X  pwd = getpwuid(getuid());
  1622. X  _home = (char*)malloc(strlen(pwd->pw_dir)+1);
  1623. X  strcpy(_home,pwd->pw_dir);
  1624. X  makeset("home",_home);
  1625. X
  1626. X  _pgrp = getpgrp(0);
  1627. X  
  1628. X  makeset("tty",tmp = (char *)ttyname(0));
  1629. X  i = open("/etc/utmp",O_RDONLY);
  1630. X  while(read(i,&utmp,sizeof(utmp)) > 0) {
  1631. X    if (!strncmp(utmp.ut_line,tmp+5,8)) {
  1632. X      if (utmp.ut_host[0]) {
  1633. X        strncpy(buf,utmp.ut_host,16);
  1634. X    buf[16] = 0;
  1635. X        makeset("remotehost",buf);
  1636. X      }
  1637. X      break;
  1638. X    }
  1639. X  }
  1640. X  close(i);
  1641. X
  1642. X  gethostname(buf,&i);
  1643. X  makeset("host",buf);
  1644. X  makeset("user",getenv("USER"));
  1645. X  makenull("insert");
  1646. X  if (_echo) makenull("echo");
  1647. X  if (_verbose) makenull("verbose");
  1648. X
  1649. X  strcpy(path,getenv("PATH"));
  1650. X  VAR = makeset("path",".");
  1651. X  PATH = VAR->sv.wrd;
  1652. X  j = k = 0;
  1653. X  free(PATH[0]);
  1654. X  for(i=0;path[i];i++) if (path[i] == ':') k++;
  1655. X  if (i > 0 && path[i-1] != ':') k++;
  1656. X  PATH = (char **)realloc(PATH,sizeof(char *) * (k+2));
  1657. X  k = 0;
  1658. X  for(i=0;path[i];i++) {
  1659. X    if (path[i] == ':') {
  1660. X      buf[k] = 0;
  1661. X      k = 0;
  1662. X      PATH[j] = (char *)malloc(strlen(buf)+1);
  1663. X      strcpy(PATH[j++],buf);
  1664. X    } else buf[k++] = path[i];
  1665. X  }
  1666. X  buf[k] = 0;
  1667. X  if (k != 0) {
  1668. X    PATH[j] = (char *)malloc(strlen(buf)+1);
  1669. X    strcpy(PATH[j++],buf);
  1670. X  }
  1671. X  PATH[j] = NULL;
  1672. X  VAR->nwrds = j;
  1673. X  VAR->sv.wrd = PATH;
  1674. X  export(VAR);
  1675. X}
  1676. X
  1677. init_term()
  1678. X{
  1679. X  char i;
  1680. X
  1681. X  for(i=0;i<11;i++) _term[i] = NULL;
  1682. X  makeset("term",getenv("TERM"));
  1683. X}
  1684. X
  1685. set_term(term)
  1686. char *term;
  1687. X{
  1688. X  char *area = path, i;
  1689. X  static char *info[11] = {"so","se","ce","ks","ke","dc","ic","ds","ts","fs",0};
  1690. X
  1691. X  if (tgetent(buf,term) < 0) return -1;
  1692. X
  1693. X  for(i=0;info[i];i++) {
  1694. X    if (_term[i]) free(_term[i]);
  1695. X    _term[i] = (char *)tgetstr(info[i],&area);
  1696. X    if (!_term[i]) continue;
  1697. X    while(isdigit(*_term[i])) _term[i]++;
  1698. X    _term[i] = (char *)strcpy((char *)malloc(strlen(_term[i])+1),_term[i]);
  1699. X  }
  1700. X  _term[HS] = (char *)tgetflag("hs");
  1701. X  return 0;
  1702. X}
  1703. X
  1704. second_pass()
  1705. X{
  1706. X  FILE *fd, *fopen();
  1707. X  int i;
  1708. X  char pass[21],tmp[21];
  1709. X
  1710. X  sprintf(path,"%s/%s",_home,SECOND_PASS);
  1711. X  if ((fd = fopen(path,"r")) == NULL) return;
  1712. X  fgets(pass,20,fd);
  1713. X  fclose(fd);
  1714. X  pass[20] = 0;
  1715. X  noecho();
  1716. X  printf("\nSecondary password: ");
  1717. X  fgets(tmp,20,stdin);
  1718. X  echo();
  1719. X  putchar('\n');
  1720. X  sprintf(path,"%s/%s",_home,WARNING);
  1721. X
  1722. X  if (strcmp(pass,tmp)) {
  1723. X    if ((fd = fopen(path,"a")) == NULL) exit(0);
  1724. X    chmod(path,0600);
  1725. X    fprintf(fd,"failed login attempt at %s ",gettime(0));
  1726. X    fprintf(fd,"%s ",gettime(3));
  1727. X    fprintf(fd,"%s ",gettime(2));
  1728. X    fprintf(fd,"%s on %s : %s",gettime(4),ttyname(0),tmp);
  1729. X    fclose(fd);
  1730. X    exit(0);
  1731. X  }
  1732. X
  1733. X  if ((fd = fopen(path,"r")) == NULL) return;
  1734. X  for(i=0;fgets(buf,256,fd);i++);
  1735. X  fprintf(stderr,"\007There have been %d failed login attempts.\n",i);
  1736. X  fclose(fd);  
  1737. X}
  1738. X
  1739. load_hist()
  1740. X{
  1741. X  char l;
  1742. X  FILE *fd;
  1743. X
  1744. X  sprintf(path,"%s/%s",_home,HIST_SAVE);
  1745. X  if ((fd = fopen(path,"r")) == NULL) return -1;
  1746. X  fgets(buf,256,fd);
  1747. X  buf[strlen(buf)-1] = 0;
  1748. X  makenvar("history",atoi(buf));
  1749. X  while(fgets(buf,256,fd) != NULL) {
  1750. X    l = strlen(buf) - 1;
  1751. X    if (buf[l] == '\n') buf[l] = 0;
  1752. X    add_history(buf);
  1753. X  }
  1754. X  fclose(fd);
  1755. X  return 0;
  1756. X}
  1757. END_OF_FILE
  1758. if test 4644 -ne `wc -c <'init.c'`; then
  1759.     echo shar: \"'init.c'\" unpacked with wrong size!
  1760. fi
  1761. # end of 'init.c'
  1762. fi
  1763. if test -f 'key.c' -a "${1}" != "-c" ; then 
  1764.   echo shar: Will not clobber existing file \"'key.c'\"
  1765. else
  1766. echo shar: Extracting \"'key.c'\" \(11531 characters\)
  1767. sed "s/^X//" >'key.c' <<'END_OF_FILE'
  1768. X/* $Copyright:    $
  1769. X * Copyright (c) 1991,1992,1993 by Steve Baker
  1770. X * All rights reserved
  1771. X *  
  1772. X * This software is provided as is without any express or implied
  1773. X * warranties, including, without limitation, the implied warranties
  1774. X * of merchantability and fitness for a particular purpose.
  1775. X */
  1776. X#include "shell.h"
  1777. X#include <sgtty.h>
  1778. X
  1779. extern char *_prompt, *_statline, **history, *_kbuf[MAX_GLVL], _kmax[MAX_GLVL];
  1780. extern char _insert, _glvl, _verbose, _notypeahead, _glob, *_term[11];
  1781. extern int _maxhist, curhist, err;
  1782. extern struct custom_keys **keys[MAX_GLVL];
  1783. extern char buf[1025], *errstr, *erru, _noassigns;
  1784. X
  1785. struct sgttyb OTTY, STTY;
  1786. char **files, **dirget();
  1787. X
  1788. char str[256], prompt[81], *pline(), *index();
  1789. int pos, len, refresh();
  1790. extern struct timeval *_timeout;
  1791. X
  1792. char *getline()
  1793. X{
  1794. X  char tstr[2], prefix[20], flg, fk = 0, ic = 0, bs = 0, *ptr = NULL;
  1795. X  char ***arg;
  1796. X  short hist = curhist;
  1797. X  int i, j, x, s, e, r, kp = 0, ch;
  1798. X  struct custom_keys *KEY;
  1799. X
  1800. X  tstr[1] = 0;
  1801. X  pos = len = 0;
  1802. X
  1803. X  noecho();
  1804. X
  1805. X  if (_statline && _term[HS]) printf("%s%s%s%s%s",_term[DS],_term[TS],pline(_statline,1023,1023),_term[CE],_term[FS]);
  1806. X  strcpy(prompt,pline(_prompt,80,80));
  1807. X  printf("\r%s",prompt);
  1808. X
  1809. X  do {
  1810. X    if (_timeout) {
  1811. X      j = 1;
  1812. X      i = select(1,&j,NULL,NULL,_timeout);
  1813. X      if (!i) {
  1814. X    printf("\r%slogout%s\n",prompt,_term[CE]);
  1815. X    files = (char **)calloc(2,sizeof(char *));
  1816. X    files[0] = "logout";
  1817. X    files[1] = NULL;
  1818. X    logout(1,files);
  1819. X      }
  1820. X    }
  1821. X    if ((ch = getchar()) == EOF) cleanup();
  1822. X
  1823. X    if (bs) {
  1824. X      tstr[0] = ch;
  1825. X      insertstr(tstr);
  1826. X      bs = ch = 0;
  1827. X      continue;
  1828. X    }
  1829. X    if (ic) {
  1830. X      if (ch >= '@' && ch <= '_') tstr[0] = ch - '@';
  1831. X      else if (ch >= 'a' && ch <= 'z') tstr[0] = (ch - 'a')+1;
  1832. X      else tstr[0] = ch;
  1833. X      insertstr(tstr);
  1834. X      ic = ch = 0;
  1835. X      continue;
  1836. X    }
  1837. X    if (fk == 0 && (ptr = index(_kbuf[_glvl],ch)) && _kmax[_glvl] > 0) {
  1838. X      kp = (int)(ptr - _kbuf[_glvl]);
  1839. X      if (!keys[_glvl][kp]->key[1]) goto PROCESS;
  1840. X      else {
  1841. X    prefix[fk++] = ch;
  1842. X    prefix[fk] = ch = 0;
  1843. X    if (fk == _kmax[_glvl]) {
  1844. X      insertstr(prefix);
  1845. X      fk = 0;
  1846. X    }
  1847. X    continue;
  1848. X      }
  1849. X    } else if (fk == 0) {
  1850. X      if (ch == '\n' || ch == '\r') break;
  1851. X      tstr[0] = ch;
  1852. X      insertstr(tstr);
  1853. X      ch = 0;
  1854. X      continue;
  1855. X    }
  1856. X    if (fk > 0 && fk <= _kmax[_glvl]) {
  1857. X      prefix[fk++] = ch;
  1858. X      prefix[fk] = 0;
  1859. X      flg = TRUE;
  1860. X      for(i=kp;i<strlen(_kbuf[_glvl]);i++) {
  1861. X    if (strlen(keys[_glvl][i]->key) == fk && !strcmp(keys[_glvl][i]->key,prefix)) {
  1862. X      kp = i;
  1863. X      goto PROCESS;
  1864. X    }
  1865. X    if (keys[_glvl][i]->key[fk-1] == prefix[fk-1]) flg = FALSE;
  1866. X      }
  1867. X      if (flg || fk == _kmax[_glvl]) {
  1868. X    insertstr(prefix);
  1869. X    kp = prefix[0] = fk = ch = 0;
  1870. X    continue;
  1871. X      }
  1872. X    }
  1873. X    continue;
  1874. X  
  1875. PROCESS:
  1876. X    prefix[0] = fk = 0;
  1877. X    KEY = keys[_glvl][kp];
  1878. X    if (KEY->func > 0) {
  1879. X      switch(KEY->func) {
  1880. X    case 1:        /* up */
  1881. X      if (hist > 0) {
  1882. X        hist--;
  1883. X        strcpy(str,history[hist]);
  1884. X        pos = len = strlen(history[hist]);
  1885. X        printf("\r%s%s",prompt,_term[CE]);
  1886. X        output(str);
  1887. X      } else {
  1888. X        hist = -1;
  1889. X        if (str[0]) printf("\r%s%s",prompt,_term[CE]);
  1890. X        str[0] = len = pos = 0;
  1891. X      }
  1892. X      break;
  1893. X    case 2:        /* down */
  1894. X      if (hist < curhist-1) {
  1895. X        hist++;
  1896. X        strcpy(str,history[hist]);
  1897. X        pos = len = strlen(history[hist]);
  1898. X        printf("\r%s%s",prompt,_term[CE]);
  1899. X        output(str);
  1900. X      } else {
  1901. X        hist = curhist;
  1902. X        if (str[0]) printf("\r%s%s",prompt,_term[CE]);
  1903. X        str[0] = 0;
  1904. X        len = pos = 0;
  1905. X      }
  1906. X      break;
  1907. X    case 3:        /* left */
  1908. X      if (pos > 0) {
  1909. X        putchar('\b');
  1910. X        pos--;
  1911. X      }
  1912. X      break;
  1913. X    case 4:        /* right */
  1914. X      if (pos < len) outch(str[pos++]);
  1915. X      break;
  1916. X    case 5:        /* delete / backspace */
  1917. X      delch();
  1918. X      break;
  1919. X    case 6:        /* toggle insert/overwrite */
  1920. X      _insert ^= 1;
  1921. X      break;
  1922. X    case 7:        /* move to beginning of line */
  1923. X      if (pos > 0) {
  1924. X        printf("\r%s",prompt);
  1925. X        pos = 0;
  1926. X      }
  1927. X      break;
  1928. X    case 8:        /* delete to the right */
  1929. X      if (pos < len) {
  1930. X        outch(str[pos++]);
  1931. X        delch();
  1932. X      }
  1933. X      break;
  1934. X    case 9:        /* move to EOL */
  1935. X      if(pos < len) {
  1936. X        str[len] = 0;
  1937. X        output(str+pos);
  1938. X        pos = len;
  1939. X      }
  1940. X      break;
  1941. X    case 10:    /* kill to EOL */
  1942. X      if (pos < len) {
  1943. X        printf("%s",_term[CE]);
  1944. X        str[len = pos] = 0;
  1945. X      }
  1946. X      break;
  1947. X    case 11:    /* restore line */
  1948. X      str[pos = len]=0;
  1949. X      printf("\r%s%s",prompt,_term[CE]);
  1950. X      output(str);
  1951. X      break;
  1952. X    case 12:    /* Kill line */
  1953. X      if (len>0) printf("\r%s%s",prompt,_term[CE]);
  1954. X      str[len = pos = 0] = 0;
  1955. X      break;
  1956. X    case 13:    /* quoted insert */
  1957. X      bs = 1;
  1958. X      break;
  1959. X    case 14:    /* find matching history */
  1960. X      if (len == 0) break;
  1961. X      str[len] = 0;
  1962. X      for(i=hist-1;i>=0;i--) {
  1963. X        for(j=0;str[j] && str[j] == history[i][j];) j++;
  1964. X        if (str[j]) continue;
  1965. X        strcpy(str,history[hist = i]);
  1966. X        pos = len = strlen(str);
  1967. X        printf("\r%s%s",prompt,_term[CE]);
  1968. X        output(str);
  1969. X        break;
  1970. X      }
  1971. X      if (i < 0) putchar('\007');
  1972. X      break;
  1973. X    case 15:    /* kill to BOL */
  1974. X      if (pos > 0) {
  1975. X        str[len] = 0;
  1976. X        for(i=pos;i<=len;i++) str[i-pos] = str[i];
  1977. X         len -= pos;
  1978. X        pos = 0;
  1979. X        printf("\r%s",prompt);
  1980. X        if (len > 0) {
  1981. X          output(str);
  1982. X          printf("%s\r%s",_term[CE],prompt);
  1983. X        } else printf("%s",_term[CE]);
  1984. X      }
  1985. X      break;
  1986. X    case 16:    /* filename completion */
  1987. X      str[len] = 0;
  1988. X      i = isspace(str[pos]) || !str[pos]? pos-1 : pos;
  1989. X      if (isspace(str[i]) || !str[i]) {
  1990. X        putchar('\007');
  1991. X        break;
  1992. X      }
  1993. X      while(!isspace(str[i]) && i > 0) i--;
  1994. X      if (isspace(str[i])) s = ++i;
  1995. X      else s = i;
  1996. X      j = 0;
  1997. X      while(!isspace(str[i]) && str[i]) buf[j++] = str[i++];
  1998. X      e = i;
  1999. X      buf[j] = 0;
  2000. X      if (!(r = (isregex(buf)==2))) {
  2001. X        buf[j++] = '*';
  2002. X        buf[j] = 0;
  2003. X      }
  2004. X      files = (char **)calloc(5,sizeof(char *));
  2005. X      i = 1;
  2006. X      files[1] = NULL;
  2007. X      files = dirget(buf,files,&i,0,NULL,r == 1,0);
  2008. X      if (!i || err) {
  2009. X        putchar('\007');
  2010. X        if (err == ERR_NO_USER) free(erru);
  2011. X        else if (err == ERR_NO_MATCH) free(errstr);
  2012. X        err = 0;
  2013. X        break;
  2014. X      }
  2015. X      if (!isspace(pos))
  2016. X        for(i=pos;!isspace(i) && str[i];i++,pos++) outch(str[i]);
  2017. X      for(i=0;str[i+(e-1)];i++) str[s+i] = str[i+e];
  2018. X      if (pos == len) for(i=0;i<(e-s);i++) printf("\b \b");
  2019. X      else for(i=0;i<(e-s);i++) delch();
  2020. X      len -= e-s;
  2021. X      str[len] = 0;
  2022. X      pos = s;
  2023. X      if (pos == len) {
  2024. X        strcat(str,files[0]);
  2025. X        output(files[0]);
  2026. X        len += strlen(files[0]);
  2027. X        pos += strlen(files[0]);
  2028. X      } else insertstr(files[0]);
  2029. X      free_list(files);
  2030. X      break;
  2031. X    case 17:    /* word left */
  2032. X      if (pos > 0) {
  2033. X        while(pos > 0 && isspace(str[pos])) {
  2034. X          putchar('\b');
  2035. X          pos--;
  2036. X        }
  2037. X        while(pos > 0 && !isspace(str[pos])) {
  2038. X          putchar('\b');
  2039. X          pos--;
  2040. X        }
  2041. X      }
  2042. X      break;
  2043. X    case 18:    /* word right */
  2044. X      if (pos < len) {
  2045. X        while(pos < len && isspace(str[pos])) outch(str[pos++]);
  2046. X        while(pos < len && !isspace(str[pos])) outch(str[pos++]);
  2047. X      }
  2048. X      break;
  2049. X    case 19:    /* Expand line */
  2050. X      str[len] = 0;
  2051. X      arg = (char ***)split_line(str);
  2052. X      arg = (char ***)parse_alias(arg);
  2053. X      arg = (char ***)parse_shellvars(arg);
  2054. X      if (!_noassigns) arg = (char ***)parse_assigns(arg);
  2055. X      if (_glob) arg = (char ***)parse_wildcards(arg);
  2056. X      if (err) {
  2057. X        free_arg(arg);
  2058. X        putchar('\007');
  2059. X        break;
  2060. X      }
  2061. X      pos = 0;
  2062. X      for(i=0;arg[i];i++) {
  2063. X        for(j=0;arg[i][j];j++) {
  2064. X          if ((pos+strlen(arg[i][j])) > 254) {
  2065. X        str[len = --pos] = 0;
  2066. X        printf("\r%s%s",prompt,_term[CE]);
  2067. X        output(str);
  2068. X        free_arg(arg);
  2069. X        return str;
  2070. X          }
  2071. X          for(x=0;arg[i][j][x];x++)
  2072. X        str[pos++] = arg[i][j][x];
  2073. X          str[pos++] = ' ';
  2074. X        }
  2075. X        if (arg[i+1]) {
  2076. X          str[pos++] = ';';
  2077. X          str[pos++] = ' ';
  2078. X        }
  2079. X      }
  2080. X      str[len = --pos] = 0;
  2081. X      printf("\r%s%s",prompt,_term[CE]);
  2082. X      output(str);      
  2083. X      free_arg(arg);
  2084. X      break;
  2085. X    case 20:    /* kill word */
  2086. X      if (len > 0) {
  2087. X        str[len] = 0;
  2088. X        if (!isspace(str[pos]))
  2089. X          for(;pos<len && !isspace(str[pos]);pos++) outch(str[pos]);
  2090. X        if (pos > 0 && isspace(str[pos-1]))
  2091. X          for(;pos>0 && isspace(str[pos]);pos--) putchar('\b');
  2092. X        if (pos > 0) {
  2093. X          if (pos == len) {
  2094. X        for(;pos > 0 && !isspace(str[pos]);pos--) printf("\b \b");
  2095. X        str[len = pos] = 0;
  2096. X          } else {
  2097. X        for(i=pos-1; i> 0 && !isspace(str[i]); i--) delch();
  2098. X        delch();
  2099. X        for(j=0;str[pos+j];j++) str[i+j] = str[pos+j];
  2100. X        str[len = (i+j)] = 0;
  2101. X        pos = i;
  2102. X          }
  2103. X        }
  2104. X      }
  2105. X      break;
  2106. X    case 21:    /* Make next char a control char */
  2107. X      ic = 1;
  2108. X      break;
  2109. X    default:
  2110. X      putchar('\007');
  2111. X      break;
  2112. X      }
  2113. X    } else if (KEY->gold) {
  2114. X      _glvl = KEY->glvl;
  2115. X    } else {
  2116. X      if (KEY->clr) {
  2117. X    if (pos || (!pos && len)) printf("\r%s%s",prompt,_term[CE]);
  2118. X    str[len = pos = 0] = 0;
  2119. X      }
  2120. X      insertstr(KEY->cmd);
  2121. X      if (KEY->rtn) break;
  2122. X      ch = 0;
  2123. X    }
  2124. X  } while(ch != '\n' && ch != '\r');
  2125. X  echo();
  2126. X  putchar('\n');
  2127. X  str[len] = 0;
  2128. X  if (str[0] == '!') {    /* uh oh... we got a csh user on our hands! */
  2129. X    if (!str[1]) return str;    /* just a measly ! */
  2130. X    if (str[1] == '!') {
  2131. X      strcpy(str,history[curhist-1]);
  2132. X      if (_verbose) puts(str);
  2133. X      return str;
  2134. X    }
  2135. X    for(i=1;isdigit(str[i]);i++);
  2136. X    if (str[i]) {    /* has to be a string */
  2137. X      for(i=curhist-1;i>=0;i--) {
  2138. X    for(j=0;str[j+1] && str[j+1] == history[i][j];) j++;
  2139. X    if (str[j+1]) continue;
  2140. X    strcpy(str,history[i]);
  2141. X    if (_verbose) puts(str);
  2142. X    return str;
  2143. X      }
  2144. X      /* no match, just return as is */
  2145. X    } else {        /* has to be a number */
  2146. X      i = atoi(str+1);
  2147. X      if (i < 0 || i >= curhist) return str;
  2148. X      strcpy(str,history[i]);
  2149. X      if (_verbose) puts(str);
  2150. X      return str;
  2151. X    }
  2152. X  }
  2153. X  return str;
  2154. X}
  2155. X
  2156. insertstr(istr)
  2157. char *istr;
  2158. X{
  2159. X  int i,j = strlen(istr);
  2160. X
  2161. X  if (_insert && pos < len) {
  2162. X    str[len] = 0;
  2163. X    if (_term[IC]) {
  2164. X      for(i=len;i>=pos;i--) str[i+j] = str[i];
  2165. X      for(i=0;istr[i];i++) {
  2166. X    if (len >= 254) {
  2167. X      putchar('\007');
  2168. X      return;
  2169. X    }
  2170. X    printf("%s",_term[IC]);
  2171. X    outch(istr[i]);
  2172. X    str[pos] = istr[i];
  2173. X    pos++;
  2174. X    len++;
  2175. X      }
  2176. X    } else {
  2177. X      for(i=len;i>=pos;i--) str[i+j] = str[i];
  2178. X      str[pos] = 0;
  2179. X      output(istr);
  2180. X      output(str+pos+j);
  2181. X      printf("\r%s",prompt);
  2182. X      if (pos > 0) output(str);
  2183. X      for(i=0;istr[i];i++) {
  2184. X    if (len >= 254) {
  2185. X      putchar('\007');
  2186. X      return;
  2187. X    }
  2188. X    outch(istr[i]);
  2189. X    str[pos] = istr[i];
  2190. X    pos++;
  2191. X    len++;
  2192. X      }
  2193. X    }
  2194. X  } else
  2195. X    for(i=0;istr[i];i++) {
  2196. X      if (len >= 254) {
  2197. X    putchar('\007');
  2198. X    return;
  2199. X      }
  2200. X      outch(istr[i]);
  2201. X      str[pos] = istr[i];
  2202. X      if(pos==len) len++;
  2203. X      pos++;
  2204. X    }
  2205. X}
  2206. X
  2207. output(str)
  2208. char *str;
  2209. X{
  2210. X  int i=0;
  2211. X  while(str[i]) outch(str[i++]);
  2212. X  return;
  2213. X}
  2214. X
  2215. outch(ch)
  2216. char ch;
  2217. X{
  2218. X  if (ch > 127) ch -= 128;
  2219. X  if (ch<32) {
  2220. X    if (_term[SO]) printf("%s%c%s",_term[SO],ch+64,_term[SE]);
  2221. X    else printf("^%c",ch+64);
  2222. X  } else if (ch == 127) {
  2223. X    if (_term[SO]) printf("%s?%s",_term[SO],_term[SE]);
  2224. X    else printf("^?");
  2225. X  } else putchar(ch);
  2226. X}
  2227. X
  2228. noecho()
  2229. X{
  2230. X  ioctl(0,TIOCGETP,&OTTY);
  2231. X  bcopy(&OTTY,&STTY,sizeof(struct sgttyb));
  2232. X  OTTY.sg_flags |= CBREAK;        /* RAW */
  2233. X  OTTY.sg_flags &= ~ECHO;
  2234. X  if (_notypeahead) ioctl(0,TIOCSETP,&OTTY);
  2235. X  else ioctl(0,TIOCSETN,&OTTY);
  2236. X}
  2237. X
  2238. echo()
  2239. X{
  2240. X  OTTY.sg_flags &= ~CBREAK;    /* RAW */
  2241. X  OTTY.sg_flags |= ECHO;
  2242. X  ioctl(0,TIOCSETN,&OTTY);
  2243. X}
  2244. X
  2245. delch()
  2246. X{
  2247. X  char e;
  2248. X  int i;
  2249. X
  2250. X  if(pos > 0) {
  2251. X    e = (str[pos-1]<32 && !_term[SO])? 2 : 1;
  2252. X    str[len] = 0;
  2253. X    while(e) {
  2254. X      if (_insert) {
  2255. X    if (pos < len) {
  2256. X      if (_term[DC]) printf("\b%s",_term[DC]);
  2257. X      else {
  2258. X        str[pos-1] = 0;
  2259. X        fputc('\b',stdout);
  2260. X        output(str+pos);
  2261. X        printf(" \r%s",prompt);
  2262. X        output(str);
  2263. X      }
  2264. X      for(i=pos;i<len;i++) str[i-1] = str[i];
  2265. X      len--; pos--;
  2266. X    } else {
  2267. X      str[pos = --len] = 0;
  2268. X      fputs("\b \b",stdout);
  2269. X    }
  2270. X      }    else {
  2271. X    printf("\b \b");
  2272. X    str[--pos] = ' ';
  2273. X      }
  2274. X      e--;
  2275. X    }
  2276. X  }
  2277. X}
  2278. END_OF_FILE
  2279. if test 11531 -ne `wc -c <'key.c'`; then
  2280.     echo shar: \"'key.c'\" unpacked with wrong size!
  2281. fi
  2282. # end of 'key.c'
  2283. fi
  2284. if test -f 'parse.c' -a "${1}" != "-c" ; then 
  2285.   echo shar: Will not clobber existing file \"'parse.c'\"
  2286. else
  2287. echo shar: Extracting \"'parse.c'\" \(8680 characters\)
  2288. sed "s/^X//" >'parse.c' <<'END_OF_FILE'
  2289. X/* $Copyright:    $
  2290. X * Copyright (c) 1991,1992,1993 by Steve Baker
  2291. X * All rights reserved
  2292. X *  
  2293. X * This software is provided as is without any express or implied
  2294. X * warranties, including, without limitation, the implied warranties
  2295. X * of merchantability and fitness for a particular purpose.
  2296. X */
  2297. X#include "shell.h"
  2298. X#include "cmds.h"
  2299. X#include <pwd.h>
  2300. X
  2301. X/* this ought to be put in a header file */
  2302. struct command cmds[] = {
  2303. X  {"alias",CMD_ALIAS},
  2304. X  {"assign",CMD_ASSIGN},
  2305. X  {"bg",CMD_BG},
  2306. X  {"break",CMD_BREAK},
  2307. X  {"cd",CMD_CD},
  2308. X  {"continue",CMD_CONTINUE},
  2309. X  {"dec",CMD_DEC},
  2310. X  {"else",CMD_ELSE},
  2311. X  {"endfor",CMD_ENDFOR},
  2312. X  {"endif",CMD_ENDIF},
  2313. X  {"endsw",CMD_ENDSW},
  2314. X  {"eval",CMD_EVAL},
  2315. X  {"exec",CMD_EXEC},
  2316. X  {"exit",CMD_EXIT},
  2317. X  {"fg",CMD_FG},
  2318. X  {"for",CMD_FOR},
  2319. X  {"foreach",CMD_FOREACH},
  2320. X  {"goto",CMD_GOTO},
  2321. X  {"history",CMD_HISTORY},
  2322. X  {"if",CMD_IF},
  2323. X  {"inc",CMD_INC},
  2324. X  {"input",CMD_INPUT},
  2325. X  {"intr",CMD_INTR},
  2326. X  {"jobs",CMD_JOBS},
  2327. X  {"key",CMD_KEY},
  2328. X  {"label",CMD_LABEL},
  2329. X  {"limit",CMD_LIMIT},
  2330. X  {"login",CMD_LOGIN},
  2331. X  {"logout",CMD_LOGOUT},
  2332. X  {"next",CMD_NEXT},
  2333. X  {"nset",CMD_SET},
  2334. X  {"protect",CMD_PROTECT},
  2335. X  {"repeat",CMD_REPEAT},
  2336. X  {"sclose",CMD_SCLOSE},
  2337. X  {"secho",CMD_SECHO},
  2338. X  {"set",CMD_SET},
  2339. X  {"setenv",CMD_SETENV},
  2340. X  {"shift",CMD_SHIFT},
  2341. X  {"sopen",CMD_SOPEN},
  2342. X  {"source",CMD_SOURCE},
  2343. X  {"sread",CMD_SREAD},
  2344. X  {"sseek",CMD_SSEEK},
  2345. X  {"stop",CMD_STOP},
  2346. X  {"switch",CMD_SWITCH},
  2347. X  {"swrite",CMD_SWRITE},
  2348. X  {"term",CMD_TERM},
  2349. X  {"umask",CMD_UMASK},
  2350. X  {"unalias",CMD_UNALIAS},
  2351. X  {"unassign",CMD_UNASSIGN},
  2352. X  {"unkey",CMD_UNKEY},
  2353. X  {"unlimit",CMD_UNLIMIT},
  2354. X  {"unset",CMD_UNSET},
  2355. X  {"unsetenv",CMD_UNSETENV},
  2356. X  {"until",CMD_UNTIL},
  2357. X  {"usage",CMD_USAGE},
  2358. X  {"version",CMD_VERSION},
  2359. X  {"wend",CMD_WEND},
  2360. X  {"while",CMD_WHILE}
  2361. X};
  2362. char *getword(), **evalwrd(), **exe(), *malloc(), *strcpy();
  2363. extern int _maxhist, curhist, _status, _pgrp, max_ent;
  2364. extern char **history, str[256], _loginshell, _inpipe;
  2365. extern struct proc_tab *proc;
  2366. extern struct set_vars **set;
  2367. extern char buf[1025],path[1025];
  2368. X
  2369. char flg;
  2370. X
  2371. add_history(str)
  2372. char *str;
  2373. X{
  2374. X  int i;
  2375. X
  2376. X  if ((strlen(str) == 0) || (curhist > 0 && !strcmp(str,history[curhist-1]))) return;
  2377. X  if (curhist == _maxhist) {
  2378. X    free(history[0]);
  2379. X    for(i=0;i<_maxhist-1;i++) history[i] = history[i+1];
  2380. X    curhist--;
  2381. X  }
  2382. X  history[curhist++] = strcpy(malloc(strlen(str)+1),str);
  2383. X}
  2384. X
  2385. X/*
  2386. X *  Parse out our line to break it up into itty-bitty words we can deal with.
  2387. X */
  2388. X
  2389. char ***split_line(str)
  2390. char *str;
  2391. X{
  2392. X  char ***tmp = NULL,*stmp=str, **t;
  2393. X  int i,x = 0, y = 0, max;
  2394. X
  2395. X  flg = 0;
  2396. X  tmp = (char ***)malloc(sizeof(char **) * 2);    /* # of sentences */
  2397. X  tmp[0] = (char **)calloc(max = 3, sizeof(char *));    /* # of words in sentence */
  2398. X
  2399. X  buf[0] = 0;
  2400. X  do {
  2401. X    stmp = getword(buf,stmp);
  2402. X    if (!*buf) continue;
  2403. X    if (!strcmp("(",buf)) flg++;
  2404. X    if (!strcmp(")",buf) && flg) flg--;
  2405. X    if (buf[0] == '`') {
  2406. X      if (!(t = (char **)exe(buf))) continue;
  2407. X      for(i=0;t[i];i++);
  2408. X      if (y+i >= (max-1)) tmp[x] = (char **)realloc(tmp[x],sizeof(char *) * (max=y+i+4));
  2409. X      for (i=0;t[i];i++) tmp[x][y++] = t[i];
  2410. X      free(t);
  2411. X      continue;
  2412. X    }
  2413. X    if (!strcmp(";",buf) && !flg) {
  2414. X      if (y == 0) continue;
  2415. X      tmp[x++][y] = NULL;
  2416. X      tmp = (char ***)realloc(tmp,sizeof(char **) * (x+2));
  2417. X      y = 0;
  2418. X      tmp[x] = (char **)malloc(sizeof(char *) * (max = 3));
  2419. X    } else {
  2420. X      if (y == (max-1)) tmp[x] = (char **)realloc(tmp[x],sizeof(char *) * (max+=4));
  2421. X      tmp[x][y] = (char *)malloc(strlen(buf)+1);
  2422. X      strcpy(tmp[x][y++],buf);
  2423. X      if (buf[0] == '&' && (!buf[1] || buf[1] == '!') && !flg) {
  2424. X        tmp[x++][y] = NULL;
  2425. X    tmp = (char ***)realloc(tmp,sizeof(char **) * (x+2));
  2426. X    y = 0;
  2427. X    tmp[x] = (char **)malloc(sizeof(char *) * (max = 3));
  2428. X      }
  2429. X    }
  2430. X  } while (*stmp);
  2431. X  tmp[x++][y] = NULL;
  2432. X  tmp[x] = NULL;
  2433. X  return tmp;
  2434. X}
  2435. X
  2436. char *getword(wrd,s)
  2437. char *wrd,*s;
  2438. X{
  2439. X  char t=0;
  2440. X
  2441. X  while(*s == ' ' || *s == '\t') s++;
  2442. X  switch (*wrd++ = *s++) {
  2443. X    case ';':
  2444. X    case '(':
  2445. X    case ')':
  2446. X      *wrd = 0;
  2447. X      return s;
  2448. X    case 0:
  2449. X      return --s;
  2450. X    case '&':
  2451. X      if (*s == '!' || *s == '&' || *s == '=') *wrd++ = *s++;
  2452. X      *wrd = 0;
  2453. X      return s;
  2454. X    case '|':
  2455. X      if (*s == '!' || *s == '&' || *s == '|' || *s == '=') *wrd++ = *s++;
  2456. X      *wrd = 0;
  2457. X      return s;
  2458. X    case '>':
  2459. X      t = FALSE;
  2460. X      if (*s != '=') {
  2461. X        if (*s == '%') {
  2462. X      *wrd++ = *s++;
  2463. X      *wrd = 0;
  2464. X      return s;
  2465. X    }
  2466. X    if (*s == '>') *wrd++ = *s++;
  2467. X    if (*s == '!' || *s == '&' || *s == '=') *wrd++ = *s++;
  2468. X    if (*s == '%') *wrd++ = *s++;
  2469. X      } else *wrd++ = *s++;
  2470. X      *wrd = 0;
  2471. X      return s;
  2472. X    case '"':
  2473. X    case '`':
  2474. X    case '\'':
  2475. X      t = *(s-1);
  2476. X      while(*wrd = *s++) {
  2477. X    if (*wrd == '\\') {
  2478. X      if (t != '`') {
  2479. X        switch(*s++) {
  2480. X          case 'e':
  2481. X        *wrd = '\033';
  2482. X        break;
  2483. X          case 'n':
  2484. X        *wrd = '\n';
  2485. X        break;
  2486. X          case 'r':
  2487. X        *wrd = '\r';
  2488. X        break;
  2489. X          case 't':
  2490. X        *wrd = '\t';
  2491. X        break;
  2492. X          case 'b':
  2493. X        *wrd = '\b';
  2494. X        break;
  2495. X          case 'a':
  2496. X        *wrd = '\007';
  2497. X        break;
  2498. X          case 'f':
  2499. X        *wrd = '\014';
  2500. X        break;
  2501. X          case '0':
  2502. X        *wrd = 0;
  2503. X        while (*s >= '0' && *s <= '7') {
  2504. X          *wrd <<= 3;
  2505. X          *wrd |= *s++ - '0';
  2506. X        }
  2507. X        if (!*wrd) --wrd;
  2508. X        break;
  2509. X          case '$':
  2510. X        if (t == '"') *wrd++ = '\\';
  2511. X        *wrd = '$';
  2512. X        break;
  2513. X          default:
  2514. X        *wrd = *(s-1);
  2515. X        break;
  2516. X        }
  2517. X      } else *wrd = *(s-1);
  2518. X    }
  2519. X    else if(*wrd == t) {
  2520. X      *++wrd = 0;
  2521. X      return s;
  2522. X    }
  2523. X    if (!*wrd) break;
  2524. X    wrd++;
  2525. X      }
  2526. X      *wrd++ = t;
  2527. X      *wrd = 0;
  2528. X      return --s;
  2529. X    case '<':
  2530. X      if (*s == '<') *wrd++ = *s++;
  2531. X      if (*s == '%') {
  2532. X    *wrd++ = *s++;
  2533. X    *wrd = 0;
  2534. X    return s;
  2535. X      }
  2536. X    case '=':
  2537. X      if (*s == '=') *wrd++ = *s++;
  2538. X      *wrd = 0;
  2539. X      return s;
  2540. X    case '$':
  2541. X      if (*s == '<') *wrd++ = *s++;
  2542. X      break;
  2543. X    case '#':
  2544. X      if (!flg) {
  2545. X    *--wrd = 0;
  2546. X    *s = 0;
  2547. X    return s;
  2548. X      }
  2549. X      break;
  2550. X    case '!':
  2551. X      if (*s == '=') {
  2552. X        *wrd++ = *s++;
  2553. X    *wrd = 0;
  2554. X    return s;
  2555. X      }
  2556. X      break;
  2557. X    case '\\':
  2558. X      *wrd--;
  2559. X      *wrd++ = *s++;
  2560. X      break;
  2561. X  }
  2562. X  while(*wrd = *s++){
  2563. X    switch(*wrd) {
  2564. X      case ';':
  2565. X      case '&':
  2566. X      case '|':
  2567. X      case '<':
  2568. X      case '>':
  2569. X      case ' ':
  2570. X      case '(':
  2571. X      case ')':
  2572. X      case '\t':
  2573. X    *wrd = 0;
  2574. X    return --s;
  2575. X      case '\\':
  2576. X    *wrd = *s++;
  2577. X    break;
  2578. X      default:
  2579. X    break;
  2580. X    }
  2581. X    wrd++;
  2582. X  }
  2583. X  return --s;
  2584. X}
  2585. X
  2586. X/*
  2587. X * check for builtin commands here...
  2588. X */
  2589. X
  2590. parse_arg(cmd,in,inf,out,outf,outa,err,errf,erra,bg)
  2591. char **cmd, *inf, *outf, *errf, outa, erra, bg;
  2592. int in, out, err;
  2593. X{
  2594. X  int i,pid,ent;
  2595. X  int start=0,end=MAX_CMD,mid=MAX_CMD/2,found=FALSE;
  2596. X
  2597. X  while(start<=end) {
  2598. X    if (!(i = strcmp(cmd[0],cmds[mid].cmd))) {
  2599. X      found = TRUE;
  2600. X      break;
  2601. X    }
  2602. X    if (i<0) end = mid-1;
  2603. X    else start = mid+1;
  2604. X    mid = (start+end)/2;
  2605. X  }
  2606. X
  2607. X  if (!found) return NORMAL_COMMAND;
  2608. X
  2609. X  pid = execute(cmds[mid].val,cmd,in,inf,out,outf,outa,err,errf,erra,bg);
  2610. X  if (pid > 0) {
  2611. X    ent = get_proc_ent(pid,TRUE);
  2612. X    proc[ent].cmd = (char *)malloc(strlen(cmd[0])+1);
  2613. X    strcpy(proc[ent].cmd,cmd[0]);
  2614. X    printf(" [%d] (%d) %s\n",ent,pid,cmd[0]);
  2615. X  }
  2616. X  return SHELL_COMMAND;
  2617. X}
  2618. X
  2619. free_arg(arg)
  2620. char ***arg;
  2621. X{
  2622. X  int i,j;
  2623. X  if (!arg) return;
  2624. X  for(i=0;arg[i];i++) {
  2625. X    for(j=0;arg[i][j];j++) free(arg[i][j]);
  2626. X    free(arg[i]);
  2627. X  }
  2628. X  free(arg);
  2629. X}
  2630. X
  2631. free_list(lst)
  2632. char **lst;
  2633. X{
  2634. X  int i;
  2635. X  for(i=0;lst[i];i++) free(lst[i]);
  2636. X  free(lst);
  2637. X}
  2638. X
  2639. X/*
  2640. X * This is bad... needs to be replaced to use to the shells run2() command
  2641. X * somehow...  probably by using shell level pipes eh?
  2642. X */
  2643. char **exe(cmd)
  2644. char *cmd;
  2645. X{
  2646. X  char *c, *s, **t;
  2647. X  int n,i,j,p[2];
  2648. X  union wait status;
  2649. X
  2650. X  pipe(p);
  2651. X  if ((i = fork()) < 0) return NULL;
  2652. X  if (i) {
  2653. X    close(p[1]);
  2654. X    s = (char *)malloc(1025);
  2655. X    i = 0;
  2656. X    while((n = read(p[0],buf,1024)) > 0) {
  2657. X      buf[n] = 0;
  2658. X      for(j=0;j<n;j++) if (buf[j] == '\n') buf[j] = ' ';
  2659. X      if (i) s = (char *)realloc(s,i+n+1);
  2660. X      strcpy(s+i,buf);
  2661. X      i += n;
  2662. X    }
  2663. X    s[i] = 0;
  2664. X    close(p[0]);
  2665. X    c = s;
  2666. X    t = (char **)calloc(n=5,sizeof(char *));
  2667. X    i = 0;
  2668. X    flg = 1;
  2669. X    do {
  2670. X      s = getword(buf,s);
  2671. X      if (!*buf) continue;
  2672. X      if (i == n) t = (char **)realloc(t,sizeof(char *) * (n += 5));
  2673. X      t[i++] = (char *)strcpy((char *)malloc(strlen(buf)+1),buf);
  2674. X    } while (*s);
  2675. X    if (i == n) t = (char **)realloc(t,sizeof(char *) * (++n));
  2676. X    t[i] = NULL;
  2677. X    free(c);
  2678. X    wait(&status);
  2679. X    return t;
  2680. X  } else {
  2681. X    _inpipe = TRUE;
  2682. X    _pgrp = getpgrp(0);
  2683. X    _loginshell = FALSE;
  2684. X    for(i=0;i<max_ent;i++)
  2685. X      if (proc[i].pid) {
  2686. X    if (proc[i].cmd) free(proc[i].cmd);
  2687. X    proc[i].pid = 0;
  2688. X      }
  2689. X    close(1);
  2690. X    close(2);
  2691. X    dup(p[1]);
  2692. X    dup(p[1]);
  2693. X    close(p[1]);
  2694. X    c = (char *)strcpy((char *)malloc(strlen(cmd)),cmd+1);
  2695. X    c[strlen(c)-1] = 0;
  2696. X    run2(c);
  2697. X    close(1);
  2698. X    close(2);
  2699. X    exit(_status);
  2700. X  }
  2701. X}
  2702. END_OF_FILE
  2703. if test 8680 -ne `wc -c <'parse.c'`; then
  2704.     echo shar: \"'parse.c'\" unpacked with wrong size!
  2705. fi
  2706. # end of 'parse.c'
  2707. fi
  2708. if test ! -d 'scripts' ; then
  2709.     echo shar: Creating directory \"'scripts'\"
  2710.     mkdir 'scripts'
  2711. fi
  2712. if test -f 'shell.c' -a "${1}" != "-c" ; then 
  2713.   echo shar: Will not clobber existing file \"'shell.c'\"
  2714. else
  2715. echo shar: Extracting \"'shell.c'\" \(10557 characters\)
  2716. sed "s/^X//" >'shell.c' <<'END_OF_FILE'
  2717. X/* $Copyright:    $
  2718. X * Copyright (c) 1991,1992,1993 by Steve Baker
  2719. X * All rights reserved
  2720. X *  
  2721. X * This software is provided as is without any express or implied
  2722. X * warranties, including, without limitation, the implied warranties
  2723. X * of merchantability and fitness for a particular purpose.
  2724. X */
  2725. X#include "shell.h"
  2726. X
  2727. char *exit_val[] = {
  2728. X  "Done", "Hangup", "Interrupted", "Quit", "Illegal Instruction",
  2729. X  "Trace Trap", "IOT", "EMT", "FP Exception", "Killed", "Bus Error",
  2730. X  "Segmentation Fault", "Bad Arg", "Broken pipe", "Alarm Clock", "Terminated",
  2731. X  0, "Stopped (signal)", "Stopped", 0, 0, "Stopped (TTY input)",
  2732. X  "Stopped (TTY output)", 0, "CPU Time Limit Expired",
  2733. X  "Filesize Limit Exceeded", "Virtual Time Alarm", "Profiler Timer Alarm",
  2734. X  0, "USR 1", "USR 2"
  2735. X};
  2736. X
  2737. X#ifdef NOSETENV
  2738. X  extern char **environ;
  2739. X#endif
  2740. X
  2741. void check_children(), cleanup(), *malloc();
  2742. char *getline(),***split_line(),***parse_alias(), ***parse_wildcards();
  2743. char ***parse_shellvars(), ***parse_assigns();
  2744. X
  2745. char **history, **_mailnotice = NULL, **_homedirs, **_cdpath;
  2746. char _source = FALSE, newmail = TRUE, _insert = TRUE, _notypeahead = FALSE;
  2747. char *_prompt, *_statline, *_home, **_mbox, **PATH, _nohup = FALSE;
  2748. char _loginshell = FALSE, _killjobs = FALSE, _inpipe = FALSE;
  2749. char _restricted = FALSE;
  2750. int _maxhist = 30, curhist = 0, _joblimit = 0, _failat = 1, _mailchkint = 60;
  2751. int _statint = 30;
  2752. char _verbose = FALSE, _willverbose = FALSE, _interactive = TRUE;
  2753. char _echo = FALSE, _willecho = FALSE, _noexec = FALSE, _oneline = FALSE;
  2754. char _fast = FALSE, _terminate = FALSE, _nobgnull = FALSE, _nofork = FALSE;
  2755. char _glob = TRUE, _nonomatch = FALSE, _nodots = FALSE;
  2756. char _noclobber = FALSE, _noassigns = FALSE, *_sourcefile = NULL, *_term[11];
  2757. struct timeval *_timeout = NULL, timeout;
  2758. X
  2759. struct _setvar *sets[37], *statvar;
  2760. struct _alias *alias[128];
  2761. char _glvl = 0, *_kbuf[MAX_GLVL], _kmax[MAX_GLVL];
  2762. struct custom_keys **keys[MAX_GLVL];
  2763. int max_ent, _pgrp, _status = 0;
  2764. unsigned long SIGMASK = ~sigmask(SIGPIPE), TIMEON;
  2765. struct proc_tab *proc;
  2766. X
  2767. char ***file;
  2768. int fptr,err;
  2769. X
  2770. char buf[1025],path[1025];
  2771. X
  2772. main(argc,argv,env)
  2773. int argc;
  2774. char **argv;
  2775. char **env;
  2776. X{
  2777. X  char *str,i;
  2778. X
  2779. X/* NeXT hack for giving us an environment we can work with. */
  2780. X#ifdef NOSETENV
  2781. X  char **en;
  2782. X
  2783. X  for(i=0;environ[i];i++);
  2784. X  en = (char **)malloc(sizeof(char **) * i+1);
  2785. X  for(i=0;environ[i];i++) en[i] = SCOPY(environ[i]);
  2786. X  en[i] = NULL;
  2787. X  environ = en;
  2788. X#endif
  2789. X
  2790. X  for(i=0;i<32;i++) signal(i,SIG_IGN);
  2791. X  signal(SIGCHLD,check_children);
  2792. X  signal(SIGHUP,cleanup);
  2793. X  signal(SIGSEGV,cleanup);
  2794. X
  2795. X  setbuf(stdin,NULL);
  2796. X  setbuf(stdout,NULL);
  2797. X  setbuf(stderr,NULL);
  2798. X  TIMEON = time(0);
  2799. X  parse_args(argc,argv);
  2800. X  init();
  2801. X  init_term();
  2802. X  if (_interactive) source(GLOBAL_INIT);
  2803. X  check_mail(TRUE);
  2804. X  if (argv[0][0] == '-' || !strcmp(argv[0],"su")) second_pass();
  2805. X  if (argv[0][0] == '-') {
  2806. X    _loginshell = TRUE;
  2807. X    sprintf(path,"%s/%s",_home,SHELL_LOGIN);
  2808. X    source(path);
  2809. X    load_hist();
  2810. X  }
  2811. X  if (!_fast) {
  2812. X    sprintf(path,"%s/%s",_home,SHELL_INIT);
  2813. X    source(path);
  2814. X  }
  2815. X
  2816. X  if (_willverbose) makenull("verbose");
  2817. X  if (_willecho) makenull("echo");
  2818. X
  2819. X  if (_interactive && _term[KS]) fputs(_term[KS],stdout);
  2820. X  if (_sourcefile) {
  2821. X    source(_sourcefile);
  2822. X    exit(0);
  2823. X  }
  2824. X
  2825. X  for(;;) {
  2826. X    err = 0;
  2827. X    str = getline();
  2828. X    add_history(str);
  2829. X    i = run2(str);
  2830. X    if (_oneline) exit(0);
  2831. X    check_mail(FALSE);
  2832. X    if (_term[KS]) fputs(_term[KS],stdout);
  2833. X  }
  2834. X}
  2835. X
  2836. source(fil)
  2837. char *fil;
  2838. X{
  2839. X  char ***arg = NULL, *str, *p, flg = TRUE;
  2840. X  int d, i, j, nt;
  2841. X  FILE *in, *fdopen();
  2842. X
  2843. X  if (fil) {
  2844. X    if ((d = open(fil,O_RDONLY)) < 0) return -1;
  2845. X    in = fdopen(d,"r");
  2846. X  } else {
  2847. X    p = _prompt;
  2848. X    _prompt = "? ";
  2849. X  }
  2850. X
  2851. X  _source = TRUE;
  2852. X  err = fptr = j = path[1025] = 0;
  2853. X  file = (char ***)calloc(nt=5,sizeof(char **));
  2854. X  while(flg) {
  2855. X    if (fil) {
  2856. X      if (!fgets(path,1024,in)) break;
  2857. X      i = strlen(path);
  2858. X      if (path[i-1] == '\n') path[i-1] = 0;
  2859. X      arg = split_line(path);
  2860. X    } else {
  2861. X      str = getline();
  2862. X      arg = split_line(str);
  2863. X    }
  2864. X    for(i=0;arg[i];i++) {
  2865. X      if (j == nt) file = (char ***)realloc(file,sizeof(char **) * (nt+=5));
  2866. X      file[j++] = arg[i];
  2867. X      if (!fil && !strcmp(arg[i][0],"exit")) flg = FALSE;
  2868. X    }
  2869. X    free(arg);
  2870. X  }
  2871. X  if (j == nt) file = (char ***)realloc(file,sizeof(char **) * (++nt));
  2872. X  file[j] = NULL;
  2873. X  if (fil) {
  2874. X    fclose(in);
  2875. X    close(d);
  2876. X  }
  2877. X
  2878. X  while(file[fptr]) {
  2879. X    run(fptr);
  2880. X    if (err < 0) {
  2881. X      switch (err) {
  2882. X        case ERR_BREAK:
  2883. X      fprintf(stderr,"break: break outside of loop or switch.\n");
  2884. X      break;
  2885. X    case ERR_CONTINUE:
  2886. X      fprintf(stderr,"continue: continue outside of loop.\n");
  2887. X      break;
  2888. X    case ERR_GOTO:
  2889. X      err = 0;
  2890. X      break;
  2891. X      }
  2892. X    }
  2893. X    if (err || badstat(_status)) break;
  2894. X    fptr++;
  2895. X  }
  2896. X  _source = FALSE;
  2897. X  free_arg(file);
  2898. X  if (!fil) _prompt = p;
  2899. X  return 0;
  2900. X}
  2901. X
  2902. X/*
  2903. X * This routine makes a process table entry for our process.
  2904. X * Called by exec only, so we won't block SIGCHLD here, cause it already
  2905. X * will be by the time it's called.
  2906. X */
  2907. get_proc_ent()
  2908. X{
  2909. X  short i,j;
  2910. X
  2911. X  for(i=0;i<max_ent;i++)
  2912. X    if (proc[i].pid == 0) return i;
  2913. X  i = max_ent;
  2914. X  proc = (struct proc_tab *)realloc(proc,(max_ent += 2) * sizeof(struct proc_tab));
  2915. X  for(j=i;j<max_ent;j++) proc[j].pid = 0;
  2916. X  return i;
  2917. X}
  2918. X
  2919. X/*
  2920. X * This is surprisingly where most of the job control lies.  The rest is
  2921. X * just waking up and stopping processes.
  2922. X */
  2923. void check_children()
  2924. X{
  2925. X  int pid,i,j,tpgrp,flg;
  2926. X  union wait st;
  2927. X  char tmp[40];
  2928. X
  2929. X  while ((pid = wait3(&st,WNOHANG | WUNTRACED,NULL)) > 0) {
  2930. X    for(i=0;i<max_ent;i++)
  2931. X      if (pid == proc[i].pid) {
  2932. X    flg = TRUE;
  2933. X    if (proc[i].bg) flg = FALSE;
  2934. X    else if (proc[i].pipe) {
  2935. X      for(j=0;j<max_ent;j++)
  2936. X        if (j != i && proc[j].pid && proc[j].pipe == proc[i].pipe && !proc[j].status) {
  2937. X          flg = FALSE;
  2938. X          break;
  2939. X        }
  2940. X    }
  2941. X    if (WIFSTOPPED(st)) {
  2942. X      if (flg) tcsetpgrp(TTY,_pgrp);
  2943. X      switch(st.w_stopsig) {
  2944. X        case SIGTTIN:
  2945. X        case SIGTTOU:
  2946. X        case SIGSTOP:
  2947. X        case SIGTSTP:
  2948. X          tpgrp = tcgetpgrp(TTY);
  2949. X          if (tpgrp == _pgrp && (!proc[i].pipe || proc[i].pipe == proc[i].pid))
  2950. X            printf("\n [%d] (%d) %-30s %s\n",i,pid,exit_val[st.w_stopsig],proc[i].cmd);
  2951. X          proc[i].status = st.w_stopsig;
  2952. X          break;
  2953. X      }
  2954. X    } else if (WIFEXITED(st)) {
  2955. X      if (flg) tcsetpgrp(TTY,_pgrp);
  2956. X      tpgrp = tcgetpgrp(TTY);
  2957. X      if (proc[i].bg && tpgrp == _pgrp && (!proc[i].pipe || proc[i].pipe == proc[i].pid))
  2958. X        printf("\n [%d] (%d) %-30s %s\n",i,pid,exit_val[st.w_termsig],proc[i].cmd);
  2959. X      _status = st.w_termsig? st.w_termsig<<8 : st.w_retcode;
  2960. X      proc[i].pid = 0;
  2961. X      free(proc[i].cmd);
  2962. X    } else if (WIFSIGNALED(st)) {
  2963. X      switch(st.w_termsig) {
  2964. X        case SIGCONT:
  2965. X          proc[i].status = STAT_RUNNING;
  2966. X          tcsetpgrp(TTY,proc[i].pgrp);
  2967. X          return;
  2968. X        default:
  2969. X          if (flg) tcsetpgrp(TTY,_pgrp);
  2970. X          tpgrp = tcgetpgrp(TTY);
  2971. X          if (_pgrp == tpgrp) {
  2972. X        sprintf(tmp,"%s%s",exit_val[st.w_termsig],(st.w_coredump?" (core dumped)":""));
  2973. X        if (proc[i].bg && (!proc[i].pipe || proc[i].pipe == proc[i].pid))
  2974. X          printf("\n [%d] (%d) %-30s %s\n",i,pid,tmp,proc[i].cmd);
  2975. X        else if (st.w_termsig) printf("%s\n",tmp);
  2976. X          }
  2977. X          proc[i].pid = 0;
  2978. X          free(proc[i].cmd);
  2979. X          _status = st.w_termsig? st.w_termsig<<8 : st.w_retcode;
  2980. X          break;
  2981. X      }
  2982. X    }
  2983. X      }
  2984. X  }
  2985. X  return;
  2986. X}
  2987. X
  2988. check_mail(f)
  2989. char f;
  2990. X{
  2991. X  static int i;
  2992. X  static time_t last = 0;
  2993. X  struct stat lbuf;
  2994. X
  2995. X  if (!_mbox) {
  2996. X    newmail = FALSE;
  2997. X    return;
  2998. X  }
  2999. X  if (!f && last+_mailchkint > time(0)) return;
  3000. X  last = time(0);
  3001. X  for(i=0;_mbox[i];i++) {
  3002. X    stat(_mbox[i],&lbuf);
  3003. X    if (((lbuf.st_mtime > lbuf.st_atime) && (lbuf.st_size != 0))) {
  3004. X      if (!newmail) {
  3005. X    if (_mailnotice) printf("\n%s",_mailnotice[0]);
  3006. X    else printf("\nYou have new mail");
  3007. X    if (i) printf(" in %s.\n",_mbox[i]);
  3008. X    else puts(".");
  3009. X    newmail = TRUE;
  3010. X      }
  3011. X    } else newmail = FALSE;
  3012. X  }
  3013. X}
  3014. X
  3015. X/*
  3016. X * Called if we have an error we can't deal with. Give a very detailed
  3017. X * error message so the user knows what's going on.
  3018. X */
  3019. void cleanup()
  3020. X{
  3021. X  printf("oops...\n");
  3022. X  exit(0);
  3023. X}
  3024. X
  3025. parse_args(n,arg)
  3026. int n;
  3027. char **arg;
  3028. X{
  3029. X  char ***tmp;
  3030. X  int i=1,x;
  3031. X
  3032. X  while(arg[i]) {
  3033. X    if (arg[i][0] == '-') {
  3034. X      for(x=1;arg[i][x];x++) {
  3035. X    switch(arg[i][x]) {
  3036. X      case 'c':            /* ignores other args */
  3037. X        if (!arg[i+1]) exit(1);
  3038. X        init();
  3039. X        init_term();
  3040. X        if (!_fast) {
  3041. X          sprintf(path,"%s/%s",_home,SHELL_INIT);
  3042. X          source(path);
  3043. X        }
  3044. X        tmp = split_line(arg[i+1]);
  3045. X        tmp = parse_alias(tmp);
  3046. X        tmp = parse_shellvars(tmp);
  3047. X        if (!_noassigns) tmp = parse_assigns(tmp);
  3048. X        if (_glob) tmp = parse_wildcards(tmp);
  3049. X        for(x=0;tmp[x];x++) {
  3050. X          EXEC(tmp[x]);
  3051. X          pwait();
  3052. X        }
  3053. X        exit(0);
  3054. X      case 'e':
  3055. X        _terminate = TRUE;        /* only when sourcing! */
  3056. X        break;
  3057. X      case 'f':
  3058. X        _fast = TRUE;
  3059. X        break;
  3060. X      case 'i':
  3061. X        _interactive = TRUE;    /* redundant */
  3062. X        break;
  3063. X      case 'n':
  3064. X        _noexec = TRUE;
  3065. X        break;
  3066. X      case 's':
  3067. X        _interactive = FALSE;
  3068. X        break;
  3069. X      case 't':
  3070. X        _oneline = TRUE;
  3071. X        break;
  3072. X      case 'v':
  3073. X        _willverbose = TRUE;
  3074. X        break;
  3075. X      case 'V':
  3076. X        _verbose = TRUE;
  3077. X        break;
  3078. X      case 'x':
  3079. X        _willecho = TRUE;
  3080. X        break;
  3081. X      case 'X':
  3082. X        _echo = TRUE;
  3083. X        break;
  3084. X    }
  3085. X      }
  3086. X    } else {
  3087. X      if (_sourcefile) {
  3088. X        fprintf(stderr,"ssh: Too many arguments\n");
  3089. X    exit(1);
  3090. X      }
  3091. X      _sourcefile = arg[i];
  3092. X    }
  3093. X    i++;
  3094. X  }
  3095. X}
  3096. X
  3097. run(line)
  3098. int line;
  3099. X{
  3100. X  char **arg;
  3101. X  int i;
  3102. X
  3103. X  if (_verbose) {
  3104. X    for(i=0;file[line][i];i++) {
  3105. X      fputs(file[line][i],stdout);
  3106. X      if (file[line][i+1]) fputc(' ',stdout);
  3107. X    }
  3108. X    fputc('\n',stdout);
  3109. X  } else for(i=0;file[line][i];i++);
  3110. X  arg = (char **)malloc(sizeof(char *) * (i+1));
  3111. X  for(i=0;file[line][i];i++)
  3112. X    arg[i] = (char *)strcpy(malloc(strlen(file[line][i])+1),file[line][i]);
  3113. X  arg[i] = NULL;
  3114. X
  3115. X  arg = (char **)exchange_alias(arg);
  3116. X  arg = (char **)evalvars(arg);
  3117. X  if (!_noassigns) arg = (char **)eval_assigns(arg);
  3118. X  if (_glob) arg = (char **)match_wildcards(arg);
  3119. X  EXEC(arg);
  3120. X  pwait();
  3121. X  statvar->sv.val = _status;
  3122. X  free_list(arg);
  3123. X  return 0;
  3124. X}
  3125. X
  3126. run2(s)
  3127. char *s;
  3128. X{
  3129. X  char ***arg;
  3130. X  int i;
  3131. X
  3132. X  if (_verbose) puts(s);
  3133. X  arg = split_line(s);
  3134. X  arg = parse_alias(arg);
  3135. X  arg = parse_shellvars(arg);
  3136. X  if (!_noassigns) arg = parse_assigns(arg);
  3137. X  if (_glob) arg = parse_wildcards(arg);
  3138. X  if (err) {
  3139. X    free_arg(arg);
  3140. X    statvar->sv.val = _status = err;
  3141. X    return -1;
  3142. X  }
  3143. X  if (arg[0][0] == NULL) {
  3144. X    free_arg(arg);
  3145. X    return -1;
  3146. X  }
  3147. X  for(i=0;arg[i];i++) {
  3148. X    EXEC(arg[i]);
  3149. X    pwait();
  3150. X    statvar->sv.val = _status;
  3151. X    if (badstat(_status)) {
  3152. X      free_arg(arg);
  3153. X      return -1;
  3154. X    }
  3155. X  }
  3156. X  free_arg(arg);
  3157. X  return 0;
  3158. X}
  3159. END_OF_FILE
  3160. if test 10557 -ne `wc -c <'shell.c'`; then
  3161.     echo shar: \"'shell.c'\" unpacked with wrong size!
  3162. fi
  3163. # end of 'shell.c'
  3164. fi
  3165. if test -f 'shell.h' -a "${1}" != "-c" ; then 
  3166.   echo shar: Will not clobber existing file \"'shell.h'\"
  3167. else
  3168. echo shar: Extracting \"'shell.h'\" \(2911 characters\)
  3169. sed "s/^X//" >'shell.h' <<'END_OF_FILE'
  3170. X/* $Copyright:    $
  3171. X * Copyright (c) 1991,1992,1993 by Steve Baker
  3172. X * All rights reserved
  3173. X *  
  3174. X * This software is provided as is without any express or implied
  3175. X * warranties, including, without limitation, the implied warranties
  3176. X * of merchantability and fitness for a particular purpose.
  3177. X */
  3178. X#ifdef DEBUG
  3179. X#include "mem/mem.h"
  3180. X#endif DEBUG
  3181. X
  3182. X#include <stdio.h>
  3183. X#include <signal.h>
  3184. X#include <ctype.h>
  3185. X#include <sys/ioctl.h>
  3186. X#include <sys/wait.h>
  3187. X#include <sys/time.h>
  3188. X#include <sys/resource.h>
  3189. X#include <sys/file.h>
  3190. X#include <sys/types.h>
  3191. X#include <sys/stat.h>
  3192. X
  3193. X#define BYTE        unsigned char
  3194. X#define WORD        unsigned short
  3195. X#define LONG        unsigned long
  3196. X#define GLOBAL_INIT    "/etc/.sshrc"
  3197. X#define SHELL_LOGIN    ".login"
  3198. X#define SHELL_INIT    ".sshrc"
  3199. X#define SHELL_EXIT    ".logout"
  3200. X#define HIST_SAVE    ".hist"
  3201. X#define SECOND_PASS    ".second"
  3202. X#define WARNING        ".warning"
  3203. X#define NULL_DEV    "/dev/null"
  3204. X
  3205. X#define SHELL_COMMAND    1
  3206. X#define NORMAL_COMMAND    0
  3207. X#define TTY        0
  3208. X#define TRUE        1
  3209. X#define FALSE        0
  3210. X
  3211. X#define ERR_NO_USER    1
  3212. X#define ERR_NO_MATCH    2
  3213. X#define ERR_BREAK    -1
  3214. X#define ERR_CONTINUE    -2
  3215. X#define ERR_GOTO    -3
  3216. X#define ERR_EXIT    -4
  3217. X
  3218. X#define RET_MASK    0x00FF
  3219. X#define TERM_MASK    0xFF00
  3220. X
  3221. X#ifndef sigmask
  3222. X#define sigmask(x)    (1<<(x))
  3223. X#endif
  3224. X
  3225. X#define calloc(x,y)    malloc((x)*(y))
  3226. X#define    _ret(x)        ((x)&RET_MASK)
  3227. X#define _trm(x)        (((x)&TERM_MASK)>>8)
  3228. X#define badstat(x)    ((x) && ((_ret(x)>=_failat) || (_trm(x) && (SIGMASK&sigmask(_trm(x))))))
  3229. X#define SCOPY(x)    ((char *)strcpy((char *)malloc(strlen(x)+1),(x)))
  3230. X
  3231. enum {SO,SE,CE,KS,KE,DC,IC,DS,TS,FS,HS};
  3232. X
  3233. X#define T_STRING    0
  3234. X#define T_INTEGER    1
  3235. X#define T_NULL        2
  3236. X
  3237. union setval {
  3238. X  long val;
  3239. X  char **wrd;
  3240. X};
  3241. X
  3242. struct _setvar {
  3243. X  char *var;
  3244. X  struct _setvar *nxt;
  3245. X  union setval sv;
  3246. X  WORD nwrds;
  3247. X  BYTE protect : 1;    /* 1 = Cannot change or remove this variable */
  3248. X  BYTE type    : 2;    /* 0 = string, 1 = numeric, 2 = null var */
  3249. X};
  3250. X
  3251. struct _alias {
  3252. X  char *cmd;
  3253. X  char **wrd;
  3254. X  struct _alias *nxt;
  3255. X};
  3256. X
  3257. struct _proc {
  3258. X  char *name;
  3259. X  char ***cmd;
  3260. X  struct _proc *nxt;
  3261. X};
  3262. X
  3263. X#define MAX_GLVL    10
  3264. struct custom_keys {
  3265. X  char *key;
  3266. X  char *cmd;
  3267. X  BYTE clr  : 1;    /* clear line? */
  3268. X  BYTE rtn  : 1;    /* auto-execute line? */
  3269. X  BYTE gold : 1;    /* gold key? */
  3270. X  BYTE glvl : 4;    /* level that gold key goes to */
  3271. X  BYTE func : 5;    /* function key? */
  3272. X};
  3273. X
  3274. X#define STAT_RUNNING    0
  3275. X
  3276. struct proc_tab {
  3277. X  char *cmd;
  3278. X  WORD pid;
  3279. X  WORD pgrp;
  3280. X  WORD pipe;
  3281. X  BYTE status : 7;
  3282. X  BYTE bg     : 1;
  3283. X};
  3284. X
  3285. X#ifndef __bsdi__
  3286. struct dirent {
  3287. X  struct dirent *next;
  3288. X  char *entry;
  3289. X};
  3290. X#endif
  3291. X
  3292. X#ifdef CANNOT_ALLOCA
  3293. X#define ALLOCA(x)   malloc(x)
  3294. X#define FREEA(x)    free(x)
  3295. X#else CAN_ALLOCA
  3296. X#define ALLOCA(x)   alloca(x)
  3297. X#define FREEA(x)    /* automatically freed */
  3298. X#endif CAN_ALLOCA
  3299. X
  3300. X#define MAX_FILES    10
  3301. X
  3302. struct _FILES {
  3303. X  char *name;
  3304. X  char *file;
  3305. X  BYTE read : 1;
  3306. X  BYTE write : 1;
  3307. X  BYTE ispipe : 1;
  3308. X  BYTE pread : 1;    /* Pipes need to have only one writer period */
  3309. X  BYTE pwrite : 1;
  3310. X  char pipe;    /* Temp for pipes */
  3311. X  char desc;
  3312. X};
  3313. END_OF_FILE
  3314. if test 2911 -ne `wc -c <'shell.h'`; then
  3315.     echo shar: \"'shell.h'\" unpacked with wrong size!
  3316. fi
  3317. # end of 'shell.h'
  3318. fi
  3319. if test -f 'stat.c' -a "${1}" != "-c" ; then 
  3320.   echo shar: Will not clobber existing file \"'stat.c'\"
  3321. else
  3322. echo shar: Extracting \"'stat.c'\" \(5124 characters\)
  3323. sed "s/^X//" >'stat.c' <<'END_OF_FILE'
  3324. X/* $Copyright:    $
  3325. X * Copyright (c) 1991,1992,1993 by Steve Baker
  3326. X * All rights reserved
  3327. X *  
  3328. X * This software is provided as is without any express or implied
  3329. X * warranties, including, without limitation, the implied warranties
  3330. X * of merchantability and fitness for a particular purpose.
  3331. X */
  3332. X#include <sys/types.h>
  3333. X#include <utmp.h>
  3334. X#include <pwd.h>
  3335. X#include "shell.h"
  3336. X
  3337. char *getnjobs(), **getusers(), *gettime();
  3338. X
  3339. extern struct proc_tab *proc;
  3340. extern int max_ent;
  3341. extern char newmail, **_mailnotice, *_home, **_homedirs, *_term[11];
  3342. extern char buf[1024], path[1024];
  3343. extern long TIMEON;
  3344. X
  3345. static int p, a, pmax,amax;
  3346. X
  3347. char *pline(s,m,n)
  3348. char *s;
  3349. short m,n;
  3350. X{
  3351. X  static char *tc[12] = {"SO","SE","CE","KS","KE","DC","IC","DS","TC","FS","HS",0};
  3352. X  int i, j, users = 0;
  3353. X  char *jobs = NULL;
  3354. X  char **user = NULL;
  3355. X  char *t;
  3356. X
  3357. X  amax = m > 1023? 1023 : m;
  3358. X  pmax = n > 1023? 1023 : n;
  3359. X
  3360. X  p = a = 0;
  3361. X  do {
  3362. X    if (*s == '%') {
  3363. X      if (isupper(*(s+1)) && isupper(*(s+2))) {
  3364. X        j = FALSE;
  3365. X    path[0] = *(s+1);
  3366. X    path[1] = *(s+2);
  3367. X    path[2] = 0;
  3368. X    for(i=0;tc[i];i++)
  3369. X      if (!strcmp(path,tc[i])) {
  3370. X        insert(_term[i]);
  3371. X        s += 2;
  3372. X        j = TRUE;
  3373. X        break;
  3374. X      }
  3375. X    if (j) continue;
  3376. X      }
  3377. X      switch(*++s) {
  3378. X    case 't':
  3379. X      insert(gettime(0));
  3380. X      break;
  3381. X    case 'w':
  3382. X      insert(gettime(1));
  3383. X      break;
  3384. X    case 'd':
  3385. X      insert(gettime(2));
  3386. X      break;
  3387. X    case 'm':
  3388. X      insert(gettime(3));
  3389. X      break;
  3390. X    case 'y':
  3391. X      insert(gettime(4));
  3392. X      break;
  3393. X    case 'M':
  3394. X      insert(gettime(5));
  3395. X      break;
  3396. X    case 'T':
  3397. X      i = time(0) - TIMEON;
  3398. X      sprintf(path,"%d:%02d",i/3600,(i%3600)/60);
  3399. X      insert(path);
  3400. X      break;
  3401. X    case 'j':
  3402. X      if (!jobs) jobs = getnjobs();
  3403. X      insert(jobs);
  3404. X      break;
  3405. X    case '~':
  3406. X      getwd(path);
  3407. X      j = strlen(_home);
  3408. X      if (!strncmp(_home,path,j)) {
  3409. X        insert("~");
  3410. X        if (strlen(path) == j) break;
  3411. X        insert(path+j);
  3412. X        break;
  3413. X      }
  3414. X      for(i=0;_homedirs[i];i++) {
  3415. X        j = strlen(_homedirs[i]);
  3416. X        if (!strncmp(_homedirs[i],path,j)) {
  3417. X          if (strlen(path) == j) continue;
  3418. X          insert("~");
  3419. X          insert(path+j+(_homedirs[i][j-1]=='/'?0:1));
  3420. X          break;
  3421. X        }
  3422. X      }
  3423. X      if (!_homedirs[i]) insert(path);
  3424. X      break;
  3425. X    case 'p':
  3426. X      getwd(path);
  3427. X      insert(path);
  3428. X      break;
  3429. X    case 'P':
  3430. X      getwd(path);
  3431. X      for(i=strlen(path);i>=0 && path[i] != '/'; i--);
  3432. X      insert(path+i+1);
  3433. X      break;
  3434. X    case 'u':
  3435. X      if (!users) user = getusers(&users);
  3436. X      sprintf(path,"%d",users);
  3437. X      insert(path);
  3438. X      break;
  3439. X    case 'U':
  3440. X      if (!user) user = getusers(&users);
  3441. X      for(i=0;user[i];i++) insert(user[i]);
  3442. X      break;
  3443. X    case 'l':
  3444. X      t = (char *)getenv("USER");
  3445. X      if (!users) user = getusers(&users);
  3446. X      for(i=j=0;user[i];i++) if (!strncmp(user[i],t,strlen(user[i])-1)) j++;
  3447. X      free(t);
  3448. X      sprintf(path,"%d",j);
  3449. X      insert(path);
  3450. X      break;
  3451. X    case 'n':
  3452. X      if (newmail){
  3453. X        if (_mailnotice) {
  3454. X          if (_mailnotice[1]) insert(_mailnotice[1]);
  3455. X          else insert(" New mail ");
  3456. X        } else insert(" New mail ");
  3457. X      }
  3458. X      break;
  3459. X    case 'i':
  3460. X      for(i=0;_term[SO][i];i++) buf[p++] = _term[SO][i];
  3461. X      break;
  3462. X    case 'I':
  3463. X      for(i=0;_term[SE][i];i++) buf[p++] = _term[SE][i];
  3464. X      break;
  3465. X    case '%':
  3466. X      buf[p++] = '%';
  3467. X      a++;
  3468. X      break;
  3469. X    default:
  3470. X      buf[p++] = '%';
  3471. X      buf[p++] = *s;
  3472. X      a += 2;
  3473. X      break;
  3474. X      }
  3475. X    } else {
  3476. X      buf[p++] = *s;
  3477. X      a++;
  3478. X    }
  3479. X  } while (*s++ && a < amax && p < pmax);
  3480. X  if (p > pmax) p = pmax;
  3481. X  buf[p] = 0;
  3482. X  if (user) {
  3483. X    for(i=0;user[i];i++) free(user[i]);
  3484. X    free(user);
  3485. X  }
  3486. X  return buf;
  3487. X}
  3488. X
  3489. char *gettime(fmt)
  3490. char fmt;
  3491. X{
  3492. X  time_t tp;
  3493. X  struct tm *ti;
  3494. X  static char str[30];
  3495. X  static char *month[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  3496. X  static char *day[7] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  3497. X
  3498. X  time(&tp);
  3499. X  ti = localtime(&tp);
  3500. X  switch(fmt) {
  3501. X    case 0:
  3502. X      sprintf(str,"%d:%02d %s",(ti->tm_hour>12?ti->tm_hour-12:ti->tm_hour),ti->tm_min,(ti->tm_hour>11?"pm":"am"));
  3503. X      break;
  3504. X    case 1:
  3505. X      sprintf(str,"%s",day[ti->tm_wday]);
  3506. X      break;
  3507. X    case 2:
  3508. X      sprintf(str,"%d",ti->tm_mday);
  3509. X      break;
  3510. X    case 3:
  3511. X      sprintf(str,"%s",month[ti->tm_mon]);
  3512. X      break;
  3513. X    case 4:
  3514. X      sprintf(str,"%d",1900+ti->tm_year);
  3515. X      break;
  3516. X    case 5:
  3517. X      sprintf(str,"%d:%02d",ti->tm_hour,ti->tm_min);
  3518. X      break;
  3519. X  }
  3520. X  return str;
  3521. X}
  3522. X
  3523. char **getusers(nusers)
  3524. int *nusers;
  3525. X{
  3526. X  char **users = (char **)malloc(sizeof(char *));
  3527. X  int fd;
  3528. X  struct utmp utmp;
  3529. X
  3530. X  fd=open("/etc/utmp",O_RDONLY);
  3531. X  for (;;) {
  3532. X    if(read(fd,&utmp,sizeof(utmp)) <= 0) {
  3533. X      close(fd);
  3534. X      users[*nusers] = NULL;
  3535. X      users[*nusers-1][strlen(users[*nusers-1])-1] = 0;
  3536. X      return users;
  3537. X    }
  3538. X    if(utmp.ut_name[0] == '\0') continue;
  3539. X    users = (char **)realloc(users, sizeof(char *) * (*nusers + 2));
  3540. X    users[*nusers] = (char *)malloc(strlen(utmp.ut_name)+2);
  3541. X    strcpy(users[*nusers],utmp.ut_name);
  3542. X    strcat(users[*nusers]," ");
  3543. X    *nusers += 1;
  3544. X  }
  3545. X}
  3546. X
  3547. char *getnjobs()
  3548. X{
  3549. X  unsigned long mask;
  3550. X  int i,j = 0;
  3551. X  char tmp[4];
  3552. X
  3553. X  mask = sigblock(sigmask(SIGCHLD));
  3554. X  for(i=0;i<max_ent;i++) if (proc[i].pid) j++;
  3555. X  sigsetmask(mask);
  3556. X  sprintf(tmp,"%d",j);
  3557. X  return tmp;
  3558. X}
  3559. X
  3560. insert(str)
  3561. char *str;
  3562. X{
  3563. X  while(*str && a < amax && p < pmax) {
  3564. X    buf[p++] = *str++;
  3565. X    a++;
  3566. X  }
  3567. X}
  3568. END_OF_FILE
  3569. if test 5124 -ne `wc -c <'stat.c'`; then
  3570.     echo shar: \"'stat.c'\" unpacked with wrong size!
  3571. fi
  3572. # end of 'stat.c'
  3573. fi
  3574. if test -f 'wc.c' -a "${1}" != "-c" ; then 
  3575.   echo shar: Will not clobber existing file \"'wc.c'\"
  3576. else
  3577. echo shar: Extracting \"'wc.c'\" \(10859 characters\)
  3578. sed "s/^X//" >'wc.c' <<'END_OF_FILE'
  3579. X/* $Copyright:    $
  3580. X * Copyright (c) 1991,1992,1993 by Thomas Moore and Steve Baker
  3581. X * All rights reserved
  3582. X *
  3583. X * This software is provided as is without any express or implied
  3584. X * warranties, including, without limitation, the implied warranties
  3585. X * of merchantability and fitness for a particular purpose.
  3586. X */
  3587. X
  3588. X/* Main entry points:
  3589. X *
  3590. X * parse_wildcards()  -- substitute all wildcards in entire command line
  3591. X * match_wildcards()  -- substitute all wildcards in arglist
  3592. X * isregex()          -- check if string contains ~ or {[*?
  3593. X * dirget()           -- replace one wildcard in arglist
  3594. X * patmatch()         -- check if string matches wildcard
  3595. X */
  3596. X
  3597. X#include "shell.h"
  3598. X#include <sys/types.h>
  3599. X#include <sys/dir.h>
  3600. X#include <pwd.h>
  3601. X
  3602. extern int err;
  3603. char *errstr,*erru;
  3604. X
  3605. extern char _nonomatch;      /* TRUE: don't crash on no match */
  3606. extern char _nodots;      /* TRUE: don't include dot-files in search unless explicit */
  3607. extern char *_home;      /* contains the name of user's home dir */
  3608. X
  3609. void *malloc();
  3610. char **dirget(), **_dirget();
  3611. char *index(),*strcat();
  3612. X
  3613. char ***parse_wildcards(), **match_wildcards(), **insertelt(), **delelt();
  3614. X
  3615. static struct stat ST;
  3616. X
  3617. char ***parse_wildcards(arg)
  3618. char ***arg;
  3619. X{
  3620. X  int i;
  3621. X
  3622. X  for(i=0;arg[i];i++)
  3623. X    arg[i] = (char **)match_wildcards(arg[i]);
  3624. X  return (char ***)arg;
  3625. X}
  3626. X
  3627. char **match_wildcards(arg)
  3628. char **arg;
  3629. X{
  3630. X  int i,j,cnt,lvl=0,match=2,k;
  3631. X  char *p;
  3632. X
  3633. X  for(cnt = 0;arg[cnt];cnt++);
  3634. X  for(i=0;arg[i];i++) {
  3635. X    if (arg[i][0] == '(') lvl++;
  3636. X    if (arg[i][0] == ')') lvl--;
  3637. X    if (!err && !lvl && (j=isregex(arg[i]))) {
  3638. X      k = cnt;
  3639. X      p = arg[i];
  3640. X      arg = dirget(p,arg,&cnt,i,NULL,j==1,0);
  3641. X      if(k<=cnt){ /* the pattern was replaced */
  3642. X    if(!match)
  3643. X      free(errstr);
  3644. X    match = 1;
  3645. X    free(p);
  3646. X      }
  3647. X      else {
  3648. X    if(_nonomatch){
  3649. X      j = i - 1;
  3650. X      arg = insertelt(arg,p,i,&j,&cnt);
  3651. X    }
  3652. X    else {
  3653. X      if(match == 2){
  3654. X        errstr = p;
  3655. X        match = 0;
  3656. X      }
  3657. X      else
  3658. X        free(p);
  3659. X    }
  3660. X      }
  3661. X      i += (cnt-k);
  3662. X    }
  3663. X  }
  3664. X  if(err == ERR_NO_USER) {
  3665. X    fprintf(stderr,"No such user: %s.\n",erru);
  3666. X    free(erru);
  3667. X  } else if(!match && !_nonomatch){
  3668. X    err = ERR_NO_MATCH;
  3669. X    fprintf(stderr,"No match: %s.\n",errstr);
  3670. X  }
  3671. X  if(!match)
  3672. X    free(errstr);
  3673. X  return arg;
  3674. X}
  3675. X
  3676. X/****************************************************************/
  3677. X
  3678. isregex(s)
  3679. char *s;
  3680. X{
  3681. X  int r= 0;
  3682. X
  3683. X  if (*s == '"' || *s == '\'' || *s == '$') return FALSE;
  3684. X  if (*s == '~') r = 1;
  3685. X  while(*s) {
  3686. X    switch(*s++) {
  3687. X      case '*':
  3688. X      case '[':
  3689. X      case '?':
  3690. X      case '{':
  3691. X    return 2;
  3692. X      case '\\':
  3693. X    if(*s)
  3694. X      s++;
  3695. X    }
  3696. X  }
  3697. X  return r;
  3698. X}
  3699. X
  3700. X/****************************************************************/
  3701. X
  3702. X/*  handle { both here and in patmatch so that dirs are handled here and
  3703. X    patmatch still handles {}
  3704. X
  3705. X    Handling {^..} was considered at length.
  3706. X    Several options were available:
  3707. X    a) assume {^a/b} meant a/{^b} (as in AmigaDOS)
  3708. X    b) use same procedure as patmatch
  3709. X    c) assume {^a/b} meant {^a}/{^b} (gad...)
  3710. X
  3711. X    Due to the complexity of implementing a) and c), I decided to let
  3712. X    the user do the {^} replacements for those cases himself.  Therefore
  3713. X    '/' is not really handled in {^} (or in [] and [^], for that matter)
  3714. X*/
  3715. X
  3716. char **dirget(pat,argarray,arglen,reppos,_repend,just_tilde,wc)
  3717. char *pat, **argarray,just_tilde,wc;
  3718. int *arglen, *_repend;
  3719. X{
  3720. X  int pl,nl,mpl = 0,al;
  3721. X  char *moreloc = NULL,*stmp,*tp,*ne,*path = NULL,*n=NULL;
  3722. X  struct passwd *pass = NULL;
  3723. X  int repend = reppos;
  3724. X
  3725. X  if(!_repend) {
  3726. X    _repend = &repend;
  3727. X    delelt(argarray,reppos,_repend,arglen);
  3728. X  }
  3729. X  if(!just_tilde) {
  3730. X    for(n=pat;*n && *n != '{';n++)
  3731. X      if(*n == '\\' && n[1])
  3732. X    n++;
  3733. X    if(!*n || n[1] == '^')
  3734. X      n = NULL;
  3735. X  }
  3736. X  if(al = !n && *pat == '~') {
  3737. X    if(moreloc = index(pat,'/'))
  3738. X      *moreloc = 0;
  3739. X    if(isregex(pat+1) != 2) {
  3740. X      n = (char *)malloc(strlen(pat));
  3741. X      for(stmp=n,ne=pat+1;*ne;ne++,stmp++) {
  3742. X    if(*ne == '\\') { /* get rid of backslashes */
  3743. X      if(*stmp = ne[1])
  3744. X        ne++;
  3745. X    } else
  3746. X      *stmp = *ne;
  3747. X      }
  3748. X      *stmp = 0;
  3749. X      if(*n) {
  3750. X    if(!(pass=getpwnam(n))) {
  3751. X      if(wc) {
  3752. X        free(n);
  3753. X        return argarray;
  3754. X      }
  3755. X      erru = n;
  3756. X      err = ERR_NO_USER;
  3757. X      return argarray;
  3758. X    }
  3759. X    free(n);
  3760. X    n = pass->pw_dir;
  3761. X      } else {
  3762. X    free(n);
  3763. X    n = _home;
  3764. X      }
  3765. X      pl = strlen(n);
  3766. X      if(just_tilde){
  3767. X    mpl = pl > 1 || *stmp != '/'; /* home != root dir */
  3768. X    /* if root dir, delete excess '/' */
  3769. X    nl = moreloc?strlen(moreloc+1)+mpl:0;
  3770. X    stmp = (char *)malloc(pl + 1 + nl);
  3771. X    strcpy(stmp,n);
  3772. X    if(moreloc) {
  3773. X      if(mpl)
  3774. X        stmp[pl] = '/';
  3775. X      strcpy(stmp+pl+mpl,moreloc+1);
  3776. X    }
  3777. X    if(!wc || !al)
  3778. X      argarray = insertelt(argarray,stmp,reppos,_repend,arglen);
  3779. X    else {
  3780. X      argarray = _dirget(stmp+1,"/",argarray,arglen,reppos,_repend);
  3781. X      free(stmp);
  3782. X    }
  3783. X    if(moreloc)
  3784. X      *moreloc = '/';
  3785. X    return argarray;
  3786. X      } else { /* moreloc must != NULL */
  3787. X    *moreloc = '/';
  3788. X    pat = moreloc+1;
  3789. X    path = (char *)ALLOCA(pl+2);
  3790. X    strcpy(path,n);
  3791. X    if(pl>1 || *path != '/'){
  3792. X      path[pl+1] = 0;
  3793. X      path[pl] = '/';
  3794. X    }
  3795. X      }
  3796. X    } else {
  3797. X      nl = strlen(moreloc+1);
  3798. X      setpwent();
  3799. X      for(pass=getpwent();pass;pass=getpwent()) {
  3800. X    if(!patmatch(pass->pw_name,pat+1))
  3801. X       continue;
  3802. X    n = pass->pw_dir;
  3803. X    pl = strlen(n);
  3804. X    if(moreloc && n[pl-1] == '/')
  3805. X       pl--;
  3806. X    n = (char *)malloc(pl+2);
  3807. X    bcopy(pass->pw_dir,n,pl);
  3808. X    if(moreloc) {
  3809. X      n[pl++] = '/';
  3810. X    }
  3811. X    n[pl] = 0;
  3812. X    if(moreloc && moreloc[1]) {
  3813. X      argarray = _dirget(moreloc+1,n,argarray,arglen,reppos,_repend); /* was pat+1 as 1st arg */
  3814. X      free(n);
  3815. X    } else
  3816. X      argarray = insertelt(argarray,n,reppos,_repend,arglen);
  3817. X      }
  3818. X      endpwent();
  3819. X      if(moreloc)
  3820. X    *moreloc = '/';
  3821. X      return argarray;
  3822. X    }
  3823. X  } else {
  3824. X    if(n) {
  3825. X      nl = n-pat;
  3826. X      moreloc = ++n;
  3827. X      for(pl=0;(*moreloc != '}' || pl) && *moreloc;moreloc++){
  3828. X    if(*moreloc == '{') pl++;
  3829. X    if(*moreloc == '}') pl--;
  3830. X    if(*moreloc == '\\' && moreloc[1]) moreloc++;
  3831. X      }
  3832. X      if(!*moreloc++)
  3833. X    return argarray;
  3834. X      al = moreloc - n - 1;
  3835. X      tp = stmp = (char *)ALLOCA(al+1);
  3836. X      bcopy(n,stmp,al);
  3837. X      stmp[al] = 0;
  3838. X      mpl = strlen(moreloc);
  3839. X      n = (char *)ALLOCA(nl+mpl+al+1);
  3840. X      bcopy(pat,n,nl);
  3841. X      while(*stmp){
  3842. X    for(pl=al=0;(stmp[al] != ',' || pl) && stmp[al];al++){
  3843. X      if(stmp[al] == '{') pl++;
  3844. X      if(stmp[al] == '}') pl--;
  3845. X      if(*stmp == '\\' && stmp[1]) stmp++;
  3846. X    }
  3847. X    bcopy(stmp,n+nl,al);
  3848. X    bcopy(moreloc,n+al+nl,mpl);
  3849. X    n[al+mpl+nl] = 0;
  3850. X    if(!(just_tilde = isregex(n)) && !wc) {
  3851. X      ne = (char *)malloc(strlen(n)+1);
  3852. X      strcpy(ne,n);
  3853. X      argarray = insertelt(argarray,ne,reppos,_repend,arglen);
  3854. X    }
  3855. X    else
  3856. X        argarray = dirget(n,argarray,arglen,reppos,_repend,just_tilde==1,1);
  3857. X    if(*(stmp += al))
  3858. X      stmp++;
  3859. X      }
  3860. X      FREEA(tp);
  3861. X      FREEA(n);
  3862. X      return argarray;
  3863. X    }
  3864. X    if(*pat == '/') {
  3865. X      path = "/";
  3866. X      pat++;
  3867. X    } else path = "";
  3868. X  }
  3869. X  argarray = _dirget(pat,path,argarray,arglen,reppos,_repend);
  3870. X  if(al)
  3871. X    FREEA(path);
  3872. X  return argarray;
  3873. X}
  3874. X
  3875. char **_dirget(pat,path,argarray,arglen,repstart,repend)
  3876. char *pat,*path,**argarray;
  3877. int *arglen,*repend;
  3878. X{
  3879. X  DIR *curdir;
  3880. X  struct direct *curent;
  3881. X  int pl,nl,mpl = 0;
  3882. X  char *moreloc,*stmp,*n;
  3883. X
  3884. X  if(moreloc = index(pat,'/'))
  3885. X    *moreloc++ = 0;
  3886. X  if(!(curdir = opendir(path))){
  3887. X    if(moreloc)
  3888. X      *--moreloc = '/';
  3889. X    return argarray;
  3890. X  }
  3891. X  if(*pat != '.' || (pat[1]&&pat[1] != '.'||pat[2])){
  3892. X    readdir(curdir);
  3893. X    readdir(curdir);
  3894. X  }
  3895. X  while(curent = readdir(curdir)){
  3896. X    n = curent->d_name;
  3897. X    if((*n != '.' || *pat == '.' || !_nodots) && patmatch(n,pat)) {
  3898. X      pl = strlen(path);
  3899. X      nl = strlen(n);
  3900. X      if(moreloc) {
  3901. X    if(pl+nl+2 > mpl){
  3902. X      if(mpl)
  3903. X        FREEA(stmp);
  3904. X      mpl = ((pl+nl+6)/5)*5;
  3905. X      stmp = (char *)ALLOCA(mpl);
  3906. X    }
  3907. X    strcpy(stmp,path);
  3908. X    strcpy(stmp+pl,n);
  3909. X    stat(stmp,&ST);
  3910. X    if((ST.st_mode&S_IFMT) == S_IFDIR){/* || (ST.st_mode&S_IFMT) == S_IFLNK){*/
  3911. X      strcpy(stmp+pl+nl,"/");
  3912. X      if(!*moreloc)
  3913. X        argarray = insertelt(argarray,(char *)strcpy(malloc(pl+nl+2),stmp),repstart,repend,arglen);
  3914. X      else
  3915. X        argarray = _dirget(moreloc,stmp,argarray,arglen,repstart,repend);
  3916. X    }
  3917. X      }
  3918. X      else{
  3919. X    stmp = (char *)malloc(pl+nl+1);
  3920. X    strcpy(stmp,path);
  3921. X    strcpy(stmp+pl,n);
  3922. X    argarray = insertelt(argarray,stmp,repstart,repend,arglen);
  3923. X      }
  3924. X    }
  3925. X  }
  3926. X  if(moreloc){
  3927. X    *--moreloc = '/';
  3928. X    if(mpl)
  3929. X      FREEA(stmp);
  3930. X  }
  3931. X  closedir(curdir);
  3932. X  return argarray;
  3933. X}
  3934. X
  3935. char **insertelt(argarray,p,s,repend,cnt)
  3936. char **argarray;
  3937. char *p;
  3938. int *repend,*cnt;
  3939. X{
  3940. X  int m,c,e = *repend;
  3941. X
  3942. X  if(s>e){
  3943. X    c = 0;
  3944. X    m = s;
  3945. X  }
  3946. X  else
  3947. X    while(s<=e){
  3948. X      m = (s + e) >> 1;
  3949. X      c = strcmp(p,argarray[m]);
  3950. X      if(!c){
  3951. X    free(p);
  3952. X    return argarray;
  3953. X      }
  3954. X      if(c<0)
  3955. X    e = m - 1;
  3956. X      else
  3957. X    s = m + 1;
  3958. X    }
  3959. X  if(c>0)
  3960. X    m++;
  3961. X  (*cnt)++;
  3962. X  (*repend)++;
  3963. X  if(!(*cnt%5))
  3964. X    argarray = (char **)realloc(argarray,(*cnt+5)*sizeof(*argarray));
  3965. X  for(s = *cnt;s>m;s--)
  3966. X    argarray[s] = argarray[s-1];
  3967. X  argarray[m] = p;
  3968. X  return argarray;
  3969. X}
  3970. X
  3971. X
  3972. char **delelt(argarray,m,repend,cnt)
  3973. char **argarray;
  3974. int *repend,*cnt;
  3975. X{
  3976. X  int e = *repend;
  3977. X
  3978. X  if(m>e)
  3979. X    return NULL;
  3980. X  (*cnt)--;
  3981. X  (*repend)--;
  3982. X  e = *cnt;
  3983. X  for(;m<=e;m++)
  3984. X    argarray[m] = argarray[m+1];
  3985. X  if(*cnt%5== 4)
  3986. X    argarray = (char **)realloc(argarray,(*cnt+1)*sizeof(*argarray));
  3987. X  return argarray;
  3988. X}
  3989. X
  3990. X/****************************************************************/
  3991. X
  3992. patmatch(buf,pat)
  3993. char *buf,*pat;
  3994. X{
  3995. X  int match = 1,m,n,l,tm;
  3996. X  char *p,*t,*tp;
  3997. X
  3998. X  while(*pat && match) {
  3999. X    switch(*pat) {
  4000. X      case '[':
  4001. X    pat++;
  4002. X    if(*pat != '^') {
  4003. X      n = 1;
  4004. X      match = 0;
  4005. X    } else {
  4006. X      pat++;
  4007. X      n = 0;
  4008. X    }
  4009. X    while(*pat != ']'){
  4010. X      if(*pat == '\\') pat++;
  4011. X      if(!*pat /* || *pat == '/' */ ) return -1;
  4012. X      if(pat[1] == '-'){
  4013. X        m = *pat;
  4014. X        pat += 2;
  4015. X        if(*pat == '\\' && *pat)
  4016. X        pat++;
  4017. X        if(*buf >= m && *buf <= *pat)
  4018. X        match = n;
  4019. X        if(!*pat)
  4020. X        pat--;
  4021. X      } else if(*buf == *pat) match = n;
  4022. X      pat++;
  4023. X    }
  4024. X    buf++;
  4025. X    break;
  4026. X      case '{':
  4027. X    p = ++pat;
  4028. X    if(*p == '^'){
  4029. X      p = ++pat;
  4030. X      tm = 0;
  4031. X    } else tm = 1;
  4032. X    n = l = 0;
  4033. X    while((*pat != '}' || l) && *pat){
  4034. X      if(*pat == '{') l++;
  4035. X      if(*pat == '}') l--;
  4036. X      n++;
  4037. X      pat++;
  4038. X    }
  4039. X    if(!*pat++)
  4040. X      return -1;
  4041. X    t = (char *)ALLOCA(n+1);
  4042. X    bcopy(p,t,n);
  4043. X    t[n] = 0;
  4044. X    tp = t;
  4045. X    m = strlen(pat);
  4046. X    n += !m; /* if no chars to match, make sure there's room for a '*' */
  4047. X    p = (char *)ALLOCA(m+n+1);
  4048. X    while(*t){
  4049. X      for(n=0;(t[n] != ',' || l) && t[n];n++){
  4050. X        if(t[n] == '{') l++;
  4051. X        if(t[n] == '}') l--;
  4052. X      }
  4053. X      bcopy(t,p,n);
  4054. X      bcopy(pat,p+n,m);
  4055. X      p[n+m] = 0;
  4056. X      if(patmatch(buf,p)){
  4057. X        FREEA(p);
  4058. X        FREEA(tp);
  4059. X        return tm;
  4060. X      }
  4061. X      if(*(t += n))
  4062. X        t++;
  4063. X    }
  4064. X    FREEA(tp);
  4065. X    if(tm ^= 1){
  4066. X      *p = '*';
  4067. X      bcopy(pat,p+1,m);
  4068. X      p[m+1] = 0;
  4069. X      tm = patmatch(buf,p);
  4070. X    }
  4071. X    FREEA(p);
  4072. X    return tm;
  4073. X      case '*':
  4074. X    pat++;
  4075. X    if(!*pat) return 1;
  4076. X    while(*buf && !(match = patmatch(buf++,pat)));
  4077. X    return match;
  4078. X      case '?':
  4079. X    if(!*buf) return 0;
  4080. X    buf++;
  4081. X    break;
  4082. X      case '\\':
  4083. X    if(*pat)
  4084. X        pat++;
  4085. X      default:
  4086. X    match = (*buf++ == *pat);
  4087. X    break;
  4088. X    }
  4089. X    pat++;
  4090. X    if(match<1) return match;
  4091. X  }
  4092. X  if(!*buf) return match;
  4093. X  return 0;
  4094. X}
  4095. X
  4096. END_OF_FILE
  4097. if test 10859 -ne `wc -c <'wc.c'`; then
  4098.     echo shar: \"'wc.c'\" unpacked with wrong size!
  4099. fi
  4100. # end of 'wc.c'
  4101. fi
  4102. echo shar: End of archive 1 \(of 4\).
  4103. cp /dev/null ark1isdone
  4104. MISSING=""
  4105. for I in 1 2 3 4 ; do
  4106.     if test ! -f ark${I}isdone ; then
  4107.     MISSING="${MISSING} ${I}"
  4108.     fi
  4109. done
  4110. if test "${MISSING}" = "" ; then
  4111.     echo You have unpacked all 4 archives.
  4112.     rm -f ark[1-9]isdone
  4113. else
  4114.     echo You still need to unpack the following archives:
  4115.     echo "        " ${MISSING}
  4116. fi
  4117. ##  End of shell archive.
  4118. exit 0
  4119.