# bmerge --- merge multiple object files into one include "bmerge_def.r.i" character arg (MAXARG), name (MAXNAME) integer i, nfiles, node (TNODESIZE) integer getarg, input, lookup, equal filedes ofd (MAXFILES) filedes open pointer table pointer mktabl call dsinit (MEMSIZE) for (i = 1; getarg (i, arg, MAXARG) ~= EOF; i += 1) { if (i > MAXFILES) { call print (ERROUT, "*s: too many object files*n"s, arg) call error (""s) } ofd (i) = open (arg, READ) if (ofd (i) == ERR) call cant (arg) } nfiles = i - 1 if (nfiles <= 0) stop table = mktabl (TNODESIZE) do i = 1, nfiles call load_table (ofd (i), table) while (input (STDIN, "*,#s"s, MAXNAME, name) ~= EOF) { call mapstr (name, LOWER) select when (equal (name, ".rfl"s) == YES) call wrbin (STDOUT, RFL_BLOCK, 2) when (equal (name, ".sfl"s) == YES) call wrbin (STDOUT, SFL_BLOCK, 2) when (lookup (name, node, table) == YES) { call output_module (node) call delete_module (name, node, table) } else call print (ERROUT, "*s: not found in object files*n"s, name) } call wrbin (STDOUT, 0, 0) # terminate object file stop end # load_table --- build the symbol table for an object file subroutine load_table (fd, table) filedes fd pointer table character name (MAXLINE) filemark addr integer size integer get_module while (get_module (fd, name, addr, size) ~= EOF) call enter_module (table, name, addr, size, fd) return end # get_module --- return name, file offset and size of next module integer function get_module (fd, name, addr, size) filedes fd character name (MAXNAME) filemark addr integer size integer buf (MAXBUF), len, kludge_size integer rdbin, has_procdef, get_name filemark markf procedure get_size forward repeat { addr = markf (fd) len = rdbin (fd, buf, MAXBUF) if (len == 0 || len == EOF) return (EOF) if (len < 0 || len ~= BLOCK_SIZE (buf)) call err (fd, "bad object file (block size mismatch)"s) select (BLOCK_TYPE (buf)) when (PREFIX_BLOCK) { if (has_procdef (buf) == YES) { kludge_size = 0 size = 1 # kludge if (get_name (buf, name, MAXLINE) == NO) { call scopy (".main"s, 1, name, 1) for ({len = rdbin (fd, buf, MAXBUF);kludge_size += 1}; BLOCK_TYPE (buf) ~= END_BLOCK; {len = rdbin (fd, buf, MAXBUF);kludge_size += 1}) if (BLOCK_TYPE (buf) == PREFIX_BLOCK && getname (buf, name, MAXLINE) == YES) break } if (BLOCK_TYPE (buf) ~= END_BLOCK) get_size size += kludge_size return (OK) } # else ignore the block } when (DATA_BLOCK) { # Fortran blockdata call scopy (".data"s, 1, name, 1) get_size return (OK) } when (END_BLOCK) call err (fd, "extraneous END block"s) else call err (fd, "bad object file (unrecognized block type)"s) } # get_size --- count the number of object blocks in a module procedure get_size { size = 1 repeat { len = rdbin (fd, buf, MAXBUF) select when (len == 0) ; when (len < 0 || len == EOF) call err (fd, "bad object file (premature EOF)"s) when (len ~= BLOCK_SIZE (buf)) call err (fd, "bad object file (block size mismatch)"s) when (BLOCK_TYPE (buf) ~= PREFIX_BLOCK && BLOCK_TYPE (buf) ~= DATA_BLOCK && BLOCK_TYPE (buf) ~= END_BLOCK) call err (fd, "bad object file (bad block type)"s) size += 1 } until (len == 0 || BLOCK_TYPE (buf) == END_BLOCK) } end # has_procdef --- search an object block for a PROCDEF group integer function has_procdef (buf) integer buf (ARB) integer len, i len = BLOCK_SIZE (buf) for (i = 1; i < len; i += GROUP_SIZE (buf (i + 1)) + 1) if (GROUP_TYPE (buf (i + 1)) == PROCDEF) return (YES) return (NO) end # get_name --- search an object block for an entry point name integer function get_name (buf, name, size) integer buf (ARB), size character name (size) integer len, i len = BLOCK_SIZE (buf) for (i = 1; i < len; i += GROUP_SIZE (buf (i + 1)) + 1) select (GROUP_TYPE (buf (i + 1))) when (ENTABS, ENTREL, ENTLB, ENTLBA) call ptoc (buf (i + 3), ' 'c, name, min0 (size, GROUP_SIZE (buf (i + 1)) * 2 - 1)) when (DYNT) call ptoc (buf (i + 2), ' 'c, name, min0 (size, GROUP_SIZE (buf (i + 1)) * 2 + 1)) ifany { call mapstr (name, LOWER) return (YES) } return (NO) end # enter_module --- add a module to the symbol table subroutine enter_module (table, name, addr, size, fd) pointer table character name (ARB) integer addr (2), size, fd DS_DECL (Mem, MEMSIZE) integer node (TNODESIZE) integer lookup pointer ptr pointer dsget ptr = dsget (MNODESIZE) Mem (ptr + SIZE) = size Mem (ptr + FILE) = fd Mem (ptr + ADDR + 0) = addr (1) Mem (ptr + ADDR + 1) = addr (2) Mem (ptr + LINK) = LAMBDA if (lookup (name, node, table) == YES) Mem (node (TAIL) + LINK) = ptr else node (HEAD) = ptr node (TAIL) = ptr call enter (name, node, table) return end # err --- print file name and error message, then croak subroutine err (fd, msg) filedes fd character msg (ARB) character name (MAXPATH) call gfnam$ (fd, name, MAXPATH) call print (ERROUT, "*s: *s*n"s, name, msg) call seterr (1000) stop end # output_module --- copy module from an input file to STDOUT subroutine output_module (node) integer node (TNODESIZE) DS_DECL (Mem, MEMSIZE) pointer p integer buf (MAXBUF), i, len integer rdbin p = node (HEAD) call seekf (Mem (p + ADDR), Mem (p + FILE), ABS) for (i = 1; i <= Mem (p + SIZE); i += 1) { len = rdbin (Mem (p + FILE), buf, MAXBUF) if (len <= 0 || len == EOF) call err (Mem (p + FILE), "error copying object module"s) call wrbin (STDOUT, buf, len) } return end # delete_module --- remove a module from the symbol table subroutine delete_module (name, node, table) character name (ARB) integer node (TNODESIZE) pointer table DS_DECL (Mem, MEMSIZE) pointer p p = node (HEAD) if (Mem (p + LINK) == LAMBDA) # last module in list? call delete (name, table) else { node (HEAD) = Mem (p + LINK) call enter (name, node, table) } return end # rdbin --- Subsystem-compatible binary input driver integer function rdbin (fd, buf, count) integer fd, buf (ARB), count integer ct longint pos integer readf, seekf rdbin = EOF if (readf (ct, 1, fd) ~= 1) return if (ct > count) { pos = ct - count call print (ERROUT, "block size (*i) exceeds buffer space*n"s, ct) ct = count } else pos = 0 if (readf (buf, ct, fd) ~= ct) return if (pos ~= 0 && seekf (pos, fd, REL) ~= OK) return return (ct) end # wrbin --- Subsystem-compatible binary output driver integer function wrbin (fd, buf, count) integer fd, buf (ARB), count integer writef wrbin = ERR if (writef (count, 1, fd) ~= 1 || writef (buf, count, fd) ~= count) return return (OK) end