# bnames --- print entry point names in object files

   include "bnames_def.r.i"

   character name (MAXLINE)
   integer state (4)
   integer gfnarg
   filedes fd
   filedes open

   procedure do_file (fd) forward

   state (1) = 1
   repeat
      select (gfnarg (name, state))
         when (EOF)
            break
         when (OK) {
            fd = open (name, READ)
            if (fd == ERR)
               call cant (name)
            do_file (fd)
            call close (fd)
            }

   stop


   # do_file --- list entry points in one object file

      procedure do_file (fd) {
      filedes fd

      local name
      character name (MAXLINE)
      integer get_module

      while (get_module (fd, name) ~= EOF)
         call print (STDOUT, "*s*n"s, name)

      }

   end


# get_module --- return name, file offset and size of next module

   integer function get_module (fd, name)
   filedes fd
   character name (MAXLINE)

   integer buf (MAXBUF), len
   integer rdbin, has_procdef, get_name

   procedure skip_to_end forward

   repeat {
      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) {
               if (get_name (buf, name, MAXLINE) == NO) {
                  call scopy (".main"s, 1, name, 1)
                  for (len = rdbin (fd, buf, MAXBUF);
                        BLOCK_TYPE (buf) ~= END_BLOCK;
                        len = rdbin (fd, buf, MAXBUF))
                     if (BLOCK_TYPE (buf) == PREFIX_BLOCK && getname (buf, name, MAXLINE) == YES)
                        break
                  }
               if (BLOCK_TYPE (buf) ~= END_BLOCK)
                  skip_to_end
               return (OK)
               }
            elif (BLOCK_SIZE (buf) == 2)
               select (buf (2))
                  when (RFL_GROUP)
                     call scopy (".rfl"s, 1, name, 1)
                  when (SFL_GROUP)
                     call scopy (".sfl"s, 1, name, 1)
                  ifany
                     return (OK)
            # else ignore the block
            }
         when (DATA_BLOCK) {  # Fortran blockdata
            call scopy (".data"s, 1, name, 1)
            skip_to_end
            return (OK)
            }
         when (END_BLOCK)
            call err (fd, "extraneous END block"s)
      else
         call err (fd, "bad object file (unrecognized block type)"s)
      }

   # skip_to_end --- find next END block in object file

      procedure skip_to_end {

      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)
         } 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


# 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


# 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
