# lf --- list files include LIBRARY_DEFS include PRIMOS_KEYS include PRIMOS_ERRD include "lf_def.r.i" include "lf_com.r.i" integer argp, code, save_argp integer getarg, follow, tscan$, finfo$, compare, expand, equal, ctoi pointer entry pointer dsget procedure do_dir forward procedure do_file forward procedure end_line forward procedure enter_entry forward procedure get_options forward procedure get_owner forward procedure get_size forward procedure print_tree forward get_options # parse command line options call dsinit (MEMSIZE) # initialize dynamic storage Root = LAMBDA # sort tree is initially empty Col = 1 # next output Column save_argp = argp for (Pl = getarg (argp, Parent, MAXPATH); Pl ~= EOF; {argp += 1; Pl = getarg (argp, Parent, MAXPATH)}) { call at$hom (code) if (Opts (DIRECTORY) || follow (Parent, 0) == ERR) do_file else do_dir } if (argp == save_argp) { # no args, list current directory Parent (1) = EOS Pl = 0 do_dir } # do_dir --- print contents of current directory procedure do_dir { local name character name (65) if (Opts (LABEL)) call print (STDOUT, "-- *s --*n"s, Parent) Level = 0 repeat { entry = dsget (NODESIZE) select (tscan$ (Parent, E_ecw (entry), Level, Max_level, PREORDER)) when (EOF) { call dsfree (entry) break } when (OK) { if ( ~Opts (ALL_FILES) && rs (E_name (entry), 8) == '.'c) { call dsfree (entry) next } if (Opts (WORDS)) get_size if (Opts (OWNER) || Opts (PASSWORD)) get_owner if (Opts (SUBTREE) || Opts (NOSORT)) { if (Opts (FULLNAME)) call put_entry (entry, Parent) else { call upkfn$ (E_name (entry), 32, name, 65) call put_entry (entry, name) } call dsfree (entry) } else enter_entry } else call dsfree (entry) } # repeat if (~ Opts (SUBTREE)) { if (~ Opts (NOSORT)) print_tree end_line } } # do_file --- print information for a single file procedure do_file { local attach, code, name integer attach, code character name (65) entry = dsget (NODESIZE) if (finfo$ (Parent, E_ecw (entry), attach) == OK) { if (Opts (WORDS)) get_size if (Opts (OWNER)) get_owner if (Opts (FULLNAME)) call put_entry (entry, Parent) else { call upkfn$ (E_name (entry), 32, name, 65) call put_entry (entry, name) } end_line if (attach ~= NO) call at$hom (code) } else call print (ERROUT, "*s: not found*n"s, Parent) call dsfree (entry) } # end_line --- terminate partially filled output line procedure end_line { if (Col > 1) { call putch (NEWLINE, STDOUT) Col = 1 } } # enter_entry --- insert entry into tree procedure enter_entry { local p, last_p, use_left pointer p, last_p bool use_left E_llink (entry) = LAMBDA E_rlink (entry) = LAMBDA if (Root == LAMBDA) Root = entry else { for (p = Root; p ~= LAMBDA; ) { last_p = p use_left = (compare (Mem (entry + Keypos), Mem (p + Keypos), Keylen) < 0) if (Opts (REVERSE)) use_left = ~ use_left if (use_left) p = E_llink (p) else p = E_rlink (p) } if (use_left) E_llink (last_p) = entry else E_rlink (last_p) = entry } } # get_options --- process option flags for lf procedure get_options { local i, key, kp, kl, arg character arg (MAXLINE) integer kp, kl, i bool key Opts (ALL_FILES) = FALSE # -a Opts (COLUMNAR) = FALSE # -c Opts (DIRECTORY) = FALSE # -d Opts (DUMPED) = FALSE # -u Opts (FILETYPE) = FALSE # -t Opts (FULLNAME) = FALSE # -f Opts (LABEL) = FALSE # -v Opts (LOCK) = FALSE # -k Opts (OWNER) = FALSE # -o Opts (PASSWORD) = FALSE # -q Opts (PROTECTIONS) = FALSE # -p Opts (REVERSE) = FALSE # -r Opts (SUBTREE) = FALSE # -s Opts (TIMEDATE) = FALSE # -m Opts (WORDS) = FALSE # -w Opts (NOSORT) = FALSE # -n if (expand ("=GaTech="s, arg, MAXLINE) == ERR || equal (arg, "yes"s) == NO) Opts (SECURITY) = FALSE else Opts (SECURITY) = TRUE Max_level = 1 Keypos = NAMEPOS Keylen = 16 for (argp = 1; getarg (argp, arg, MAXLINE) ~= EOF; argp += 1) { if (arg (1) ~= '-'c) break for (i = 2; arg (i) ~= EOS; i += 1) { if (arg (i) == '/'c || arg (i) == '\'c) { if (arg (i + 1) ~= EOS) { Opts (REVERSE) = (arg (i) == '\'c) i += 1 key = TRUE } else break } else key = FALSE kp = NAMEPOS kl = 16 select (arg (i)) when ('a'c) Opts (ALL_FILES) = TRUE when ('c'c) Opts (COLUMNAR) = TRUE when ('d'c) Opts (DIRECTORY) = TRUE when ('f'c) Opts (FULLNAME) = TRUE when ('k'c) Opts (LOCK) = TRUE when ('l'c) { Opts (FILETYPE) = TRUE Opts (PROTECTIONS) = TRUE Opts (TIMEDATE) = TRUE Opts (LOCK) = TRUE Opts (DUMPED) = TRUE Opts (WORDS) = TRUE Opts (OWNER) = TRUE } when ('m'c) { Opts (TIMEDATE) = TRUE kp = DTMPOS kl = 2 } when ('n'c) Opts (NOSORT) = TRUE when ('o'c) { Opts (OWNER) = TRUE kp = OWNERPOS kl = 3 } when ('p'c) { Opts (PROTECTIONS) = TRUE kp = PROPOS kl = 1 } when ('q'c) Opts (PASSWORD) = TRUE when ('r'c) Opts (REVERSE) = TRUE when ('s'c) { Opts (SUBTREE) = TRUE i += 1 Max_level = ctoi (arg, i) i -= 1 } when ('t'c) Opts (FILETYPE) = TRUE when ('u'c) Opts (DUMPED) = TRUE when ('v'c) Opts (LABEL) = TRUE when ('w'c) { Opts (WORDS) = TRUE kp = SIZEPOS kl = 2 } if (key) { Keypos = kp Keylen = kl } } } if (Max_level <= 0) Max_level = MAX_INTEGER } # get_owner --- determine owner of a directory procedure get_owner { local i integer i if (and (E_filtyp (entry), 7) == 4) { call gpas$$ (E_name (entry), 32, E_owner (entry), E_passwd (entry), code) if (code ~= 0) do i = 0, 2; { E_owner (entry + i) = " " E_passwd (entry + i) = " " } } else do i = 0, 2; { E_owner (entry + i) = " " E_passwd (entry + i) = " " } } # get_size --- determine size of named file procedure get_size { local fd, typ, code integer fd, typ, code call srch$$ (KREAD + KGETU, E_name (entry), 32, fd, typ, code) if (code == 0) { call fsize (fd, and (typ, 7), E_fsize (entry)) call srch$$ (KCLOS, 0, 0, fd, typ, code) } else { E_fsize (entry) = 0 E_fsize1 (entry) = 0 } } # print_tree --- do inorder traversal of tree, printing each node procedure print_tree { local i integer i if (Root ~= LAMBDA) { if (Opts (FULLNAME)) { i = Pl + 1 if (Pl > 0 && Parent (Pl) ~= '\'c) { Parent (i) = '/'c i += 1 } } else i = 1 call print_sub_tree (Root, Parent, i) } } stop end # compare --- compare strings of length len integer function compare (s1, s2, len) integer s1 (ARB), s2 (ARB), len integer i compare = 0 do i = 1, len; { compare = rt (intl (s1 (i)), 16) - rt (intl (s2 (i)), 16) if (compare ~= 0) break } return end # fsize --- find length of a file subroutine fsize (fd, typ, size) integer fd, typ longint size integer rc, entrya, entryb size = 0 if (typ == 2 || typ == 3) { call sgdr$$ (KGOND, fd, entrya, entryb, rc) if (rc == 0) size = entryb * 2 } else { if (typ == 4) { repeat call rden$$ (KUPOS, fd, loc (0), 0, 0, 100000, 0, rc) until (rc ~= 0) } else { repeat call prwf$$ (KPOSN, fd, loc (0), 0, 100000, 0, rc) until (rc ~= 0) } if (rc ~= EEOF) return if (typ == 4) { call rden$$ (KGPOS, fd, loc (0), 0, 0, size, 0, rc) size += 1 } else call prwf$$ (KRPOS, fd, loc (0), 0, size, 0, rc) } return end # print_sub_tree --- handle a single sub_tree subroutine print_sub_tree (ptr, prefix, i) pointer ptr character prefix (ARB) integer i include "lf_com.r.i" if (E_llink (ptr) ~= LAMBDA) # do left-hand sub-tree call print_sub_tree (E_llink (ptr), prefix, i) call upkfn$ (E_name (ptr), 32, prefix (i), MAXPATH - i + 1) call put_entry (ptr, prefix) if (E_rlink (ptr) ~= LAMBDA) # do right-hand sub-tree call print_sub_tree (E_rlink (ptr), prefix, i) call dsfree (ptr) # release space used by this subtree ptr = LAMBDA return end # put_entry --- print a file entry with all requested information subroutine put_entry (entry, name) pointer entry character name (ARB) include "lf_com.r.i" integer i, j, k, tmp, tmp2 integer scopy, encode, length character buf (MAXLINE) k = 1 # next free position in buf ### Build file type string if requested: if (Opts (FILETYPE)) { if (and (E_filtyp (entry), SPECIAL_FILE) ~= 0) call scopy ("spc "s, 1, buf, k) else select (and (E_filtyp (entry), 7)) when (0) # SAM file call scopy ("sam "s, 1, buf, k) when (1) # DAM file call scopy ("dam "s, 1, buf, k) when (2) # SAM segment directory call scopy ("sgs "s, 1, buf, k) when (3) # DAM segment directory call scopy ("sgd "s, 1, buf, k) when (4) # UFD call scopy ("ufd "s, 1, buf, k) when (6) # Access Category call scopy ("act "s, 1, buf, k) else # unknown type call scopy ("??? "s, 1, buf, k) k += 4 } ### Build protections string if requested: if (Opts (PROTECTIONS)) { call scopy (" / "s, 1, buf, k) tmp = E_protec (entry) i = k + 2 if (and (tmp, 8r3400) == 8r3400) buf (i) = 'a'c else { if (and (tmp, 8r400) ~= 0) { buf (i) = 'r'c i -= 1 } if (and (tmp, 8r1000) ~= 0) { buf (i) = 'w'c i -= 1 } if (and (tmp, 8r2000) ~= 0) buf (i) = 't'c } i = k + 4 if (and (tmp, 7) == 7) buf (i) = 'a'c else { if (and (tmp, 4) ~= 0) { buf (i) = 't'c i += 1 } if (and (tmp, 2) ~= 0) { buf (i) = 'w'c i += 1 } if (and (tmp, 1) ~= 0) buf (i) = 'r'c } buf (k + 7) = ' 'c k += 8 } ### Build modification time/date string if requested: if (Opts (TIMEDATE)) { tmp = E_datmod (entry) tmp2 = E_timmod (entry) k += encode (buf (k), 19, "*2,,0u*i/*i/*i *i:*i:*i "s, and (rs (tmp, 5), 8r17), # month and (tmp, 8r37), # day rs (tmp, 9), # year tmp2 / 900, # hours mod (tmp2 / 15, 60), # minutes mod (tmp2, 15) * 4) # seconds } ### Build owner string if requested: if (Opts (OWNER)) k += encode (buf (k), 8, "*7,6h"s, E_owner (entry)) ### Build password string if requested: if (Opts (PASSWORD)) k += encode (buf (k), 8, "*7,6h"s, E_passwd (entry)) ### Build file size string if requested: if (Opts (WORDS)) k += encode (buf (k), 10, "*8l "s, E_fsize (entry)) ### Build read/write lock string if requested: if (Opts (LOCK)) { select (and (E_filtyp (entry), RWLOCK)) when (0) # default call scopy ("sys "s, 1, buf, k) when (LOCK1) # n readers or 1 writer call scopy ("n-1 "s, 1, buf, k) when (LOCK2) # n readers and 1 writer call scopy ("n+1 "s, 1, buf, k) else # n readers and n writers call scopy ("n+n "s, 1, buf, k) k += 4 } ### Indicate status of "dumped" bit if requested: if (Opts (DUMPED)) { if (and (E_filtyp (entry), DUMPED_BIT) ~= 0) buf (k) = 'd'c else buf (k) = ' 'c if (and (E_filtyp (entry), MODIFIED_BIT) ~= 0) buf (k + 1) = 'm'c else buf (k + 1) = ' 'c buf (k + 2) = ' 'c k += 3 } ### Include length of name in buffer size: buf (k) = EOS k += length (name) ### Now print out requested information about the file: if (~ Opts (COLUMNAR)) { if (Opts (SUBTREE)) { for (i = 1; i < Level; i += 1) # do indentation call putlin ("| "s, STDOUT) call putlin (buf, STDOUT) call putlin (name, STDOUT) call putch (NEWLINE, STDOUT) } else { if (Col > 1) { j = Col _ # current cursor position + 1 _ # one blank between file names + TAB_WIDTH - 1 # to get to or beyond next tab stop j -= mod (j, TAB_WIDTH) - 1 # back to the tab stop if (j + k - 1 <= OUTPUT_WIDTH) { while (Col < j) { call putch (' 'c, STDOUT) Col += 1 } } else { call putch (NEWLINE, STDOUT) Col = 1 } } call putlin (buf, STDOUT) call putlin (name, STDOUT) Col += k - 1 } } else { # Opts (COLUMNAR) call putlin (buf, STDOUT) call putlin (name, STDOUT) call putch (NEWLINE, STDOUT) } return end