  PROCEDURE find_applicable_policy
    (    criteria: ost$ecp_criteria;
         policies_sequence_header: ^ost$ecp_header;
     VAR applicable_actions: ost$ecp_actions;
     VAR applicable_policy: ^ost$ecp_policy_header;
     VAR status: ost$status);


{ Design:
{ This is a common procedure used to find the applicable policy in a sequence
{ of exception condition policies.
{
{ Policies are stored in chronological order in the policies sequence.  Each
{ policy defines criteria such as "who" is accessing an object that has an
{ exception condition and "what" kind of object is accessed.  Policy criteria
{ are all weighted differently so that the best policy is applied in any given
{ situation.  All of the policies are visited in the order in which they were
{ defined, with the most recent policy that applies and whose criteria weight
{ is >= to that of any preceding policy being the chosen one.

{ The applicable policy is the one 1) that has any of its "who" or "what"
{ criteria parameters match the corresponding value of the CRITERIA parameter
{ of this procedure 2) that is the most specific (i.e., has the greatest
{ weight), and 3) that is the most recently specified policy.

{ Policy parameters are investigated in order of least weight to greatest
{ weight.  All policy criteria defined within the same CHAEP subcommand are
{ considered.  A policy with multiple criteria parameters specified is
{ processed in the same manner as if multiple commands were specified, each
{ with a single policy criteria, i.e.  it is sufficient that any single
{ policy criteria be satisfied for the policy to be considered a candidate.

{ The CRITERIA.CONDITION field could have been investigated either first or
{ last.  The decision to consider it first was made out of consideration for
{ performance; however, technically, CRITERIA.CONDITION is the most specific
{ aspect of the policy.


    VAR
      candidate: boolean,
      candidate_actions: ost$ecp_actions,
      candidate_policy_weight: ost$ecp_policy_weight,
      condition: ^ost$ecp_exception_condition,
      greatest_policy_weight: ost$ecp_policy_weight,
      i: ost$non_negative_integers,
      policy: ^ost$ecp_policy_header,
      policy_number: ost$non_negative_integers;

?? NEWTITLE := '  match_all_files', EJECT ??

    PROCEDURE match_all_files;

      IF policy^.files.specified THEN
        IF policy^.files.all_specified THEN
          candidate_policy_weight := osc$ecp_all_files_priority;
        IFEND;
      IFEND;
    PROCEND match_all_files;
?? OLDTITLE ??
?? NEWTITLE := '  match_condition', EJECT ??

    PROCEDURE match_condition;

?? NEWTITLE := 'find_exception_condition' ??

      PROCEDURE find_exception_condition
        (    policy: ^ost$ecp_policy_header;
             condition_ordinal: fst$file_access_condition;
         VAR condition_entry: ^ost$ecp_exception_condition);

        VAR
          i: ost$ecp_number_of_conditions;

        condition_entry := NIL;
        FOR i := 1 TO UPPERBOUND (policy^.conditions) DO
          IF condition_ordinal IN policy^.conditions [i].
                file_access_conditions THEN
            condition_entry := ^policy^.conditions [i];
            RETURN;
          IFEND;
        FOREND;
      PROCEND find_exception_condition;
?? OLDTITLE, EJECT ??

      candidate := FALSE;
      condition := NIL;

      find_exception_condition (policy, criteria.condition, condition);
      IF condition <> NIL THEN
        candidate := condition^.specified;
        IF candidate THEN
          candidate_actions := condition^.actions;
        IFEND;
      IFEND;
    PROCEND match_condition;
?? OLDTITLE ??
?? NEWTITLE := '  match_family_name', EJECT ??

    PROCEDURE match_family_name;

      IF (policy^.families <> NIL) AND (criteria.family_path_name <>
            osc$null_name) THEN
        FOR i := 1 TO UPPERBOUND (policy^.families^) DO
          IF criteria.family_path_name = policy^.families^ [i] THEN
            candidate_policy_weight := osc$ecp_family_priority;
            RETURN;
          IFEND;
        FOREND;
      IFEND;
    PROCEND match_family_name;
?? OLDTITLE ??
?? NEWTITLE := '  match_specific_file', EJECT ??

    PROCEDURE match_specific_file;

      VAR
        evaluated_file_reference: fst$evaluated_file_reference,
        local_status: ost$status,
        match_info: clt$string_pattern_match_info,
        path: fst$path,
        path_size: fst$path_size,
        string_pattern: ^clt$string_pattern,
        target_path_size: 1 .. fsc$max_path_size,
        work_area: ^clt$work_area;

      PUSH work_area :[[REP (5 * fsc$max_path_size) OF CELL]];
      IF policy^.files.specified AND (NOT policy^.files.all_specified) AND
            (criteria.file <> osc$null_name) THEN
        target_path_size := clp$trimmed_string_size (criteria.file);
        FOR i := 1 TO UPPERBOUND (policy^.files.path_list^) DO
          path_size := STRLENGTH (policy^.files.path_list^ [i].path^);
          CASE policy^.files.path_list^ [i].file_reference_type OF
          = osc$ecp_evaluated_reference =
            IF target_path_size >= path_size THEN
              IF policy^.files.path_list^ [i].path^ (1, path_size) =
                    criteria.file (1, path_size) THEN
                candidate_policy_weight := osc$ecp_specific_path_priority;
                RETURN;
              IFEND;
            IFEND;

          = osc$ecp_generic_reference, osc$ecp_wild_card_reference =

            clp$evaluate_file_reference (policy^.files.path_list^ [i].path^,
                  $clt$file_ref_parsing_options [clc$multiple_reference_allowed]
                  , FALSE, evaluated_file_reference, local_status);
            IF local_status.normal THEN
              clp$convert_file_ref_to_string (evaluated_file_reference, TRUE,
                    path, path_size, local_status);
              IF local_status.normal THEN
                IF evaluated_file_reference.multiple_reference_specified THEN
                  clp$build_pattern_for_wild_card
                        (policy^.files.path_list^ [i].wild_card_pattern_type,
                        $clt$string_pattern_build_opts
                        [clc$sp_file_reference_pattern, clc$sp_match_at_right,
                        clc$sp_ignore_matched_substring], path (1, path_size),
                        work_area, string_pattern, local_status);
                  IF local_status.normal THEN
                    clp$match_string_pattern (criteria.
                          file (1, target_path_size), string_pattern,
                          clc$sp_anchored, clc$sp_quick_scan, match_info,
                          local_status);
                    IF local_status.normal THEN
                      IF match_info.result = clc$sp_success THEN
                        candidate_policy_weight :=
                              osc$ecp_specific_path_priority;
                        RETURN;
                      IFEND;
                    IFEND;
                  IFEND;
                ELSE
                  IF target_path_size >= path_size THEN
                    IF path (1, path_size) = criteria.file (1, path_size) THEN
                      candidate_policy_weight := osc$ecp_specific_path_priority;
                      RETURN;
                    IFEND;
                  IFEND;
                IFEND;
              IFEND;
            IFEND;
          CASEND;
        FOREND;
      IFEND;
    PROCEND match_specific_file;
?? OLDTITLE ??
?? NEWTITLE := '  match_job', EJECT ??

    PROCEDURE match_job;

      IF policy^.jobs <> NIL THEN
        FOR i := 1 TO UPPERBOUND (policy^.jobs^) DO
          IF criteria.job = policy^.jobs^ [i] THEN
            candidate_policy_weight := osc$ecp_job_priority;
            RETURN;
          IFEND;
        FOREND;
      IFEND;
    PROCEND match_job;
?? OLDTITLE ??
?? NEWTITLE := '  match_job_class', EJECT ??

    PROCEDURE match_job_class;

      IF policy^.job_classes <> NIL THEN
        FOR i := 1 TO UPPERBOUND (policy^.job_classes^) DO
          IF criteria.job_class = policy^.job_classes^ [i] THEN
            candidate_policy_weight := osc$ecp_job_class_priority;
            RETURN;
          IFEND;
        FOREND;
      IFEND;
    PROCEND match_job_class;
?? OLDTITLE ??
?? NEWTITLE := '  match_job_mode', EJECT ??

    PROCEDURE match_job_mode;

      IF policy^.job_mode.specified THEN
        IF (criteria.job_mode = policy^.job_mode.value) THEN
          candidate_policy_weight := osc$ecp_job_mode_priority;
        IFEND;
      IFEND;
    PROCEND match_job_mode;
?? OLDTITLE ??
?? NEWTITLE := '  match_login_user', EJECT ??

    PROCEDURE match_login_user;

      VAR
        list_item_candidate: boolean,
        list_item_policy_weight: ost$ecp_policy_weight;

      IF policy^.login_users <> NIL THEN
        FOR i := 1 TO UPPERBOUND (policy^.login_users^) DO
          list_item_candidate := TRUE;
          list_item_policy_weight := osc$ecp_nonapplicable_policy;
          IF osc$lu_user_name IN policy^.login_users^ [i].specified_fields THEN
            list_item_candidate := list_item_candidate AND
                  (criteria.login_user = policy^.login_users^ [i].user_name);
            list_item_policy_weight := osc$ecp_lu_user_priority;
          IFEND;
          IF osc$lu_family_name IN policy^.login_users^ [i].
                specified_fields THEN
            list_item_candidate := list_item_candidate AND
                  (criteria.login_family = policy^.login_users^ [i].
                  family_name);
            list_item_policy_weight := osc$ecp_lu_family_priority;
          IFEND;
          IF osc$lu_job_class IN policy^.login_users^ [i].specified_fields THEN
            list_item_candidate := list_item_candidate AND
                  (criteria.job_class = policy^.login_users^ [i].job_class);
            list_item_policy_weight := osc$ecp_lu_job_class_priority;
          IFEND;
          IF osc$lu_job_mode IN policy^.login_users^ [i].specified_fields THEN
            list_item_candidate := list_item_candidate AND
                  (criteria.job_mode = policy^.login_users^ [i].job_mode);
            list_item_policy_weight := osc$ecp_lu_job_mode_priority;
          IFEND;
          IF list_item_candidate AND (list_item_policy_weight >=
                candidate_policy_weight) THEN
            candidate_policy_weight := list_item_policy_weight;
          IFEND;
        FOREND;
      IFEND;
    PROCEND match_login_user;
?? OLDTITLE ??
?? NEWTITLE := '  match_ms_class', EJECT ??

    PROCEDURE match_ms_class;

      IF policy^.mass_storage_classes.specified THEN
        IF (criteria.mass_storage_class IN policy^.mass_storage_classes.value)
              THEN
          candidate_policy_weight := osc$ecp_ms_class_priority;
        IFEND;
      IFEND;
    PROCEND match_ms_class;
?? OLDTITLE ??
?? NEWTITLE := '  match_set_name', EJECT ??

    PROCEDURE match_set_name;

      IF policy^.sets <> NIL THEN
        FOR i := 1 TO UPPERBOUND (policy^.sets^) DO
          IF criteria.set_name = policy^.sets^ [i] THEN
            candidate_policy_weight := osc$ecp_set_priority;
            RETURN;
          IFEND;
        FOREND;
      IFEND;
    PROCEND match_set_name;
?? OLDTITLE ??
?? NEWTITLE := '  match_volume', EJECT ??

    PROCEDURE match_volume;

      VAR
        j: ost$positive_integers;

      IF (criteria.volume_list <> NIL) AND (policy^.volumes <> NIL) THEN
        FOR i := 1 TO UPPERBOUND (policy^.volumes^) DO
          FOR j := 1 TO UPPERBOUND (criteria.volume_list^) DO
            IF criteria.volume_list^ [j].recorded_vsn = policy^.
                  volumes^ [i] THEN
              candidate_policy_weight := osc$ecp_volume_priority;
              RETURN;
            IFEND;
          FOREND;
        FOREND;
      IFEND;
    PROCEND match_volume;
?? OLDTITLE ??
?? EJECT ??

    VAR
      local_status: ost$status;

    status.normal := TRUE;

    applicable_actions := $ost$ecp_actions [];
    candidate_actions := $ost$ecp_actions [];
    applicable_policy := NIL;
    greatest_policy_weight := osc$ecp_nonapplicable_policy;

    IF (policies_sequence_header <> NIL) THEN
      policy := policies_sequence_header^.first_policy;
      policy_number := 1;
      WHILE (policy <> NIL) AND (policy_number <=
            policies_sequence_header^.number_of_policies) DO

       candidate_policy_weight := osc$ecp_nonapplicable_policy;
        match_condition;
        IF candidate THEN
          match_all_files;
          match_set_name;
          match_family_name;
          match_ms_class;
          match_volume;
          match_specific_file;
          match_job_class;
          match_job_mode;
          match_login_user;
          match_job;
          IF (candidate_policy_weight >= greatest_policy_weight) AND
                 (candidate_policy_weight <> osc$ecp_nonapplicable_policy) THEN
            applicable_actions := candidate_actions;
            applicable_policy := policy;
            greatest_policy_weight := candidate_policy_weight;
          IFEND;
        IFEND;
        policy := policy^.next_policy;
        policy_number := policy_number + 1;
      WHILEND;
    IFEND;
  PROCEND find_applicable_policy;

