[comp.sources.amiga] v91i089: CShell 5.10 - alternative command interface, Part02/06

amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (04/17/91)

Submitted-by: umueller@iiic.ethz.ch
Posting-number: Volume 91, Issue 089
Archive-name: shells/cshell-5.10/part02

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 6)."
# Contents:  changes.doc csh.doc.ad rawcon.c sub.c
# Wrapped by tadguy@ab20 on Tue Apr 16 15:34:34 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'changes.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'changes.doc'\"
else
echo shar: Extracting \"'changes.doc'\" \(11556 characters\)
sed "s/^X//" >'changes.doc' <<'END_OF_FILE'
XNew features to 5.10:
X- totally rewritten parser, therefore:
X-  local variables, in aliases as well as in batch files
X-  blocks can be formed, redirected, aborted: {e yo;e ho}
X-  $(foo) will insert output of program foo at that point, similar with `foo`
X-  wildcard expansion also done in first arg, e.g. '*' is a legal command line
X-  command lines like '$mydir/$mycommand ram:' now works
X-  aliases/foreach/forline/fornum/source can be redirected as a whole
X-  direct recursion in aliases prevented, 'alias ls "ls -s"' works
X-  additional speedup; twice as fast as 4.xx, four times as fast as c:Execute
X- '.bra' and '.ket' introduced as dummy commands for script compatibility
X- 'assign' now yields a list of all assings including late/nonbinding, paths
X- 'assign -p' does path assigns (like 'c:Assign ... ADD)
X- 'cat' CR terminated non-CR-termintad files again if not redirected
X- 'class' can pattern-match now, e.g. 'class sound name="mod.*"'
X- 'copy' has a larger buffer and checks for ^C more often
X- 'copy -m' moves files (but not directories yet)
X- 'dir -p' prints full paths and suppresses titles
X- 'dir' can separate direcories at the top or bottom
X- 'dir -z formatstring' is a very powerful formatting feature
X- 'error' generates a desired return code
X- 'forline i STDIN' reads args from stdin
X- 'input' removes leading, trailing and multiple blanks
X- 'local' and 'unlocal' for generating and deleting local variables
X- 'man' can handle multiple .doc files, so you can document your own aliases
X- 'mem' uses , instead of ' and is right adjusted
X- 'source' can handle multiple line blocks of arbitrary length
X- 'qsort' can now sort in reverse order
X- 'rback'/'run' now set the variable '$_newproc' to the # of the new process
X- $_abbrev can be used to disable abbreviation if internal commands
X- $_ioerr contains the secondary return code after an error
X- $_path now contains S: and CSH: in order to run scripts
X- $_pipe now holds the directory for the temporary pipe files
X- $_verbose need to be set to special values, now can trace alias calls
X- @console tells whether stdin or stdout are interactive
X- @ioerr converts a secondary error number to a string (like 'Why')
X- @mounted indicates whether a device has been mounted yet or not
X- @sortnum sorts its arguments numerically
X- @volume now suppresses ugly system requesters
X- shift-arrow-up and shift-arrow-down now behave like under AmigaDOS
X- there is now an editing function that duplicates the last word
X- csh has a startup option to enable '*' as an alias for '#?' in AmigaDOS
X- a directory CSH: is proposed for scripts and the doc
X- concatted lines in source files can be as long as you want
X- . now stands for current directory, .. for parent
X- soft and hard links to directories are ignored on wild card expansion
X
XBug fixes of 5.10 (in order of severity):                  bug present since
X- AmigaDOS residents should work fine now. V37 kickstart required       5.00
X- 'Wait 5&' as an alias for 'rback Wait 5' now works                    5.00
X- 'rm -r ram:' and 'search -r "" hello' finally do their job            4.00
X- 'c:execute' works. check the restrictions chapter                     3.00
X- '!!' was broken in the first parser rewrite, fixed now.               5.00
X- 'return' occasionally didn't skip the whole source file               5.00
X- '~' now can correctly be used in path names: ~/*.c                    5.00
X- 'Repeat' from menu caused a loop (correct behaviour!)                 5.00
X- 'forline' no longer crashes if the from-file does not exist           4.00
X- 'set x 1 2;echo hello$x' finally yields 'hello1 2'.                   1.00
X- 'goto' also works if there are '\' in the source file                 4.00
X- command line editing on VT100's was broken. fixed.                    5.00
X- low mem situations now cause a graceful exit instead of a crash       1.00
X- actions on files with embedded blanks are performed correcty          5.00
X- 'man' no longer opens garbage files (SnoopDos is hard to cheat)       5.00
X- 'dir -o' now works (ls -o always did)                                 5.00
X- 'dir df0:' with no disk in drive yields correct error message         5.00
X- 'dir' no longer adds line feeds to invalid date stamps                5.00
X- 'set _prompt "% "' is now allowed (not only 'set _prompt "%% "')      5.00
X- 'search -l' no longer does unnecessary line feeds                     5.00
X- '@pickopts' stops picking options at the first non-option             5.00
X- system requesters are no longer unintentionally disabled              5.00
X
XIncompatibilities in 5.10
X- a stand-alone '.' must be quoted now. check your strhead's and strtail's!
X- the quick-cd file and the manual (now named csh.doc) should reside in csh:
X- some builtin aliases and preset function keys have been moved to compat.sh
X- the functions of shift-arrow-up & down are mapped to esc-arrow-up & down
X- the path is now searched before auto CD is attempted (mimicking AmigaDOS)
X- the characters { } @ ( ) should be quoted if you just want to echo them
X- a redirection error now causes a return code of 20 instead of 1
X- _verbose now holds numeric values, 'set _verbose yes' won't work anymore
X- @volume no longer appends a trailing colon to the volume name
X- an empty string is now passed to external commands as ""
X- future: a leading '/' and '~' might change meaning towards UNIX
X
XNew features to 5.00
X- read the doc! almost everything's new.
X
XBug fixes to 5.00: 
X- recursive wild card expansion does not crash the Amiga 3000 anymore
X- recursive wild card expansion does not lose memory anymore
X- now works on AUX:
X- trying to start a non-object-file now properly prints 'Command Not Found'
X- automatic sourcing now also works if you already add .sh to the file name
X- files longer than 999999 bytes no longer misalign 'dir'
X- exec does not discard the rest of the command line ('exec echo hi;echo ho')
X- all memory trashing fixed. Thanks to C= for their great debugging tools!
X- source doesn't forget last character if batchfile was not CR terminated
X- run & rback also search AmigaDOS path now
X- division by zero does not crash rpn anymore
X- temporary pipe files are now written to t: instead of ram:
X- shift-tab does not cause a lockup anymore
X- running the shell via aux: no longer crashes the machine
X- 'history partial' now numbers the lines correctly
X- strleft, strright and strmid no longer crash on strings > 256 bytes
X- source with no arguments now prints correct error message
X- 'input' now cuts down lines longer than 256 bytes instead of crashing
X- cursor-up no more deletes lines if there's an invalid entry in the history
X- if history fails, no empty history entry is generated
X- 'echo "---"' and even 'echo ---' work, but 'echo "-a"' still doesn't
X- international character sets can be used
X- 'copy -u' won't copy a file with identical date stamp but in uppercase
X- 'copy -u' will no longer access low memory
X- 'echo "echo mem | shell" | shell' now works, not only every second time
X- starting from workbench now prevented
X- editing lines longer than 256 bytes is now correctly prevented
X- word-right cursor movement works correclty with multiple blanks
X- 'if'-stack will be adjusted when a batch file is exited
X- relabel occasionally crashed in Syquest drives. should be okay now
X
XKnown bugs in 5.00:
X- under 2.0, doing a 'cat' with no args and pressing return will cause a 
X  character to appear at the right border of the window. seems to be a
X  kickstart bug, as it does not happen under older kickstarts.
X- AmigaDOS 2.0 CLI commands cannot be made resident. They read their command
X  line from stdin. This is definitely a kickstart bug.
X- guaranteed to crash in extreme low mem situations
X- command line editing doesn't quite work on a (physical) vt100. OK on VT200
X- under kick 2.00, fast repetition of ^W crashed. OK under 2.02
X- 'set x a b;echo hello$x' still outputs only 'a b'
X
XIncompatibilities in 5.00:
X- 'copy -f' now means 'freshen'. Old meaning of -f is now -p (protection)
X- '~' at the beginning of a file name must now be quoted
X- '@' is the beginning of an argument should be quoted
X- 'cat' no longer adds a CR to a non-CR-terminated file
X- '0' is now 'false'. Example: 'if 0;e hi;else;e ho;endif --> ho
X- variables with comparision operators inside now cause problems in 'if'
X- a single '?' will not pattern match, but be passed as a string
X
X
X
XNew to 4.02A:
X- Fixed bug that caused loss of memory on exit.
X- cp now copies protection bits; use -f switch if you want to avoid this.
X- Added  commands: man (and alias manlist), uniq, head, tail, tee.
X- This doc has been reformatted to work with man.
X
XNew to 4.01A:
X- This version features mostly bug fixes and corrections:
X * Window title is restored after quitting.
X * rxrec now answers to the 'bye' message.
X * rpn can now be redirected and piped; however, this causes
X	some problem (see rpn for info).
X * resident list now works with ARP 1.3. To recompile source, you must
X	modify include file "libraries/arpbase.h".
X	Change definition of rpn_Usage in struct ResidentProgramNode from LONG
X	to WORD.
X * pri no more assumes 20 CLI maximum.
X * you can now split long lines in source files even into more than 2 lines.
X- Added much info in this doc about source files (chapter XI)
X- Added copyright notice (see under restrictions).
X
XNew to 4.00A:
X- This version is called 4.00A because it is not 100% compatible with
X  previous versions. We choose to accept this in order to better support
X  the new ARP.library 1.3.
X- External commands are searched in a different order than before; Shell
X  path is now searched AFTER current directory, AmigaDOS path and C:.
X- ARP pattern matching has been implemented (in part for line arg expanding,
X  fully for search -w).
X- Internal changes for various optimizations.
X- Search command has been improved in several ways.
X- New commands: basename, tackon.
X- New options: if -v, resident -d, fornum -v -s, dir -n.
X- Fixed bugs with dir (some dirs remained locked), foreach -v, htype
X  (blanks were treated as binary), info (for devices > 32M).
X- rback command now works ok (run, however, doesn't).
X- Oh, I forgot: it also has an AREXX port... And you don't even have to get
X  AREXX to use it. See new commands rxsend, rxrec
X
XNew to 3.03A:
X- New filter commands fltlower, fltupper.
X- Added configuration file feature: now if you have a file named S:.login,
X  it will be sourced for every Shell you start.
X- New option dir -c.
X- New editing feature: shift-left(right) arrow move cursor to previous(next)
X  word.
X- Bugs fixed: alias command wasn't listed in help; typing a number as a
X  command was interpreted like 'alias'.
X
XNew to 3.02A:
X- New commands: fornum, forline, strleft, strright, strmid, strlen, exec.
X- Improved commands: foreach, pri.
X- New system variable _clinumber.
X- You can now split long lines in source files (see source for details).
X- window -q now lists also position of screens/windows, not only dimension.
X- Since strings are handled directly from Shell with new commands,
X  rpn is now used only for calculations; string commands are gone.
X  However, now RPN is really usable.
X- Changed rawgets() to fix some problems with function keys, multi-line
X  editing and window resizing; also, fixed bug with ^E.
X- cat now warns you if it can't find any file matching your pattern.
X- Now uses DOS packets to get ptr to CLI window; this fixes a bug that
X  caused problems if Shell was run on unactive windows.
X- Fixed minor bugs (htype printed some more ASCII bytes, some commands
X  returned random values, history didn't print CR's).
END_OF_FILE
if test 11556 -ne `wc -c <'changes.doc'`; then
    echo shar: \"'changes.doc'\" unpacked with wrong size!
fi
# end of 'changes.doc'
fi
if test -f 'csh.doc.ad' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'csh.doc.ad'\"
else
echo shar: Extracting \"'csh.doc.ad'\" \(11563 characters\)
sed "s/^X//" >'csh.doc.ad' <<'END_OF_FILE'
X	If  no  _except variable exists, any command which fails causes the
X	rest of the line to abort as if an ABORTLINE had been executed.  If
X	the _except variable exists, it is of the form:
X
X	"nnn;commands..."
X
X	where  nnn  is  some  value  representing  the  minimum return code
X	required  to  cause  an  error.   Whenever a command returns a code
X	which  is  larger  or  equal  to  nnn,  the commands in _except are
X	executed  before  anything.   WHEN _except EXISTS, THE COMMAND LINE
X	DOES  NOT  ABORT AUTOMATICALLY.  Thus, if you want the current line
X	being executed to be aborted, the last command in _except should be
X	an "abortline".
X
X	Exception  handling  is  disabled  while  in the exception handling
X	routine (thus you can't get into any infinite loops this way).
X
X	Thus if _except = ";", return codes are completely ignored.
X
X	Example:
X
X	set _except "20;abortline"
X
X
XXII. EXAMPLE SOURCE FILES
X-------------------------
X
XIf from a CLI or the startup-script you say 'SHELL filename', that file is
Xsourced first.
X
X### compat.sh ###
X
X# this makes sure that your old abbreviations don't call new commands
X
Xalias as  aset
Xalias cl  close
Xalias g   goto
Xalias h   help
Xalias he  help
Xalias m   md
Xalias q   quit
Xalias re  rename
Xalias w   window
X
Xalias kr  "rm -r ram:* >NIL:
X
X### End of compat.sh ###
X
X
XMoreover, if you have a file called S:.login, it will be sourced for every
XShell you run. This is useful for aliases and setting that you want in ALL
XShells.
X
X
X### Example S:.login ###
X
XHere is an example .login file:
X
Xset F5 "cdir WORK:"^M
Xset f9 "ed s:login.sh"^M
Xset F9 "ed df0:s/startup-sequence"^M
X
Xalias toram  "%q foreach i ( $q ) \"cp -r $i: ram:$i >NIL:;assign $i: ram:$i
Xalias ramop  "md RAM:op; assign OP: ram:op
Xalias noop   "assign OP: ; rm -r ram:op
Xalias newop  "rm -r OP:*
Xalias dc     "dfc df0: to df1:
Xalias go     "%q assign WORK: Boot:$q; cd WORK:; source startme.sh
Xalias get    "%q cp $q RAM: >NIL:
Xalias filter "%a%b%c exec $b \\<$a \\>$c
X	# reads $a, filters it with $b and writes result to $c
X
Xalias rm     "%q \\rm @confirm( Remove $q )
X
X#alias rm     "%a set f @pickargs( $a );set opts @pickargs( $a );\
X# e -n OK to delete @words( @files( $f ) ) file(s) and @words( @dirs( $f ) )\
X# directories\"? \";input b;if $b = y;\\rm $opts $f;endif 
X#		# for the anxious among us: confirmed rm
X
Xset _prompt   "%c%p> "
X	# this puts the path highlighted in the prompt
X
X# this one puts cli number, free mem, date and time in title bar
Xset _titlebar "Shell %n    Mem %m     Date %d    Time %t
X
X# This file will be sourced for every Shell you start
X
X### End of example .login ###
X
X****************************************************************************
X
XIf you are a CLI user, your startup-sequence may be as simple as:
X
X	C:csh S:startup.sh
X
XHere's a startup code:
X
X### Example S:startup.sh ###
X
Xwind -l	# if you are on a PAL machine, or use overscan
X	# note that commands may be abbreviated (wind=window)
X
Xassign LC: Stuff:c  INCLUDE: Stuff:include   LIB: Boot:lib   QUAD: RAM:
X
Xrback C:FaccII; sleep 1
X	# after spawning a process, it is always better to allow it
X	# to load the command, to avoid excessive drive head movement
X
Xresident -d blink lc1 lc2 >NIL:	#defer loading
X
XC:PopCli 300 C:Newcli 		#using full pathname loads faster
XC:FF -1 Siesta.font >NIL:
XC:Patch_1 >NIL:
Xstack 8000			# lc1 and lc2 need this
X
Xsource S:setdate.sh		# this is listed next 
X
X### End of example startup.sh ###
X
X****************************************************************************
X
XThe following is an example source file to set date and time; it may be
Xused at startup if you don't have an internal clock.
X
X### setdate.sh ###
X
Xopen CON:200/100/440/80/SetDate write 1
Xecho >.1 -n "Current date is "
Xdate >.1
Xecho >.1 -n "Please enter date: "
Xinput <.1 d
Xclose 1
Xstrlen len $d
Xif $len > 1 ; date $d ; endif
Xecho -n "New date: " ; date
X
X### End of setdate.sh ###
X
X***************************************************************************
X
XNext comes a makefile that needs no Make program: may be executed from
XShell directely!!!
X
X### make.sh ###
X
Xif -t Shell.syms Shell.h; cc +HShell.syms Shell.h; rm shell.o; endif
Xif -t RAM:Shell.syms Shell.syms; cp -d Shell.syms RAM:; endif
X
Xforeach i ( main comm1 comm2 comm3 execom globals rawconsole run set \
X sub ) "if -t $i.o $i.c; echo Compile $i...;cc +IRAM:shell.syms $i.c; endif"
X
X# we used line continuation for better visibility. this is not necessary,
X# you can type it all in one line. no more limit of 256 bytes per line
X
Xif -t Shell run.o main.o comm1.o comm2.o comm3.o execom.o \
Xset.o sub.o globals.o rawconsole.o
X	ln  +q -m -o Shell run.o main.o comm1.o comm2.o comm3.o\
X	execom.o set.o sub.o globals.o rawconsole.o -la -lc
Xendif
X
X### End of make.sh ###
X
X
XXIII.  Default Values
X--------------------
X
XTo make things easier, some aliases are predefined whenever you start a
Xnew Shell. These are:
X
X    CLS
X	Simply clear the screen.
X
X    CDIR
X	Use "cdir directory" to clear the screen, set CD to directory,
X	and list it.
X
X    EXIT
X	Leave Shell and exit CLI.
X
X    FG
X	Runs current shell in foreground, this means priority 1.
X
X    KR
X	Used to delete everything on RAM:. This one is gone, if you still
X	want it, you'll have to put it in your s:.login
X
X    LP
X	List to printer one or more files.
X
X    MANLIST
X	Display  a list of possible arguments to man.  You can pipe this to
X	qsort to get a sorted output.
X
X    NICE
X	Sets this shell to priority -1.
X
XMoreover, many variables have default values, and many function keys are
Xpredefined. You can use set command to determine all of these.
X
XXIV.  Object oriented features
X------------------------------
X
X    CLASSES OF FILES
X
X	You can define a class of files using several 'class' commands.
X	Here a simple example:
X
X	  class picture  suff=.pic suff=.iff suff=.ilbm 
X	  class anim     suff=.anim
X
X	From now on, everything with the suffix .pic, .iff or .ilbm will
X	be identified as a picture. Please note that there may be no blanks
X	between the names and the '=', and that blanks inside the names
X	must be put in quotes. So these are the ways to identify a file:
X
X	  suff=.doc        True if the suffix of the file is .doc
X	  name=readme      True if the file is "readme"
X	  name="mod.*"     True if the name starts with 'mod.'
X	  offs=14,DC..C4FD True if the bytes starting at $14 are $DC,
X	                   anything, $C4, $FD  (all numbers hexadecimal!). 
X	                   Each pair of dots means one byte ignored.
X	  chars            True if 90% of the bytes in the file are 32..127
X	                   or 9..13
X	  default          Always true, used to define the default type
X
X	Note that only the first character is examined, so 's' = 'suff'.
X	One class can be identified by more than one 'class' statement.
X	They are looked at in the same sequence they were entered. So to
X	make sure that an zoo archive misnamed as .lzh is identified
X	correctly, use the following 'class' statements:
X
X	  class zoo offs=14,DCA7C4FD
X	  class lzh offs=2,2D6C68..2D
X	  class zoo suff=.zoo
X	  class lzh suff=.lzh
X
X	Moreover, there is a builtin class 'dir', which means directory.
X	Now we know many file types. But what to do with them? This is
X	where we define 'actions'.
X
X    ACTIONS ON CLASSES
X
X	There may be one or more 'class' commands that define what actions
X	need to be taken in various cases for that specific class:
X
X	  class zoo actions view="zoo -list" extr="zoo -extract"
X	  class lzh actions view="lz l"      extr="lz e"
X
X	Whenever somebody tries to 'view' a test.zoo, the command
X	'zoo -list test.zoo' will be issued, but if he tries to
X	view test.lzh, then 'lz l test.lzh' will be executed. Note
X	that any command supplied here goes through the normal csh
X	parser, so AmigaDOS and csh paths will be searched. Aliases
X	with arguments are allowed here, too, so whatever the user
X	typed will be stored in the variable after the '%'.
X
X	How do I tell a file that I want to 'view' it? There comes the
X	second command used for object oriented features:
X
X	  action view test.zoo
X
X	will first identify the type of that file and then apply, if
X	possible, the 'view' action to it. Of course, this works best
X	inside an alias:  alias v "action view" will define a v-command
X	that views all types of files known to cshell. Similarly, you
X	can define   alias xtr "action extr" and use this command to
X	extract files from any type of archive.
X	There is one action that will be sent to every file that you
X	try to start but is not executable. This action is 'exec'. 
X	Assume you have defined the class 'picture', then after
X
X	  class picture actions view=Mostra exec=Mostra
X
X	you can display a picture using Mostra by just typing its name.
X	More builtin actions like 'rm' and 'dir' may be implemented,
X	so don't use command names for action names.
X
X	The batch file class.sh defines a few useful classes.
X
X
X
XXV.     Keymaps
X---------------
X
X	You define a keymap as a collection of key/function pairs. Both
X	are given as numbers. There can be several keymaps which activate
X	each other, but at first we only edit keymap 0, which is active
X	at the beginning. All keys you define will eventually overwrite
X	the old definitions in an existing keymap. Everithing marked with
X	a (*) is not yet implemented.
X
X    KEYCODES
X
X	1..255    The corresponding ASCII character
X	256	  Up Arrow
X	257	  Down Arrow
X	258	  Right Arrow
X	259	  Left Arrow
X	260	  Help
X	261..270  F1..F10  (unshifted)
X
X
X	Modifiers (add them to the key code)
X
X	512       SHIFT (only necessary for arrows and fkeys)
X	1024      ESC   (was pressed & released before this key)
X
X    EDITFUNCTIONS
X
X	- Movement      Move cursor...
X	 0  CursLeft    1 left
X	 1  CursRight   1 right
X	 2  WordLeft    1 word left
X	 3  WordRight   1 word right
X	 4  BegOfLine   to beginning of line
X	 5  EndOfLine   to end of line
X
X	- Deleting      Delete...
X	10  Backspace   char left from cursor
X	11  Delete      char right from cursor
X	12  BkspcWord   word left from cursor
X	13  DelWord     word right from cursor
X	14  DeleteToSOL to start of line
X	15  DeleteToEOL to end of line
X	16  DeleteLine  whole line
X
X	- History insert
X	20  Back        Move one line back in history
X	21  Forward     Move one line forward in history
X	22  Beg         Move to first line in history
X	23  End         Move to last line in history
X	24  Complete    History retrieve like '!'
X	25  Exec        Execute history line & bring up next
X	26  Tail        Insert previous line except first word
X	27  Bottom      Go below last history command
X	28  DupWord     Duplicates the last word on this line
X
X	- Completion
X	30  Normal      Insert first matching file (or cycle)
X	31  Partial     Insert substring of all matching files
X	32  All         Insert all matching files
X	33  Directory   Find dir in quick cd list
X	34  LastCD      Insert last current directory
X
X	- Special
X	40  Insert      Toggle Insert/Overwrite
X	41  Quit        Silently perform 'quit'
X	42  Help        Silently perform 'help'
X	43  Refresh     Redraw current line
X	44  Execute     Execute current line
X	45  Leave       Edit new line, store this in hist
X	46  EOF         Terminate shell
X	47  NOP         Do nothing
X	48  Echo^O      Echoes a ^O
X	49  Beep        Echoes a ^G
X
X	- Other
X	50  Fkey        Execute command associated to last fkey
X	51  Menu        Execute command associated to last menu
X	52  Undo        Undoes last edit
X	53  Repeat      Repeats last function
X
X
X	Command types
X
X	0   +x	  Editing function x, see above descriptions
X	512 +x	  Setmap x,     x=0..7
X	1024+x	  Insert key x, x=1..255
X	1536+x	  Macro x       x=1..15         (*)
X	2048+x	  String x      x=1..15         (*)
END_OF_FILE
if test 11563 -ne `wc -c <'csh.doc.ad'`; then
    echo shar: \"'csh.doc.ad'\" unpacked with wrong size!
fi
# end of 'csh.doc.ad'
fi
if test -f 'rawcon.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rawcon.c'\"
else
echo shar: Extracting \"'rawcon.c'\" \(18348 characters\)
sed "s/^X//" >'rawcon.c' <<'END_OF_FILE'
X/*
X * rawcon.c
X *
X * Shell 2.07M  17-Jun-87
X * console handling, command line editing support for Shell
X * using new console packets from 1.2.
X * Written by Steve Drew. (c) 14-Oct-86.
X * 16-Dec-86 Slight mods to rawgets() for Disktrashing.
X *
X * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
X * Version 5.00L by Urban Mueller 17-Feb-91
X *
X */
X
X#include "shell.h"
X
Xstatic int myget( void );
Xstatic void myunget(int c);
Xstatic void setrawcon( long flag, int ievent );
Xstatic int get_seq( long *param );
Xstatic int bkspcword( int i, int max, int cnt );
X
X
X#if RAW_CONSOLE
X
Xstatic char *tyahdptr, *lasttya;
Xstatic int tabctr, qcdctr, unget;
X
X#define SETRAW setrawcon(-1L,1);
X#define SETCON setrawcon( 0L,1);
X
Xint w_width;
Xextern char *MenuCommand[MAXMENUS][MAXITEMS];
X
X#define CTRL  -64
X#define SHIFT 512
X#define ESC   1024
X
X#define CUP   256
X#define CDN   257
X#define CRT   258
X#define CLT   259
X#define TAB   9
X
Xstatic int Curmap;
Xstatic USHORT *Keymap[8];
Xstatic USHORT DefKeymap0[]={
X       CLT,  0, /* CursLt = Move.Left  */
X       CRT,  1, /* CursRt = Move.Right */
X SHIFT+CLT,  2, /* SCursLt= Move.WordL */
X SHIFT+CRT,  3, /* SCursRt= Move.WordR */
X   ESC+CLT,  4, /* ESC-CLt= Move.SOL   */
X   ESC+CRT,  5, /* ESC-CRt= Move.EOL   */
X  CTRL+'A',  4, /* ^A     = Move.SOL   */
X  CTRL+'E',  5, /* ^E     = Move.EOL   */
X  CTRL+'Z',  4, /* ^Z     = Move.SOL   */
X         8, 10, /* BackSp = Del.BackSp */
X       127, 11, /* Delete = Del.Delete */
X   ESC+  8, 12, /* ESC-BkS= Del.WordL  */
X   ESC+127, 13, /* ESC-Del= Del.WordR  */
X  CTRL+'W', 12, /* ^W     = Del.WordL  */
X  CTRL+'B', 14, /* ^B     = Del.SOL    */
X  CTRL+'K', 15, /* ^K     = Del.EOL    */
X   ESC+'x',513, /* ESC-x  = Setmap 1   */
X   ESC+'d', 16, /* ESC-d  = Del.Line   */
X  CTRL+'X', 16, /* ^X     = Del.Line   */
X       CUP, 20, /* CursUp = Hist.Back  */
X       CDN, 21, /* CursDn = Hist.Forw  */
X   ESC+CUP, 22, /* ECursUp= Hist.Beg   */
X   ESC+CDN, 23, /* ECursDn= Hist.End   */
X SHIFT+CUP, 24, /* SCursUp= Hist.Compl */
X   ESC+CUP, 24, /* ESC-!  = Hist.Compl */
X   ESC+ 13, 25, /* ESC-Ret= Hist.Exec  */
X  CTRL+'T', 26, /* ^T     = Hist.Tail  */
X SHIFT+CDN, 27, /* SCursDn= Hist.Clr   */
X  CTRL+'P', 28, /* ^P     = Hist.DupWrd*/
X       TAB, 30, /* Tab    = Comp.Norm  */
X SHIFT+TAB, 31, /* STab   = Comp.Part  */
X   ESC+TAB, 32, /* ESC-TAB= Comp.All   */
X   ESC+'c', 33, /* ESC-c  = Comp.CD    */
X   ESC+'~', 34, /* ESC-~  = Comp.LastCD*/
X   ESC+'i', 40, /* ESC-i  = Spec.Insert*/
X  CTRL+'L', 43, /* ^L     = Spec.Refr  */
X        10, 44, /* Enter  = Spec.Accept*/
X        13, 44, /* ^Enter = Spec.Accept*/
X  CTRL+'N', 45, /* ^N     = Spec.Next  */
X  CTRL+'O', 48, /* ^O     = Spec.EchoO */
X CTRL+'\\', 46, /* ^\     = Spec.EOF   */
X       260, 42, /* Help   = Misc.Help  */
X       271, 51, /* Menu   = Menu       */
X  CTRL+'U', 52, /* Undo   = Spec.Undo  */
X  CTRL+'R', 53, /* Repeat = Spec.Repeat*/
X         0,  0
X};
X
Xstatic USHORT DefKeymap1[]={
X         8, 14,
X       127, 15
X};
X
Xstatic char *Line, *Prompt;
Xstatic int Pl;
Xstatic char LastDir[128];
X
Xvoid
Xinitmap(void)
X{
X	if( !Keymap[0] )
X		Keymap[0]=DefKeymap0, Keymap[1]=DefKeymap1;
X}
X
Xchar *
Xrawgets( char line[], char prompt[] )
X{
X	static int inslen, lastrecall=-1;
X	static int lastfn, lastkey;
X
X	int    n, pl, max, i, c, key, fn, cnt;
X	USHORT *p;
X	char   *s, *ps, typeahd[256], undo[256], *src, tmp;
X	int    savn, insert=1, recall, undo_i=0, undo_max=0;
X	struct HIST *hist;
X	char   **eav=NULL, *ret, fake;
X	int    eac, eactr=0;
X	long   param[10], *par;
X
X	typeahd[0]=0;
X	tyahdptr=lasttya=typeahd;
X
X	newwidth();
X
X	if ( o_noraw || !IsInteractive(Input()) ) {
X		if( IsInteractive(Input())) {
X			printf("%s",prompt);
X			fflush(stdout);
X		}
X		return(gets(line));
X	}
X
X	if (WaitForChar((long)Input(), 100L) ||   /* don't switch to 1L ...*/
X	        CHARSWAIT(stdin)) {               /* else causes read err's*/
X		gets(line);
X		return(line);
X	}
X
X	SETRAW;
Xbegin:
X	printf("\015%s\033[6n",prompt);
X	fake= savn = pl = n = 0;
X	tyahdptr = typeahd;
X
X	while( (typeahd[n]=getchar()) != 'R') {
X		if (typeahd[n] == 155) savn = n;
X		if (typeahd[n] == 27 && getchar()=='[')
X			typeahd[n] =155, savn=n;
X		n++;
X	}
X	/* typeahd now contains possible type a head chars
X	   followed by <CSI> cursor position report. */
X
X	typeahd[savn]  = '\0';
X	if (typeahd[n-2] != ';') pl = (typeahd[n-2] -'0') * 10;
X	pl += typeahd[n-1] - 49;
X	ps = line + pl;
X	line[max = i = pl] = '\0';
X
X	Line=line; Prompt=prompt; Pl=pl;
X
X	if (s = get_var (LEVEL_SET, "_insert")) insert = atoi(s) ? 1 : 0;
X
X	if( (recall=lastrecall)>=0 ) {
X		lastrecall=-1;
X		goto recallh;
X	}
X
X	while( (c=myget()) != -1) {
X		int esc=0;
X		key=-1;
X		if( c==27 ) {
X			esc=ESC;
X			if((c=myget())=='[')
X				c=155,esc=0;
X		}
X		switch(c) {
X		case 155:
X			switch(c=myget()) {
X			case 'A': key=256;       break; /* CursUp */
X			case 'B': key=257;       break; /* CursDn */
X			case 'C': key=258;       break; /* CursRt */
X			case 'D': key=259;       break; /* CursLt */
X			case 'T': key=256+SHIFT; break; /* SCursUp */
X			case 'S': key=257+SHIFT; break; /* SCursDn */
X			case ' ':
X				switch( myget() ) {
X				case '@': key=258+SHIFT; break; /* SCursRt */
X				case 'A': key=259+SHIFT; break; /* SCursLt */
X				}
X				break;
X			case 'Z': key= 9+SHIFT;       break; /* STab    */
X			case '?': key= 260; myget();  break; /* Help    */
X			default :
X				myunget(c);
X				par=param;
X				do {
X					for( *par=0; (c=myget())>='0' && c<='9';  )
X						*par=10* *par + c-'0';
X					par++;
X				} while( c==';' );
X				if( c=='~' ) {
X					key=param[0]+261;
X					if( key>270 ) key+=SHIFT-10;
X				}
X				if( c=='|' ) key=271;
X			} break;
X		default: key=c; break;
X		}
X		key+=esc;
X
X		for( fn=-1, p=Keymap[Curmap]; *p; p+=2 )
X			if( *p==key )
X				{ fn=p[1]; break; }
X		if( fn==-1 && key>=261 && key<=270 || key>=261+SHIFT && key<=270+SHIFT )
X			fn=50;
X
X		if( fn!=52 && !*lasttya) {
X			memcpy( undo+pl, line+pl, max-pl );
X			undo_i=i; undo_max=max;
X		}
X
X		switch( fn/512 ) {
X		case 1:
X			fn&=511;
X			if( fn<8 && Keymap[fn] ) Curmap=fn;
X			fn=-2;
X			break;
X		case 2:
X			key=fn&511, fn=-1;
X			break;
X		}
X
X		if( fn!=-2 )
X			Curmap=0;
X
X		if( fn!=53 && !*lasttya )
X			lastfn=fn, lastkey=key;
X
Xdofn:
X		switch( fn ) {
X		case -2:
X			break;
X
X		case 0:                                 /* cursor left  */
X			if (i > pl) 
X				i--, printf("\033[D");
X			break;
X		case 1:                                 /* cursor right */
X			if (i < max)
X				i++, printf("\033[C");
X			break;
X		case 2:                                 /* word left    */
X			for (cnt=0; i>pl && line[i-1] == ' '; cnt++,i--); 
X			for (     ; i>pl && line[i-1] != ' '; cnt++,i--);
X			if( cnt ) printf("\033[%dD",cnt);
X			break;
X		case 3:                                 /* word right   */
X			for( cnt=0; i<max && line[i] != ' '; i++,cnt++) ;
X			for(      ; i<max && line[i] == ' '; i++,cnt++) ;
X			if( cnt ) printf("\033[%dC",cnt);
X			break;
X		case 4:                                 /* beg of line  */
X			if (i>pl) printf("\033[%dD",i-pl);
X			i = pl;
X			break;
X		case 5:                                 /* end of line  */
X			if (i!=max) printf("\033[%dC",max - i);
X			i = max;
X			break;
X
X		case 10:                                /* backspace    */
X			if (i > pl) {
X				i--;
X				printf("\010");
X			} else break;
X		case 11:                                /* delete       */
X			if (i < max) {
X				int j,t,l = 0;
X				memmove(&line[i],&line[i+1],max-i);
X				--max;
X				printf("\033[P");
X				j = w_width - i % w_width - 1;  /* amount to end */
X				t = max/w_width - i/w_width;    /* no of lines   */
X				for(n = 0; n < t; n++) {
X					l += j;                     /* # of char moved*/
X					if (j) printf("\033[%dC",j);/* goto eol       */
X					printf("%c\033[P",line[w_width*(i/w_width+n+1)-1]);
X					j = w_width-1;
X				}
X				if (t)
X					printf("\033[%dD",l+t);     /* get back       */
X			}
X			break;
X		case 12:                                /* bkspc word     */
X			cnt= bkspcword(i,max,-1);
X			max-=cnt; i-=cnt;
X			break;
X		case 13:
X			for( cnt=0; i<max && line[i]!=' '; i++,cnt++ ) ;
X			for(      ; i<max && line[i]==' '; i++,cnt++ ) ;
X			if ( cnt ) printf("\033[%dC",cnt);
X			cnt=bkspcword(i,max,cnt);
X			i-=cnt; max-=cnt;
X			break;
X		case 14:
X			cnt=bkspcword(i,max,i-pl);
X			i-=cnt; max-=cnt;
X			break;
X		case 16:                                /* delete line    */
X			if (i>pl) printf("\033[%dD",i-pl);
X			i = pl;
X		case 15:                                /* delete to EOL  */
X			printf("\033[J");
X			max = i;
X			line[i] = '\0';
X			break;
X
X
X		case 20:                                /* history up   */
X			++recall;
X		case 21:                                /* history down */
Xrecallh:
X			line[pl] = '\0';
X			if (recall >= 0 || fn==20) {
X				if ( fn==21 ) --recall;
X				n=recall;
X				if (recall >= 0) {
X					for(hist = H_head; hist && n--;
X					hist = hist->next);
X					if (hist) strcpy(&line[pl],hist->line);
X					else recall = H_len;
X				}
X			}
X			if (i != pl)
X				printf("\033[%dD",i-pl);
X			printf("\033[J%s",ps);
X			i = max = strlen(ps) + pl;
X			break;
X		case 22:                                /* beg of hist */
X			recall = H_len-1;
X		case 23:                                /* end of hist */
X			line[pl] = '\0';
X			if (fn == 23) {
X				recall = 0;
X				if (H_head) strcpy(&line[pl], H_head->line);
X			} else if (H_tail)
X				strcpy(&line[pl], H_tail->line);
X			printf("\015\033[J%s%s", prompt, ps);
X			i = max = strlen(ps) + pl;
X			break;
X		case 24:                                /* complete hist */
X			line[max]=0;
X			if( s=get_history(&line[pl-1],0 )) {
X				if (i>pl) printf("\033[%dD\033[J",i-pl);
X				line[i=max=pl]=0;
X				strncpy(typeahd,s,256);
X				tyahdptr=typeahd;
X			}
X			break;
X		case 25:                                /* exec hist  */
X			lastrecall= recall;
X			goto done;
X		case 26:                                /* tail of prev */
X			if( H_head && (s=H_head->line) && (s=index(s,' ')) )
X				tyahdptr=s;
X			break;
X		case 27:                                /* botton   */
X			recall=-1;
X			goto recallh;
X		case 28:                                /* duplicate word */
X			for(s=line+i; s>ps && *(s-1)==' '; --s ) ;
X			tmp=*s; *s=0;
X			if( !(src=rindex(ps,' '))) src="";
X			strcpy(tyahdptr=typeahd,src);
X			*s=tmp;
X			break;
X
X		case 30:                                /* complete */
X		case 31:
X		case 32:
X		case 33: {
X			static int lastcompl;
X			int j, k, n, e, cnt, len, radlen;
X			char *name, *q, abbrev;
X
X			abbrev= fn==31;
Xcomplete:
X			tyahdptr="";
X			if( tabctr!=0 ) {
X				char *dest=typeahd, *lcd;
X
X				lastcompl=fn;
X				for( cnt=0; i<max && line[i]!=' '; ++i, ++cnt ) ;
X				if(cnt) printf("\033[%dC",cnt);
X				for( e=i, j=i-1, cnt=0; j>=pl && line[j]!=' ' && line[j]!='<' &&
X				                 line[j]!='>' && line[j]!=';' ; --j ) cnt++;
X				++j;
X
X				if( line[j]=='~' && (lcd=get_var(LEVEL_SET,v_lcd))) {
X					strcpy(dest,lcd);
X					dest+=strlen(dest);
X					j++;
X				}
X				memcpy(dest,&line[j],e-j);
X				dest+=e-j;
X				if( fn!=33 )
X					*dest++='*';
X				*dest=0;
X				if( eav ) free_expand( eav ), eav=NULL;
X				breakreset();
X				tabctr=1;
X				if( fn==33 ) {
X					strncpy(LastDir,typeahd,128);
X					if( !quick_cd( name=typeahd+128, LastDir, 0))
X						{ putchar(7); break; }
X				} else {
X					eav =expand(typeahd,&eac);
X					if( eac==0 ) { putchar(7); break; }
X					QuickSort(eav, eac);
X					if( fn==30 )
X						name=eav[ eactr=0 ];
X					else
X						name=compile_av(eav,0,eac,' ',1), tabctr=0;
X				} 
X				inslen=cnt;
X			} else {
X				abbrev=0, tabctr=1;
X				if( lastcompl==33 ) {
X					quick_cd( name=typeahd+128, LastDir, 1);
X				} else {
X					if( !eac ) break;
X					name=eav[eactr=++eactr % eac];
X				}
X			}
X			len=bkspcword(i,max,inslen);
X			i-=len; max-=len;
X			if( abbrev && eac>1) {
X				strcpy( typeahd, eav[0] );
X				radlen= 9999;
X				for( k=0; k<eac; k++ ) {
X					if ( (n=strlen(eav[k])) < radlen ) radlen=n;
X					for( n=0; n<radlen && eav[0][n]==eav[k][n]; n++ ) ;
X					if ( n<radlen ) radlen=n;
X				}
X				typeahd[radlen]=0;
X				eactr--;
X			} else {
X				if( lastcompl==32 ) {
X					strncpy( typeahd,name,250 );
X					name[250]=0;
X				} else {
X					strcpy(typeahd,(q=index( name, ' ' )) ? "\"" : "" );
X					strcat(typeahd,name);
X					if( q ) strcat(typeahd,"\"");
X					if( lastcompl==33 || isdir(name) )
X						appendslash( typeahd );
X					else 
X						strcat( typeahd, " " );
X				}
X			}
X			tyahdptr=typeahd;
X			inslen=strlen(typeahd);
X			}
X			break;
X		case 34:
X			strncpy(typeahd,get_var( LEVEL_SET, v_lcd ),230);
X			appendslash(tyahdptr=typeahd);
X			break;
X
X		case 40:                      /* ins/ovr */
X			insert ^= 1;
X			break;
X		case 41:                      /* quit */
X			strcpy(ps,"quit");
X			goto done;
X		case 42:                      /* help */
X			strcpy(ps,"help");
X			goto done;
X		case 43:                      /* refresh   */
X			if ((n = i/w_width)) printf("\033[%dF",n);
X			printf("\015\033[J%s%s",prompt,ps);
X			i = max;
X			break;
X		case 44:
X			line[max] = '\0';
Xdone:		printf("\033[%dC\n",max - i);
X			strcpy(line, ps);
X			ret=line;
X			if( fake ) goto begin;
X			goto exit;
X		case 45:                      /* leave   */
X			line[max] = '\0';
X			add_history( ps );
X			fake=1;
X			goto done;
X		case 46:                      /* EOF */
X			ret=NULL;
X			goto exit;
X		case 47:
X			break;
X		case 48:
X			printf("\017");
X			break;
X		case 49:
X			printf("\07");
X			break;
X
X		case 50: {
X			char fkeys[8];
X			sprintf(fkeys,"%c%d",param[0]>=10?'F':'f',param[0]%10+1);
X			if (s = get_var(LEVEL_SET, fkeys)) {
X				tyahdptr = strcpy(typeahd,s);
X				a0tospace( tyahdptr );
X			}
X			break;
X			}
X		case 51: {
X			int class=param[0], code=param[2];
X			if( class==10 ) {
X				int num=MENUNUM( code ), item=ITEMNUM( code );
X				tyahdptr="";
X				if( num>=0 && num<MAXMENUS && item>=0 && item<=MAXITEMS )
X					tyahdptr=MenuCommand[num][item];                                 
X			}
X			if( class==11 ) {
X				strcpy(ps,"quit");
X				goto done;
X			}
X			}
X		case 52: {
X			int t;
X
X			if ((n = i/w_width)) printf("\033[%dF",n);
X			swapmem( undo+pl, line+pl, MAX( max, undo_max)-pl );
X			t=max; max=undo_max; undo_max=t;
X			t=i;   i  =undo_i;   undo_i  =t;
X			line[max]=0;
X			printf("\015\033[J%s%s",prompt,ps);
X			if( i<max ) printf("\033[%dD",max-i);
X			}
X			break;
X		case 53:
X			fn=lastfn; key=lastkey;
X			goto dofn;
X
X		default:
X			key&=255;
X			if (key == 9) key = 32;
X			if (key > 31 && (insert?max:i) < 256) {
X				if (i < max && insert) {
X					int j,t,l = 0;
X					memmove(&line[i+1], &line[i], max - i);
X					printf("\033[@%c",key);
X					t = max/w_width - i/w_width;
X					j = w_width - i % w_width - 1;
X					for(n = 0; n < t; n++) {
X						l += j;
X						if (j) printf("\033[%dC",j);
X						printf("\033[@%c",line[w_width*(i/w_width+n+1)]);
X						j = w_width-1;
X					}
X					if (t) printf("\033[%dD",l + t);
X					++max;
X				}
X				else {
X					if(i == pl && max == i) printf("\015%s%s",prompt,ps);
X					putchar(key);
X				}
X				line[i++] = key;
X				if (max < i) max = i;
X				line[max] = '\0';
X			}
X		}
X	}
X	ret=NULL;
Xexit:
X	newwidth();
X	if( eav ) free_expand(eav);
X	SETCON;
X	return ret;
X}
X
Xint
Xbkspcword( int i, int max, int cnt )
X{
X	int o=i;
X
X	if( !cnt ) return 0;
X
X	if( cnt==-1 ) {
X		cnt=0;
X		while( i>Pl && Line[i-1]==' ' )  i--, cnt++;
X		while( i>Pl && Line[i-1]!=' ' )  i--, cnt++;
X	} else 
X		i-=cnt;
X
X	if( cnt ) printf("\033[%dD",cnt);
X	memmove( Line+i, Line+o, max-o );
X	memset ( Line+max-cnt, ' ', cnt  );
X    
X	printf("%s",Line+i);
X    
X	if( max-i ) printf("\033[%dD", max-i );
X	fflush(stdout);
X	Line[max-=cnt]=0;
X
X	return cnt;
X}
X
Xvoid
Xsetrawcon( long flag, int ievent ) /* -1L=RAW:, 0L=CON: */
X{
X	static char menuon, button;
X	long packargs[8];
X
X	if( !o_nowindow && ievent && flag==0 && menuon)
X		printf("\033[10}"), menuon=0;
X
X	packargs[0]=flag;
X	SendPacket(994L, packargs, (void *)Myprocess->pr_ConsoleTask);
X
X	if( !o_nowindow && ievent && flag==-1 ) {
X		if( !menuon )
X			printf("\033[10{"), menuon=1;
X		if( !button )
X			printf("\033[11{"), button=1;
X	}
X	fflush(stdout);
X}
X
X
X
Xstatic int row, height, cnt, noquick=1;
Xstatic char scrollstr[10];
X
Xextern BPTR OldCin;
X
Xstatic int FromTee;
X
Xvoid
Xprepscroll( int fromtee )
X{
X	BPTR truecin=0;
X	long param[8];
X
X	row=height=0;
X	FromTee=fromtee;
X
X	if(( noquick=!o_scroll ||o_noraw || o_nofastscr ))
X		return;
X	if(( noquick=!IsInteractive(Output()) && !fromtee ))
X		return;
X	if( !IsInteractive(Input())) {
X		truecin=Myprocess->pr_CIS;
X
X		if( noquick=!IsInteractive(OldCin) )
X			return;
X
X		Myprocess->pr_CIS = DEVTAB(stdin) = OldCin;
X	}
X
X	if( !CHARSWAIT(stdin) ) {
X		SETRAW;
X		fprintf(fromtee?stderr:stdout,"\033[ q");
X		get_seq( param );
X		height=param[2];
X		while( getchar()!='r') ;
X
X		fprintf(fromtee?stderr:stdout,"\033[6n");
X		get_seq( param );
X		row=param[0];
X
X		SETCON;
X
X		cnt= height-row+1;
X		noquick= height<o_minrows;
X	}
X
X	sprintf(scrollstr,"\033[%cS\033[%cA", o_scroll+'0', o_scroll+'0');
X
X	if( truecin )
X		Myprocess->pr_CIS = DEVTAB(stdin) = truecin;
X}
X
Xstatic int
Xget_seq( long *param )
X{
X	int c;
X
X	while( (c=getchar())!=155 ) ;
X	do {
X		*param=0;
X		while( (c=getchar())>='0' && c<='9' )
X			*param=10* *param + c-'0';
X		param++;
X	} while( c==';' );
X
X	return c;
X}
X
X
Xvoid
Xquickscroll( void )
X{
X	if( noquick ) return;
X
X	if( --cnt<=0 ) {
X		cnt=o_scroll;
X		fprintf( FromTee ? stderr : stdout, "%s",scrollstr);
X	}
X}
X
Xint
Xdo_keymap( void )
X{
X	int i, n, len;
X	USHORT *tmp, *put, *get, *map;
X	char   *ind;
X
X	n=myatoi(av[1],0,7);
X	if( atoierr ) return 20;
X
X	map=Keymap[n]; len=0;
X	if( map )
X		for( len=0; map[2*len]; len++ ) ;
X
X	put=tmp=salloc((len+ac)*2*sizeof(USHORT));
X	for( i=2; i<ac; i++ ) {
X		if( !(ind=index(av[i],'='))) {
X			ierror( av[i],500);
X			free( tmp );
X			return 20;
X		}
X		*put++=atoi(av[i]);
X		*put++=atoi(ind+1);
X	}
X
X	for( i=0; i<len; i++ ) {
X		for( get=tmp; get<put; get+=2 )
X			if( *get==map[2*i] )
X				break;
X		if( get==put ) {
X			*put++=map[2*i];
X			*put++=map[2*i+1];
X		}
X	}
X
X	if( map && map!=DefKeymap0 && map!=DefKeymap1 )
X		free( map );
X	Keymap[n]=tmp;
X	Curmap=0;
X
X	return 0;
X}
X
Xstatic int
Xmyget( void )
X{
X	int c;
X
X	lasttya=tyahdptr;
X	if( unget )
X		c=unget, unget=0;
X	else if( tyahdptr && *tyahdptr)
X		c=*tyahdptr++;
X	else {
X#ifndef AZTEC_C
X		fflush(stdout);
X#endif
X		if( (c=getchar())!=155 )
X			tabctr--, qcdctr--;
X	}
X
X	return c;
X}
X
Xstatic void
Xmyunget(int c)
X{
X	unget=c;
X}
X
Xint
Xnewwidth( void )
X{
X	extern struct Window *Win;
X
X	w_width=80;
X	if( !o_nowindow && Win )
X		w_width=(Win->Width-(Win->BorderLeft+Win->BorderRight))/
X		         Win->RPort->TxWidth;
X	if( w_width<1 ) w_width=1;          /* crash after resizing was reported */
X	return w_width;
X}
X
X
X
X#else
X
Xprepscroll(){}
Xquickscroll(){}
X
X#endif
X
END_OF_FILE
if test 18348 -ne `wc -c <'rawcon.c'`; then
    echo shar: \"'rawcon.c'\" unpacked with wrong size!
fi
# end of 'rawcon.c'
fi
if test -f 'sub.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sub.c'\"
else
echo shar: Extracting \"'sub.c'\" \(21464 characters\)
sed "s/^X//" >'sub.c' <<'END_OF_FILE'
X
X/*
X * SUB.C
X *
X * (c)1986 Matthew Dillon     9 October 1986
X *
X * Version 2.07M by Steve Drew 10-Sep-87
X * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
X * Version 5.00L by Urban Mueller 17-Feb-91
X *
X */
X
X#include "shell.h"
X#include "proto.h"
X
Xstatic void del_history( void );
Xstatic int dnext( struct DPTR *dp, char **pname, int *stat);
Xstatic char *svfile( char *s1, char *s2, FIB *fib);
Xstatic int exall( BPTR lock, char *path );
Xstatic void quicksort( char **av, int n );
X
X
X#define HM_STR 0              /* various HISTORY retrieval modes */
X#define HM_REL 1
X#define HM_ABS 2
X
Xvoid
Xseterr( int err )
X{
X	static int LastErr;
X	char buf[32], *val;
X	int  stat=0;
X
X	Lastresult=err;
X
X	if( LastErr!=err ) {
X		LastErr=err;
X		sprintf(buf, "%d", err);
X		set_var(LEVEL_SET, v_lasterr, buf);
X
X		if( val=get_var(LEVEL_SET, v_stat))
X			stat = atoi(val);
X		if (stat < Lastresult) set_var(LEVEL_SET, v_stat, buf);
X	}
X}
X
X#define ISSPACE(c) ((c)==' ' || (c)==9 || (c)==0xA0)
X
Xchar *
Xnext_word( char *str )
X{
X	while (*str && ! ISSPACE(*str)) ++str;
X	while (*str &&   ISSPACE(*str)) ++str;
X	return str;
X}
X
X/*
X * FREE(ptr)   --frees without actually freeing, so the data is still good
X *               immediately after the free.
X */
X
X
Xvoid
XFree( void *ptr )
X{
X	static char *old_ptr;
X
X	if (old_ptr) free (old_ptr);
X	old_ptr = ptr;
X}
X
X/*
X * Add new string to history (H_head, H_tail, H_len,
X *  S_histlen
X */
X
Xvoid
Xadd_history( char *str )
X{
X	struct HIST *hist;
X	char *get;
X
X	for( get=str; *get; get++ )
X		if( (*get&127)<' ')
X			*get=' ';
X
X	if (H_head != NULL && !strcmp(H_head->line, str))
X		return;
X	while (H_len > S_histlen)
X		del_history();
X	hist = (struct HIST *)salloc (sizeof(struct HIST));
X	if (H_head == NULL) {
X		H_head = H_tail = hist;
X		hist->next = NULL;
X	} else {
X		hist->next = H_head;
X		H_head->prev = hist;
X		H_head = hist;
X	}
X	hist->prev = NULL;
X	hist->line = salloc (strlen(str) + 1);
X	strcpy (hist->line, str);
X	++H_len;
X}
X
Xstatic void
Xdel_history()
X{
X	if (H_tail) {
X		--H_len;
X		++H_tail_base;
X		free (H_tail->line);
X		if (H_tail->prev) {
X			H_tail = H_tail->prev;
X			free (H_tail->next);
X		H_tail->next = NULL;
X		} else {
X			free (H_tail);
X			H_tail = H_head = NULL;
X		}
X	}
X}
X
Xchar *
Xget_history( char *ptr, int echo )
X{
X	struct HIST *hist;
X	int len;
X	int mode = HM_REL;
X	int num  = 1;
X	char *str=NULL;
X	char *result = NULL;
X
X	if (ptr[1] >= '0' && ptr[1] <= '9') {
X		mode = HM_ABS;
X		num  = atoi(&ptr[1]);
X		goto skip;
X	}
X	switch (ptr[1]) {
X	case '!':
X		break;
X	case '-':
X		num += atoi(&ptr[2]);
X		break;
X	default:
X		mode = HM_STR;
X		str  = ptr + 1;
X		break;
X	}
Xskip:
X	switch (mode) {
X	case HM_STR:
X		len = strlen(str);
X		for (hist = H_head; hist; hist = hist->next) {
X			if (strncmp(hist->line, str, len) == 0 && *hist->line != '!') {
X				result = hist->line;
X				break;
X			}
X		}
X		break;
X	case HM_REL:
X		for (hist = H_head; hist && num--; hist = hist->next);
X		if (hist)
X		result = hist->line;
X		break;
X	case HM_ABS:
X		len = H_tail_base;
X		for (hist = H_tail; hist && len != num; hist = hist->prev, ++len);
X		if (hist)
X		result = hist->line;
X		break;
X	}
X	if( echo )
X		fprintf(stderr, result ? "%s\n" : "History failed\n", result);
X	if( !result ) result="";
X	return result;
X}
X
Xvoid
Xreplace_head( char *str )
X{
X	if (str && strlen(str) && H_head) {
X		free (H_head->line);
X		H_head->line = salloc (strlen(str)+1);
X		strcpy (H_head->line, str);
X	}
X}
X
X
X#if 0
X#define CDLEN 20
Xstatic int   cd_len=CDLEN, cd_read, cd_write, cd_current;
Xstatic char *cd_hist[CDLEN];
X
Xadd_cdhist( char *str )
X{
X	if( !str )
X		return;
X	if( cd_hist[cd_write] )
X		free(cd_hist[cd_write]);
X	cd_hist[cd_write++]=str;
X	cd_write%=cd_len;
X	cd_current=cd_write;
X}
X
Xchar *
Xback_cdhist( void )
X{
X	if( cd_current!=cd_write ) cd_current= --cd_current % cd_len;
X	return cd_hist[cd_current];
X}
X
Xchar *
Xforw_cdhist( void )
X{
X	if( cd_current!=cd_read  ) cd_current= ++cd_current % cd_len;
X	return cd_hist[cd_current];
X}
X#endif
X
Xvoid
XpError(char *str )
X{
X	int ierr = (long)IoErr();
X	ierror(str, ierr);
X}
X
Xierror( char *str, int err )
X{
X	struct PERROR *per = Perror;
X
X	setioerror(err);
X
X	if (err) {
X		for (; per->errstr; ++per) {
X			if (per->errnum == err) {
X				fprintf (stderr, "%s%s%s\n",
X				per->errstr,
X				(str) ? ": " : "",
X				(str) ? str : "");
X				return err;
X			}
X		}
X		fprintf (stderr, "Unknown DOS error %d: %s\n", err, (str) ? str : "");
X	}
X	return err;
X}
X
Xvoid
Xsetioerror( int err )
X{
X	static int LastIoError=-1;
X	char buf[20];
X
X	IoError=err;
X	if( IoError<0 ) IoError=0;
X	if( LastIoError!=IoError) {
X		LastIoError=IoError;
X		sprintf(buf, "%d", IoError);
X		set_var(LEVEL_SET, v_ioerr, buf);
X	}
X}
X
Xchar *
Xioerror(int num)
X{
X	struct PERROR *per = Perror;
X
X	for ( ; per->errstr; ++per)
X		if (per->errnum == num)
X			return per->errstr;
X	return NULL;
X}
X
X/*
X * Disk directory routines
X *
X * dptr = dopen(name, stat)
X *    struct DPTR *dptr;
X *    char *name;
X *    int *stat;
X *
X * dnext(dptr, name, stat)
X *    struct DPTR *dptr;
X *    char **name;
X *    int  *stat;
X *
X * dclose(dptr)                  -may be called with NULL without harm
X *
X * dopen() returns a struct DPTR, or NULL if the given file does not
X * exist.  stat will be set to 1 if the file is a directory.  If the
X * name is "", then the current directory is openned.
X *
X * dnext() returns 1 until there are no more entries.  The **name and
X * *stat are set.  *stat != 0 if the file is a directory.
X *
X * dclose() closes a directory channel.
X *
X */
X
Xstruct DPTR *
Xdopen( char *name, int *stat)
X{
X	struct DPTR *dp;
X
X	IoError=0;
X	*stat = 0;
X	dp = (struct DPTR *)salloc(sizeof(struct DPTR));
X	if (*name == '\0')
X		dp->lock = DupLock(Myprocess->pr_CurrentDir);
X	else
X		dp->lock = Lock (name,ACCESS_READ);
X	if (dp->lock == NULL) {
X		IoError=IoErr();
X		free (dp);
X		return NULL;
X	}
X	dp->fib = (FIB *)SAllocMem((long)sizeof(FIB), MEMF_PUBLIC);
X	if (!Examine (dp->lock, dp->fib)) {
X		pError (name);
X		dclose (dp);
X		return NULL;
X	}
X	if (dp->fib->fib_DirEntryType >= 0) *stat = 1;
X	return dp;
X}
X
Xstatic int
Xdnext( struct DPTR *dp, char **pname, int *stat)
X{
X	if (dp == NULL) return (0);
X
X	if (ExNext (dp->lock, dp->fib)) {
X		*stat = 0;
X		if( dp->fib->fib_DirEntryType >= 0)
X			*stat= dp->fib->fib_DirEntryType!=ST_USERDIR ? 2 : 1;
X		*pname = dp->fib->fib_FileName;
X		return 1;
X	}
X	return 0;
X}
X
Xint
Xdclose( struct DPTR *dp )
X{
X	if (dp == NULL)
X		return 1;
X	if (dp->fib)
X		FreeMem (dp->fib,(long)sizeof(*dp->fib));
X	if (dp->lock)
X		UnLock (dp->lock);
X	free (dp);
X	return 1;
X}
X
X
Xint
Xisdir( char *file )
X{
X	struct DPTR *dp;
X	int stat;
X
X	stat = 0;
X	if (dp = dopen (file, &stat))
X		dclose(dp);
X	return (stat!=0);
X}
X
X
Xvoid
Xfree_expand( char **av )
X{
X	char **get = av;
X
X	if (av) {
X		while (*get)
X		free (*get++-sizeof(struct file_info));
X		free (av);
X	}
X}
X
X/*
X * EXPAND(base,pac)
X *    base           - char * (example: "df0:*.c")
X *    pac            - int  *  will be set to # of arguments.
X *
X * 22-May-87 SJD.  Heavily modified to allow recursive wild carding and
X *                 simple directory/file lookups. Returns a pointer to
X *                 an array of pointers that contains the full file spec
X *                 eg. 'df0:c/sear*' would result in : 'df0:C/Search'
X *
X *                 Now no longer necessary to Examine the files a second time
X *                 in do_dir since expand will return the full file info
X *                 appended to the file name. Set by formatfile().
X *                 eg. fullfilename'\0'rwed  NNNNNN NNNN  DD-MMM-YY HH:MM:SS
X *
X *                 Caller must call free_expand when done with the array.
X *
X * base             bname =       ename =
X * ------           -------       -------
X *  "*"               ""            "*"
X *  "!*.info"         ""            "*.info" (wild_exclude set)
X *  "su*d/*"          ""            "*"      (tail set)
X *  "file.*"          ""            "file.*"
X *  "df0:c/*"         "df0:c"       "*"
X *  ""                ""            "*"
X *  "df0:.../*"       "df0:"        "*"      (recur set)
X *  "df0:sub/.../*"   "df0:sub"     "*"      (recur set)
X *
X * ---the above base would be provided by execom.c or do_dir().
X * ---the below base would only be called from do_dir().
X *
X *  "file.c"          "file.c"      ""       if (dp == 0) fail else get file.c
X *  "df0:"            "df0:"        "*"
X *  "file/file"       "file/file"   ""       (dp == 0) so fail
X *  "df0:.../"        "df0:"        "*"      (recur set)
X *
X */
X
Xchar **
Xexpand( char *base, int *pac )
X{
X	char *ptr;
X	char **eav = (char **)salloc(sizeof(char *) * (2));
X	short eleft, eac;
X	char *name;
X	char *bname, *ename, *tail;
X	int stat, recur, scr, bl;
X	struct DPTR *dp;
X
X	IoError = *pac = recur = eleft = eac = 0;
X
X	base = strcpy(malloc(strlen(base)+1), base);
X	for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
X
X	if (!*ptr)   /* no wild cards */
X		--ptr;
X	else
X		for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
X
X	if (ptr < base) {
X		bname = strcpy (malloc(1), "");
X	} else {
X		scr = ptr[1];
X		ptr[1] = '\0';
X		if (!strcmp(ptr-3,".../")) {
X			recur = 1;
X			*(ptr-3) = '\0';
X		}
X		bname = strcpy (salloc(strlen(base)+2), base);
X		ptr[1] = scr;
X	}
X	bl = strlen(bname);
X	ename = ++ptr;
X	for (; *ptr && *ptr != '/'; ++ptr);
X	scr = *ptr;
X	*ptr = '\0';
X	if (scr) ++ptr;
X	tail = ptr;
X
X	if ((dp = dopen (bname, &stat)) == NULL || (stat == 0 && *ename)) {
X		free (bname);
X		free (base);
X		free (eav);
X		return (NULL);
X	}
X
X	if (!stat) {                /* eg. 'dir file' */
X		char *p,*s;
X		for(s = p = bname; *p; ++p) if (*p == '/' || *p == ':') s = p;
X		if (s != bname) ++s;
X		*s ='\0';
X		eav[eac++] = svfile(bname,dp->fib->fib_FileName,dp->fib);
X		goto done;
X	}
X	if (!*ename) ename = "*";    /* eg. dir df0: */
X	if (*bname && bname[bl-1] != ':' && bname[bl-1] != '/') { /* dir df0:c */
X		bname[bl] = '/';
X		bname[++bl] = '\0';
X	}
X	while ((dnext (dp, &name, &stat)) && !breakcheck()) {
X		int match = compare_ok(ename,name,0);
X		if (match && (recur || !*tail)) {
X			if (eleft < 2) {
X				char **scrav = (char **)salloc(sizeof(char *) * (eac + 10));
X				memmove (scrav, eav, (eac + 1) << 2);
X				free (eav);
X				eav = scrav;
X				eleft = 10;
X			}
X			eav[eac++] = svfile(bname,name,dp->fib);
X			--eleft;
X		}
X		if ((*tail && match) || recur) {
X			int alt_ac;
X			char *search, **alt_av, **scrav;
X			BPTR lock;
X
X			if (stat!=1)           /* expect more dirs, but this not a dir */
X				continue;
X			lock = CurrentDir (dp->lock);
X			search = salloc(strlen(ename)+strlen(name)+strlen(tail)+6);
X			strcpy (search, name);
X			strcat (search, "/");
X			if (recur) {
X				strcat(search, ".../");
X				strcat(search, ename);
X			}
X			strcat (search, tail);
X			scrav = alt_av = expand (search, &alt_ac);
X			free(search);
X			CurrentDir (lock);
X			if (scrav) {
X				while (*scrav) {
X					int l;
X					if (eleft < 2) {
X						char **scrav = (char **)salloc(sizeof(char *)*(eac+10));
X						memmove ( scrav, eav, (eac + 1) << 2);
X						free (eav);
X						eav = scrav;
X						eleft = 10;
X					}
X
X					l = strlen(*scrav);
X					eav[eac] = salloc(bl+l+1+sizeof(struct file_info));
X					memcpy( eav[eac], *scrav-sizeof(struct file_info),
X					sizeof(struct file_info));
X					eav[eac]+=sizeof(struct file_info);
X					strcpy( eav[eac], bname);
X					strcat( eav[eac], *scrav);
X
X					free (*scrav-sizeof(struct file_info));
X					++scrav;
X					--eleft, ++eac;
X				}
X				free (alt_av);
X			}
X		}
X	}
Xdone:
X	dclose (dp);
X	*pac = eac;
X	eav[eac] = NULL;
X	free (bname);
X	free (base);
X	if (eac)
X		return (eav);
X	free (eav);
X	return (NULL);
X}
X
Xchar *
Xstrupr( char *s )
X{
X	char *old=s;
X	while (*s) *s=toupper(*s), s++;
X	return old;
X}
X
Xchar *
Xstrlwr( char *s )
X{
X	char *old=s;
X	while (*s) *s=tolower(*s), s++;
X	return old;
X}
X
X/*
X * Compare a wild card name with a normal name
X */
X
Xint
Xcompare_ok( char *wild, char *name, int casedep)
X{
X	int queryflag;
X	char buf[260], wildbuf[260], *lowname;
X
X	if (queryflag=(*wild=='&')) wild++;
X	if (*wild=='!') *wild='~';
X
X	if (! casedep) {
X		strupr(wild);
X		strcpy(buf,name);
X		strupr(buf);
X		lowname=buf;
X	} else
X		lowname=name;
X
X	PreParse(wild, wildbuf);
X	if ( ! PatternMatch(wildbuf,lowname)) return 0;
X
X	if (queryflag) {
X		printf("Select %s%-16s%s [y/n] ? ",o_hilite,name,o_lolite);
X		gets(buf);
X		return (toupper(*buf)=='Y');
X	}
X	return 1;
X}
X
Xstatic char *
Xsvfile( char *s1, char *s2, FIB *fib)
X{
X	int len=strlen(s1)+strlen(s2)+1;
X	char *p = salloc (len+sizeof(struct file_info));
X	struct file_info *info;
X
X	info=(struct file_info *)p;
X	p+=sizeof(struct file_info);
X	strcpy(p, s1);
X	strcat(p, s2);
X	info->flags = fib->fib_Protection;
X	if( fib->fib_DirEntryType<0 ) {
X		info->size  = fib->fib_Size;
X		info->blocks= fib->fib_NumBlocks;
X	} else {
X		info->size  = -1;
X		info->blocks= 0;
X	}
X	if( fib->fib_Comment[0] )
X		info->flags|= 1<<30;
X	info->date=fib->fib_Date;
X	info->class[0]=1;
X	return p;
X}
X
X
X
Xstatic FILE *out;
Xstatic int NumDirs;
X
Xvoid
Xexpand_all( char *name, FILE *file )
X{
X	BPTR lock;
X	char path[300];
X	FIB  *fib;
X
X	out=file;
X	printf( " %s\n", name );
X	NumDirs=0;
X
X	if(fib=AllocMem(sizeof(struct FileInfoBlock),0)) {
X		if( lock=Lock( name, ACCESS_READ )) {
X			strcpy( path, name );
X			exall( lock, path );
X			printf( "\n", NumDirs );
X		}
X		FreeMem(fib,sizeof(struct FileInfoBlock));
X	}
X}
X
Xstatic int
Xexall( BPTR lock, char *path )
X{
X	BPTR old, sublock;
X	int len;
X	struct FileInfoBlock *fib;
X
X	old=CurrentDir( lock );
X
X	if( !(fib=AllocMem(sizeof(struct FileInfoBlock),0)) )
X		return 1;
X
X	len=strlen( path );
X	Examine( lock, fib );
X	while( ExNext( lock, fib ) ) {
X		if( fib->fib_DirEntryType==ST_USERDIR )
X			if( sublock=Lock( fib->fib_FileName, ACCESS_READ )) {
X				if( !len || path[len-1]==':' )
X					sprintf(path+len,"%s",  fib->fib_FileName);
X				else 
X					sprintf(path+len,"/%s", fib->fib_FileName);
X				fprintf( out, "%s\n", path );
X				fprintf( stdout, " Directories: %d\015", ++NumDirs );
X				fflush ( stdout );
X				if(exall( sublock, path ))
X					break;
X				path[len]=0;
X			}
X	}
X	FreeMem( fib, sizeof(struct FileInfoBlock));
X	CurrentDir( old );
X	return dobreak();
X}
X
X
X
X/* Sort routines */
X
Xstatic int reverse, factor;
X
Xint
Xcmp( FILEINFO *s1, FILEINFO *s2)
X{
X	return Strcmp( (char *)(s1+1), (char *)(s2+1) );
X}
X
Xint
Xsizecmp( FILEINFO *s1, FILEINFO *s2)
X{
X	return s2->size - s1->size;
X}
X
Xint
Xdatecmp( FILEINFO *s1, FILEINFO *s2 )
X{
X	int r;
X	struct DateStamp *d1=&s1->date, *d2=&s2->date;
X	if( !(r= d2->ds_Days - d1->ds_Days))
X		if( !(r=d2->ds_Minute - d1->ds_Minute ) )
X			r=d2->ds_Tick - d1->ds_Tick;
X	return r;
X}
X
X
Xint
Xnumcmp( FILEINFO *s1, FILEINFO *s2 )
X{
X	return atoi((char *)(s1+1))-atoi((char *)(s2+1));
X}
X
Xstatic void
Xenterclass( FILEINFO *info )
X{
X	char *class, *iclass=info->class, *t;
X
X	if( *iclass==1 ) {
X		if( class=getclass( (char *)(info+1))) {
X			strncpy( iclass, class, 11 );
X			iclass[11]=0;
X			if( t=index(iclass,0xA0))
X				*t=0;
X		} else 
X			iclass[0]=0;
X	}
X}
X
Xint
Xclasscmp( FILEINFO *info1, FILEINFO *info2 )
X{
X	int r;
X
X	enterclass( info1 );
X	enterclass( info2 );
X
X	r= Strcmp( info1->class, info2->class );
X	if( !r ) r=Strcmp((char *)(info1+1),(char *)(info2+1));
X	return r;
X}
X
X
Xvoid
XQuickSort( char *av[], int n)
X{
X	reverse=factor=0;
X	DirQuickSort( av, n, cmp, 0, 0 );
X}
X
Xstatic int (*compare)(FILEINFO *, FILEINFO *);
X
Xvoid
XDirQuickSort( char *av[], int n, int (*func)(FILEINFO *,FILEINFO *), int rev, int fac)
X{
X	reverse=rev; compare=func; factor=fac;
X	quicksort( av, n-1 );
X}
X
Xstatic int
Xdocompare(char *s1,char *s2)
X{
X	FILEINFO *i1=(FILEINFO *)s1-1, *i2=(FILEINFO *)s2-1;
X	int r=(*compare)( i1,i2 );
X
X	if( reverse ) r =-r;
X	if( factor )  r+= factor*((i2->size<0) - (i1->size<0));
X	return r;
X}
X
X
Xstatic void
Xquicksort( char **av, int n )
X{
X	char **i, **j, *x, *t;
X
X
X	if( n>0 ) {
X		i=av; j=av+n; x=av[ n>>1 ];
X		do {
X			while( docompare(*i,x)<0 ) i++;
X			while( docompare(x,*j)<0 ) --j;
X			if( i<=j )
X				{ t=*i; *i=*j; *j=t; i++; j--; }
X		} while( i<=j );
X
X		if( j-av < av+n-i ) {
X			quicksort( av, j-av  );
X			quicksort( i , av+n-i);
X		} else {
X			quicksort( i , av+n-i);
X			quicksort( av, j-av  );
X		}
X	}
X}
X
X
Xint
Xfilesize( char *name )
X{
X	BPTR lock;
X	struct FileInfoBlock *fib;
X	int  len=0;
X
X	if( lock = Lock (name,ACCESS_READ)) {
X		if( fib=(struct FileInfoBlock *)AllocMem(sizeof(*fib),MEMF_PUBLIC)) {
X			if (Examine (lock, fib))
X				len=fib->fib_Size;
X			FreeMem( fib, sizeof(*fib));
X		}
X		UnLock(lock);
X	}
X	return len;
X}
X
X
X#ifndef MIN
X#define MIN(x,y) ((x)<(y)?(x):(y))
X#endif
X
Xchar **
Xand( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
X{
X	char **av=(char **)salloc(MIN(ac1,ac2)*sizeof(char *) ), *str;
X	int i, j, k=0;
X
X	for( i=0; i<ac1; i++ )
X		for( j=0, str=base ? BaseName(av1[i]) : av1[i]; j<ac2; j++ )
X			if( !Strcmp(str, base ? BaseName(av2[j]) : av2[j]))
X				av[k++]=av1[i];
X	*ac=k;
X	return av;
X}
X
Xchar **
Xwithout( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
X{
X	char **av=(char **)salloc(ac1*sizeof(char *) ), *str;
X	int i, j, k=0;
X
X	for( i=0; i<ac1; i++ ) {
X		for( j=0, str=base ? BaseName(av1[i]) : av1[i]; j<ac2; j++ )
X			if( !Strcmp(str, base ? BaseName(av2[j]) : av2[j] ) )
X				break;
X		if( j==ac2 )
X			av[k++]=av1[i];
X	}
X	*ac=k;
X	return av;
X}
X
Xchar **
Xor( char **av1, int ac1, char **av2, int ac2, int *ac, int base )
X{
X	char **av=(char **)salloc((ac1+ac2)*sizeof(char *) ), *str;
X	int i, j, k=0;
X
X	for( i=0; i<ac1; i++ )
X		av[k++]=av1[i];
X
X	for( i=0; i<ac2; i++ ) {
X		for( j=0, str=base ? BaseName(av2[i]) : av2[i]; j<ac1; j++ )
X			if( !Strcmp(str, base ? BaseName(av1[j]) : av1[j] ) )
X				break;
X		if( j==ac1 )
X			av[k++]=av2[i];
X	}
X
X	*ac=k;
X	return av;
X}
X
Xvoid
Xclear_archive_bit( char *name )
X{
X	struct DPTR *dp;
X	int stat;
X
X	if(dp = dopen(name,&stat) ) {
X		SetProtection( name, dp->fib->fib_Protection&~FIBF_ARCHIVE);
X		dclose( dp );
X	}
X}
X
Xchar *
Xitoa( int i )
X{
X	static char buf[20];
X	char *pos=buf+19;
X	int count=4, flag=0;
X
X	if( i<0 )
X		flag=1, i=-i;
X
X	do {
X		if( !--count )
X			count=3, *--pos=',';
X		*--pos= i%10+'0';
X	} while( i/=10 );
X
X	if( flag )
X		*--pos='-';
X
X	return pos;
X}
X
Xchar *
Xitok( int i )
X{
X	static char buf[16], which;
X	char *exp=" KMG", *ptr= buf+(which=8-which);
X
X	do
X		i=(i+512)/1024, exp++;
X	while( i>1024 );
X	sprintf( ptr,"%d%c",i,*exp);
X
X	return ptr;
X}
X
Xchar *
Xnext_a0( char *str )
X{
X	while( *str && *str!=0xA0 && *str!='=' && *str!=',') str++;
X	return *str ? str+1 : NULL;
X}
X
Xstatic int
Xgethex( char *str, int l )
X{
X	int i, val=0, n, c;
X
X	if( *str=='.' ) return l==2 ? 256 : 0;
X
X	for( i=0; i<l || !l; i++ ) {
X		c=*str++;
X		if     ( c>='0' && c<='9' ) n=c-'0';
X		else if( c>='a' && c<='f' ) n=c-'a'+10;
X		else if( c>='A' && c<='F' ) n=c-'A'+10;
X		else break;;
X		val=16*val+n;
X	}
X	return (l && i!=l) ? -1 : val;
X}
X
Xstrwrdcmp( char *str, char *wrd )
X{
X	int ret;
X	char *ind=index(wrd,0xA0);
X
X	if( ind ) *ind=0;
X	ret=compare_ok(wrd,str,0);
X	if( ind ) *ind=0xA0;
X	return !ret;
X}
X
Xint
Xwrdlen( char *str )
X{
X	char *old=str;
X
X	while( *str && *str!=0xA0 ) str++;
X	return str-old;
X}
X
Xchar *classfile;
X
Xchar *
Xgetclass(char *file)
X{
X	CLASS *cl;
X	char *class, *str, *arg, *get, *buf;
X	int offs, byte, len, fail;
X	BPTR fh;
X
X	if( classfile ) {
X		char buf[80];
X		sprintf(buf,"source %s",classfile);
X		execute(buf);
X		classfile=0;
X	}
X
X	if( isdir(file) ) return "dir";
X
X	if( !(buf=calloc(1024,1))) return NULL;
X	if( !(fh=Open(file,MODE_OLDFILE))) return NULL;
X	len=Read( fh,buf,1023);
X	Close(fh);
X
X	for( cl=CRoot; cl; cl=cl->next ) {
X		class=cl->name;
X		if(!(str=next_a0(cl->name))) continue;
X		while( str ) {
X			if(!(arg=next_a0( str ))) goto nextclass;
X			switch( *str ) {
X			case 's':
X				if( (offs=strlen(file)-wrdlen(arg))<0 ) break;
X				if( !strwrdcmp(file+offs,arg)) goto found;
X				break;
X			case 'n':
X				if( !strwrdcmp(BaseName(file),arg) ) goto found;
X				break;
X			case 'd':
X				goto found;
X			case 'o':
X				offs=gethex(arg,0);
X				if( !(arg=index(arg,','))) goto nextclass;
X				if( offs>len-10 ) break;
X				for( get=buf+offs, ++arg; (byte=gethex(arg,2))>=0; arg+=2 )
X					if( *get++!=byte && byte!=256 )
X						goto nexttry;
X				goto found;
X			case 'c':
X				if( !len )
X					goto nexttry;
X				for( get=buf, fail=0; get<buf+len; get++ )
X					if( *get<9 || *get>13 && *get<32 || *get>127  )
X						fail++;
X				if( fail*8>len )
X					goto nexttry;
X				goto found;
X			case 'a':
X				goto nextclass;
X			default:
X				goto nextclass;
X			}
Xnexttry:	str=next_a0(arg);
X		}
Xnextclass: ;
X	}
X
X	free(buf);
X	return NULL;
X
Xfound:
X	free(buf);
X	return class;
X}
X
Xchar *
Xgetaction( char *class, char *action )
X{
X	CLASS *cl;
X	char *cur, *ind;
X	int len;
X
X	for( len=0; class[len] && class[len]!=0xA0; len++ ) ;
X	for( cl=CRoot; cl; cl=cl->next ) {
X		if( strncmp( cur=cl->name,class,len+1 ))
X			continue;
X		do
X			cur=index( cur,0xA0 );
X		while( cur && *++cur!='a');
X
X		if( cur && (cur=index( ++cur,0xA0 ))) {
X			do {
X				if( !(ind=index( ++cur,'=' )))
X					return NULL;
X				len=ind-cur;
X				if( len==strlen(action) && !strncmp(action,cur,len))
X					return ++ind;
X			} while( cur=index(cur,0xA0) );
X		}
X	}
X	return NULL;
X}
X
Xint
Xdoaction( char *file, char *action, char *args )
X{
X	char *class, *com, *c, *copy, *spc=index(file,' ');
X
X	if( !(class=getclass(file)))
X		return 10;
X	if( !(com=getaction(class,action)))
X		return 11;
X	if( c=index(com,0xA0) )
X		*c=0;
X	copy=salloc( strlen(com)+strlen(file)+strlen(args)+7 );
X	sprintf(copy,spc?"%s \"%s\" %s":"%s %s %s", com, file, args);
X	execute(copy);
X	free(copy);
X	if( c )
X		*c=0xA0;
X	return 0;
X}
X
Xvoid *
Xsalloc( int len )
X{
X	void *ret;
X
X	if( !len ) len++;
X
X	if( !(ret=malloc(len))) {
X		fprintf(stderr,"Out of memory -- exiting\n");
X		main_exit( 20 );
X	}
X	return ret;
X}
X
Xvoid *
XSAllocMem( long size, long req  )
X{
X	void *ret;
X
X	if( !(ret=AllocMem(size,req))) {
X		fprintf(stderr,"Out of memory -- exiting\n");
X		main_exit( 20 );
X	}
X	return ret;
X}
END_OF_FILE
if test 21464 -ne `wc -c <'sub.c'`; then
    echo shar: \"'sub.c'\" unpacked with wrong size!
fi
# end of 'sub.c'
fi
echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.