! ! >>> LOCAL <<< ! ! This module of the IMP RTS handles input/output to objects known ! as "local files". These have some similarity to the old idea of ! a "tank" in that they are read/write stream-like objects residing in ! store, but they have several telling differences. ! ! 1) Tanks were independent of streams, local files are fully integrated. ! Thus select/print/read etc can all be used as usual. ! 2) Tanks were fixed-size; local files are self-sizing. ! 3) Tanks were numbered; local files are named. ! ! Use of SCB for LOCAL files ! ! _FAB will point to the LOCALFM block for this local file, ! _RAB will point to the SEGMENTFM block currently active (if any) ! ! Revision history: ! ! 1.0.0 antiquity IAY creation of package and debug to functionality ! 1.0.1 24-OCT-1984 IAY close on zero-length output does not update RAB ! as none has been created (result was an access ! violation as location 0 was used as the RAB). ! 1.0.2 24-OCT-1984 IAY remove clearing of SIZE field to prevent ! deallocation of allocated buffers, as this is now ! done in an entirely different way. ! 1.0.3 15-APR-1985 IAY change to generic I/O system ! %from IMP %include Formats, Streams, Buffers, HandCall, Depio, Mcode %record %format Segment Fm ( - %record(Buff Fm) Buffer, %integer Base Addr, Limit Addr, {for positioning operations} %record(Segment Fm) %name Next, Prev ) %record %format Local Fm ( - %byte Readers, Writers, %record(Segment Fm) %name Segment List, %record(Local Fm) %name File Chain, %record(SCB Fm) %name SCB, %integer Eof Addr, {for positioning operations} %string(15) File Name ) %own %record(Local Fm) %name Files == 0 ! ! > Find File < ! %record(Local Fm) %map Find File ( %string(15) S ) %record(Local Fm) %name F == Files %while F ## Nil %cycle %result == F %if F_File Name = S F == F_File Chain %repeat F == New(F); F = 0 {no segment list, eof addr=0} F_File Chain == Files; Files == F F_File Name = S %result == F %end ! ! >> Step Input Buffer << ! ! Called when the current input stream has hit the end of its buffer ! %externalroutine Step Input Buffer %alias "3L___sib" {In: R1 = addr(SCB)} {Out: R1 : unchanged} { R2 = address of first character position} %record(SCB Fm) %name S %integer P *STR _ 1, S %record(Local Fm) %name F == S_Fab %record(Segment Fm) %name R == S_Rab %if R == Nil %start {not any active as yet} R == F_Segment List %else R == R_Next %finish Eof %if R == Nil {at end of the list now} S_Rab == R S_ThisB = R_Buffer S_Next = S_ThisB_Base S_Limit = S_ThisB_Base + S_ThisB_Size S_Position = R_Base Addr P = S_Next *LDR _ 2, P *LDR _ 1, S %end ! ! > Close Input < ! %externalroutine Close Input %alias "3L___local_close_in"( %integer SS, Abandon ) %record(SCB Fm) %name S == Record(SS) %record(Local Fm) %name F == S_Fab F_Readers = F_Readers - 1 %end %externalroutine Reset Input %alias "3L___local_reset_in"(%integer SS) %record(SCB Fm) %name S == Record(SS) S_Rab == Nil S_Limit = S_Next {nothing in it for now} %end ! ! >> OPEN LOCAL INPUT << ! %external %routine Open Local Input %alias "3L_IMP_OPEN_LOCAL_INPUT" - ( %integer Stream, %string(15) File ) %record(Local Fm) %name F == Find File(File) %if F_Writers # 0 %start Event_Message = File." currently being written" %signal 9, 3 %finish F_Readers = F_Readers + 1 %record(SCB Fm) %name S == New SCB(0) S_Close Handler = Addr 2(Close Input) S_Reset Handler = Addr 1(Reset Input) S_Buffer Handler = Addr 0(Step Input Buffer) S_Rab == Nil; S_Fab == F S_Limit = S_Next {nothing in it for now} Push Input Stream(Stream,S) %end ! ! >> Step Output Buffer << ! %externalroutine Step Output Buffer %alias "3L___sob" {R1 = addr(SCB)} {R0 = Char} %record(SCB Fm) %name S %integer Char *STR _ 1, S *STR _ 0, Char %record(Local Fm) %name F == S_Fab %record(Segment Fm) %name R == S_Rab, N == Nil %integer Size = 1024, Base = 0 %if R ## Nil %start Size = R_Buffer_Size Base = R_Base Addr + Size %finish Size = Size + Size>>1 {50% growth factor} N == New(N); N_Buffer = Create Buffer(Size); N_Next == Nil N_Base Addr = Base; N_Limit Addr = Base + Size - 1 {link onto end of list} %if R == Nil %then F_Segment List == N - %else R_Next == N N_Prev == R S_Rab == N S_ThisB = N_Buffer S_Limit = S_ThisB_Base + S_ThisB_Size S_Position = Base S_Next = S_ThisB_Base *LDR _ R0, Char *LDR _ R2, S *LDR _ R3, [R2] {buffer pointer} *STRB_ R0, [R3], #1 *STR _ R3, [R2] %end ! ! > Close Output < ! %externalroutine Close Output %alias "3L___local_close_out"( %integer SS, Abandon ) %record(SCB Fm) %name S == Record(SS) %record(Local Fm) %name F == S_Fab F_Writers = F_Writers-1 %record(Segment Fm) %name R == S_Rab %if R ## Nil %start R_Buffer_Size = S_Next - R_Buffer_Base R_Limit Addr = R_Base Addr + R_Buffer_Size - 1 F_Eof Addr = R_Limit Addr %finish %end ! ! >> OPEN LOCAL OUTPUT << ! %external %routine Open Local Output %alias "3L_IMP_OPEN_LOCAL_OUTPUT" - ( %integer Stream, %string(15) File ) %record(Local Fm) %name F == Find File(File) %if F_Readers # 0 %start Event_Message = FIle." currently being read" %signal 9, 3 %finish %if F_Writers = 0 %start {delete space associated with the file} %record(Segment Fm) %name R, N == F_Segment List F_Segment List == Nil %while N ## Nil %cycle Delete Buffer(N_Buffer) R == N_Next; Dispose(N); N == R %repeat %else {already are some writers} %signal 15 %if F_Writers # 0 {cant cope with this so far...} %finish F_Writers = F_Writers+1 %record(SCB Fm) %name S == New SCB(0) S_Close Handler = Addr 2 ( Close Output ) S_Buffer Handler = Addr 0(Step Output Buffer) S_Rab == Nil; S_Fab == F S_Next = 0; S_Limit = 0 {FULL} Push Output Stream(Stream,S) %end