!@GENERAL !The commands available within CLEAN are as follows. !(Commands may be abbreviated to their first letter). ! Move on to the next file in the directory. ! HELP Generate more information about any particular command. ! DELETE Mark a file for deletion when the program stops. ! SAVE Unmark a file. (To prevent the program deleting it). ! COPY Copy the first lines of the file to the console. ! FILE The file called becomes the current file. ! RENAME The name of the file is changed to ! ANALYSE Display information about the size of the file etc. ! PERMIT The access permissions on the file are changed to ! TOP Move back to the top of the directory ! UP or LAST Move back up to the previous file. ! NEXT Equivalent to ! STOP Stops the program. ! QUIT Equivalent to STOP. ! EXIT Identical to QUIT and STOP. !Note that the directory is circular: moving past the end brings the !current file up to the top of the directory and moving up past the !top takes the current file down to the bottom. !@FILE !Format: FILE !Effect: ! immediately becomes the current file, without having !to step one by one through the files in the directory. !@HELP ! ! The basic command information can be printed by typing ! ! HELP ! !The second form is used to ask for more information about a !particular command: ! ! HELP command-name ! !Examples: ! HELP ! HELP QUIT ! HELP DELETE ! !@DELETE !Format: DELETE !Effect: !The current file is "marked for deletion" and the next file becomes the !current file. When CLEAN stops, the file will be physically deleted. !(This is so that a file mistakenly DELETED my be rescued. See HELP SAVE). ! To indicate which files a user has asked to have deleted, !when CLEAN prompts for a marked file, it prints a '>' character !before the filename. E.g. ! ! Command:clean ! JIM.EXE:d ! JIM.IMP: ! SORT.EXE:top ! *TOP* ! > JIM.EXE: ! JIM.IMP: ! SORT.EXE:quit ! Command: ! !@SAVE !Format: SAVE !Effect: ! If the current file has been marked for deletion, it is unmarked !and will not be deleted, otherwise the command has no effect. !Any change in the status of a file (marked/unmarked) is indicated !by the presence or absence respectively of the '>' marker beside !the filename prompt for marked files. ! !@PERMIT !Format: PERMIT new-permissions ! !where "new-permissions" are any of: ! ! ALL ! NONE ! list of letters in the range A to H !Effect: ! The access permissions on the current file are changed to !the "new-permissions". ALL is equivalent to ABCDEFGH and allows !any user to access the file. NONE is equivalent to an empty list !of permissions and prevents all users but its owner from accessing !the file (and event the owner may not delete the file without first !altering the permissions on the file to include 'D' access). !Users in groups 'A', 'B', 'C' etc. may be independently granted !or withheld access to the file by using the third form. ! !Examples: PERMIT ABH access for A,B and H users only ! PERMIT ALL access for everybody ! P NONE no one else may access the file ! PERMIT D allow deletion of the file ! !@COPY !Format: COPY !Effect: ! The first lines of the file are copied onto the console. ! defaults to the entire file. ! The listing may be interrupted at any time, and the user !returned to the CLEAN prompt level, by typing the !sequence ("Int:!"). ! !Examples: ! COPY list all of the current file ! COPY 10 list the first 10 lines ! C22 copy the first 22 lines ! !@TOP !Format: ! TOP !Effect: ! The first file in the directory becomes the current file. ! !@NEXT !Format: NEXT !Effect: ! The current file becomes the next file in the directory. If !the current file is the last file in the directory and the NEXT !(or ) command is given, the current file position wraps round !to the top of the directory again. ! !@UP !Format: ! LAST !Effect: ! The current file becomes the previous current file. (I.e. !moves back up one position in the directory). Moving back up past !the top of the directory causes the current file position to !'wrap around' to the bottom again. (C.f. the NEXT command). ! !@RENAME !Format: RENAME ! where is a valid MOUSES filename. I.e. FILE.EXT. ! Any UNIT_ or USER: parts will be ignored. !Effect: ! The current file is renamed immediately as . ! !@ANALYSE !Format: ! ANALYSE !Effect: ! The following information about the current file is displayed. ! !BLOCKS: The number of disc blocks (512 bytes each) presently ! occupied by the file. !EXTENTS: The number of distinct contiguous groups of blocks ! making up the file. (Max 126). This is a measure ! of how fragmented the file is. !CREATED: The date the file was created in the form dd-mmm-yy. ! !If the program was invoked using the CLEAN! form the disc address !of the file's spine block is also displayed ! !@QUIT !Stop the program. ! !@EXIT !Stops the program. !$ !$ !Program for fiddling MOUSES directories !Alan Culloch, August 1980 !System message block format %recordformat parmfm(%short dsno, dact, (%short ssno, sact,(%integer p1,p2,p3,p4,p5,p6 %or %string(23) text) %or %short xsno, %string(25) fname)) !Magic numbers for system calls %const %integer kill TTY IO = 6; !svc# to throw away console output buf %const %integer unpack date = 13; !svc# %const %integer to director = 20; !svc# pass message to the file system %const %integer pack filename = 17; !svc#s to convert filename strings to %const %integer unpack filename = 18; ! and from the packed system form !destination activity (DACT) values !for file system (DIRECTOR) operations. %const %integer delete = 14; !delete %const %integer rename = 15; ! %const %integer files = 17; !read dir blk %const %integer status = 18; !of file: %const %integer set file access = 22; !alter protections on file %const %integer become = 27; !change hats: !Directory format %record %format filef (%integer name1, name2, {packed filename} %short spine block, {disc block number} %short day) {creation date + achive} {info in the top 2 bits} %record %format directoryf(%short files, {No. of files in directory} %byte access rights, {of the directory's owner} %byte check, {always '?'} %short spare, %byte spare1, %byte permissions, {required to access dir} %record(filef) %array file(1:42)) %begin %include "Sysinc:command.inc" %externalstring(17)%spec Console int %externalstring(63)%fnspec ItoS(%integer N, P) %externalstring(8)%fnspec XtoS(%integer N, P) %const %string(31) program source = "Newsrc:CLEAN.IMP" %const %integer infinity = 16_7FFFFFFF %own %string(31) version = "(pre-release) vsn 0.00"; !%OWN shows in diags %const %integer non zero = 1 !Events %const %integer input ended = 9; !end-of-file on current input stream %const %integer fault = 11; !user event, signalled on input errors %own %integer XEVENT = input ended %routine FAULTS Xevent = fault %signal fault %end %record(parm fm) %fn packed (%string(31) filename) %record(parm fm) P P_fname = filename; SVC (pack filename,P) %result = P %end %routine report (%string(63) message) print string (message); newline %end %routine say (%string(63) message) spaces (15); print string (message); newline %end %string(15) %fn access (%integer mask); !translate access bits %string(15) s = "" %integer j mask = mask & 255 %result = "*NONE*" %if mask = 0 %result = "*ALL*" %if mask = 255 %for j = 0,1,7 %cycle s = s . to string ('A'+j) %if mask & 1< ("-") . s %for k = 1,1,length(s) %cycle b == char no (s,k) report (s . "?") %and %signal fault %unless '0' <= b <= '9' j = 10*j + (b-'0') %repeat %result = sign*j %end %routine test (%string(63) context, %record(parm fm)%name P) !log a parameterised error message if the !director call failure parameter is set in P (P_P6). %return %if P_p6 = 0 report ("*" . context . " -- " . P_text) %signal fault %end %integer %fn upper (%integer sym) %result = sym %unless 'a' <= sym <= 'z' %result = sym - 'a' + 'A' %end %routine get (%string(*)%name s) %integer sym skip symbol %while next symbol = ' ' s = "" %cycle sym = next symbol %exit %if sym <= ' ' s <- s . to string (sym) skip symbol %repeat %end %routine get alpha (%string(*)%name s) %integer sym skip symbol %while next symbol = ' ' s = "" %cycle sym = upper (next symbol) %exit %unless 'A' <= sym <= 'Z' s <- s . to string (sym) skip symbol %repeat %end %routine drain input line %string(63) s = """" %if next symbol # NL %start %while next symbol # NL %cycle s <- s . to string (next symbol) skip symbol %repeat s <- s . """ ignored" report (s) %finish skip symbol; !past NL %end %string(15) %array unpacked (1:42) %byte %array pos (1:42); !map n -> nth dir entry (sorted) %record(directoryf) D %routine sort dir; !set up POS and UNPACKED %integer j, k, flag, swap, no files = 0 %record(parm fm) P %record(filef)%name f %for j = 1,1,42 %cycle; !unpack directory entries pos(j) = j f == D_file(j) %if f_name2 = 0 %start unpacked(j) = "" %else no files = no files + 1 P = 0; P_p3 = f_name1; P_p4 = f_name2 SVC (unpack filename,P) unpacked(j) = P_fname %finish %repeat %if no files = 0 %start report ("No files") %stop %finish %for j = 1,1,42 %cycle; !do the sort flag = 0 %for k = 1,1,42-j %cycle %if unpacked(pos(k)) > unpacked(pos(k+1)) %start flag = non zero swap = pos(k); pos(k) = pos(k+1); pos(k+1) = swap %finish %repeat %repeat %until flag = 0 %end %own %byte %array del(1:42) = 0(*); !#0 => file#n is to be deleted %record(filef)%name f %string(63) s, fname, topic %integer j, k, m, sym, lines, flag %byte %name b %record(parm fm) P, Q %on %event input ended, fault %start %if EVENT_event = input ended %start !Kill all files which were marked for deletion %for j = 1,1,42 %cycle f == D_file(pos(j)) %if del(j) # 0 %start P = 0 P_dact = DELETE; P_p3 = f_name1; P_p4 = f_name2 SVC (to director,P) s = unpacked (pos(j)) %if P_p6 # 0 %start s = "*cannot delete " . s . " -- " . P_text %else s = s . " deleted" %finish report (s) %finish %repeat %if command_parameter # "" %start; !return to home directory P = 0; P_dact = BECOME SVC (to director,P); !and we're ourselves again test ("Become fails",P); !maybe %finish %stop %finish drain input line XEVENT = input ended; !again -> RECOVER %finish !Main program select input (0); select output (0) %if command_parameter # "" %start; !CLEAN someone else's directory, command_parameter = command_parameter . ":"; !syntax id CLEAN(UNIT_USER) P = packed (command_parameter); P_dact = BECOME; P_p6 = 0;!me SVC (to director,P) %if P_p6 # 0 %start report ("CLEAN fails -- " . P_text) %stop %finish %finish P_p1 = 0; P_p2 = 0; !read current default directory block P_p6 = addr(D) P_dact = FILES; SVC (to director,P) test ("CLEAN fails",P) %if command_modifier # 0 %start say ("Directory on unit " . itos(p_p1,0) . " block " . %c itos(p_p2,0) . " (X'" . xtos(p_p2,4) . "')") %finish j = 0; !index into directory sort dir RECOVER: %cycle %if j < 0 %or j >= 42 %start j = 0 say ("*TOP*") %finish j = j + 1; f == D_file(pos(j)) %continue %if f_name2 = 0; !unused directory slot? !prompt user with filename P = 0; P_p3 = f_name1; P_p4 = f_name2; !unpack it first fname = unpacked (pos(j)) s = fname; s = " " . s %while length(s) < 14 s = s . ":"; char no (s,1) = '>' %if del(j) # 0 prompt (s) get alpha (s); !user gives command to act on file %if s # "" %or next symbol = '?' %start skip symbol %while next symbol = ' ' skip symbol %and -> HELP %if next symbol = '?' -> STOP %if s = "STOP"; !one-off frigs P = 0; !set up P for all commands to use P_p3 = f_name1; P_p4 = f_name2 sym = char no (s,1); !only 1st char of command significant %if sym = 'D' %start; !mark file for deletion at the end del(j) = non zero say ("marked for deletion") %else %if sym = 'S'; !retain file previously marked del(j) = 0 say ("saved!") %else %if sym = 'H'; !HELP get alpha (s); !topic HELP: s = "GENERAL" %if s = "" j = j - 1 open input (3,program source) select input (3) flag = 0 %cycle skip symbol; !past '!' %if next symbol = '$' %start say ("Nothing about " . s) %if flag = 0 %exit %finish %if next symbol = '@' %start; !start of new topic skip symbol get alpha (topic) %exit %if flag # 0; !end of one we wanted flag = non zero %if char no(s,1) = char no (topic,1) skip symbol; !past nl %else %while next symbol # NL %cycle print symbol (next symbol) %if flag # 0 skip symbol %repeat newline %if flag # 0 skip symbol; !past nl %finish %repeat close input select input (0) %else %if sym = 'C'; !COPY file on T: j = j - 1 get (s); !only the 1st n lines lines = stoi (s); lines = infinity %if lines <= 0 open input (3,fname) select input (3) console int = "" %begin %on input ended %start %return; !to enclosing block %finish %for k = 1,1,lines %cycle %while next symbol # NL %cycle %if console int # "" %start; !user has caused "Int:!" P_p1 = 0; P_p2 = non zero; P_p3 = 0 SVC (kill TTY IO,P); !chuck content of TT output buf close input; select input (0) newline FAULTS %finish print symbol (next symbol) skip symbol %repeat newline; !in output skip symbol; !past NL %repeat %end close input select input (0) %else %if sym = 'P'; !set protection mask j = j - 1 get alpha (s); !new mask (ALL,NONE, or A..H) %if s = "ALL" %start k = 255 %else %if s = "NONE" k = 0 %else k = 0 %for m = 1,1,length(s) %cycle b == char no (s,m) say (to string(b)."?") %and FAULTS %unless 'A' <= b <= 'H' k = k ! 1<<(b-'A') %repeat %finish P_p6 = k; P_dact = set file access SVC (to director,P) test ("Change access fails",P) %else %if sym = 'F'; !find get (s) say ("filename?") %and j = j - 1 %and FAULTS %if s = "" P = packed (s) %if P_p1 # 0 %or P_p2 < 0 %start; !bad fname say (s . "?") j = j - 1 FAULTS %finish SVC (unpack filename,P) s = P_fname %for k = 1,1,42 %cycle %if unpacked(pos(k)) = s %start j = k %exit %finish %if k = 42 %start say (s . " not found") j = j - 1 FAULTS %finish %repeat j = j - 1 %else %if sym = 'R'; !rename get (s); Q = packed (s) %if Q_p1 # 0 %or Q_p2 < 0 %start j = j - 1 say (s . "?") FAULTS %finish P_p5 = Q_p3; P_p6 = Q_p4 P_dact = RENAME; SVC (to director,P) test ("Rename fails",P) f_name1 = Q_p3; f_name2 = Q_p4; !make our copy of dir consistent SVC (unpack filename,Q); unpacked (pos(j)) = Q_fname s = unpacked (pos(j)) say (fname . " renamed " . s) j = j - 1 %else %if sym = 'T'; !move to first file in directory j = -1 %else %if sym = 'U' %or sym = 'L'; !move back up to last file j = j - 1; !back 1 past this one j = j - 1 %while j > 0 %and D_file(pos(j))_name2 = 0; !find valid j = 42 %and say ("*END*") %if j = 0; !wrap j = j - 1; !& back off one %else %if sym = 'N'; !move to NEXT file (for completeness) %else %if sym = 'A'; !analyse file j = j - 1 P_dact = status; SVC (to director,P) test ("analyse fails",P) s <- itos (P_p2,0) . " block"; s <- s . "s" %if P_p2 # 1 s <- s . " " s <- s . itos (P_p3,0) ." extent"; s <- s . "s" %if P_p3 # 1 s <- s . " " s <- s . " access " . access(P_p4) . ", created on " s <- s . sys date(P_p5&16_3FFF) say (s) %if command_modifier # 0 %start s <- "spine block at " . itos(f_spine block,0) . %c " (X'" . xtos(f_spine block,4) . "')" say (s) %finish %else %if sym = 'Q' %or sym = 'E' STOP: xEVENT = input ended; !!!TEMP %signal input ended %else report (s . "? Try HELP") %finish %finish DRAIN: drain input line %repeat %end %of %program , topic %integer j, k, m, sym, lines, flag %byte %name b %record(parm fm) P, Q %on %event input ended, fault %start %if EVENT_event = input ended %start !Kill all files which were marked for deletion %for j = 1,1,42 %cycle f == D_file(pos(j)) %if del(j) # 0 %start P = 0 P_dact = DELETE; P_p3 = f_name1; P_p4 = f_name2 SVC (to director,P) s = unpacked (pos(j)) %if P_p6 # 0 %start s = "*cannot delete " . s . " -- " . P_text %else s = s . " deleted" %finish report (s) %finish %repeat %if command_parameter # "" %start; !return to home directory P = 0; P_dact = BECOME SVC (to director,P); !and we're ourselves again test ("Become fails",P); !maybe %finish %stop %finish drain input line XEVENT = input ended; !again -> RECOVER %finish !Main program select input (0); select output (0) %if command_parameter # "" %start; !CLEAN someone else's directory, command_parameter = command_parameter . ":"; !syntax id CLEAN(UNIT_USER) P = packed (command_parameter); P_dact = BECOME; P_p6 = 0;!me SVC (to director,P) %if P_p6 # 0 %start report ("CLEAN fails -- " . P_text) %stop %finish %finish P_p1 = 0; P_p2 = 0; !read current default directory block P_p6 = addr(D) P_dact = FILES; SVC (to director,P) test ("CLEAN fails",P) %if command_modifier # 0 %start say ("Directory on unit " . itos(p_p1) . " block " . %c itos(p_p2) . " (X'" . xtos(p_p2,4) . "')") %finish j = 0; !index into directory sort dir RECOVER: %cycle %if j < 0 %or j >= 42 %start j = 0 say ("*TOP*") %finish j = j + 1; f == D_file(pos(j)) %continue %if f_name2 = 0; !unused directory slot? !prompt user with filename P = 0; P_p3 = f_name1; P_p4 = f_name2; !unpack it first fname = unpacked (pos(j)) s = fname; s = " " . s %while length(s) < 14 s = s . ":"; char no (s,1) = '>' %if del(j) # 0 prompt (s) get alpha (s); !user gives command to act on file %if s # "" %or next symbol = '?' %start skip symbol %while next symbol = ' ' skip symbol %and -> HELP %if next symbol = '?' -> STOP %if s = "STOP"; !one-off frigs P = 0; !set up P for all commands to use P_p3 = f_name1; P_p4 = f_name2 sym = char no (s,1); !only 1st char of command significant %if sym = 'D' %start; !mark file for deletion at the end del(j) = non zero say ("marked for deletion") %else %if sym = 'S'; !retain file previously marked del(j) = 0 say ("saved!") %else %if sym = 'H'; !HELP get alpha (s); !topic HELP: s = "GENERAL" %if s = "" j = j - 1 open input (3,program source) select input (3) flag = 0 %cycle skip symbol; !past '!' %if next symbol = '$' %start say ("Nothing about " . s) %if flag = 0 %exit %finish %if next symbol = '@' %start; !start of new topic skip symbol get alpha (topic) %exit %if flag # 0; !end of one we wanted flag = non zero %if char no(s,1) = char no (topic,1) skip symbol; !past nl %else %while next symbol # NL %cycle print symbol (next symbol) %if flag # 0 skip symbol %repeat newline %if flag # 0 skip symbol; !past nl %finish %repeat close input select input (0) %else %if sym = 'C'; !COPY file on T: j = j - 1 get (s); !only the 1st n lines lines = stoi (s); lines = infinity %if lines <= 0 open input (3,fname) select input (3) console int = "" %begin %on input ended %start %return; !to enclosing block %finish %for k = 1,1,lines %cycle %while next symbol # NL %cycle %if console int # "" %start; !user has caused "Int:!" P_p1 = 0; P_p2 = non zero; P_p3 = 0 SVC (kill TTY IO,P); !chuck content of TT output buf close input; select input (0) newline FAULTS %finish print symbol (next symbol) skip symbol %repeat newline; !in output skip symbol; !past NL %repeat %end close input select input (0) %else %if sym = 'P'; !set protection mask j = j - 1 get alpha (s); !new mask (ALL,NONE, or A..H) %if s = "ALL" %start k = 255 %else %if s = "NONE" k = 0 %else k = 0 %for m = 1,1,length(s) %cycle b == char no (s,m) say (to string(b)."?") %and FAULTS %unless 'A' <= b <= 'H' k = k ! 1<<(b-'A') %repeat %finish P_p6 = k; P_dact = set file access SVC (to director,P) test ("Change access fails",P) %else %if sym = 'F'; !find get (s) say ("filename?") %and j = j - 1 %and FAULTS %if s = "" P = packed (s) %if P_p1 # 0 %or P_p2 < 0 %start; !bad fname say (s . "?") j = j - 1 FAULTS %finish SVC (unpack filename,P) s = P_fname %for k = 1,1,42 %cycle %if unpacked(pos(k)) = s %start j = k %exit %finish %if k = 42 %start say (s . " not found") j = j - 1 FAULTS %finish %repeat j = j - 1 %else %if sym = 'R'; !rename get (s); Q = packed (s) %if Q_p1 # 0 %or Q_p2 < 0 %start j = j - 1 say (s . "?") FAULTS %finish P_p5 = Q_p3; P_p6 = Q_p4 P_dact = RENAME; SVC (to director,P) test ("Rename fails",P) f_name1 = Q_p3; f_name2 = Q_p4; !make our copy of dir consistent SVC (unpack filename,Q); unpacked (pos(j)) = Q_fname s = unpacked (pos(j)) say (fname . " renamed " . s) j = j - 1 %else %if sym = 'T'; !move to first file in directory j = -1 %else %if sym = 'U' %or sym = 'L'; !move back up to last file j = j - 1; !back 1 past this one j = j - 1 %while j > 0 %and D_file(pos(j))_name2 = 0; !find valid j = 42 %and say ("*END*") %if j = 0; !wrap j = j - 1; !& back off one %else %if sym = 'N'; !move to NEXT file (for completeness) %else %if sym = 'A'; !analyse file j = j - 1 P_dact = status; SVC (to director,P) test ("analyse fails",P) s <- itos (P_p2) . " block"; s <- s . "s" %if P_p2 # 1 s <- s . " " s <- s . itos (P_p3) ." extent"; s <- s . "s" %if P_p3 # 1 s <- s . " " s <- s . " access " . access(P_p4) . ", created on " s <- s . sys date(P_p5&16_3FFF) say (s) %if command_modifier # 0 %start s <- "spine block at " . itos(f_spine block) . %c " (X'" . xtos(f_spine block,4) . "')" say (s) %finish %else %if sym = 'Q' %or sym = 'E' STOP: xEVENT = input ended; !!!TEMP %signal input ended %else report (s . "? Try HELP") %finish %finish DRAIN: drain input line %repeat {just a dummy comment} %endofprogram