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.