?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE : Loader : Library list management' ??
MODULE lom$library_list_management;

{  PURPOSE:
{    This module contains procedures which manage the library_list.  The library_list identifies
{    (and contains descriptive information about) all libraries which are to be used to satisfy
{    module and external references.  The order in which libraries appear in the list determines
{    the order in which they will be searched to satisfy module and external references.  Libraries
{    can be included in the list by four means and are classified accordingly:
{        - Execute libraries are specified via the object_library_list on a program load
{          request.
{        - Text_embedded libraries are specified via an interpretive text record encountered
{          by the loader as a module is loaded.
{        - Job libraries are copied from the job_library_list.  (This list is managed via a
{          'change_job_library_list' interface and applies to all program loads in a job.
{        - Debug libraries are copied from the debug_library_list.  (This list is managed via a
{          'change_debug_library_list' interface and applies to all program loads in a job.
{    The library_list is maintained for the duration of a task and is used to satisfy external
{    references arising from dynamic load requests.

{  NOTE:
{    Condition raised: LOE$LOADER_MALFUNCTION.

?? NEWTITLE := '  Global declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cyd$run_time_error_condition
*copyc lle$loader_status_conditions
*copyc llt$entry_point_dictionary
*copyc llt$module_dictionary
*copyc llt$object_library_header
*copyc loc$deferred_entry_pt_library
*copyc loc$task_services_library_name
*copyc loe$abort_load
*copyc lot$deferred_library_list
*copyc lot$loader_type_definitions
*copyc oss$job_paged_literal
*copyc ost$status
*copyc pme$execution_exceptions
?? POP ??
*copyc lop$augment_lib_list_container
*copyc lop$build_file_descriptor
*copyc lop$report_error
*copyc osp$generate_message
*copyc osp$set_status_abnormal
*copyc osp$set_status_from_condition
*copyc pmp$cause_condition
*copyc pmp$continue_to_cause
*copyc pmp$establish_condition_handler
*copyc pmp$exit
*copyc lov$file_descriptors
*copyc lov$head_of_unsat_ref_list
*copyc lov$library_list
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  TYPE
    library_counts_type = record
      execute_libs: integer,
      embedded_libs: integer,
      job_libs: integer,
    recend;

  VAR
    library_counts: [STATIC] library_counts_type := [0, 0, 0];

?? OLDTITLE ??
?? NEWTITLE := '  [INLINE] adjust_library_searched ', EJECT ??

  PROCEDURE adjust_library_searched
    (    highest_library_number: integer);

    VAR
      unsatisfied_reference: ^lot$unsatisfied_reference_list;

    IF (lov$head_of_unsat_ref_list = NIL) OR (lov$head_of_unsat_ref_list^.f_link = lov$head_of_unsat_ref_list)
          THEN
      RETURN;
    IFEND;

    unsatisfied_reference := lov$head_of_unsat_ref_list^.f_link;

    WHILE unsatisfied_reference <> lov$head_of_unsat_ref_list DO
      IF unsatisfied_reference^.library_searched >= highest_library_number THEN
        unsatisfied_reference^.library_searched := highest_library_number;
      IFEND;

      unsatisfied_reference := unsatisfied_reference^.f_link;
    WHILEND;

  PROCEND adjust_library_searched;

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] lop$activate_library', EJECT ??

  PROCEDURE [XDCL] lop$activate_library
    (    library_name: amt$local_file_name);

{  PURPOSE:
{    This procedure adds a phantom library to the library_list at the head of the list.  The library
{    is set active so that subsequent searches of the library list for entry points will use this
{    library.  The intent is that after a given search the library will be set inactive so that the
{    user is not aware of the library.  This is for use only by the operating system and must be used
{    in conjunction with the procedure LOP$DEACTIVATE_LIBRARY.

    VAR
      library: ^lot$library_descriptor,
      library_in_list: boolean,
      predecessor_forward_link: ^^lot$library_descriptor;

    IF library_name = osc$null_name THEN
      RETURN;
    IFEND;

{!  Temporary until PSR CILA170 is answered.

    IF lov$library_list.link_to_first_job_library = NIL THEN
      lov$library_list.link_to_first_job_library := ^lov$library_list.first;
    IFEND;

{!  End temporary.

    predecessor_forward_link := ^lov$library_list.first;

  /add_library/
    BEGIN
      lop$find_library_descriptor (library_name, library, library_in_list);
      IF library_in_list THEN
        IF library^.phantom_library THEN
          library^.phantom_library_active := TRUE;
        IFEND;
      ELSE;

        add_library_to_list (library_name, {deferred_library_segment} 0, predecessor_forward_link^,
              library_in_list);
        IF NOT library_in_list THEN
          EXIT /add_library/;
        IFEND;

        library_counts.execute_libs := library_counts.execute_libs + 1;

        IF (library_name <> loc$task_services_library_name) AND
              (library_name (1, loc$deferred_entry_pt_lib_size) <> loc$deferred_entry_pt_library) THEN
          predecessor_forward_link^^.segment := NIL;
          predecessor_forward_link^^.attributes.name := library_name;
          predecessor_forward_link^^.library_open := FALSE;
          predecessor_forward_link^^.library_valid := TRUE;
          predecessor_forward_link^^.phantom_library := TRUE;
          predecessor_forward_link^^.phantom_library_active := TRUE;
          predecessor_forward_link^^.text_embedded_library := FALSE;
        IFEND;
        adjust_library_searched (0);
      IFEND;
    END /add_library/;

  PROCEND lop$activate_library;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] lop$deactivate_library', EJECT ??

  PROCEDURE [XDCL] lop$deactivate_library
    (    library_name: amt$local_file_name);


    VAR
      library: ^lot$library_descriptor,
      library_in_list: boolean;

    IF library_name = osc$null_name THEN
      RETURN;
    IFEND;

    lop$find_library_descriptor (library_name, library, library_in_list);
    IF library_in_list THEN
      IF library^.phantom_library THEN
        library^.phantom_library_active := FALSE;
        library_counts.execute_libs := library_counts.execute_libs - 1;
      IFEND;
    IFEND;

    adjust_library_searched (0);

  PROCEND lop$deactivate_library;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] lop$add_program_load_libraries', EJECT ??

  PROCEDURE [XDCL] lop$add_program_load_libraries
    (    execute_libraries: ^pmt$object_library_list;
         job_libraries: ^pmt$object_library_list;
         deferred_libraries: ^lot$deferred_library_list);

{  PURPOSE:
{    This procedure initializes the library_list for a program load.  Execute libraries and
{    job libraries are added to the library_list in the appropriate positions.
{  NOTE:
{    Debug libraries may already be in the list if the debugger is activated prior to initiation
{    of the program load.

    VAR
      i: pmt$number_of_libraries,
      library: ^lot$library_descriptor,
      library_in_list: boolean,
      execute_libs: integer,
      job_libs: integer,
      predecessor_forward_link: ^^lot$library_descriptor;

{!  Temporary until PSR CILA170 is answered.

    IF lov$library_list.link_to_first_job_library = NIL THEN
      lov$library_list.link_to_first_job_library := ^lov$library_list.first;
    IFEND;

{!  End temporary.

    predecessor_forward_link := ^lov$library_list.first;

    IF deferred_libraries <> NIL THEN

      WHILE (predecessor_forward_link^ <> NIL) AND (predecessor_forward_link^^.attributes.
            name (1, loc$deferred_entry_pt_lib_size) = loc$deferred_entry_pt_library) DO
        predecessor_forward_link := ^predecessor_forward_link^^.nnext;
      WHILEND;

    /add_deferred_libraries/
      FOR i := LOWERBOUND (deferred_libraries^) TO UPPERBOUND (deferred_libraries^) DO
        lop$find_library_descriptor (deferred_libraries^ [i].name, library, library_in_list);
        IF library_in_list THEN
          CYCLE /add_deferred_libraries/
        IFEND;

        add_library_to_list (deferred_libraries^ [i].name, deferred_libraries^ [i].segment,
              predecessor_forward_link^, library_in_list);
        IF NOT library_in_list THEN
          CYCLE /add_deferred_libraries/
        IFEND;

        predecessor_forward_link := ^predecessor_forward_link^^.nnext;
      FOREND /add_deferred_libraries/;

      IF lov$library_list.link_to_first_job_library = ^lov$library_list.first THEN
        lov$library_list.link_to_first_job_library := predecessor_forward_link;
      IFEND;

    IFEND;

    IF execute_libraries <> NIL THEN

      execute_libs := library_counts.execute_libs;

      WHILE (predecessor_forward_link^ <> NIL) AND (predecessor_forward_link^^.attributes.
            name (1, loc$deferred_entry_pt_lib_size) = loc$deferred_entry_pt_library) DO
        predecessor_forward_link := ^predecessor_forward_link^^.nnext;
      WHILEND;

    /add_execute_libraries/
      FOR i := LOWERBOUND (execute_libraries^) TO UPPERBOUND (execute_libraries^) DO
        lop$find_library_descriptor (execute_libraries^ [i], library, library_in_list);
        IF library_in_list THEN
          CYCLE /add_execute_libraries/
        IFEND;

        add_library_to_list (execute_libraries^ [i], {deferred_library_segment} 0, predecessor_forward_link^,
              library_in_list);
        IF NOT library_in_list THEN
          CYCLE /add_execute_libraries/
        IFEND;

        library_counts.execute_libs := library_counts.execute_libs + 1;

        IF (execute_libraries^ [i] <> loc$task_services_library_name) AND
              (execute_libraries^ [i] (1, loc$deferred_entry_pt_lib_size) <>
              loc$deferred_entry_pt_library) THEN
          predecessor_forward_link^^.segment := NIL;
          predecessor_forward_link^^.attributes.name := execute_libraries^ [i];
          predecessor_forward_link^^.library_open := FALSE;
          predecessor_forward_link^^.library_valid := TRUE;
          predecessor_forward_link^^.phantom_library := FALSE;
          predecessor_forward_link^^.phantom_library_active := FALSE;
          predecessor_forward_link^^.text_embedded_library := FALSE;
        IFEND;

        predecessor_forward_link := ^predecessor_forward_link^^.nnext;
      FOREND /add_execute_libraries/;

      IF lov$library_list.link_to_first_job_library = ^lov$library_list.first THEN
        lov$library_list.link_to_first_job_library := predecessor_forward_link;
      IFEND;

      IF execute_libs < library_counts.execute_libs THEN
        adjust_library_searched (0);
      IFEND;
    IFEND;

    IF job_libraries <> NIL THEN
      predecessor_forward_link := lov$library_list.link_to_first_job_library;
      job_libs := library_counts.job_libs;

    /add_job_libraries/
      FOR i := LOWERBOUND (job_libraries^) TO UPPERBOUND (job_libraries^) DO
        lop$find_library_descriptor (job_libraries^ [i], library, library_in_list);
        IF library_in_list THEN
          CYCLE /add_job_libraries/
        IFEND;

        add_library_to_list (job_libraries^ [i], {deferred_library_segment} 0, predecessor_forward_link^,
              library_in_list);
        IF NOT library_in_list THEN
          CYCLE /add_job_libraries/
        IFEND;

        library_counts.job_libs := library_counts.job_libs + 1;

        IF (job_libraries^ [i] <> loc$task_services_library_name) AND
              (job_libraries^ [i] (1, loc$deferred_entry_pt_lib_size) <> loc$deferred_entry_pt_library) THEN
          predecessor_forward_link^^.segment := NIL;
          predecessor_forward_link^^.attributes.name := job_libraries^ [i];
          predecessor_forward_link^^.library_open := FALSE;
          predecessor_forward_link^^.library_valid := TRUE;
          predecessor_forward_link^^.phantom_library := FALSE;
          predecessor_forward_link^^.phantom_library_active := FALSE;
          predecessor_forward_link^^.text_embedded_library := FALSE;
        IFEND;

        predecessor_forward_link := ^predecessor_forward_link^^.nnext;
      FOREND /add_job_libraries/;

      IF job_libs < library_counts.job_libs THEN
        adjust_library_searched (library_counts.execute_libs + library_counts.embedded_libs + job_libs);
      IFEND;
    IFEND;

  PROCEND lop$add_program_load_libraries;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] lop$add_text_embedded_libraries', EJECT ??

  PROCEDURE [XDCL] lop$add_text_embedded_libraries
    (    text_embedded_libraries: ^llt$libraries);

{  PURPOSE:
{    This procedure processes 'libraries' object text records.  It adds the text_embedded libraries
{    to the library_list in the order they are encountered, with the first text_embedded library
{    appearing immediately after the last execute library.

    VAR
      i: 1 .. llc$max_libraries,
      library: ^lot$library_descriptor,
      predecessor_forward_link: ^^lot$library_descriptor,
      embedded_libs: integer,
      library_in_list: boolean;

{!  Temporary until PSR CILA170 is answered.

    IF lov$library_list.link_to_first_job_library = NIL THEN
      lov$library_list.link_to_first_job_library := ^lov$library_list.first;
    IFEND;

{!  End temporary.

    predecessor_forward_link := lov$library_list.link_to_first_job_library;
    embedded_libs := library_counts.embedded_libs;

  /add_text_embedded_libraries/
    FOR i := LOWERBOUND (text_embedded_libraries^) TO UPPERBOUND (text_embedded_libraries^) DO
      lop$find_library_descriptor (text_embedded_libraries^ [i], library, library_in_list);
      IF library_in_list THEN
        CYCLE /add_text_embedded_libraries/
      IFEND;

      add_library_to_list (text_embedded_libraries^ [i], {deferred_library_segment} 0,
            predecessor_forward_link^, library_in_list);
      IF NOT library_in_list THEN
        CYCLE /add_text_embedded_libraries/
      IFEND;

      library_counts.embedded_libs := library_counts.embedded_libs + 1;

      IF (text_embedded_libraries^ [i] <> loc$task_services_library_name) AND
            (text_embedded_libraries^ [i] (1, loc$deferred_entry_pt_lib_size) <>
            loc$deferred_entry_pt_library) THEN
        predecessor_forward_link^^.segment := NIL;
        predecessor_forward_link^^.attributes.name := text_embedded_libraries^ [i];
        predecessor_forward_link^^.library_open := FALSE;
        predecessor_forward_link^^.library_valid := TRUE;
        predecessor_forward_link^^.phantom_library := FALSE;
        predecessor_forward_link^^.phantom_library_active := FALSE;
        predecessor_forward_link^^.text_embedded_library := TRUE;
      IFEND;

      predecessor_forward_link := ^predecessor_forward_link^^.nnext;
    FOREND /add_text_embedded_libraries/;

    lov$library_list.link_to_first_job_library := predecessor_forward_link;
    IF embedded_libs < library_counts.embedded_libs THEN
      adjust_library_searched (library_counts.execute_libs + embedded_libs);
    IFEND;

  PROCEND lop$add_text_embedded_libraries;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] lop$add_debug_libraries', EJECT ??

  PROCEDURE [XDCL] lop$add_debug_libraries
    (    debug_library_list: pmt$object_library_list;
     VAR status {control} : ost$status);

{  PURPOSE:
{    This procedure adds debug libraries at the end of the library_list.

?? NEWTITLE := 'terminate_request', EJECT ??

    PROCEDURE terminate_request
      (    condition: pmt$condition;
           malfunction_status: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR condition_status: ost$status);

{   PURPOSE:
{      Circumstances may arise during the addition of debug libraries which cause
{      the addition to be unsuccessful.  These abnormalities are reported via conditions.
{      This condition handler is responsible for fielding the condition and reporting
{      the abnormality to the caller of lop$add_debug_libraries.
{
{      The conditions and their meanings are:
{      1.  system conditions: the hardware detected a condition which is probably
{          caused by a loader coding error.  The specific condition is reported to
{          the output file and the request is terminated with the loader malfunctioned
{          exception code.  SEE: code for pmc$detected_uncorrected_err processing.
{      2.  segment access conditions:
{          a. mmc$sac_read_beyond_eoi, mmc$sac_segment_access_error,
{             mmc$sac_key_lock_violation, mmc$sac_ring_violation:
{             segment management detected an inconsistency which was probably
{             caused by a loader coding error.  The specific condition is reported
{             to the output file and the request is terminated with the loader
{             malfunctioned exception code.
{          b. mmc$sac_read_write_beyond_msl: user limits prevented the loader from
{             completing the load process.  The request is terminated with the
{             insufficient memory to load exception code.
{          c. mmc$sac_io_read_error: a hardware error was detected attempting to
{             read a page from a device.  The specific condition is reported to
{             the output file and the request is terminated with the premature load
{             termination exception code.
{      3.  user defined conditions:
{          a. cye$run_time_condition: the CYBIL run time checking detected an
{             error which was probably cause by a loader coding error.  The
{             specific condition is reported to the output file and the request is
{             terminated with loader malfunctioned exception code.
{          b. loe$abort_load: several constituent procedures of the loader detect
{             circumstances which prohibit continuation of the load process.  The
{             detecting procedure reports the circumstance to load map and causes
{             the loe$abort_load condition.  This condition handler terminates the
{             request with the premature load termination exception code.
{          c. loe$loader_malfunction: a constituent procedure of the loader
{             detected an inconsistency which probably was caused by a loader
{             coding error.  The detecting procedure causes the condition
{             pointing to a status variable which identifies the inconsistency.
{             This condition handler reports the identified inconsistency to
{             the output file and terminates the request with the loader malfunctioned
{             exception code.
{          d. loe$insufficient_memory: several constituent procedures of the
{             loader detect circumstances where there is not enough virtual memory
{             to complete the load process - this is generally a case of user
{             limit being exceeded.  The detecting procedure reports the shortage
{             to the load map and causes the condition.  This condition handler
{             terminates the request with insufficient memory to load exception code.
{          e. other: other user defined conditions will be continued and
{             otherwise ignored.
{

      VAR
        termination_descriptor: pmt$established_handler,
        cybil_error: ^ost$status,
        malfunction: ^ost$status,
        message: ost$status;

      CASE condition.selector OF
      = pmc$system_conditions =
        osp$set_status_from_condition ('LL', condition, save_area, message, condition_status);
        osp$generate_message (message, condition_status);
        IF NOT (pmc$detected_uncorrected_err IN condition.system_conditions) THEN
          osp$set_status_abnormal ('LL', lle$loader_malfunctioned, 'DEBUGGER', status);
        ELSE
          status := message;
        IFEND;
      = mmc$segment_access_condition =
        CASE condition.segment_access_condition.identifier OF
        = mmc$sac_read_beyond_eoi, mmc$sac_segment_access_error, mmc$sac_key_lock_violation,
              mmc$sac_ring_violation =
          osp$set_status_from_condition ('LL', condition, save_area, message, condition_status);
          osp$generate_message (message, condition_status);
          osp$set_status_abnormal ('LL', lle$loader_malfunctioned, 'DEBUGGER', status);
        = mmc$sac_read_write_beyond_msl =
          osp$set_status_abnormal ('LL', lle$insufficient_memory_to_load, '', status);
        = mmc$sac_io_read_error =
          osp$set_status_from_condition ('LL', condition, save_area, message, condition_status);
          osp$generate_message (message, condition_status);
          osp$set_status_abnormal ('LL', lle$premature_load_termination, 'Debugger', status);
        ELSE
          osp$set_status_from_condition ('LL', condition, save_area, message, condition_status);
          osp$generate_message (message, condition_status);
          osp$set_status_abnormal ('LL', lle$premature_load_termination, 'Debugger', status);
        CASEND;
      = pmc$user_defined_condition =
        IF (condition.user_condition_name = cye$run_time_condition) THEN
          cybil_error := malfunction_status;
          osp$generate_message (cybil_error^, condition_status);
          osp$set_status_abnormal ('LL', lle$loader_malfunctioned, 'DEBUGGER', status);
        ELSEIF (condition.user_condition_name = loe$abort_load) THEN
          osp$set_status_abnormal ('LL', lle$premature_load_termination, 'Debugger', status);
        ELSEIF (condition.user_condition_name = loe$loader_malfunction) THEN
          malfunction := malfunction_status;
          osp$generate_message (malfunction^, condition_status);
          osp$set_status_abnormal ('LL', lle$loader_malfunctioned, 'DEBUGGER', status);
        ELSEIF (condition.user_condition_name = loe$insufficient_memory) THEN
          osp$set_status_abnormal ('LL', lle$insufficient_memory_to_load, '', status);
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, condition_status);
          RETURN;
        IFEND;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, condition_status);
        RETURN;
      CASEND;
      EXIT lop$add_debug_libraries;
    PROCEND terminate_request;
?? OLDTITLE, EJECT ??

    VAR
      predecessor_forward_link: ^^lot$library_descriptor,
      i: pmt$number_of_libraries,
      library: ^lot$library_descriptor,
      library_in_list: boolean,
      termination_descriptor: pmt$established_handler,
      termination_conditions: [STATIC, READ, oss$job_paged_literal] pmt$condition :=
            [pmc$condition_combination, $pmt$condition_combination
            [pmc$system_conditions, mmc$segment_access_condition, pmc$user_defined_condition]];

    pmp$establish_condition_handler (termination_conditions, ^terminate_request, ^termination_descriptor,
          status);
    IF status.normal THEN

{!  Temporary until PSR CILA170 is answered.

      IF lov$library_list.link_to_first_job_library = NIL THEN
        lov$library_list.link_to_first_job_library := ^lov$library_list.first;
      IFEND;

{!  End temporary.

      predecessor_forward_link := ^lov$library_list.first;

      WHILE predecessor_forward_link^ <> NIL DO
        predecessor_forward_link := ^predecessor_forward_link^^.nnext;
      WHILEND;

    /add_debug_libraries/
      FOR i := LOWERBOUND (debug_library_list) TO UPPERBOUND (debug_library_list) DO
        lop$find_library_descriptor (debug_library_list [i], library, library_in_list);
        IF library_in_list THEN
          CYCLE /add_debug_libraries/
        IFEND;

        add_library_to_list (debug_library_list [i], {deferred_library_segment} 0, predecessor_forward_link^,
              library_in_list);
        IF NOT library_in_list THEN
          CYCLE /add_debug_libraries/
        IFEND;

        IF (debug_library_list [i] <> loc$task_services_library_name) AND
              (debug_library_list [i] (1, loc$deferred_entry_pt_lib_size) <>
              loc$deferred_entry_pt_library) THEN
          predecessor_forward_link^^.segment := NIL;
          predecessor_forward_link^^.attributes.name := debug_library_list [i];
          predecessor_forward_link^^.library_open := FALSE;
          predecessor_forward_link^^.library_valid := TRUE;
          predecessor_forward_link^^.phantom_library := FALSE;
          predecessor_forward_link^^.phantom_library_active := FALSE;
          predecessor_forward_link^^.text_embedded_library := FALSE;
        IFEND;

        predecessor_forward_link := ^predecessor_forward_link^^.nnext;
      FOREND /add_debug_libraries/;
    IFEND;
  PROCEND lop$add_debug_libraries;
?? OLDTITLE ??
?? NEWTITLE := 'add_library_to_list', EJECT ??

  PROCEDURE add_library_to_list
    (    library_name: amt$local_file_name;
         deferred_library_segment: ost$segment;
     VAR predecessor_forward_link {input_output} : ^lot$library_descriptor;
     VAR library_added_to_list {control} : boolean);

{  PURPOSE:
{    This procedure is responsible for including files in the library_list as directed.  It verifies
{    that the identified file is indeed a library file, prepares the library for use in the load
{    process, and inserts a descriptor for the library into the library_list at the directed location.


    VAR
      entry_point_index: 1 .. llc$max_deferred_entry_points,
      file_descriptor: lot$file_descriptor,
      file_descriptor_found: boolean,
      ignore_status: ost$status,
      library: ^lot$library_descriptor,
      library_found: boolean;

    library_added_to_list := FALSE;

    lop$find_library_descriptor (library_name, library, library_found);
    IF library_found THEN
      RETURN
    IFEND;

    build_library_descriptor (predecessor_forward_link);
    library_added_to_list := TRUE;
    predecessor_forward_link^.attributes.name := library_name;
    predecessor_forward_link^.segment := NIL;

    IF library_name = loc$task_services_library_name THEN

{ Construct a library descriptor for the conventional task services entry point "library".

      predecessor_forward_link^.ring_brackets.r1 := osc$tmtr_ring;
      predecessor_forward_link^.ring_brackets.r2 := osc$tsrv_ring;
      predecessor_forward_link^.ring_brackets.r3 := osc$user_ring_2;
      predecessor_forward_link^.attributes.library_file := TRUE;
      predecessor_forward_link^.attributes.key_lock.global := FALSE;
      predecessor_forward_link^.attributes.key_lock.local := FALSE;
      predecessor_forward_link^.attributes.key_lock.value := loc$master_key;
      predecessor_forward_link^.attributes.execute_privilege := osc$local_privilege;
      predecessor_forward_link^.attributes.load_file_number := 0;
      predecessor_forward_link^.library_open := TRUE;
      predecessor_forward_link^.library_valid := TRUE;
      predecessor_forward_link^.phantom_library := FALSE;
      predecessor_forward_link^.phantom_library_active := FALSE;
      predecessor_forward_link^.text_embedded_library := FALSE;

    ELSEIF (library_name (1, loc$deferred_entry_pt_lib_size) = loc$deferred_entry_pt_library) THEN

{ Construct a library descriptor for the deferred entry point "library".  The segment number
{ of the object file is used to find either the file or library descriptor for the object
{ file that the deferred entry points are from.

      search_for_file_descriptor (deferred_library_segment, file_descriptor, file_descriptor_found);

      IF file_descriptor_found THEN
        predecessor_forward_link^.ring_brackets := file_descriptor.ring_brackets;
        predecessor_forward_link^.segment := file_descriptor.segment;
        predecessor_forward_link^.attributes.key_lock := file_descriptor.attributes.key_lock;
        predecessor_forward_link^.attributes.execute_privilege :=
              file_descriptor.attributes.execute_privilege;
          predecessor_forward_link^.attributes.load_file_number :=
                file_descriptor.attributes.load_file_number;
      ELSE
        search_for_library_descriptor (deferred_library_segment, library, library_found);
        IF library_found THEN
          predecessor_forward_link^.ring_brackets := library^.ring_brackets;
          predecessor_forward_link^.segment := library^.segment;
          predecessor_forward_link^.attributes.key_lock := library^.attributes.key_lock;
          predecessor_forward_link^.attributes.execute_privilege := library^.attributes.execute_privilege;
            predecessor_forward_link^.attributes.load_file_number := library^.attributes.load_file_number;
        IFEND;
      IFEND;

      predecessor_forward_link^.attributes.library_file := TRUE;
      predecessor_forward_link^.library_open := TRUE;
      predecessor_forward_link^.library_valid := TRUE;
      predecessor_forward_link^.phantom_library := FALSE;
      predecessor_forward_link^.phantom_library_active := FALSE;
      predecessor_forward_link^.text_embedded_library := FALSE;
    IFEND;

  PROCEND add_library_to_list;
?? OLDTITLE ??
?? NEWTITLE := 'build_library_descriptor', EJECT ??

  PROCEDURE build_library_descriptor
    (VAR predecessor_forward_link: ^lot$library_descriptor);

{  PURPOSE:
{    This procedure is responsible for building a library_list entry.
{

    VAR
      library: ^lot$library_descriptor,
      malfunction_status: ^ost$status,
      abort_status: ^ost$status;


    IF lov$library_list.container = NIL THEN
      library := NIL;
    ELSE
      NEXT library IN lov$library_list.container;
    IFEND;

    IF library = NIL THEN
      lop$augment_lib_list_container;
      NEXT library IN lov$library_list.container;
      IF library = NIL THEN
        PUSH malfunction_status;
        osp$set_status_abnormal ('LL', lle$loader_malfunctioned, 'add library to list', malfunction_status^);
        PUSH abort_status;
        pmp$cause_condition (loe$loader_malfunction, malfunction_status, abort_status^);
        pmp$exit (abort_status^);
      IFEND;
    IFEND;
    library^.nnext := predecessor_forward_link;
    predecessor_forward_link := library;

  PROCEND build_library_descriptor;
?? OLDTITLE ??
?? NEWTITLE := 'search_for_file_descriptor', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to search through the list of file
{   descriptors for one with a matching segment number.

  PROCEDURE search_for_file_descriptor
    (    segment_number: ost$segment;
     VAR file_descriptor: lot$file_descriptor;
     VAR file_descriptor_found: boolean);

    VAR
      i: pmt$number_of_object_files;

    file_descriptor_found := FALSE;
    IF lov$file_descriptors <> NIL THEN
      FOR i := 1 TO UPPERBOUND (lov$file_descriptors^) DO
        IF segment_number = #SEGMENT (lov$file_descriptors^ [i].segment) THEN
          file_descriptor_found := TRUE;
          file_descriptor := lov$file_descriptors^ [i];
          RETURN;
        IFEND;
      FOREND;
    IFEND;
  PROCEND search_for_file_descriptor;
?? OLDTITLE ??
?? NEWTITLE := 'search_for_library_descriptor', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to search through the library list
{   for an entry with a matching segment number.

  PROCEDURE search_for_library_descriptor
    (    segment_number: ost$segment;
     VAR library: ^lot$library_descriptor;
     VAR library_found: boolean);

    library_found := FALSE;
    library := lov$library_list.first;
    WHILE library <> NIL DO
      IF (library^.attributes.name (1, loc$deferred_entry_pt_lib_size) <> loc$deferred_entry_pt_library) AND
            (segment_number = #SEGMENT (library^.segment)) THEN
        library_found := TRUE;
        RETURN;
      IFEND;
      library := library^.nnext;
    WHILEND;
  PROCEND search_for_library_descriptor;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] lop$open_library ', EJECT ??

  PROCEDURE [XDCL] lop$open_library
    (    library_name: amt$local_file_name;
     VAR file_descriptor {input_output} : lot$file_descriptor;
     VAR library_valid {control} : boolean);

    VAR
      file_loadable: boolean,
      library_header: ^llt$object_library_header,
      library_hdr: ^llt$object_library_header_v1_0,
      entry_dictionary: ^llt$entry_point_dictionary,
      module_dictionary: ^llt$module_dictionary,
      number_of_modules: 0 .. llc$max_modules_in_library,
      number_of_entry_points: 0 .. llc$max_entry_points_in_library,
      library_dictionary: ^llt$object_library_dictionaries,
      i: 0 .. llc$max_dictionaries_on_library;

    library_valid := FALSE;

    lop$build_file_descriptor (library_name, file_loadable, file_descriptor);
    IF NOT file_loadable THEN
      RETURN;
    IFEND;
    IF NOT file_descriptor.attributes.library_file THEN
      lop$report_error (lle$file_not_library, library_name, '', 0);
      RETURN;
    IFEND;

{ Verify that dictionaries are accessible.

    RESET file_descriptor.segment;
    NEXT library_header IN file_descriptor.segment;
    IF library_header = NIL THEN
      lop$report_error (lle$library_header_missing, library_name, '', 0);
      RETURN
    IFEND;

    IF library_header^.version = llc$object_library_version THEN

      NEXT library_dictionary: [1 .. library_header^.number_of_dictionaries] IN file_descriptor.segment;
      IF library_dictionary = NIL THEN
        lop$report_error (lle$library_header_missing, library_name, '', 0);
        RETURN;
      IFEND;

      number_of_modules := 0;
      number_of_entry_points := 0;

      FOR i := LOWERBOUND (library_dictionary^) TO UPPERBOUND (library_dictionary^) DO
        CASE library_dictionary^ [i].kind OF
        = llc$module_dictionary =
          module_dictionary := #PTR (library_dictionary^ [i].module_dictionary, file_descriptor.segment^);
          number_of_modules := UPPERBOUND (module_dictionary^);
        = llc$entry_point_dictionary =
          entry_dictionary := #PTR (library_dictionary^ [i].entry_point_dictionary, file_descriptor.segment^);
          number_of_entry_points := UPPERBOUND (entry_dictionary^);
        ELSE

        CASEND;
      FOREND;

    ELSEIF library_header^.version = 'V1.0' THEN

      RESET file_descriptor.segment;

      NEXT library_hdr IN file_descriptor.segment;
      IF library_hdr = NIL THEN
        lop$report_error (lle$library_header_missing, library_name, '', 0);
        RETURN;
      IFEND;

      number_of_modules := library_hdr^.number_of_modules;
      module_dictionary := #PTR (library_hdr^.module_dictionary, file_descriptor.segment^);
      number_of_entry_points := library_hdr^.number_of_entry_points;
      entry_dictionary := #PTR (library_hdr^.entry_point_dictionary, file_descriptor.segment^);

    ELSE
      lop$report_error (lle$wrong_library_version, llc$object_library_version, library_name, 0);
      RETURN;
    IFEND;

    IF number_of_modules = 0 THEN
      lop$report_error (lle$empty_module_dictionary, library_name, '', 0);
      RETURN
    IFEND;
    IF module_dictionary = NIL THEN
      lop$report_error (lle$bad_module_dictionary_ptr, library_name, '', 0);
      RETURN
    IFEND;
    IF number_of_entry_points <> 0 THEN
      IF entry_dictionary = NIL THEN
        lop$report_error (lle$bad_entry_dictionary_ptr, library_name, '', 0);
        RETURN
      IFEND;
    IFEND;

    library_valid := TRUE;

  PROCEND lop$open_library;
?? OLDTITLE ??
?? NEWTITLE := 'lop$find_library_descriptor', EJECT ??

  PROCEDURE [XDCL] lop$find_library_descriptor
    (    library_name: amt$local_file_name;
     VAR library {input_output} : ^lot$library_descriptor;
     VAR library_found {control} : boolean);

{  PURPOSE:
{    This procedure is returns a pointer to the library_descriptor in the library_list corresponding to
{    the library name.  If the library is not in the library_list then library_found is set to FALSE.
{

    library_found := TRUE;
    library := lov$library_list.first;
    WHILE library <> NIL DO
      IF library_name = library^.attributes.name THEN
        RETURN
      IFEND;
      library := library^.nnext
    WHILEND;
    library_found := FALSE;

  PROCEND lop$find_library_descriptor;
?? OLDTITLE ??
MODEND lom$library_list_management;
