// (C) Copyright 1979 Tripos Research Group // University of Cambridge // Computer Laboratory // This version includes modifications by // Topexpress Ltd, 1 Portugal Place, Cambridge SECTION "EX" GET "LIBHDR" GET "IOHDR" GET "PATTERN" GET "MANHDR" GET "FH2HDR" STATIC $( WORK=0; WP=0; SUCCFLAG=FALSE PAT=0; AUX=0 CH=0; PATP=0; PATLEN=0 ERRORFLAG=FALSE $) GET "CLIHDR" MANIFEST $( argvupb = 50 $) global $( /* Defined in FH2HDR are DeviceId : ug UnitNo : ug+1 */ blk1 : ug+2 blk2 : ug+3 ptr : ug+4 tsk : ug+5 parent:ug+6 pattern : ug + 7 $) MANIFEST $( copygloblwb = ug+70 copyglobupb = ug+95 $) // Globals defined in FH2HDR in which the disc description resides LET start() BE $( LET argv = VEC argvupb LET V1 = VEC argvupb // Auxiliary vector for pattern matching LET string.to.dat.overlay = "SYS:L.STRING-TO-DAT" LET rc = 0 LET Dirname = ? LET p, s = ?, ? LET Disckeysopt, Datesopt, NoDatesOpt = ?, ?, ? LET NEntries = 0 LET Seg = LoadSeg("SYS:L.DAT-TO-STRINGS") LET Date = VEC 14 LET Stamp = VEC 2 LET since.stamp = VEC 2 LET upto.stamp = VEC 2 LET Day = DatStamp(Stamp)!0 LET ENTRYINFO = VEC 60 LET Total = 0 LET Dir, Entry, IsDir = 0, ?, ? LET OldOutput, ToStream = OutPut(), ? LET BreakCondition = False Pattern := getvec(argvupb) Blk1, Blk2 := 0, 0 IF pattern=0 THEN $( Writef("Insufficient free store for %S*N", cli.commandname) GOTO exit $) IF rdargs("DIR,P=PAT/K,DISCKEYS/S,DATES/S,* *NODATES/S,TO/K,S/K,SINCE/K,UPTO/K", argv, argvupb)=0 | [argv!3\=0 & argv!4\=0] THEN $( writes("Parameters no good for ex command*N") rc := 20 GOTO exit $) since.stamp!0, since.stamp!1, since.stamp!2 := 0, 0, 0 upto.stamp!0, upto.stamp!1, upto.stamp!2 := maxint, maxint, maxint UNLESS argv!7=0 & argv!8=0 IF callseg(string.to.dat.overlay, since.stamp, argv!7) = 0 | callseg(string.to.dat.overlay, upto.stamp, argv!8) = 0 THEN $( TEST result2 = 0 THEN writes("****** Invalid *'UPTO*' or *'SINCE*' parameter* * - ignored*N") ELSE writef("****** Can't load %S - *'UPTO*' or *'SINCE*' parameter* * ignored*N", string.to.dat.overlay) $) Dirname := argv!0 Disckeysopt := argv!2\=0 Datesopt := argv!3\=0 | Day=0 NoDatesopt := argv!4\=0 ToStream := ArgV!5 // Construct the pattern // The form is "#?(<s>)#?/(<p>)" so that the filenames // printed are those which have <s> as a substring // or match the pattern <p>. // Defaults for <s> and <p> are "!" which will // never match, except when neither is specified // in which case <s> and <p> are set to "%" so that all // filenames are listed. // Pattern cannot overflow, as its vector // is the same size as the rdargs vector. p := argv!1 s := argv!6=0 -> (p=0 -> "%", "!"), argv!6 IF p=0 THEN p := "!" pattern%0 := 0 concat(pattern, "#?(") concat(pattern, s) concat(pattern, ")#?/(") concat(pattern, p) concat(pattern, ")") UNLESS ToStream=0 DO $( LET Stream = FindOutput(ToStream) TEST stream = 0 THEN $( writef("****** Can't open %S*N", tostream) rc := 20 GOTO exit $) ELSE selectoutput(stream) $) TEST Seg=0 THEN NoDatesOpt := TRUE ELSE Globin(seg) // Must be after Findoutput IF dirname=0 THEN dirname := currentdir=0 -> "$", "(CWD)" TEST compstring(dirname, "(CWD)")=0 THEN dir := currentdir ELSE dir := locatedir(dirname) IF Dir=0 DO $( Writef("Directory *"%S*" not found*N", Dirname) rc := 20 GOTO exit $) // Now find out about the disc we are about to examine $( LET mygv,fhgv=@globsize,? tsk := dir=-1 -> task.filehandler,dir!lock.task fhgv := rootnode!rtn.tasktab!tsk!tcb.gbase FOR globno=copygloblwb TO copyglobupb DO mygv!globno := fhgv!globno DeviceId := fhgv!(@DeviceId-@Globsize) UnitNo := fhgv!(@UnitNo -@Globsize) $) Blk1,Blk2 := getvec(size.block),getvec(size.block) IF Blk1=0 | Blk2=0 DO $( writef("Insufficient free store for %S*N",cli.commandname) GOTO exit $) Entry := exFirst(Dir) IF Entry=0 DO $( writes("Directory *"") writename(dir!lock.key) writes("*" is empty*n") GOTO exit $) IF Entry=-1 DO $( wrch('*"') writename(dir!lock.key) writes("*" is not a directory*n") rc := 20 GOTO exit $) UNLESS CmplPat(Pattern, V1) DO $( Writes("Bad pattern for EX*N") rc := 20 GOTO exit $) UNLESS Seg=0 DO Start(Stamp, Date) writes("Directory *"") writename(dir!lock.key) TEST Seg=0 THEN writes("*"*N") ELSE WriteF("*" on %S %S*N", Date+10, Date) $( LET Type, Count = ?, ? IF TestFlags(1) DO $( BreakCondition := TRUE BREAK $) exInfo(Entry, EntryInfo) UNLESS Match(Pattern, V1, EntryInfo) GOTO NEXT Type, Count := EntryInfo!17, EntryInfo!18 UNLESS Seg=0 DO Start(EntryInfo+19, Date) UNLESS compstamp(entryinfo+19, since.stamp) >= 0 GOTO next UNLESS compstamp(entryinfo+19, upto.stamp) <= 0 GOTO next writef("*S*S%TI", entryinfo) IF disckeysopt DO writef(" [%I3]", entryinfo!16) writef(" %S", type=1 -> "dir", " ") Writef(" %I3%S%S%S", Count, [count=200 -> "+", " "], [Type=1 -> "Pr.Ent", Type=2 -> " Word", Type=3 -> " Block", " ?"], Count=1 -> " ", "s") TEST EntryInfo!19=0 | NoDatesOpt THEN NewLine() ELSE $( LET DayName = Day=EntryInfo!19 -> "Today", Day=EntryInfo!19+1 -> "Yesterday", Day=EntryInfo!19-1 -> "Tomorrow", Day<=EntryInfo!19+7 -> Date+10, Date IF Datesopt DO Dayname := Date Writef(" %T9 %S*N", DayName, Date+5) $) NEXT: NEntries := NEntries+1 Total := Total+ [Type=3 -> Count+1, 1] Entry := exNext(Entry) $) REPEATUNTIL Entry=0 Exit: UnloadSeg(Seg) UNLESS OldOutput=Output() DO $( EndWrite() SelectOutput(OldOutput) $) IF BreakCondition DO Writes("****BREAK*N") // Writef("%N entr%S processed*N", NEntries, // NEntries=1 -> "y", "ies") // UNLESS IsDir DO // Writef("%N+1 blocks allocated*N", Total) freevec(blk1) freevec(blk2) freevec(pattern) UNLESS dir=-1 | dir=CurrentDir THEN FreeObj(dir) $) AND compstamp(s1, s2) = VALOF $( FOR i = 0 TO 2 UNLESS s1!i=s2!i DO RESULTIS s1!i-s2!i RESULTIS 0 $) AND getb(key, vector) = SendPkt(-1, tsk, Action.GetBlock, 0, 0, key, vector) AND exfirst(lock) = VALOF // returns disc address of first entry $( ptr := b.dir.hashtablebase parent := lock=-1 -> rootkey, lock!lock.key getb(parent, blk1) if blk1!b.file.secondarytype<=0 resultis -1 until ptr>=b.file.infobase do $( if blk1!ptr\=0 resultis blk1!ptr ptr := ptr+1 $) resultis 0 $) and exnext(key) = valof // gets disc address of next beast $( getb(key, blk2) unless blk2!b.file.hashchain=0 resultis blk2!b.file.hashchain ptr := ptr+1 until ptr>=b.file.infobase do $( if blk1!ptr\=0 resultis blk1!ptr ptr := ptr+1 $) resultis 0 $) AND exInfo(key, Vector) = valof // analyse key putting // name into 0 - 15 // key into 16 // type into 17 // count into 18 // date into 19 - 21 $( if key=currentdir do key := key!lock.key getb(key, blk2) for i = 0 to 15 do vector!i := blk2![b.file.filename+i] vector!16 := key vector!17 := blk2!b.file.secondarytype<0 -> 3, 1 test vector!17=1 then $( let c = 0 for i = b.file.database to b.file.infobase-1 do if blk2!i\=0 then c := c+1 vector!18 := c $) else vector!18 := blk2!b.file.highestseq for i = 0 to 2 do vector![19+i] := blk2![b.file.creationdate+i] UNLESS hashvalue(vector)=ptr & blk2!b.file.parentdir=parent DO writes("********** WARNING - FOLLOWING ENTRY INVALID - SEEK ADVICE* ************n") resultis vector $) AND HashValue(String) = VALOF $( LET Res = String%0 FOR i = 1 TO Res DO Res := (Res*13 + CapitalCh[String%i]) & #X7FF // (Make sure RES is always positive) RESULTIS B.Dir.HashTableBase + Res REM Size.HashTable $) AND writename(key) BE $( LET devicename = DeviceId=-5 -> "DP", "DF" LET link = 0 writef("%S%N:", devicename, UnitNo) $( LET x = ? getb(key, blk2) IF blk2!b.file.secondarytype=1 THEN $( IF link=0 THEN $( wrch('$') RETURN $) BREAK $) x := getvec([blk2+b.file.filename]%0/bytesperword+1) FOR i = 0 TO [blk2+b.file.filename]%0 DO [x+1]%i := [blk2+b.file.filename]%i !x := link link := x key := blk2!b.file.parentdir $) REPEAT $( LET next = !link writes(link+1) freevec(link) IF next=0 BREAK wrch('.') link := next $) REPEAT $) AND concat(str1, str2) BE $( // Adds the second string to the first LET len = str1%0 FOR j=1 TO str2%0 DO len, str1%len := len+1, str2%j str1%0 := len $) // The Interpreter AND MATCH(PAT, AUX, STR) = VALOF $(1 LET W = VEC 128 LET S = 0 WORK, WP, SUCCFLAG := W, 0, FALSE PUT(1) UNLESS GETBYTE(AUX,0)=0 DO PUT(GETBYTE(AUX,0)) $(2 // FIRST COMPLETE THE CLOSURE $( LET N = 1 UNTIL N>WP DO $( LET P = WORK!N LET K, Q = GETBYTE(PAT,P), GETBYTE(AUX,P) SWITCHON K INTO $( CASE '#': PUT(P+1) CASE '%': PUT(Q) DEFAULT: ENDCASE CASE '(': CASE '/': PUT(P+1) UNLESS Q=0 DO PUT(Q) $) N := N+1 $) IF S>=GETBYTE(STR,0) RESULTIS SUCCFLAG IF WP=0 RESULTIS FALSE S := S+1 CH := GETBYTE(STR,S) // NOW DEAL WITH MATCH ITEMS $( LET N = WP WP, SUCCFLAG := 0, FALSE FOR I = 1 TO N DO $( LET P = WORK!I LET Q = P LET K = GETBYTE(PAT,P) SWITCHON K INTO $( CASE '#': CASE '/': CASE '%': CASE '(': LOOP CASE '*'':K := GETBYTE(PAT,Q+1) Q := Q+1 DEFAULT: // A MATCH ITEM $( LET K1 = K IF GETBYTE(PAT,Q+1)='-' DO $( K1 := GETBYTE(PAT,Q+2) IF K1='*'' DO K1 := GETBYTE(PAT,Q+3) $) UNLESS K<=CH<=K1 LOOP // I.E. NO MATCH $) CASE '?': // SUCCESSFUL MATCH PUT(GETBYTE(AUX,P)) LOOP $) $) $) $)2 REPEAT $)1 AND PUT(N) BE TEST N=0 THEN SUCCFLAG := TRUE ELSE $( FOR I = 1 TO WP IF WORK!I=N RETURN WP := WP+1 WORK!WP := N $) // The Compiler LET RCH() BE TEST PATP>=PATLEN THEN CH := ENDSTREAMCH ELSE $( PATP := PATP+1 CH := GETBYTE(PAT,PATP) $) AND NEXTITEM() BE SWITCHON CH INTO $( CASE '#': CASE '(': CASE '/': CASE ')': CASE '%': CASE '?': RCH() RETURN CASE '*'':RCH() DEFAULT: RCH() IF CH='-' DO $( RCH() IF CH='*'' DO RCH() RCH() $) $) AND PRIM() = VALOF $(1 LET A, OP = PATP, CH NEXTITEM() SWITCHON OP INTO $( CASE ENDSTREAMCH: CASE ')': CASE '-': CASE '/': ERRORFLAG := TRUE DEFAULT: RESULTIS A CASE '#': SETEXITS(PRIM(), A) RESULTIS A CASE '(': A := EXP(A) UNLESS CH=')' DO ERRORFLAG := TRUE NEXTITEM() RESULTIS A $) $)1 AND EXP(ALTP) = VALOF $(1 LET EXITS = 0 $(2 LET A = PRIM() TEST CH='/' \/ CH=')' \/ CH=ENDSTREAMCH THEN $( EXITS := JOIN(EXITS,A) UNLESS CH='/' RESULTIS EXITS PUTBYTE(AUX,ALTP,PATP) ALTP := PATP NEXTITEM() $) ELSE SETEXITS(A,PATP) $)2 REPEAT $)1 AND SETEXITS(LIST,VAL) BE UNTIL LIST=0 DO $( LET A = GETBYTE(AUX,LIST) PUTBYTE(AUX,LIST,VAL) LIST := A $) AND JOIN(A,B) = VALOF $( LET T = A IF A=0 RESULTIS B UNTIL GETBYTE(AUX,A)=0 DO A := GETBYTE(AUX,A) PUTBYTE(AUX,A,B) RESULTIS T $) AND CMPLPAT(PATTERN, CMPLPATTERN) = VALOF $(1 PAT, AUX := PATTERN, CMPLPATTERN PATP, PATLEN := 0, GETBYTE(PAT,0) ERRORFLAG := FALSE FOR I = 0 TO PATLEN DO PUTBYTE(AUX,I,0) RCH() SETEXITS(EXP(0),0) RESULTIS NOT ERRORFLAG $)1