PROCEDURE (ram$discc) display_catalog_content, discc, display_file_sizes, disfs (
  catalog, c: file = $working_catalog
  output, o: file = $output
  depth, d: any of
      key
        all
      keyend
      integer 1..$max_integer
    anyend = 2
  display_option, do: key
      (cycles, cycle, c)
      (descriptor, d)
      (files, f)
      (log, l)
      (permits, permit, p)
      (subcatalogs, s)
    keyend = cycles
  exclude_catalog, exclude_catalogs, ec: (BY_NAME, ADVANCED) list 0..$max_list of string = ()
  exclude_file, exclude_files, ef: (BY_NAME, ADVANCED) list 0..$max_list of string = ()
  include_catalog, include_catalogs, ic: (BY_NAME, ADVANCED) list 0..$max_list of string = ()
  include_file, include_files, if: (BY_NAME, ADVANCED) list 0..$max_list of string = ()
  prefix_string, ps: (BY_NAME, ADVANCED) string = ''
  suffix_string, ss: (BY_NAME, ADVANCED) string = ''
  status)

" PURPOSE:
"   Display the content/structure of a catalog.
" DESIGN:
"   Display all files meeting the criteria selected by parameter values. String values for INCLUDE or EXCLUDE
"   parameters are processed as substrings of the file or catalog names, allowing similarly named files or
"   catalogs to be selected or excluded.  Display option parameter values select the type of information to be
"   displayed for each file and/or catalog.  The depth parameter limits the number of subcatalogs displayed,
"   and to what depth this procedure recurses.  The prefix and suffix strings can be used to form command or
"   procedure calls for subsequent include_file processing.

  VAR
    attributes : file = $unique(:$local)
    attributes_list : list 0..$max_list of string
    delete_status : status
    files : list 0..$max_list of file = ()
    ignore : status
    last_path : string 1..31 = ' '
    line : string
    subcatalogs : list 0..$max_list of file = ()
  VAREND

  WHEN exit DO
    delete_file file=attributes status=ignore
  WHENEND

  IF $nil(include_file) THEN " select the list of all files "
    files=$catalog_contents(catalog, include_files, paths)
  ELSE " accumulate a list of files with the include_file strings present "
    FOR EACH included_file IN include_file DO
      files=$union(files, $select($catalog_contents(catalog, include_files, paths), ..
            $scan_string($translate(ltu, included_file), ' '//$path(x, last)//' ')<>0))
    FOREND
  IFEND
  FOR EACH excluded_file IN exclude_file DO " select only those files missing the exclude_file string "
    files=$select(files, $scan_string($translate(ltu, excluded_file), ' '//$path(x, last)//' ')=0)
  FOREND

  set_file_attributes file=attributes page_format=continuous file_contents=legible
  IF $file(output, assigned) THEN " format display for output file page width
    display_file_attributes file=output output=attributes.$boi do=page_width
    get_lines variable=line input=attributes.$boi
    delete_file file=attributes
    set_file_attributes file=attributes page_format=continuous file_contents=legible ..
          page_width=$integer(line($scan_string(':', line)+1, all))
  IFEND

  IF (display_option = cycles) AND (depth = 1) THEN
    $system.display_catalog catalog=catalog output=attributes.$boi do=content depth=1
    get_lines variable=line input=attributes.$boi
    put_line line=' CATALOG: '//$path(catalog, catalog)//'.'//$justify($path(catalog, last), 31, left)//..
line($scan_string(' ', line), all) output=output.$eoi
  ELSEIF display_option = permits THEN
    $system.display_catalog catalog=catalog output=attributes.$boi do=display_option
    get_lines variable=attributes_list input=attributes.$boi
    put_line line=(' ', ' CATALOG: '//catalog) output=output.$eoi
    put_line line=$apply(attributes_list, '    '//x) output=output.$eoi
  ELSEIF (display_option <> files) AND (display_option <> subcatalogs) THEN
    put_line line=(' ', ' CATALOG: '//catalog) output=output.$eoi
  IFEND

  IF $generic_type(depth)= 'INTEGER' THEN " decrement depth counter, to limit recursion"
    EXIT_PROC WHEN depth = 1
    depth=depth - 1
  IFEND

  IF display_option <> subcatalogs THEN
    FOR EACH filename IN files DO " process the list of file names "
      IF display_option = files THEN
        put_line line=$apply($file_cycles(filename, paths), ' '//ps//' '//$string(x)//' '//ss) output=output.$eoi
      ELSEIF display_option = cycles THEN
        $system.display_catalog_entry file=filename output=attributes.$boi do=cycles depth=2 status=ignore
        IF NOT ignore.normal THEN
          put_line line=$path(filename, last)//' '//$file(filename, size)//' bytes' output=attributes.$boi
        IFEND
        get_lines variable=attributes_list input=attributes.$boi
        FOR EACH attribute IN attributes_list DO
          blank=$scan_string(' ', attribute)
          bytes=$scan_string('bytes', attribute)
          IF bytes = 0 THEN
            put_line line='          '//attribute(1, blank)//' '//attribute(blank, all) output=output.$eoi
          ELSEIF attribute(1, blank) = '--' THEN
            aligned=$justify(attribute(blank, bytes-blank), 43, right)
            put_line line='          '//attribute(1, blank)//aligned//attribute(bytes, all) output=output.$eoi
          ELSE
            numbers=$scan_any('0123456789', attribute(blank, bytes-blank)) + blank - 1
            aligned=$justify(attribute(numbers, bytes-numbers), 15, right)
            put_line line='    FILE: '//$justify(attribute(1, blank), 31, left)//aligned//..
attribute(bytes, all) output=output.$eoi
          IFEND
          EXIT WHEN depth <= 2
        FOREND
      ELSE
        CYCLE WHEN last_path = $path(filename, last)
        IF $string(catalog)= ':$LOCAL' THEN
          put_line line=('    FILE: '//$path(filename, last)) output=output.$eoi
        ELSE
          put_line line=('    FILE: '//filename) output=output.$eoi
        IFEND
        $system.display_catalog_entry file=filename output=attributes.$boi do=display_option
        get_lines variable=attributes_list input=attributes.$boi
        put_line line=$apply(attributes_list, '    '//x) output=output.$eoi
        last_path=$path(filename, last)
      IFEND
    FOREND
  IFEND

  IF $nil(include_catalog) THEN " select the list of all catalogs "
    subcatalogs=$catalog_contents(catalog, include_catalogs, paths)
  ELSE " accumulate a list of catalogs with the include_catalog strings present "
    FOR EACH included IN include_catalog DO
      subcatalogs=$union(subcatalogs, $select($catalog_contents(catalog, include_catalogs, paths), ..
            $scan_string($translate(ltu, included), ' '//$path(x, last)//' ')<>0))
    FOREND
  IFEND

  FOR EACH excluded IN exclude_catalog DO " select catalogs missing the exclude_catalog string "
    subcatalogs=$select(subcatalogs, $scan_string($translate(ltu, excluded), ' '//$path(x, last)//' ')=0)
  FOREND

  IF display_option = 'SUBCATALOGS' THEN
    put_line line=$apply(subcatalogs, ' '//ps//' '//$string(x)//' '//ss) output=output.$eoi
    EXIT_PROC WHEN depth = 1
  IFEND

  FOR EACH subcatalog IN subcatalogs DO " recurse to process each subcatalog "
    IF (display_option = cycles) AND (depth = 1) THEN
      $system.display_catalog subcatalog output=attributes.$boi do=content depth=1
      get_lines variable=line input=attributes.$boi
      blank=$scan_string(' ', line)
      bytes=$scan_string('bytes', line)
      put_line line='  ' output=output.$eoi
      IF bytes = 0 THEN
        put_line line=' CATALOG: '//$path(subcatalog, catalog)//'.'//$justify($path(subcatalog, last), 31, ..
              left)//line(blank, all) output=output.$eoi
      ELSE
        aligned=$justify(line(blank, bytes-blank), 15, right)
        put_line line=' CATALOG: '//$path(subcatalog, catalog)//'.'//$justify($path(subcatalog, last), 31, ..
              left)//aligned//line(bytes, all) output=output.$eoi
      IFEND
    ELSE
      $source.display_catalog_content catalog=subcatalog o=output d=depth do=display_option ef=exclude_file ..
            ec=exclude_catalog ic=include_catalog if=include_file ps=prefix_string ss=suffix_string
    IFEND
  FOREND

PROCEND display_catalog_content
