?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE SCL Interpreter : Command Utility Helper Routines' ??
MODULE clm$command_utility_helper;

{
{ PURPOSE:
{   This module contains the procedures that help the command utility manager to create and change
{   utility block information.
{
{ DESIGN:
{   Attributes defined for a utility are validated and then used to create a utility's environment or
{   change a utility's environment.
{

?? NEWTITLE := 'Global Declarations', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cle$ecc_command_processing
*copyc cle$ecc_miscellaneous
*copyc cle$ecc_utilities
*copyc clt$utility_attributes
*copyc ost$caller_identifier
*copyc ost$name_reference
?? POP ??
*copyc clp$add_utility_to_command_list
*copyc clp$close_command_library
*IF NOT $true(osv$unix)
*copyc clp$convert_integer_to_string
*copyc clp$convert_string_to_file
*IFEND
*copyc clp$find_current_block
*copyc clp$find_task_block
*copyc clp$find_utility_block
*copyc clp$get_command_search_mode
*copyc clp$open_command_library
*copyc clp$pop_block_stack
*copyc clp$push_utility_block
*copyc clp$search_command_table
*IF $true(osv$unix)
*copyc clt$command_name
*copyc clt$command_table
*copyc clt$command_table_index
*IFEND
*copyc clp$set_prompt_string
*copyc clp$validate_name
*IF NOT $true(osv$unix)
*copyc mmp$create_segment
*IFEND
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc osv$lower_to_upper
*copyc osv$task_shared_heap

?? TITLE := 'clp$create_utility_environment', EJECT ??

  PROCEDURE [XDCL, #GATE] clp$create_utility_environment
    (    name: clt$utility_name;
         defined_at_command_level: boolean;
         called_from_push_utility: boolean;
         attributes: clt$utility_attributes;
     VAR status: ost$status);

    VAR
      block: ^clt$block,
      caller_id: ost$caller_identifier,
      ignore_status: ost$status,
      index: integer,
      index_string: ost$string,
      library_names: ^array [1 .. * ] of fst$path_handle_name,
      name_is_valid: boolean,
      number_of_attributes: integer,
      prompt_size: ost$name_size,
      task_block: ^clt$block,
      termination_command_ordinal: clt$named_entry_ordinal,
      termination_command_index: clt$command_table_index,
      validated_utility_name: ost$name;


    status.normal := TRUE;
    block := NIL;

    clp$validate_name (name, validated_utility_name, name_is_valid);
    IF (NOT name_is_valid) OR (validated_utility_name = 'JOB') OR (validated_utility_name = 'LOCAL') OR
          (validated_utility_name = 'XDCL') OR (validated_utility_name = 'XREF') OR (validated_utility_name =
          'ALL') OR (validated_utility_name = 'NONE') THEN
      osp$set_status_abnormal ('CL', cle$improper_utility_name, name, status);
      RETURN;
    IFEND;
    number_of_attributes := UPPERBOUND (attributes);

    FOR index := 1 TO number_of_attributes DO
      IF (attributes [index].key = clc$utility_name) OR ((attributes [index].key = clc$utility_libraries) AND
            (NOT defined_at_command_level)) THEN
*IF NOT $true(osv$unix)
        clp$convert_integer_to_string (index, 10, FALSE, index_string, ignore_status);
        IF status.normal THEN
          osp$set_status_abnormal ('CL', cle$improper_utility_attribute, index_string.
                value (1, index_string.size), status);
        ELSE
          osp$append_status_parameter (',', index_string.value (1, index_string.size), status);
        IFEND;
*ELSE
        osp$set_status_abnormal ('CL', cle$improper_utility_attribute, '', status);
*IFEND
      IFEND;
    FOREND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

*IF NOT $true(osv$unix)
    #CALLER_ID (caller_id);
*ELSE
    caller_id.ring := osc$user_ring;
*IFEND
    validate_utility_attributes (caller_id.ring, defined_at_command_level, called_from_push_utility,
          attributes, NIL, 'QUIT', termination_command_ordinal, termination_command_index, library_names,
          status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    clp$find_task_block (task_block, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

  /create_utility/
    BEGIN
      clp$push_utility_block (validated_utility_name, block);
      block^.command_environment.task_id := task_block^.task_id;
      block^.command_environment.libraries := library_names;
      block^.command_environment.command_level := defined_at_command_level;
      block^.command_environment.termination_command_ordinal := termination_command_ordinal;
      block^.command_environment.termination_command_index := termination_command_index;

      prompt_size := STRLENGTH (validated_utility_name);
      IF prompt_size > clc$max_prompt_size THEN
        block^.prompt.size := clc$max_prompt_size;
      ELSE
        block^.prompt.size := prompt_size;
      IFEND;
      block^.prompt.value := validated_utility_name (1, block^.prompt.size);

      FOR index := 1 TO number_of_attributes DO
        CASE attributes [index].key OF

        = clc$null_utility_attribute =
          ;

        = clc$utility_command_search_mode =
          block^.command_search_mode := attributes [index].command_search_mode;

        = clc$utility_command_table =
          IF block^.command_environment.commands <> NIL THEN
            FREE block^.command_environment.commands IN osv$task_shared_heap^;
          IFEND;
          IF attributes [index].command_table = NIL THEN
            block^.command_environment.commands := NIL;
          ELSE
            ALLOCATE block^.command_environment.commands: [1 .. UPPERBOUND (attributes [index].
                  command_table^)] IN osv$task_shared_heap^;
            block^.command_environment.commands^ := attributes [index].command_table^;
          IFEND;

        = clc$utility_function_table =
          IF block^.command_environment.original_functions <> NIL THEN
            FREE block^.command_environment.original_functions IN osv$task_shared_heap^;
          IFEND;
          IF attributes [index].function_table = NIL THEN
            block^.command_environment.original_functions := NIL;
          ELSE
            ALLOCATE block^.command_environment.original_functions:
                  [1 .. UPPERBOUND (attributes [index].function_table^)] IN osv$task_shared_heap^;
            block^.command_environment.original_functions^ := attributes [index].function_table^;
          IFEND;

        = clc$utility_function_proc_table =
          IF block^.command_environment.contemporary_functions <> NIL THEN
            FREE block^.command_environment.contemporary_functions IN osv$task_shared_heap^;
          IFEND;
          IF attributes [index].function_processor_table = NIL THEN
            block^.command_environment.contemporary_functions := NIL;
          ELSE
            ALLOCATE block^.command_environment.contemporary_functions:
                  [1 .. UPPERBOUND (attributes [index].function_processor_table^)] IN osv$task_shared_heap^;
            block^.command_environment.contemporary_functions^ := attributes [index].
                  function_processor_table^;
          IFEND;

        = clc$utility_interactive_include =
          block^.interactive_include_processor := attributes [index].interactive_include_processor;

        = clc$utility_libraries =
          IF block^.libraries <> NIL THEN
            FREE block^.libraries IN osv$task_shared_heap^;
          IFEND;
          IF attributes [index].libraries <> NIL THEN
            ALLOCATE block^.libraries: [1 .. UPPERBOUND (attributes [index].libraries^)] IN
                  osv$task_shared_heap^;
            block^.libraries^ := attributes [index].libraries^;
          IFEND;

        = clc$utility_line_preprocessor =
          block^.line_preprocessor := attributes [index].line_preprocessor;

        = clc$utility_online_manual =
          #TRANSLATE (osv$lower_to_upper, attributes [index].online_manual_name, block^.online_manual_name);

        = clc$utility_prompt =
          block^.prompt := attributes [index].prompt;

        = clc$utility_subcmnd_log_enabled =
          block^.command_environment.subcommand_logging_enabled :=
                attributes [index].subcommand_logging_enabled;

        = clc$utility_termination_command =
          ;

        ELSE

{ Should never get here.

*IF NOT $true(osv$unix)
          clp$convert_integer_to_string (index, 10, FALSE, index_string, status);
          osp$set_status_abnormal ('CL', cle$improper_utility_attribute, index_string.
                value (1, index_string.size), status);
*ELSE
          osp$set_status_abnormal ('CL', cle$improper_utility_attribute, '', status);
*IFEND
          EXIT /create_utility/;
        CASEND;
      FOREND;

      clp$add_utility_to_command_list (block, status);

    END /create_utility/;

    IF NOT status.normal THEN
      IF block^.command_environment.commands <> NIL THEN
        FREE block^.command_environment.commands IN osv$task_shared_heap^;
      IFEND;
      IF block^.command_environment.original_functions <> NIL THEN
        FREE block^.command_environment.original_functions IN osv$task_shared_heap^;
      IFEND;
      IF block^.command_environment.contemporary_functions <> NIL THEN
        FREE block^.command_environment.contemporary_functions IN osv$task_shared_heap^;
      IFEND;
      IF block^.command_environment.libraries <> NIL THEN
        release_libraries (UPPERBOUND (block^.command_environment.libraries^),
              block^.command_environment.libraries);
      IFEND;
      IF block^.libraries <> NIL THEN
        FREE block^.libraries IN osv$task_shared_heap^;
      IFEND;
      clp$pop_block_stack (block);
    IFEND;

  PROCEND clp$create_utility_environment;
*IF NOT $true(osv$unix)
?? TITLE := 'clp$change_utility_environment', EJECT ??

  PROCEDURE [XDCL, #GATE] clp$change_utility_environment
    (    name: clt$utility_name;
         defined_at_command_level: boolean;
         attributes: clt$utility_attributes;
     VAR status: ost$status);

    VAR
      block: ^clt$block,
      block_in_current_task: boolean,
      caller_id: ost$caller_identifier,
      change_input_blocks: boolean,
      current_block: ^clt$block,
      default_termination_command: clt$command_name,
      ignore_library_names: ^array [1 .. * ] of fst$path_handle_name,
      ignore_status: ost$status,
      index: integer,
      index_string: ost$string,
      name_is_valid: boolean,
      number_of_attributes: integer,
      repeat_block: ^clt$block,
      termination_command_ordinal: clt$named_entry_ordinal,
      termination_command_index: clt$command_table_index,
      validated_utility_name: clt$utility_name;


    status.normal := TRUE;
    block := NIL;

    clp$validate_name (name, validated_utility_name, name_is_valid);
    IF NOT name_is_valid THEN
      osp$set_status_abnormal ('CL', cle$improper_utility_name, name, status);
      RETURN;
    IFEND;

    clp$find_utility_block (validated_utility_name, block, block_in_current_task);
    IF block = NIL THEN
      osp$set_status_abnormal ('CL', cle$unknown_utility, name, status);
      RETURN;
    ELSEIF defined_at_command_level THEN
      IF NOT block^.command_environment.command_level THEN
        osp$set_status_abnormal ('CL', cle$inaccessible_utility, name, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'CHANGE_UTILITY_ATTRIBUTES', status);
        RETURN;
      IFEND;
    ELSE
      IF (block^.command_environment.command_level OR (NOT block_in_current_task)) THEN
        osp$set_status_abnormal ('CL', cle$inaccessible_utility, name, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'CHANGE_UTILITY_ATTRIBUTES', status);
        RETURN;
      IFEND;
    IFEND;
    number_of_attributes := UPPERBOUND (attributes);

    FOR index := 1 TO number_of_attributes DO
      CASE attributes [index].key OF
      = clc$utility_command_search_mode, clc$utility_libraries, clc$utility_name,
            clc$utility_termination_command =
        clp$convert_integer_to_string (index, 10, FALSE, index_string, ignore_status);
        IF status.normal THEN
          osp$set_status_abnormal ('CL', cle$improper_utility_attribute, index_string.
                value (1, index_string.size), status);
        ELSE
          osp$append_status_parameter (',', index_string.value (1, index_string.size), status);
        IFEND;
      ELSE
        ;
      CASEND;
    FOREND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF block^.command_environment.commands = NIL THEN
      default_termination_command := 'QUIT';
    ELSE
      default_termination_command := block^.command_environment.
            commands^ [block^.command_environment.termination_command_index].name;
    IFEND;
*IF NOT $true(osv$unix)
    #CALLER_ID (caller_id);
*ELSE
    caller_id.ring := osc$user_ring;
*IFEND
    validate_utility_attributes (caller_id.ring, defined_at_command_level, FALSE, attributes,
          block^.command_environment.commands, default_termination_command, termination_command_ordinal,
          termination_command_index, ignore_library_names, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    block^.command_environment.termination_command_ordinal := termination_command_ordinal;
    block^.command_environment.termination_command_index := termination_command_index;

    clp$find_current_block (current_block);

    FOR index := 1 TO number_of_attributes DO
      CASE attributes [index].key OF

      = clc$null_utility_attribute =
        ;

      = clc$utility_command_table =
        IF block^.command_environment.commands <> NIL THEN
          FREE block^.command_environment.commands IN osv$task_shared_heap^;
        IFEND;
        IF attributes [index].command_table = NIL THEN
          block^.command_environment.commands := NIL;
        ELSE
          ALLOCATE block^.command_environment.commands: [1 .. UPPERBOUND (attributes [index].
                command_table^)] IN osv$task_shared_heap^;
          block^.command_environment.commands^ := attributes [index].command_table^;
        IFEND;

      = clc$utility_function_table =
        IF block^.command_environment.original_functions <> NIL THEN
          FREE block^.command_environment.original_functions IN osv$task_shared_heap^;
        IFEND;
        IF attributes [index].function_table = NIL THEN
          block^.command_environment.original_functions := NIL;
        ELSE
          ALLOCATE block^.command_environment.original_functions:
                [1 .. UPPERBOUND (attributes [index].function_table^)] IN osv$task_shared_heap^;
          block^.command_environment.original_functions^ := attributes [index].function_table^;
        IFEND;

      = clc$utility_function_proc_table =
        IF block^.command_environment.contemporary_functions <> NIL THEN
          FREE block^.command_environment.contemporary_functions IN osv$task_shared_heap^;
        IFEND;
        IF attributes [index].function_processor_table = NIL THEN
          block^.command_environment.contemporary_functions := NIL;
        ELSE
          ALLOCATE block^.command_environment.contemporary_functions:
                [1 .. UPPERBOUND (attributes [index].function_processor_table^)] IN osv$task_shared_heap^;
          block^.command_environment.contemporary_functions^ := attributes [index].function_processor_table^;
        IFEND;

      = clc$utility_interactive_include =
        block^.interactive_include_processor := attributes [index].interactive_include_processor;

      = clc$utility_line_preprocessor =
        change_input_blocks := FALSE;
        IF block^.line_preprocessor.call_method = clc$unspecified_call THEN
          IF attributes [index].line_preprocessor.call_method <> clc$unspecified_call THEN
            change_input_blocks := TRUE;
          IFEND;
        ELSEIF attributes [index].line_preprocessor.call_method = clc$unspecified_call THEN
          change_input_blocks := TRUE;
        IFEND;

        block^.line_preprocessor := attributes [index].line_preprocessor;

        IF change_input_blocks THEN
          repeat_block := current_block;
          REPEAT
            IF (repeat_block^.kind = clc$input_block) AND (repeat_block^.associated_utility = block) THEN
              repeat_block^.line_preprocessor_specified := attributes [index].line_preprocessor.call_method <>
                    clc$unspecified_call;
            IFEND;
            IF NOT (repeat_block = block) THEN
              repeat_block := repeat_block^.previous_block;
            IFEND;
          UNTIL repeat_block = block;
        IFEND;

      = clc$utility_online_manual =
        #TRANSLATE (osv$lower_to_upper, attributes [index].online_manual_name, block^.online_manual_name);

      = clc$utility_prompt =
        IF block^.prompt <> attributes [index].prompt THEN
          block^.prompt := attributes [index].prompt;
          repeat_block := current_block;
          REPEAT
            IF (repeat_block^.kind = clc$input_block) AND (repeat_block^.associated_utility = block) AND
                  (repeat_block^.input.interactive_device) THEN
              CASE repeat_block^.input.kind OF
              = clc$file_input, clc$sequence_input =
                clp$set_prompt_string (repeat_block, attributes [index].prompt.value (1,
                      attributes [index].prompt.size));
              ELSE
                ;
              CASEND;
            IFEND;
            IF NOT (repeat_block = block) THEN
              repeat_block := repeat_block^.previous_block;
            IFEND;
          UNTIL repeat_block = block;
        IFEND;

      = clc$utility_subcmnd_log_enabled =
        block^.command_environment.subcommand_logging_enabled := attributes [index].
              subcommand_logging_enabled;

      ELSE

{ Should never get here.

        clp$convert_integer_to_string (index, 10, FALSE, index_string, status);
        osp$set_status_abnormal ('CL', cle$improper_utility_attribute, index_string.
              value (1, index_string.size), status);
        RETURN;
      CASEND;
    FOREND;

  PROCEND clp$change_utility_environment;
?? TITLE := 'clp$store_utility_dialog_info', EJECT ??
*copyc clh$store_utility_dialog_info

  PROCEDURE [XDCL, #GATE] clp$store_utility_dialog_info
    (    utility: clt$utility_name;
         commands: ^clt$command_table;
         functions: ^clt$function_processor_table;
         create_scratch_segment: boolean;
     VAR dialog_info: ^clt$utility_dialog_info;
     VAR status: ost$status);

    VAR
      block: ^clt$block,
      block_in_current_task: boolean,
      caller_id: ost$caller_identifier,
      name_is_valid: boolean,
      segment_attributes: array [1 .. 1] of mmt$attribute_descriptor,
      segment_pointer: mmt$segment_pointer,
      validated_utility_name: clt$utility_name;


    status.normal := TRUE;
    dialog_info := NIL;

*IF NOT $true(osv$unix)
    clp$validate_name (utility, validated_utility_name, name_is_valid);
*ELSE
    clp$validate_name (name, validated_utility_name, name_is_valid);
*IFEND
    IF NOT name_is_valid THEN
      osp$set_status_abnormal ('CL', cle$improper_utility_name, utility, status);
      RETURN;
    IFEND;

    clp$find_utility_block (validated_utility_name, block, block_in_current_task);
    IF block = NIL THEN
      osp$set_status_abnormal ('CL', cle$unknown_utility, utility, status);
      RETURN;
    ELSEIF NOT (block^.command_environment.command_level OR block_in_current_task) THEN
      osp$set_status_abnormal ('CL', cle$inaccessible_utility, utility, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'CLP$STORE_UTILITY_DIALOG_INFO', status);
      RETURN;
    IFEND;

    IF block^.command_environment.dialog_info.commands <> NIL THEN
      FREE block^.command_environment.dialog_info.commands IN osv$task_shared_heap^;
    IFEND;
    IF commands = NIL THEN
      block^.command_environment.dialog_info.commands := NIL;
    ELSE
      ALLOCATE block^.command_environment.dialog_info.commands: [1 .. UPPERBOUND (commands^)] IN
            osv$task_shared_heap^;
      block^.command_environment.dialog_info.commands^ := commands^;
    IFEND;

    IF block^.command_environment.dialog_info.functions <> NIL THEN
      FREE block^.command_environment.dialog_info.functions IN osv$task_shared_heap^;
    IFEND;
    IF functions = NIL THEN
      block^.command_environment.dialog_info.functions := NIL;
    ELSE
      ALLOCATE block^.command_environment.dialog_info.functions: [1 .. UPPERBOUND (functions^)] IN
            osv$task_shared_heap^;
      block^.command_environment.dialog_info.functions^ := functions^;
    IFEND;

    IF create_scratch_segment AND (block^.command_environment.dialog_info.scratch_segment = NIL) THEN
*IF NOT $true(osv$unix)
      #CALLER_ID (caller_id);
*ELSE
      caller_id.ring := osc$user_ring;
*IFEND
      segment_attributes [1].keyword := mmc$kw_ring_numbers;
      segment_attributes [1].r1 := caller_id.ring;
      segment_attributes [1].r2 := osc$user_ring_2;
      mmp$create_segment (^segment_attributes, mmc$sequence_pointer, caller_id.ring, segment_pointer, status);
      IF NOT status.normal THEN
        IF block^.command_environment.dialog_info.commands <> NIL THEN
          FREE block^.command_environment.dialog_info.commands IN osv$task_shared_heap^;
        IFEND;
        IF block^.command_environment.dialog_info.functions <> NIL THEN
          FREE block^.command_environment.dialog_info.functions IN osv$task_shared_heap^;
        IFEND;
        RETURN;
      IFEND;
      block^.command_environment.dialog_info.scratch_segment := segment_pointer.seq_pointer;
    IFEND;

    dialog_info := ^block^.command_environment.dialog_info;

  PROCEND clp$store_utility_dialog_info;
?? TITLE := 'clp$add_auxiliary_utility_lib', EJECT ??
*copyc clh$add_auxiliary_utility_lib

  PROCEDURE [XDCL, #GATE] clp$add_auxiliary_utility_lib
    (    utility: clt$utility_name;
         library: fst$file_reference;
         checkout_library: fst$file_reference;
     VAR status: ost$status);

    VAR
      block: ^clt$block,
      block_in_current_task: boolean,
      caller_id: ost$caller_identifier,
      name_is_valid: boolean,
      search_mode: clt$command_search_modes,
      validated_utility_name: clt$utility_name;

?? TITLE := 'add_auxiliary_library', EJECT ??

    PROCEDURE add_auxiliary_library
      (    library: fst$file_reference;
       VAR status: ost$status);

      VAR
        file: clt$file,
        i: integer,
        library_list_entry: ^clt$command_library_list_entry,
        new_auxiliary_libraries: ^clt$utility_auxiliary_libraries,
        path_handle_name: fst$path_handle_name;


      clp$convert_string_to_file (library, file, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      clp$open_command_library (caller_id.ring, file.local_file_name, library_list_entry, path_handle_name,
            status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      IF block^.command_environment.auxiliary_libraries = NIL THEN
        ALLOCATE new_auxiliary_libraries: [1 .. 1] IN osv$task_shared_heap^;
      ELSE
        FOR i := 1 TO UPPERBOUND (block^.command_environment.auxiliary_libraries^) DO
          IF block^.command_environment.auxiliary_libraries^ [i].name = path_handle_name THEN
            RETURN;
          IFEND;
        FOREND;
        ALLOCATE new_auxiliary_libraries: [1 .. UPPERBOUND (block^.command_environment.auxiliary_libraries^) +
              1] IN osv$task_shared_heap^;
        FOR i := 1 TO UPPERBOUND (block^.command_environment.auxiliary_libraries^) DO
          new_auxiliary_libraries^ [i + 1] := block^.command_environment.auxiliary_libraries^ [i];
        FOREND;
        FREE block^.command_environment.auxiliary_libraries IN osv$task_shared_heap^;
      IFEND;

      new_auxiliary_libraries^ [1].name := path_handle_name;
      new_auxiliary_libraries^ [1].contains.commands :=
            library_list_entry^.dictionaries.command_dictionary <> NIL;
      new_auxiliary_libraries^ [1].contains.functions :=
            library_list_entry^.dictionaries.function_dictionary <> NIL;
      new_auxiliary_libraries^ [1].contains.help_modules :=
            library_list_entry^.dictionaries.help_module_dictionary <> NIL;
      new_auxiliary_libraries^ [1].contains.message_modules :=
            library_list_entry^.dictionaries.message_module_dictionary <> NIL;
      new_auxiliary_libraries^ [1].contains.panels :=
            library_list_entry^.dictionaries.panel_dictionary <> NIL;

      block^.command_environment.auxiliary_libraries := new_auxiliary_libraries;

    PROCEND add_auxiliary_library;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

*IF NOT $true(osv$unix)
    clp$validate_name (utility, validated_utility_name, name_is_valid);
*ELSE
    clp$validate_name (name, validated_utility_name, name_is_valid);
*IFEND
    IF NOT name_is_valid THEN
      osp$set_status_abnormal ('CL', cle$improper_utility_name, utility, status);
      RETURN;
    IFEND;

    clp$find_utility_block (validated_utility_name, block, block_in_current_task);
    IF block = NIL THEN
      osp$set_status_abnormal ('CL', cle$unknown_utility, utility, status);
      RETURN;
    ELSEIF NOT (block^.command_environment.command_level OR block_in_current_task) THEN
      osp$set_status_abnormal ('CL', cle$inaccessible_utility, utility, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'CLP$ADD_AUXILIARY_COMMAND_LIB', status);
      RETURN;
    IFEND;

*IF NOT $true(osv$unix)
    #CALLER_ID (caller_id);
*ELSE
    caller_id.ring := osc$user_ring;
*IFEND

    add_auxiliary_library (library, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_command_search_mode (search_mode);

    IF (checkout_library = '') OR (checkout_library = library) OR
          (search_mode <> clc$global_command_search) THEN
      RETURN;
    IFEND;

    add_auxiliary_library (checkout_library, status);
    status.normal := TRUE {ignore status from attempt to add checkout library} ;

  PROCEND clp$add_auxiliary_utility_lib;
*IFEND
?? TITLE := 'validate_utility_attributes', EJECT ??

  PROCEDURE validate_utility_attributes
    (    caller_ring: ost$valid_ring;
         defined_at_command_level: boolean;
         called_from_push_utility: boolean;
         attributes: clt$utility_attributes;
         default_command_table: ^clt$command_table;
         default_termination_command: ost$name_reference;
     VAR termination_command_ordinal: clt$named_entry_ordinal;
     VAR termination_command_index: clt$command_table_index;
     VAR library_names: ^array [1 .. * ] of fst$path_handle_name;
     VAR status: ost$status);

    VAR
      file: clt$file,
      functions_given: boolean,
      index: integer,
      index_string: ost$string,
      i: integer,
      ignore_library_list_entry: ^clt$command_library_list_entry,
      ignore_status: ost$status,
      number_of_libraries: integer,
      validated_name: ost$name,
      command_table: ^clt$command_table,
      termination_command: clt$command_name,
      termination_command_defined: boolean,
      attribute_key_is_good: boolean,
      attribute_value_is_good: boolean;


    status.normal := TRUE;
    library_names := NIL;
    functions_given := FALSE;
    command_table := default_command_table;
    termination_command := default_termination_command;

{ The same attribute key can be specified more than once.  The last one specified
{ is used.

  /validate_attributes/
    FOR index := 1 TO UPPERBOUND (attributes) DO
      attribute_key_is_good := TRUE;
      attribute_value_is_good := TRUE;

      CASE attributes [index].key OF

      = clc$null_utility_attribute =
        ;

      = clc$utility_command_search_mode =
        IF (attributes [index].command_search_mode < LOWERVALUE (clt$command_search_modes)) OR
              (attributes [index].command_search_mode > UPPERVALUE (clt$command_search_modes)) THEN
          attribute_value_is_good := FALSE;
        IFEND;

      = clc$utility_command_table =
        command_table := attributes [index].command_table;

      = clc$utility_function_table =
        IF (attributes [index].function_table <> NIL) AND defined_at_command_level THEN
          osp$set_status_abnormal ('CL', cle$not_yet_implemented, 'Command level functions', status);
          EXIT /validate_attributes/;
        IFEND;

      = clc$utility_function_proc_table =
        ;

      = clc$utility_interactive_include =
        IF (attributes [index].interactive_include_processor.call_method < LOWERVALUE (clt$call_method)) OR
              (attributes [index].interactive_include_processor.call_method > UPPERVALUE (clt$call_method))
              THEN
          attribute_value_is_good := FALSE;
        ELSE
          CASE attributes [index].interactive_include_processor.call_method OF
          = clc$proc_call, clc$program_call =

{ This error will be removed when an interactive include processor proc or
{ program call method is implemented.

            osp$set_status_abnormal ('CL', cle$not_yet_implemented,
                  'interactive include processor call method clc$proc_call/clc$program_call', status);
            EXIT /validate_attributes/;
          ELSE
            ;
          CASEND;
        IFEND;

      = clc$utility_libraries =
        IF library_names <> NIL THEN
          release_libraries (UPPERBOUND (library_names^), library_names);
        IFEND;

        IF attributes [index].libraries <> NIL THEN
          number_of_libraries := 0;
          FOR i := 1 TO UPPERBOUND (attributes [index].libraries^) DO
            IF attributes [index].libraries^ [i] <> '' THEN
              number_of_libraries := number_of_libraries + 1;
            IFEND;
          FOREND;

          IF number_of_libraries > 0 THEN
            ALLOCATE library_names: [1 .. number_of_libraries] IN osv$task_shared_heap^;
            number_of_libraries := 0;

          /validate_libraries/
            FOR i := 1 TO UPPERBOUND (attributes [index].libraries^) DO
              IF attributes [index].libraries^ [i] <> '' THEN
                number_of_libraries := number_of_libraries + 1;
*IF NOT $true(osv$unix)
                clp$convert_string_to_file (attributes [index].libraries^ [i], file, status);
                IF NOT status.normal THEN
                  attribute_value_is_good := FALSE;
                  number_of_libraries := number_of_libraries - 1;
                  EXIT /validate_libraries/;
                IFEND;
                clp$open_command_library (caller_ring, file.local_file_name, ignore_library_list_entry,
                      library_names^ [number_of_libraries], status);
                IF NOT status.normal THEN
                  attribute_value_is_good := FALSE;
                  number_of_libraries := number_of_libraries - 1;
                  EXIT /validate_libraries/;
                IFEND;
*ELSE
                library_names^ [number_of_libraries] := attributes [index].libraries^ [i];
*IFEND
              IFEND;
            FOREND /validate_libraries/;
          IFEND;
        IFEND;

      = clc$utility_line_preprocessor =
        IF (attributes [index].line_preprocessor.call_method < LOWERVALUE (clt$call_method)) OR
              (attributes [index].line_preprocessor.call_method > UPPERVALUE (clt$call_method)) THEN
          attribute_value_is_good := FALSE;
        ELSE
          CASE attributes [index].line_preprocessor.call_method OF
          = clc$proc_call, clc$program_call =

{ This error will be removed when a line preprocessor proc or program call method is implemented.

            osp$set_status_abnormal ('CL', cle$not_yet_implemented,
                  'line preprocessor call method clc$proc_call/clc$program_call', status);
            EXIT /validate_attributes/;
          ELSE
            ;
          CASEND;
        IFEND;

      = clc$utility_name =
        clp$validate_name (attributes [index].name, validated_name, attribute_value_is_good);

      = clc$utility_online_manual =
        IF attributes [index].online_manual_name <> osc$null_name THEN
          clp$validate_name (attributes [index].online_manual_name, validated_name, attribute_value_is_good);
        IFEND;

      = clc$utility_prompt =
        IF (attributes [index].prompt.size < LOWERVALUE (clt$prompt_size)) OR
              (attributes [index].prompt.size > UPPERVALUE (clt$prompt_size)) THEN
          attribute_value_is_good := FALSE;
        IFEND;

      = clc$utility_subcmnd_log_enabled =
        IF (attributes [index].subcommand_logging_enabled < LOWERVALUE (boolean)) OR
              (attributes [index].subcommand_logging_enabled > UPPERVALUE (boolean)) THEN
          attribute_value_is_good := FALSE;
        IFEND;

      = clc$utility_termination_command =
        IF attributes [index].termination_command <> osc$null_name THEN
          clp$validate_name (attributes [index].termination_command, termination_command,
                attribute_value_is_good);
        IFEND;

      ELSE
        attribute_key_is_good := FALSE;
      CASEND;

      IF NOT attribute_key_is_good THEN
*IF NOT $true(osv$unix)
        clp$convert_integer_to_string (index, 10, FALSE, index_string, ignore_status);
        IF status.normal OR (status.condition <> cle$unknown_utility_attribute) THEN
          osp$set_status_abnormal ('CL', cle$unknown_utility_attribute, index_string.
                value (index_string.size), status);
        ELSE
          osp$append_status_parameter (',', index_string.value (1, index_string.size), status);
        IFEND;
*ELSE
        osp$set_status_abnormal ('CL', cle$unknown_utility_attribute, '', status);
*IFEND
      ELSEIF NOT attribute_value_is_good THEN
*IF NOT $true(osv$unix)
        clp$convert_integer_to_string (index, 10, FALSE, index_string, ignore_status);
        IF status.normal THEN
          osp$set_status_abnormal ('CL', cle$improper_utility_attr_value, index_string.
                value (index_string.size), status);
        ELSEIF status.condition = cle$improper_utility_attr_value THEN
          osp$append_status_parameter (',', index_string.value (1, index_string.size), status);
        IFEND;
*ELSE
        osp$set_status_abnormal ('CL', cle$improper_utility_attr_value, '', status);
*IFEND
      IFEND;
    FOREND /validate_attributes/;

    IF status.normal THEN
      termination_command_ordinal := UPPERVALUE (termination_command_ordinal);
      termination_command_index := UPPERVALUE (termination_command_index);
      IF command_table <> NIL THEN
        clp$search_command_table (termination_command, command_table, termination_command_index,
              termination_command_defined);
        IF termination_command_defined THEN
          termination_command_ordinal := command_table^ [termination_command_index].ordinal;
        ELSEIF NOT called_from_push_utility THEN
          osp$set_status_abnormal ('CL', cle$term_command_not_defined, termination_command, status);
        IFEND;
      IFEND;
    IFEND;

    IF (NOT status.normal) AND (library_names <> NIL) THEN
      release_libraries (number_of_libraries, library_names);
    IFEND;

  PROCEND validate_utility_attributes;
?? TITLE := 'release_libraries', EJECT ??

  PROCEDURE release_libraries
    (    count: integer;
     VAR libraries {input, output} : ^array [1 .. * ] of fst$path_handle_name);

    VAR
      i: integer,
      ignore_status: ost$status,
      local_libraries: ^array [1 .. * ] of fst$path_handle_name;


    local_libraries := libraries;
    libraries := NIL;

    FOR i := 1 TO count DO
      clp$close_command_library (local_libraries^ [i], ignore_status);
    FOREND;

    FREE local_libraries IN osv$task_shared_heap^;

  PROCEND release_libraries;
?? TITLE := 'clp$set_include_processor_state', EJECT ??

  PROCEDURE [XDCL, #GATE] clp$set_include_processor_state
    (    name: clt$utility_name;
         active: boolean;
     VAR status: ost$status);

    VAR
      block: ^clt$block,
      ignore_block_in_current_task: boolean,
      name_is_valid: boolean,
      validated_utility_name: clt$utility_name;

    status.normal := TRUE;
    block := NIL;

    clp$validate_name (name, validated_utility_name, name_is_valid);
    IF NOT name_is_valid THEN
      osp$set_status_abnormal ('CL', cle$improper_utility_name, name, status);
      RETURN;
    IFEND;

    clp$find_utility_block (validated_utility_name, block, ignore_block_in_current_task);
    IF block = NIL THEN
      osp$set_status_abnormal ('CL', cle$unknown_utility, name, status);
      RETURN;
    IFEND;

    block^.include_processor_active := active;

  PROCEND clp$set_include_processor_state;

MODEND clm$command_utility_helper;
