# svsave --- save shell variables integer function svsave (file, trace) character file (ARB) bool trace define (NULL_PTR,16rFFF0000) define (FUNCTION,'<'c) # start mnemonic function define (END_FUNC,'>'c) # end the mnemonic function include SV_COMMON integer h, junk pointer p filedes fd filedes open pointer val call break$ (DISABLE) fd = open (file, WRITE, junk, 20) # wait for up to 10 seconds if (fd == ERR) { call break$ (ENABLE) return (ERR) } if (trace) call print (TTY, "Saving variables in *s*n"p, file) for (h = 1; h <= SV_MAXHASH; h += 1) for (p = Sv_tbl (1, h); p ~= LAMBDA; p = Sv_mem (p + SV_HLINK)) { call putlin (Sv_mem (Sv_mem (p + SV_NAME)), fd) call putch (NEWLINE, fd) call svctmn (Sv_mem (Sv_mem (p + SV_VALUE)), val) call putlin (Sv_mem (val), fd) call putch (NEWLINE, fd) if (trace) { call putlin (Sv_mem (Sv_mem (p + SV_NAME)), TTY) call putch (NEWLINE, TTY) call putlin (Sv_mem (val), TTY) call putch (NEWLINE, TTY) } call svfree (val) } call trunc (fd) call close (fd) call break$ (ENABLE) return (OK) end # svrest --- restore shell variables integer function svrest (file, trace) character file (ARB) bool trace include SV_COMMON pointer name, value integer len, junk integer svgetl, length filedes fd filedes open call break$ (DISABLE) fd = open (file, READ, junk, 20) if (fd == ERR) { call break$ (ENABLE) return (ERR) } if (trace) call print (TTY, "Restoring variables from *s*n"p, file) repeat { len = svgetl (name, fd) if (len == EOF) break Sv_mem (name + len - 1) = EOS len = svgetl (value, fd) if (len == EOF) { # variable value is missing call close (fd) call break$ (ENABLE) return (ERR) } Sv_mem (value + len - 1) = EOS if (trace) call print (TTY, "*s = *s*n"p, Sv_mem (name), Sv_mem (value)) call svmake (Sv_mem (name), Sv_mem (value)) call svfree (value) call svfree (name) } call close (fd) call break$ (ENABLE) return (OK) end # svscan --- scan the shell variable structure and return names integer function svscan (name, maxlen, info, offset) character name (maxlen) integer maxlen, info (3), offset include SV_COMMON integer ctoc bool missin integer i pointer p if (info (1) == 0) { info (1) = 1 info (2) = 0 if (missin (offset)) info (3) = 0 else info (3) = offset } name (1) = EOS if (info (1) < 1) info (1) = 1 if (info (1) > SV_MAXHASH) return (EOF) if (info (2) < 0) info (2) = 0 if (Sv_ll <= info (3)) info (3) = Sv_ll - 1 if (info (3) < 0) info (3) = 0 p = Sv_tbl (Sv_ll - info (3), info (1)) for (i = 1; i <= info (2) && p ~= LAMBDA; i += 1) p = Sv_mem (p + SV_HLINK) repeat { if (p ~= LAMBDA) { info (2) += 1 return (ctoc (Sv_mem (Sv_mem (p + SV_NAME)), name, maxlen)) } info (1) += 1 if (info (1) > SV_MAXHASH) break info (2) = 0 p = Sv_tbl (Sv_ll - info (3), info (1)) } return (EOF) end # svmake --- create a shell variable in the current scope integer function svmake (name, value) character name (ARB), value (ARB) include SV_COMMON integer h, nl, vl, i integer length, svfind, svhash, svmntc pointer p, np, vp pointer svallo ### traverse string once before inhibiting breaks nl = length (name) + 1 if (svfind (name, p) ~= Sv_ll) { # not in this scope call break$ (DISABLE) p = svallo (3) # allocate a new pointer block np = svallo (nl) # allocate space for name call svmntc (value, vp) # allocate space for value h = svhash (name) Sv_mem (p + SV_NAME) = np Sv_mem (p + SV_VALUE) = vp Sv_mem (p + SV_HLINK) = Sv_tbl (Sv_ll, h) Sv_tbl (Sv_ll, h) = p call ctoc (name, Sv_mem (np), nl) call svfix (name, Sv_mem (vp), Sv_ll) call break$ (ENABLE) } # else { # already declared in this scope; change value # call break$ (DISABLE) # call svfree (Sv_mem (p + SV_VALUE)) # call svmntc (value, vp) # Sv_mem (p + SV_VALUE) = vp # call break$ (ENABLE) # } return (Sv_ll) end # svput --- assign value to shell variable integer function svput (name, value) character name (ARB), value (ARB) include SV_COMMON integer ll integer svmntc, svfind, svmake pointer p, vp pointer svallo ll = svfind (name, p) # see if variable is declared if (ll == EOF) # no; create it in the current scope ll = svmake (name, value) else { call break$ (DISABLE) call svfree (Sv_mem (p + SV_VALUE)) call svmntc (value, vp) Sv_mem (p + SV_VALUE) = vp call svfix (name, Sv_mem (vp), ll) call break$ (ENABLE) } return (ll) end # svdel --- destroy a shell variable in the current scope subroutine svdel (name) character name (ARB) include SV_COMMON include SWT_COMMON integer h, i integer equal, svhash, strlsr pointer p, q stringtable pos, text / "_eof" _ / "_erase" _ / "_escape" _ / "_kill" _ / "_kill_resp" _ / "_newline" _ / "_retype" _ / "_prt_dest" _ / "_prt_form" q = LAMBDA h = svhash (name) for (p = Sv_tbl (Sv_ll, h); p ~= LAMBDA; p = Sv_mem (p + SV_HLINK)) { if (equal (name, Sv_mem (Sv_mem (p + SV_NAME))) == YES) { call break$ (DISABLE) if (q == LAMBDA) Sv_tbl (Sv_ll, h) = Sv_mem (p + SV_HLINK) else Sv_mem (q + SV_HLINK) = Sv_mem (p + SV_HLINK) call svfree (Sv_mem (p + SV_NAME)) call svfree (Sv_mem (p + SV_VALUE)) call svfree (p) i = strlsr (pos, text, 0, name) # update SWT common blocks if (i ~= EOF) select (i - 1) when (1) Eofchar = Eofsave (Sv_ll) when (2) Echar = Esave (Sv_ll) when (3) Escchar = Escsave (Sv_ll) when (4) Kchar = Ksave (Sv_ll) when (5) call ctoc (Kresp_save (1, Sv_ll), Kill_resp, MAXKILLRESP) when (6) Nlchar = Nlsave (Sv_ll) when (7) Rtchar = Rtsave (Sv_ll) when (8) call ctoc (Pdest_save (1, Sv_ll), Prt_dest, MAXPRTDEST) when (9) call ctoc (Pform_save (1, Sv_ll), Prt_form, MAXPRTFORM) call break$ (ENABLE) break } q = p } return end # svget --- fetch the value of a shell variable integer function svget (name, value, maxval) character name (ARB), value (ARB) integer maxval include SV_COMMON integer ctoc, svfind pointer p if (svfind (name, p) == EOF) svget = EOF else svget = ctoc (Sv_mem (Sv_mem (p + SV_VALUE)), value, maxval) return end # svfind --- locate a shell variable; return scope level and location integer function svfind (name, loc) character name (ARB) pointer loc include SV_COMMON integer h, i integer equal, svhash pointer p h = svhash (name) for (i = Sv_ll; i > 0; i -= 1) for (p = Sv_tbl (i, h); p ~= LAMBDA; p = Sv_mem (p + SV_HLINK)) if (equal (name, Sv_mem (Sv_mem (p + SV_NAME))) == YES) { loc = p return (i) } loc = LAMBDA return (EOF) end # svhash --- compute hash number for a shell variable name integer function svhash (name) character name (ARB) if (IS_LETTER (name (1))) svhash = mod (name (1), SV_MAXHASH) + 1 else svhash = mod (name (2), SV_MAXHASH) + 1 return end # svpop --- exit the current shell variable scope level subroutine svpop include SV_COMMON include SWT_COMMON integer i pointer p, q call break$ (DISABLE) do i = 1, SV_MAXHASH for (p = Sv_tbl (Sv_ll, i); p ~= LAMBDA; p = q) { q = Sv_mem (p + SV_HLINK) call svfree (Sv_mem (p + SV_NAME)) call svfree (Sv_mem (p + SV_VALUE)) call svfree (p) } Eofchar = Eofsave (Sv_ll) Echar = Esave (Sv_ll) Escchar = Escsave (Sv_ll) Kchar = Ksave (Sv_ll) Nlchar = Nlsave (Sv_ll) Rtchar = Rtsave (Sv_ll) call ctoc (Kresp_save (1, Sv_ll), Kill_resp, MAXKILLRESP) call ctoc (Pdest_save (1, Sv_ll), Prt_dest, MAXPRTDEST) call ctoc (Pform_save (1, Sv_ll), Prt_form, MAXPRTFORM) Sv_ll -= 1 call break$ (ENABLE) return end # svpush --- enter a new shell variable scope level subroutine svpush include SV_COMMON include SWT_COMMON integer i call break$ (DISABLE) Sv_ll += 1 do i = 1, SV_MAXHASH Sv_tbl (Sv_ll, i) = LAMBDA Eofsave (Sv_ll) = Eofchar Esave (Sv_ll) = Echar Escsave (Sv_ll) = Escchar Ksave (Sv_ll) = Kchar Nlsave (Sv_ll) = Nlchar Rtsave (Sv_ll) = Rtchar call ctoc (Kill_resp, Kresp_save (1, Sv_ll), MAXKILLRESP) call ctoc (Prt_dest , Pdest_save (1, Sv_ll), MAXPRTDEST ) call ctoc (Prt_form , Pform_save (1, Sv_ll), MAXPRTFORM ) call break$ (ENABLE) return end # svinit --- initial shell variable tables subroutine svinit include SV_COMMON pointer t Sv_ll = 0 # set up avail list: t = SV_AVAIL Sv_mem (t + SV_SIZE) = 0 Sv_mem (t + SV_LINK) = SV_AVAIL + SV_OHEAD # set up first block of space: t = SV_AVAIL + SV_OHEAD Sv_mem (t + SV_SIZE) = SV_MEMSIZE - SV_OHEAD - 1 # -1 for MEMEND Sv_mem (t + SV_LINK) = LAMBDA # record end of memory: Sv_mem (SV_MEMEND) = SV_MEMSIZE call svpush return end # svdump --- dump shell variable table subroutine svdump (fd) integer fd include SV_COMMON pointer val integer h, i pointer p for (i = 1; i <= Sv_ll; i += 1) { call print (fd, "Scope level *i:*n"p, i) for (h = 1; h <= SV_MAXHASH; h += 1) { call print (fd, " Hash list *i:*n"p, h) for (p = Sv_tbl (i, h); p ~= LAMBDA; p = Sv_mem (p + SV_HLINK)) { call svctmn (Sv_mem (Sv_mem (p + SV_VALUE)), val) call print (fd, "*6i: *s (*i) = *s (*i)*n"p, p, Sv_mem (Sv_mem (p + SV_NAME)), Sv_mem (p + SV_NAME), Sv_mem (val), Sv_mem (p + SV_VALUE)) call svfree (val) } } } return end # svallo --- allocate space for shell variables pointer function svallo (w) integer w include SV_COMMON pointer p, q, l integer n, k n = w + SV_OHEAD q = SV_AVAIL repeat { p = Sv_mem (q + SV_LINK) if (p == LAMBDA) { call break$ (ENABLE) # assume we were called inhibited call signl$ ("NO_SVMEM"v, NULL_PTR, 0, NULL_PTR, 0, 0) } if (Sv_mem (p + SV_SIZE) >= n) break q = p } k = Sv_mem (p + SV_SIZE) - n if (k >= SV_CLOSE) { Sv_mem (p + SV_SIZE) = k l = p + k Sv_mem (l + SV_SIZE) = n } else { Sv_mem (q + SV_LINK) = Sv_mem (p + SV_LINK) l = p } return (l + SV_OHEAD) end # svfree --- return a block of storage to the available space list subroutine svfree (block) pointer block include SV_COMMON pointer p0, p, q integer n p0 = block - SV_OHEAD n = Sv_mem (p0 + SV_SIZE) q = SV_AVAIL repeat { p = Sv_mem (q + SV_LINK) if (p == LAMBDA || p > p0) break q = p } if (q + Sv_mem (q + SV_SIZE) > p0) { call remark ("in svfree: attempt to free unallocated block"p) return # do not attempt to free the block } if (p0 + n == p & p ~= LAMBDA) { n = n + Sv_mem (p + SV_SIZE) Sv_mem (p0 + SV_LINK) = Sv_mem (p + SV_LINK) } else Sv_mem (p0 + SV_LINK) = p if (q + Sv_mem (q + SV_SIZE) == p0) { Sv_mem (q + SV_SIZE) = Sv_mem (q + SV_SIZE) + n Sv_mem (q + SV_LINK) = Sv_mem (p0 + SV_LINK) } else { Sv_mem (q + SV_LINK) = p0 Sv_mem (p0 + SV_SIZE) = n } return end # svmntc --- convert a string with mnemonics to real characters integer function svmntc (value, out) character value (ARB) pointer out include SV_COMMON pointer svallo integer i, j, k character c, mn (4) procedure handle_escape forward procedure handle_function forward out = svallo (length (value) + 1) for ({i = 1; j = 0}; value (i) ~= EOS; i += 1) select (value (i)) when (ESCAPE) handle_escape when (FUNCTION) handle_function else { Sv_mem (out + j) = value (i) j += 1 } Sv_mem (out + j) = EOS return (j) # handle_escape --- process escape sequences procedure handle_escape { if (value (i + 1) ~= EOS) i += 1 select (value (i)) when ('n'c) Sv_mem (out + j) = NEWLINE when ('t'c) Sv_mem (out + j) = TAB else Sv_mem (out + j) = value (i) j += 1 } # handle_function --- process a mnemonic function procedure handle_function { local k, mn, c, l integer k, l character mn (4), c character mntoc for (k = 1; value (i + k) ~= END_FUNC && value (i + k) ~= FUNCTION && value (i + k) ~= EOS && k <= 3; k += 1 ) mn (k) = value (i + k) mn (k) = EOS if (value (i + k) ~= END_FUNC) { Sv_mem (out + j) = value (i) j += 1 } else { l = 1 c = mntoc (mn, l, ERR) if (c == ERR) { Sv_mem (out + j) = value (i) j += 1 } else { Sv_mem (out + j) = c j += 1 i += k } } } end # svctmn --- convert a string of real characters to mnemonics integer function svctmn (in, value) character in (ARB) pointer value include SV_COMMON pointer svallo integer i, j, len character mn (4) character ctomn for ({i = 1; j = 1}; in (i) ~= EOS; i += 1) if (in (i) <= US || in (i) == DEL) j += 5 else j += 1 value = svallo (j) for ({i = 1; j = 0}; in (i) ~= EOS; {i += 1; j += len}) { len = ctomn (in (i), mn) if (len == 1 || in (i) == ' 'c) { if (in (i) == FUNCTION) { Sv_mem (value + j) = ESCAPE j += 1 } elif (in (i) == ' 'c) len = 1 Sv_mem (value + j) = in (i) } else { Sv_mem (value + j) = FUNCTION call ctoc (mn, Sv_mem (value + j + 1), len + 1) Sv_mem (value + len + j + 1) = END_FUNC j += 2 } } Sv_mem (value + j) = EOS return (j) end # svfix --- fix the SWT common blocks after changing a special variable subroutine svfix (name, val, ll) character name (ARB), val (ARB) integer ll include SV_COMMON include SWT_COMMON integer i integer strlsr stringtable pos, text / "_eof" _ / "_erase" _ / "_escape" _ / "_kill" _ / "_kill_resp" _ / "_newline" _ / "_retype" _ / "_prt_dest" _ / "_prt_form" i = strlsr (pos, text, 0, name) if (i == EOF) return select (i - 1) when (1) { Eofchar = val (1) do i = ll, Sv_ll Eofsave (i) = val (1) } when (2) { Echar = val (1) do i = ll, Sv_ll Esave (i) = val (1) } when (3) { Escchar = val (1) do i = ll, Sv_ll Escsave (i) = val (1) } when (4) { Kchar = val (1) do i = ll, Sv_ll Ksave (i) = val (1) } when (5) { call ctoc (val, Kill_resp, MAXKILLRESP) do i = ll, Sv_ll call ctoc (val, Kresp_save (1, i), MAXKILLRESP) } when (6) { Nlchar = val (1) do i = ll, Sv_ll Nlsave (i) = val (1) } when (7) { Rtchar = val (1) do i = ll, Sv_ll Rtsave (i) = val (1) } when (8) { call ctoc (val, Prt_dest, MAXPRTDEST) do i = ll, Sv_ll call ctoc (val, Pdest_save (1, ll), MAXPRTDEST) } when (9) { call ctoc (val, Prt_form, MAXPRTFORM) do i = ll, Sv_ll call ctoc (val, Pform_save (1, ll), MAXPRTFORM) } return end # svgetl --- get an arbitrarily long line from fd integer function svgetl (ptr, fd) pointer ptr file_des fd include SV_COMMON pointer tptr integer getlin pointer svallo integer len, pos character buf (MAXLINE) pos = 1 ptr = svallo (pos) Sv_mem (ptr) = EOS repeat { len = getlin (buf, fd) if (len == EOF) return (EOF) tptr = svallo (pos + len) call ctoc (Sv_mem (ptr), Sv_mem (tptr), pos) call ctoc (buf, Sv_mem (tptr + pos - 1), len) call svfree (ptr) ptr = tptr pos += len } until (buf (len) == NEWLINE) return (pos - 1) end # svlevl --- return the current shell variable lexic level integer function svlevl (level) integer level include SV_COMMON level = Sv_ll return (Sv_ll) # not much to do end undefine (NULL_PTR) undefine (FUNCTION) undefine (END_FUNC)