amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (03/04/91)
Submitted-by: <umueller@iiic.ethz.ch>
Posting-number: Volume 91, Issue 028
Archive-name: shells/cshell-5.00/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 rawcon.c sub.c
# Wrapped by tadguy@ab20 on Sun Mar 3 16:55:58 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'\" \(13639 characters\)
sed "s/^X//" >'changes.doc' <<'END_OF_FILE'
XOverview
X
XThe new CShell 4.9 is no longer adequate to low end systems, it's too large
Xand consumes too much memory. I advise everybody who doesn't own a hard
Xdrive to stick with the old versions. For those who can afford to run it,
Xhowever, this version is a practical tool in command mode and a powerful
Xlanguage for writing scripts while remaining compatible with its old
Xscripts. As the version number 4.9 suggests, I'm note quite done yet, and
Xthere might be bugs left. I count on you to report them to me. The source
Xis not included this time, but still available.
X
XSome of the new features:
X
X- works fine on an Amiga 3000 and under Kickstart 2.0
X- is residentable
X- file name completion with TAB
X- freely programmable command line editing keys
X- many new editing functions
X- jump scrolling (three lines scrolled in one step, useful in interlace)
X- automatic cd (type 'system' instead of 'cd system')
X- quick cd (cd knows about all directories on your HD and jumps directly)
X- ~ stands for previous current directory
X- special support for the closing kickstart 2.0 gadget
X- you can 'rback' programs by adding a single '&' to the command line
X- it is possible to install menus to the console window
X- some internal functions csh have become faster
X- runs on VT terminals again, even command line editing works now
X- many builtin functions now like 'echo @strleft( hello 3 )'
X- you can finally use foreign character sets
X- any letter can be coded using backslash: echo \101 ouputs 'A'
X- more startup options: -b (priority -1) -t (terminal) -k (no ^C) etc.
X- automatic rx-ing: you can 'rx' .rexx files by typing their name
X- ^D now aborts batchfiles like under AmigaDOS
X- will 'source' files with script bit set
X- limit of 256 arguments removed
X- limit of 20 commands per line removed
X- limit of 256 bytes per source line extended to 512
X
XNew commands (and options):
X
X- 'addbuffers' accepts any number drive/buffer pairs
X- 'action' sends a action request to a file class
X- 'alias'es can have more than one argument
X- 'alias'es can prevent wild card expansion
X- 'ascii' shows an ascii table
X- 'assign' accepts any number logical/physical pairs
X- 'assign' can create late/nonbinding assigns under kick 2.0
X- 'cd' has an option to generate the list of all your directories
X- 'class' defines a class of files and the actions allowed on them
X- 'close' without arguments closes all open files
X- 'cls' clears the screen, but now also works on a vt terminal
X- 'copy' now copies the protection bits but clears archive bit
X- 'copy -f' now 'freshens' like zoo. NOTE: *incompatible* with 4.02
X- 'date' has a stopwatch built in
X- 'dir' can sort forwards and backwards by name, size or time.
X- 'dir' can hide .info files and files with the h-bit set
X- 'dir' can show differences between directories
X- 'dir' can show filenotes and file types
X- 'echo' has an option to print to stderr
X- 'exec' works better now
X- 'filenote' can display filenotes, too
X- 'getenv' reads a ARP or ENV: environment variable
X- 'head', a filter, displays the first n lines of stdin
X- 'input' can get characters in single character mode (!)
X- 'info' also gives information on a single device
X- 'linecnt', a filter, counts number of lines
X- 'man' gets documentation to a shell command
X- 'mem' can show only chip, only fast or bytes used sinc last mem -s
X- 'menu' adds a menu
X- 'mv' now clears the archive bit
X- 'path' can also be used to set the path, not only to list it
X- 'protect' can clear and set bits without disturbing the others
X- 'ps' by default only shows the basenames of the started commands
X- 'qsort' quicksorts from stdin to stdout
X- 'readfile' completely reads a file and stores it in a variable
X- 'rxsend' can receive results (now it's useful!)
X- 'search' is much faster and has new output
X- 'setenv' is used to set ENV: variables
X- 'tail', a filter, prints the last lines of a file
X- 'tee' copies stdin to stdout and stderr
X- 'truncate' cuts the width of an ascii file
X- 'touch' now clears the archive bit
X- 'uniq' removes consecutive identical lines
X- 'usage' shows the usage of a command
X- 'waitforport' waits for an (arexx) port
X- 'whereis' looks for a file on your hard drive
X
XNew system variables:
X
X- '_every' contains a command to be executed before the prompt appears
X- '_hilite' holds the highlighting attributes
X- '_history' now can be set to 0, which disables history
X- '_kick2x' indicates whether V36 dos.library could be opened
X- '_lcd' is the last current directoy
X- '_minrows' is the minimum number of rows a window must have to quickscroll
X- '_nobreak', if set, disables ^C
X- '_noreq' disables system requesters
X- '_path' no more need slashes at the end of directories
X- '_prompt' now has many special symbols like %t for current time
X- '_qcd' holds the name of the file where the directoy list for cd is stored
X- '_rxpath' stores the list of directories where .rexx files reside
X- '_scroll' contains the scroll jump or 0 for no quick scrolling
X- '_terminal' indicates wheter or not shell was started in terminal mode
X- '_titlebar' can have special %-symbols like _prompt
X- '_tool_xxx' holds default tools for file ending .xxx
X- '_version' is the current shell version number
X
XFunctions:
X
X- @abbrev is true if the str1 is an abbreviation of str2
X- @abs returns absolute value of <num>
X- @appext appends an extension to a string
X- @availmem returns free 'chip', 'fast' or otherwise total memory
X- @basename returns the file name without path
X- @center centers a string
X- @checkport indicates if given port exists
X- @clinum returns the number of the given process
X- @complete returns the first word an abbreviation matches
X- @concat concats all args in one blank separated string
X- @confirm gets confirmation for all its arguments
X- @dectohex returns a string representing number in hex
X- @delword returns a string with the n-th word deleted.
X- @delwords deletes the next m words from the n-th.
X- @dirs returns the directories among the given file names
X- @drive outputs the drive ( device ) name associated to path
X- @drives outputs all available drives
X- @exists tells whether a file exists or not
X- @fileblks returns the # of blocks needed for the files
X- @filelen count the total number of bytes of the given files
X- @fileprot returns a string like ---arwed
X- @filereq brings up the arp file requester and returns the selected file
X- @files gives you the files among those names, no directories
X- @freebytes the number of free bytes on the given path
X- @freeblks the number of free blocks on the given path
X- @freestore the amount of free store on that path, given in K, M and G
X- @getenv returns the value of the named env: variable
X- @howmany indicates the # of shells running
X- @index returns the index of str2 in str1 (starting at 1)
X- @info the corresponding line from the 'info' command
X- @intersect returns all words which are in both lists
X- @lookfor looks for a file in the current directory and the given paths
X- @lower lowercases its arguments
X- @match returns the words in the that match the arp-pattern
X- @max computes the maximum of all given numbers
X- @megs expresses a number in K, M and G (-bytes)
X- @member tells you if the first arg is among the remaining
X- @min computes the minimum of all given numbers
X- @nameext returns all after the last dot of filename.
X- @nameroot returns all before the LAST dot of filename.
X- @union returns all names that are in either list
X- @pathname strips the base name from a path
X- @pickargs picks of its arguments those which don't start with a '-'
X- @pickopts picks of its arguments those which start witch a '-'
X- @rpn computes the rpn expression. See rpn command
X- @sortargs sorts its arguments alphabetically
X- @split makes each blank separated part of @string a word
X- @strcmp returns -1, 0 or 1 depending of alphabetical comparison
X- @strhead see strhead command
X- @strleft see strleft command
X- @strmid see strmid command
X- @strright see strright command
X- @strtail see strtail command
X- @subword returns the n-th word of the given list
X- @subword returns the next m words word of the given list starting from n
X- @tackon see tackon command
X- @unique sorts the arguments and makes each of them unique
X- @upper upper cases the given words
X- @volume returns the volume name in that path or "" if no disk present
X- @without returns all names of list 1 that are not in list 2
X- @word same as @subword
X- @words returns the number of args
X
XBug fixes:
X
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
XNew to 4.02A:
X
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
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
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
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
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).
X- Heavy mods to this file.
X
END_OF_FILE
if test 13639 -ne `wc -c <'changes.doc'`; then
echo shar: \"'changes.doc'\" unpacked with wrong size!
fi
# end of 'changes.doc'
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'\" \(17773 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 SHIFT+CUP, 22, /* SCursUp= Hist.Beg */
X SHIFT+CDN, 23, /* SCursDn= Hist.End */
X ESC+'!', 24, /* ESC-! = Hist.Compl */
X ESC+ 13, 25, /* ESC-Ret= Hist.Exec */
X CTRL+'T', 26, /* ^T = Hist.Tail */
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];
X int savn, insert=1, recall, undo_i, undo_max;
X struct HIST *hist;
X char **eav=NULL, *ret, fake;
X int eac, eactr;
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 ) esc=ESC, c=myget();
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 } 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 */
X line[pl] = '\0';
X if (recall >= 0 || fn==20) {
X if ( fn==21 ) --recall;
Xrecallh:
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
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}
X
X
X
Xstatic int row, height, cnt, noquick=1;
Xstatic char scrollstr[10];
X
Xextern char *Cin_name, *Cout_name;
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=Cout_name && !fromtee ))
X return;
X if( Cin_name ) {
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=malloc((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 if( !o_nowindow && Win )
X w_width=(Win->Width-(Win->BorderLeft+Win->BorderRight))/
X Win->RPort->TxWidth;
X else
X w_width=80;
X return w_width;
X}
X
X
X
X#else
X
Xprepscroll(){}
Xquickscroll(){}
X
X#endif
X
END_OF_FILE
if test 17773 -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'\" \(21051 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 hasspace( char *s );
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( void )
X{
X char buf[32], *val;
X int stat=0;
X
X sprintf(buf, "%d", Lastresult);
X set_var(LEVEL_SET, v_lasterr, buf);
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#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
Xstatic int
Xhasspace( char *s )
X{
X for ( ; *s; s++)
X if (ISSPACE(*s)) return 1;
X return 0;
X}
X
Xchar *
Xcompile_av(char **av, int start, int end, char delim, int quote)
X{
X char *cstr, *p;
X int len, i;
X
X len = 1;
X for (i = start; i < end; ++i) len += strlen(av[i]) + 3;
X p = cstr = malloc(len);
X *cstr = '\0';
X for (i = start; i < end; ++i) {
X if (debug) fprintf (stderr, "AV[%2d] :%s:\n", i, av[i]);
X if (quote && hasspace(av[i]))
X p += sprintf(p, "\"%s\"", av[i]);
X else
X p += sprintf(p, "%s", av[i]);
X if (i+1 < end) *p++=delim;
X }
X *p='\0';
X return cstr;
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 *)malloc (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 = malloc (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;
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 = malloc (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 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
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 = 1 if the file is a directory.
X *
X * dclose() closes a directory channel.
X *
X */
X
Xextern long IoError;
X
Xstruct DPTR *
Xdopen( char *name, int *stat)
X{
X struct DPTR *dp;
X
X *stat = 0;
X dp = (struct DPTR *)malloc(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 *)AllocMem((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 if (ExNext (dp->lock, dp->fib)) {
X *stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 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 == 1);
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
Xint expand_err;
X
Xchar **
Xexpand( char *base, int *pac )
X{
X char *ptr;
X char **eav = (char **)malloc(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 expand_err = *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 (malloc(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 expand_err=1;
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 **)malloc(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) /* expect more dirs, but this not a dir */
X continue;
X lock = CurrentDir (dp->lock);
X search = malloc(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 **)malloc(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] = malloc(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 = malloc (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>=0 )
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
Xint reverse;
X
Xint
Xcmp( char *s1, char *s2)
X{
X int r=Strcmp(s1, s2);
X return reverse ? -r : r;
X}
X
Xint
Xsizecmp( char *s1, char *s2)
X{
X int r= ((struct file_info *)(s2-sizeof(struct file_info)))->size -
X ((struct file_info *)(s1-sizeof(struct file_info)))->size;
X return reverse ? -r : r;
X}
X
Xint
Xdatecmp( char *s1, char *s2 )
X{
X int r;
X struct DateStamp
X *d1=&((struct file_info *)(s1-sizeof(struct file_info)))->date,
X *d2=&((struct file_info *)(s2-sizeof(struct file_info)))->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 reverse ? -r : r;
X}
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( char *s1, char *s2 )
X{
X int r;
X FILEINFO *info1=(FILEINFO *)s1-1, *info2=(FILEINFO *)s2-1;
X
X enterclass( info1 );
X enterclass( info2 );
X
X r= Strcmp( info1->class, info2->class );
X if( !r ) r=Strcmp(s1, s2);
X return reverse ? -r : r;
X}
X
X
Xvoid
XQuickSort( char *av[], int n)
X{
X DirQuickSort( av, n, cmp, 0 );
X}
X
Xstatic int (*compare)(char *, char *);
X
Xvoid
XDirQuickSort( char *av[], int n, int (*func)(char *,char *), int rev)
X{
X reverse=rev; compare=func;
X quicksort( av, n-1 );
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( (*compare)(*i,x)<0 ) i++;
X while( (*compare)(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 **)malloc(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 **)malloc(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 **)malloc((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 len1=strlen(str);
X char *ind=index(wrd,0xA0);
X if( ind )
X return len1!=ind-wrd || Strncmp(str,wrd,len1);
X else
X return Strcmp(str,wrd);
X
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;
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=malloc( strlen(com)+strlen(file)+strlen(args)+5 );
X sprintf(copy,"%s %s %s",com,file,args);
X execute(copy);
X free(copy);
X if( c )
X *c=0xA0;
X return 0;
X}
END_OF_FILE
if test 21051 -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.