!*********************************************************************** !* !* Utility program to copy the 'tail end' of a file !* !* R.D.Eager UKC MCMLXXXII !* !*********************************************************************** ! CONSTANTINTEGER VERSION = 2; ! Major version number CONSTINTEGER EDIT = 0; ! Edit number within major version ! !*********************************************************************** !* !* Constants !* !*********************************************************************** ! CONSTANTINTEGER NO = 0, YES = 1 CONSTANTINTEGER CHARS = 0, LINES = 1 CONSTANTINTEGER SSCHARFILETYPE = 3 CONSTANTINTEGER HDSIZE = 32; ! Size of a file header CONSTANTSTRING (1) SNL = " " CONSTANTINTEGER KEYMAX = 5; ! Number of parameter keywords CONSTANTSTRING (8)ARRAY KEYS(1:KEYMAX) = C "INPUT", "OUTPUT", "POSITION", "UNITS", "VERSION" ! ! !*********************************************************************** !* !* Record formats !* !*********************************************************************** ! RECORDFORMAT HF(INTEGER DATAEND,DATASTART,FILESIZE,FILETYPE,C SUM,DATETIME,FORMAT,RECORDS) RECORDFORMAT RF(INTEGER CONAD,FILETYPE,DATASTART,DATAEND) ! ! !*********************************************************************** !* !* Subsystem references !* !*********************************************************************** ! SYSTEMROUTINESPEC CONNECT(STRING (31) FILE,INTEGER MODE,HOLE,C PROT,RECORD (RF)NAME R,INTEGERNAME FLAG) SYSTEMINTEGERFUNCTIONSPEC DEVCODE(STRING (16) DEVICE) SYSTEMROUTINESPEC DISCONNECT(STRING (31) FILE,INTEGERNAME FLAG) SYSTEMSTRINGFUNCTIONSPEC FAILUREMESSAGE(INTEGER MESS) SYSTEMSTRINGFUNCTIONSPEC ITOS(INTEGER N) SYSTEMROUTINESPEC MOVE(INTEGER LENGTH,FROM,TO) SYSTEMSTRINGFUNCTIONSPEC NEXTTEMP SYSTEMROUTINESPEC OUTFILE(STRING (31) FILE,INTEGER SIZE,HOLE,C PROT,INTEGERNAME CONAD,FLAG) SYSTEMINTEGERFUNCTIONSPEC PSTOI(STRING (63) S) SYSTEMROUTINESPEC SENDFILE(STRING (31) FILE,STRING (16) DEVICE,C STRING (11) NAME,INTEGER COPIES,FORMS,C INTEGERNAME FLAG) SYSTEMROUTINESPEC SETFNAME(STRING (63) S) EXTERNALROUTINESPEC SET RETURN CODE(INTEGER I) ! ! !*********************************************************************** !* !* Service routines !* !*********************************************************************** ! INTEGERFUNCTION MATCHSTRINGS(STRINGNAME A,STRING (255) B) INTEGER L ! L = LENGTH(A) IF LENGTH(B) < L THEN RESULT = 0 LENGTH(B) = L IF A = B THEN RESULT = YES ELSE RESULT = NO END ; ! of MATCHSTRINGS ! ! INTEGERFUNCTION PARAMDECODE(STRING (255) PARAM,INTEGER PMAX,C STRINGARRAYNAME KEYS,PARS) INTEGER I,PNUM,PN,RES,C,PARPTR,PARLENG STRING (255) WKSP ! INTEGERFUNCTION FINDKEY INTEGER F,I ! IF LENGTH(WKSP) = 0 THEN RESULT = -2; ! Missing keyword F = 0 FOR I = 1,1,PMAX CYCLE IF MATCHSTRINGS(WKSP,KEYS(I)) = YES THEN START UNLESS F = 0 THEN RESULT = -1 F = I FINISH REPEAT RESULT = F END ; ! of FINDKEY ! INTEGERFUNCTION GETPAR INTEGER C,INPR ! INPR = 0 WKSP = "" ! CYCLE PARPTR = PARPTR + 1 IF PARPTR > PARLENG THEN RESULT = -1 C = CHARNO(PARAM,PARPTR) IF C = ',' OR C = '=' THEN RESULT = C WKSP = WKSP.TOSTRING(C) REPEAT END ; ! of GETPAR ! FOR I = 1,1,PMAX CYCLE PARS(I) = ""; ! Initialise REPEAT PARPTR = 0 PNUM = 1 PARLENG = LENGTH(PARAM) ! CYCLE C = GETPAR RES = 0 IF C # '=' THEN START PN = PNUM FINISH ELSE START PN = FINDKEY IF PN = 0 THEN RES = 322; ! Unknown keyword IF PN = -1 THEN RES = 321; ! Ambiguous keyword IF PN = -2 THEN RES = 325; ! Missing keyword C = GETPAR IF C = '=' THEN RES = 320; ! Format error FINISH IF PN > PMAX THEN RES = 323; ! Too many parameters IF RES = 0 THEN START IF WKSP # "" # PARS(PN) THEN RES = 324 ! Duplicated parameter PARS(PN) = WKSP FINISH IF RES # 0 THEN RESULT = RES IF C = -1 THEN RESULT = 0; ! Finished, all OK PNUM = PNUM + 1 REPEAT END ; ! of PARAMDECODE ! ! ROUTINE FAIL(INTEGER N) PRINTSTRING(SNL."TAIL fails - ".FAILUREMESSAGE(N)) SET RETURN CODE(N) STOP END ; ! of FAIL ! ! INTEGERFUNCTION YES OR NO(STRINGNAME S,INTEGER KEYNO) INTEGER REPLY ! REPLY = NO IF S # "" THEN START IF MATCHSTRINGS(S,"YES") = YES THEN REPLY = YES ELSE START UNLESS MATCHSTRINGS(S,"NO") = YES THEN START SETFNAME(KEYS(KEYNO)) FAIL(326); ! Invalid value for parameter FINISH FINISH FINISH RESULT = REPLY END ; ! of YES OR NO ! ! !*********************************************************************** !* !* T A I L !* !*********************************************************************** ! EXTERNALROUTINE TAIL(STRING (255) S) INTEGER FLAG,I,J,UNITS,SPOOL,PTR,SIZE,OUTCONAD,SIGN INTEGER GVERSION,POSITION,CONAD STRINGNAME FILE,OUT,PS,US,VS STRING (15) DEVICE STRING (255)ARRAY OPTIONS(1:KEYMAX) RECORD (RF) RR RECORD (HF)NAME OUTHD ! SET RETURN CODE(1000); ! In case of catastrophic failure FLAG = PARAMDECODE(S,KEYMAX,KEYS,OPTIONS) IF FLAG # 0 THEN FAIL(FLAG) FILE == OPTIONS(1) OUT == OPTIONS(2) PS == OPTIONS(3) US == OPTIONS(4) VS == OPTIONS(5) ! FAIL(263) IF FILE = ""; ! Wrong number of parameters OUT = ".OUT" IF OUT = "" PS = "-22" IF PS = "" POSITION = -1 SIGN = CHARNO(PS,1) IF SIGN = '+' OR SIGN = '-' THEN START IF LENGTH(PS) > 1 THEN START POSITION = PSTOI(SUBSTRING(PS,2,LENGTH(PS))) FINISH FINISH ELSE START SIGN = '+' POSITION = PSTOI(PS) FINISH IF POSITION < 0 THEN START SETFNAME(KEYS(3)) FAIL(326); ! Invalid value for parameter FINISH ! UNITS = LINES IF US # "" THEN START IF MATCHSTRINGS(US,"CHARACTERS") = YES THEN START UNITS = CHARS FINISH ELSE START UNLESS MATCHSTRINGS(US,"LINES") = YES THEN START SETFNAME(KEYS(4)) FAIL(326); ! Invalid value for parameter FINISH FINISH FINISH ! GVERSION = YES OR NO(VS,5) IF GVERSION = YES THEN START PRINTSTRING("Version: E".ITOS(VERSION).".".ITOS(EDIT).SNL) FINISH ! CONNECT(FILE,1,0,0,RR,FLAG) IF FLAG # 0 THEN FAIL(FLAG) IF RR_FILETYPE # SSCHARFILETYPE THEN START SETFNAME(FILE) FAIL(267); ! Invalid filetype FINISH CONAD = RR_CONAD ! IF UNITS = CHARS THEN START IF SIGN = '+' THEN START IF POSITION = 0 THEN POSITION = 1 PTR = RR_DATASTART + POSITION - 1 IF PTR > RR_DATAEND THEN PTR = RR_DATAEND FINISH ELSE START PTR = RR_DATAEND - POSITION IF PTR < RR_DATASTART THEN PTR = RR_DATASTART FINISH PTR = PTR + CONAD FINISH ELSE START IF SIGN = '+' THEN START PTR = CONAD + RR_DATASTART J = CONAD + RR_DATAEND WHILE PTR < J AND POSITION > 1 CYCLE IF BYTEINTEGER(PTR) = NL THEN START POSITION = POSITION - 1 FINISH PTR = PTR + 1 REPEAT PTR = PTR - 1 FINISH ELSE START PTR = CONAD + RR_DATAEND IF PTR > CONAD + RR_DATASTART THEN START IF BYTEINTEGER(PTR-1) = NL THEN PTR = PTR - 1 ! In case last line is incomplete FINISH J = CONAD + RR_DATASTART WHILE PTR > J AND POSITION > 0 CYCLE PTR = PTR - 1 IF BYTEINTEGER(PTR) = NL THEN START POSITION = POSITION - 1 FINISH REPEAT FINISH PTR = PTR + 1 FINISH SIZE = RR_DATAEND - PTR + CONAD ! IF SIZE > 0 THEN START IF OUT = ".OUT" THEN START FOR I = PTR,1,CONAD + RR_DATAEND - 1 CYCLE PRINTSYMBOL(BYTEINTEGER(I)) REPEAT FINISH ELSE START IF CHARNO(OUT,1) = '.' THEN START IF DEVCODE(OUT) <= 0 THEN START ! Illegal, or .TEMP, or .NULL SETFNAME(OUT) FAIL(264); ! Invalid device code FINISH SPOOL = 1; DEVICE = OUT OUT = "T#".NEXTTEMP FINISH ELSE SPOOL = 0 OUTFILE(OUT,SIZE+HDSIZE,0,0,OUTCONAD,FLAG) IF FLAG # 0 THEN FAIL(FLAG) OUTHD == RECORD(OUTCONAD) OUTHD_FILETYPE = SSCHARFILETYPE MOVE(SIZE,PTR,OUTCONAD+OUTHD_DATASTART) OUTHD_DATAEND = OUTHD_DATASTART + SIZE DISCONNECT(OUT,FLAG) IF SPOOL = 1 THEN START SENDFILE(OUT,DEVICE,"TAILLIST",0,0,FLAG) IF FLAG # 0 THEN FAIL(FLAG) FINISH FINISH FINISH SET RETURN CODE(0) END ; ! of TAIL ENDOFFILE