Blame maint/extractstates.in

Packit 0848f5
#! /usr/bin/env perl
Packit 0848f5
# -*- Mode: perl; -*-
Packit 0848f5
# This file contains the routines specific to extracting the states from 
Packit 0848f5
# the source files and writing them to the .states-cache files.  This
Packit 0848f5
# file is input into the "extractstrings" perl script that creates
Packit 0848f5
# cache files in directory trees
Packit 0848f5
#
Packit 0848f5
# Creates the following files:
Packit 0848f5
#    src/include/mpiallstates.h - an enum of all of the states used in the
Packit 0848f5
#                                 code
Packit 0848f5
#    src/util/logging/common/state_names.h - a header file that provides an
Packit 0848f5
#                                 array of structures that map state
Packit 0848f5
#                                 value (from the enum in
Packit 0848f5
#                                 mpiallstates.h) to string names (and
Packit 0848f5
#                                 optional display colors).
Packit 0848f5
#                                 Replaces describe_states.c in the
Packit 0848f5
#                                 older version.
Packit 0848f5
#
Packit 0848f5
# Also allows an exceptions list on a per-directory basis.  This file is
Packit 0848f5
# describe_estates.txt, and contains
Packit 0848f5
# statename routine-name [r g b]
Packit 0848f5
# where [r g b] are optional and provide the color values as bytes, e.g.,
Packit 0848f5
#    255 0 0 
Packit 0848f5
# is red
Packit 0848f5
#
Packit 0848f5
# FIXME: Add better error detection and reporting
Packit 0848f5
# In the previous genstates.in script, a different set of problems in
Packit 0848f5
# the source code was detected.  Those included:
Packit 0848f5
#   Using STATE_DECL without FUNC_ENTER/EXIT
Packit 0848f5
#   Using FUNC_ENTER after FUNC_ENTER without FUNC_EXIT first
Packit 0848f5
#   Using FUNC_ENTER after FUNC_EXIT without a STATE_DECL first
Packit 0848f5
#
Packit 0848f5
# Some uses of these macros do not permit lexical scope checks.  For
Packit 0848f5
# example, code that has multiple "return"s, each of which has its
Packit 0848f5
# own FUNC_EXIT, will defeat the check for FUNC_ENTER after FUNC_EXIT
Packit 0848f5
# without a STATE_DECL
Packit 0848f5
#
Packit 0848f5
# Defaults for this step.  These are globals variables that are used
Packit 0848f5
# by routines in the extractstrings script.
Packit 0848f5
# findStateDecl is the routine that is run to scan a file for information
Packit 0848f5
use warnings;
Packit 0848f5
Packit 0848f5
$scanFile = "findStateDecl";
Packit 0848f5
$cachefile = '.state-cache';
Packit 0848f5
$pattern = '\.[chi](pp){0,1}$';
Packit 0848f5
$exceptionsFile = "estates.txt";
Packit 0848f5
Packit 0848f5
# Load in the routines to extract strings from files
Packit 0848f5
$maintdir = "./maint";
Packit 0848f5
require "$maintdir/extractstrings";
Packit 0848f5
Packit 0848f5
# These are "states" that are internal to a function, but still 
Packit 0848f5
# use FUNC_ENTER/EXIT
Packit 0848f5
%exceptionState = ( # System Calls
Packit 0848f5
                    'MPID_STATE_READ'   => 'read', 
Packit 0848f5
                    'MPID_STATE_WRITE'  => 'write', 
Packit 0848f5
                    'MPID_STATE_READV'  => 'readv', 
Packit 0848f5
                    'MPID_STATE_WRITEV' => 'writev', 
Packit 0848f5
                    'MPID_STATE_MEMCPY' => 'memcpy',
Packit 0848f5
                    'MPID_STATE_MPIDU_SOCK_LISTEN',   # used in sock code
Packit 0848f5
                    'MPID_STATE_MPIDU_SOCK_ACCEPT',
Packit 0848f5
                    'MPID_STATE_POLL'   => 'poll',
Packit 0848f5
                    # MPICH internal implementation routines
Packit 0848f5
                    'MPID_STATE_UPDATE_REQUEST' => 'update_request',
Packit 0848f5
                    'MPID_STATE_CREATE_REQUEST' => 'create_request',
Packit 0848f5
                    'MPID_STATE_MPIDU_YIELD'       => 'MPIDU_Yield',
Packit 0848f5
                    'MPID_STATE_MPIDU_SLEEP_YIELD' => 'MPIDU_Sleep_yield',
Packit 0848f5
                    'MPID_STATE_GETQUEUEDCOMPLETIONSTATUS' => 
Packit 0848f5
                                         'GetQueuedCompletionStatus',
Packit 0848f5
                    'MPID_STATE_CH3_CA_COMPLETE' => 'CH3_CA_Complete',
Packit 0848f5
		    'MPID_STATE_VAPI_REGISTER_MR' => 'vapi_register_mr',
Packit 0848f5
		    'MPID_STATE_VAPI_DEREGISTER_MR' => 'vapi_deregister_mr',
Packit 0848f5
		    'MPID_STATE_VAPI_POST_SR' => 'vapi_post_sr',
Packit 0848f5
                  );
Packit 0848f5
Packit 0848f5
# Set the default directories
Packit 0848f5
$dirs = "src/include src/mpi src/mpid/ch3 src/mpid/common src/util src/pmi src/binding src/nameserv";
Packit 0848f5
# Add mm for debugging
Packit 0848f5
#$dirs .= " src/mpid/mm";
Packit 0848f5
Packit 0848f5
# Check for options
Packit 0848f5
foreach (@ARGV) {
Packit 0848f5
    if (/-updateall/) { $gUpdateAll = 1; }
Packit 0848f5
    elsif (/-quiet/) {  $gVerbose = 0; }
Packit 0848f5
    elsif (/-verbose=(\d+)/) { $gVerbose = $1; }
Packit 0848f5
    elsif (/-verbose/) { $gVerbose = 1; }
Packit 0848f5
    elsif (/-xxx/) {
Packit 0848f5
        # gUpdateAll and scanFile are used in the extractstrings file.  To 
Packit 0848f5
        # keep perl -w happy, we provide another use of these two 
Packit 0848f5
        # symbols
Packit 0848f5
        print STDERR "gUpdateAll = $gUpdateAll, gVerbose = $gVerbose, and scanFile = $scanFile\n";
Packit 0848f5
    }
Packit 0848f5
    elsif (/-dirs=(.*)/) {
Packit 0848f5
        $dirs = $1;
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        print STDERR "Unrecognized argument $_\n";
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# First, update any cache files
Packit 0848f5
# This step reads each cache file and rescans any files more recent than 
Packit 0848f5
# their cached information are rescanned and the cachefiles are updated
Packit 0848f5
# Any file that needs to be updated is read with the routine given by
Packit 0848f5
# the variable "scanFile", which is "findStateDecl" in this script.
Packit 0848f5
foreach my $dir (split(/\s/,$dirs)) {
Packit 0848f5
    &processDirs( $dir, $cachefile, $pattern );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Now, extract all of the info from the cachefiles into allInfo
Packit 0848f5
# This reads the cached information.  catState will also read any
Packit 0848f5
# per-directory (allInfo is global and is accessed by catState)
Packit 0848f5
%allInfo = ();
Packit 0848f5
foreach my $dir (split(/\s/,$dirs)) {
Packit 0848f5
    &processDirsAndAction( $dir, "catState", $cachefile );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Make sure that there are no inconsistencies in the list by 
Packit 0848f5
# ensuring that all keys have the same descriptions.  Report on 
Packit 0848f5
# any problems
Packit 0848f5
&CheckAllInfo;
Packit 0848f5
Packit 0848f5
# Finally, use allInfo to create the final description.
Packit 0848f5
# What we do first is to convert it from lines that hash to a location 
Packit 0848f5
# (which makes it easier to identify problems) to a hash that maps keys to 
Packit 0848f5
# values.  This gives us one more opportunity to detect duplicate or 
Packit 0848f5
# mismatched values
Packit 0848f5
%allKeys = ();
Packit 0848f5
%allKeysLoc = ();
Packit 0848f5
foreach my $key (keys(%allInfo)) {
Packit 0848f5
     # Split line into value
Packit 0848f5
     my $val = "";
Packit 0848f5
     my $origKey = $key;
Packit 0848f5
     if ($key =~ /(\S+)\s+(.*)/) {
Packit 0848f5
          $key = $1;
Packit 0848f5
          $val = $2;
Packit 0848f5
      }
Packit 0848f5
     if (defined($allKeys{$key})) {
Packit 0848f5
         my $valForKey = $allKeys{$key};
Packit 0848f5
	 if ($valForKey ne $val) {
Packit 0848f5
	     print STDERR "\nInconsistent values for keys:\n";
Packit 0848f5
	     print STDERR "In $allInfo{$origKey}, have\n";
Packit 0848f5
             print STDERR" $key -> $val\n";
Packit 0848f5
	     print STDERR "also to $key -> $valForKey\n";
Packit 0848f5
             print STDERR "seen in $allKeysLoc{$key} .\n";
Packit 0848f5
             print STDERR "Using $key -> $val\n";
Packit 0848f5
	 }
Packit 0848f5
     }
Packit 0848f5
     $allKeys{$key} = $val;
Packit 0848f5
     $allKeysLoc{$key} = $allInfo{$origKey};
Packit 0848f5
}
Packit 0848f5
#
Packit 0848f5
Packit 0848f5
# # FIXME: Who uses this now
Packit 0848f5
# # This roughly reproduces the describe_states file
Packit 0848f5
# open DS, ">src/describe_states.txt" || die "Cannot open src/describe_states.txt";
Packit 0848f5
# foreach my $key (sort(keys(%allInfo))) {
Packit 0848f5
#     $key =~ s/\r?\n//;
Packit 0848f5
#     my $funcname = "";
Packit 0848f5
#     if ($key =~ /(\S+)\s+(\S+)/) {
Packit 0848f5
#         $key      = $1;
Packit 0848f5
#         $funcname = $2;
Packit 0848f5
#     }
Packit 0848f5
#     else {
Packit 0848f5
#        $funcname = $key;
Packit 0848f5
#        if ($key =~ /^(MPID[A-Z]*_STATE_)+(MPI[A-Z]*)_(\w)(\S+)/) {
Packit 0848f5
#   	    $funcname = "$2_$3" . lc($4);
Packit 0848f5
#        }
Packit 0848f5
#     }
Packit 0848f5
#     print DS "$key $funcname\n";
Packit 0848f5
# }
Packit 0848f5
# close DS;
Packit 0848f5
Packit 0848f5
open DH, ">src/include/mpiallstates.h" || die "Cannot open src/include/mpiallstates.h";
Packit 0848f5
print DH "/* -*- Mode: C; c-basic-offset:4 ; -*- */
Packit 0848f5
/*  
Packit 0848f5
 *  (C) 2005 by Argonne National Laboratory.
Packit 0848f5
 *      See COPYRIGHT in top-level directory.
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
/* DO NOT EDIT: AUTOMATICALLY GENERATED BY extractstates */
Packit 0848f5
#ifndef MPIALLSTATES_H_INCLUDED
Packit 0848f5
#define MPIALLSTATES_H_INCLUDED\n";
Packit 0848f5
# print the enum of states
Packit 0848f5
print DH "\nenum MPID_TIMER_STATE {\n";
Packit 0848f5
foreach my $key (sort(keys(%allKeys))) {
Packit 0848f5
    print DH "\t$key,\n";
Packit 0848f5
}
Packit 0848f5
print DH "\tMPID_NUM_TIMER_STATES };\n";
Packit 0848f5
print DH "#endif\n";
Packit 0848f5
close DH;
Packit 0848f5
Packit 0848f5
Packit 0848f5
# Create the description of the states
Packit 0848f5
# This roughly reproduces the describe_states.c file
Packit 0848f5
open DC, ">src/util/logging/common/state_names.h" || 
Packit 0848f5
    die "Cannot open new state_names.h file";
Packit 0848f5
Packit 0848f5
# Print header
Packit 0848f5
# Note that we include only mpiallstates.h .  It is important not to
Packit 0848f5
# include mpiimpl.h, since this file may be used in code that wants to
Packit 0848f5
# be well modularized and not be entangled with the general MPICH 
Packit 0848f5
# implementation header.
Packit 0848f5
print DC "/* -*- Mode: C; c-basic-offset:4 ; -*- */
Packit 0848f5
/*  
Packit 0848f5
 *  (C) 2005 by Argonne National Laboratory.
Packit 0848f5
 *      See COPYRIGHT in top-level directory.
Packit 0848f5
 */
Packit 0848f5
/* DO NOT EDIT: AUTOMATICALLY GENERATED BY extractstates */
Packit 0848f5
#ifndef STATE_NAMES_H_INCLUDED
Packit 0848f5
#define STATE_NAMES_H_INCLUDED
Packit 0848f5
#include \"mpiallstates.h\"
Packit 0848f5
/* STATES:SKIP */\n";
Packit 0848f5
Packit 0848f5
# Change in definition:
Packit 0848f5
# We simply build an array of names and colors; the routine
Packit 0848f5
# that is called will generate a color if none is provided.
Packit 0848f5
print DC "typedef struct { 
Packit 0848f5
    int state; const char *funcname; const char *color; } MPIU_State_defs;
Packit 0848f5
static MPIU_State_defs mpich_states[] = {\n";
Packit 0848f5
foreach my $key (sort(keys(%allInfo))) {
Packit 0848f5
    $key =~ s/\r?\n//;
Packit 0848f5
    my $funcname = "";
Packit 0848f5
    my $color = "";
Packit 0848f5
    if ($key =~ /(\S+)\s+(\S+)\s+(\S.*\S+)\s*/) {
Packit 0848f5
        # This allows colors to be either a name or a tuple
Packit 0848f5
        $key      = $1;
Packit 0848f5
        $funcname = $2;
Packit 0848f5
        $color    = $3;
Packit 0848f5
    }
Packit 0848f5
    elsif ($key =~ /(\S+)\s+(\S+)/) {
Packit 0848f5
        $key = $1;
Packit 0848f5
        $funcname = $2;
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        $funcname = $key;
Packit 0848f5
        if ($key =~ /^(MPID[A-Z]*_STATE_)+(MPI[A-Z]*)_(\w)(\S+)/) {
Packit 0848f5
	    $funcname = "$2_$3" . lc($4);
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
    # Turn color into a quoted string or null 
Packit 0848f5
    if ($color ne "") { 
Packit 0848f5
        $color = "\"$color\"";
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        $color = "(const char *)0";
Packit 0848f5
    }
Packit 0848f5
    print DC "    { $key, \"$funcname\", $color },\n";
Packit 0848f5
}
Packit 0848f5
print DC "    { -1, (const char *)0, (const char *)0 } };\n";
Packit 0848f5
print DC "#endif\n";
Packit 0848f5
close DC;
Packit 0848f5
Packit 0848f5
# --------------------
Packit 0848f5
# Read a file and find the state definitions
Packit 0848f5
# This routine is invoked by the "ProcessFile" script in extractstates, 
Packit 0848f5
# which in turn is invoked by ProcessDir.  It returns a string
Packit 0848f5
# of newline-separated items which are simply the items that need to be
Packit 0848f5
# added to the cache file for a given directory, for this particular file.
Packit 0848f5
sub findStateDecl {
Packit 0848f5
    my $file = $_[0];
Packit 0848f5
    my $info = "";           # newline separate list of states in a file
Packit 0848f5
    my $linenum = 0;         # Keep track of location in file
Packit 0848f5
    my $curfuncname = "";
Packit 0848f5
    my $lastFuncname = "";   # Last funcname and state are used to help with
Packit 0848f5
    my $lastState    = "";   # routines that have multiple declaration
Packit 0848f5
                             # blocks protected by ifdefs (to avoid false
Packit 0848f5
                             # warnings about missing FUNCNAME definitions).
Packit 0848f5
    my %knownLines = ();     # Hash used to detect duplicate lines
Packit 0848f5
    my %knownStates = ();    # Hash used to detect known states, to avoid
Packit 0848f5
                             # adding additional lines of the for "state"
Packit 0848f5
                             # where "state name" has been already added 
Packit 0848f5
                             # (this can happen in places where there are 
Packit 0848f5
                             # multiple STATE_DECLS for a single FUNCNAME,
Packit 0848f5
                             # which is discouraged but allowed.
Packit 0848f5
    my $inDecls = 0;         # Keep track of whether we're still seeing
Packit 0848f5
                             # state declarations or not.
Packit 0848f5
    my $inComment = 0;
Packit 0848f5
    my $showWarnings = 1;    # Allow files to turn off warnings
Packit 0848f5
Packit 0848f5
    open FD, "<$file" || die "Cannot open $file\n";
Packit 0848f5
    while (<FD>) {
Packit 0848f5
	$linenum++;
Packit 0848f5
	# This allows us to skip files that are, for example, generated
Packit 0848f5
	# from the states information (e.g., the describe_states.h file)
Packit 0848f5
	if (/\/\*\s+STATES:SKIP\s+\*\//) {
Packit 0848f5
	    last;
Packit 0848f5
	}
Packit 0848f5
	if (/\/\*\s+STATES:NO WARNINGS\s+\*\//) {
Packit 0848f5
	    $showWarnings = 0;
Packit 0848f5
	    next;
Packit 0848f5
	}
Packit 0848f5
	# Skip commented out definitions.  The complexity here handles
Packit 0848f5
	# multi-line comments
Packit 0848f5
	if ($inComment) {
Packit 0848f5
	    if (/.*\*\/(.*)/) {
Packit 0848f5
		$_ = 1;
Packit 0848f5
		$inComment = 0;
Packit 0848f5
	    }
Packit 0848f5
	    else {
Packit 0848f5
		$_ = "";
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    $processed = "";
Packit 0848f5
	    while (/(.*)\/\*(.*)/) {
Packit 0848f5
		$processed .= $1;
Packit 0848f5
		$_ = $2;
Packit 0848f5
		if (/.*\*\/(.*)/) {
Packit 0848f5
		    $inComment = 0;
Packit 0848f5
		    $_ = $1;
Packit 0848f5
		}
Packit 0848f5
		else {
Packit 0848f5
		    $inComment = 1;
Packit 0848f5
		    $_ = "";
Packit 0848f5
		}
Packit 0848f5
	    }
Packit 0848f5
	    $_ = $processed . $_;
Packit 0848f5
	}
Packit 0848f5
	
Packit 0848f5
Packit 0848f5
	if (/^\#\s*define\s+FUNCNAME\s+(\S*)/) {
Packit 0848f5
	    $curfuncname = $1;
Packit 0848f5
	    $lastState = "";
Packit 0848f5
	}
Packit 0848f5
	elsif (/STATE_DECL\((.*)\)/ && !/^\#\s*define\s/) {
Packit 0848f5
	    my $state = $1;
Packit 0848f5
	    my $candidateLine = "";
Packit 0848f5
	    $state =~ s/\s+//g;   # Remove blanks
Packit 0848f5
	    $candidateLine .= $state;
Packit 0848f5
	    # Check for special cases (mostly system calls embedded within
Packit 0848f5
	    # other routines that are not implemented by MPICH.
Packit 0848f5
	    # In the long run, these should use a different macro instead
Packit 0848f5
	    # of MPIxxx_STATE_DECL
Packit 0848f5
	    if (!$inDecls) { $lastState = ""; }
Packit 0848f5
	    $inDecls = 1;
Packit 0848f5
	    if (defined($exceptionState{$state})) {
Packit 0848f5
		$candidateLine .= " " . $exceptionState{$state};
Packit 0848f5
		$lastState .= ":$state:";
Packit 0848f5
	    }
Packit 0848f5
	    else {
Packit 0848f5
		# Check for (a) this state is known, (b) that state
Packit 0848f5
		# has an associated name, and (c) curfuncname is null
Packit 0848f5
		if (defined($knownStates{$state}) && 
Packit 0848f5
		    $knownStates{$state} ne "" && $curfuncname eq "") {
Packit 0848f5
		    print "Skipping state definition $state because already set to $knownStates{$state}\n" if $gVerbose;
Packit 0848f5
		    # Skip this state
Packit 0848f5
		    next;
Packit 0848f5
		}
Packit 0848f5
Packit 0848f5
  	        # Reload curfuncname if this is the same state as the last 
Packit 0848f5
		# state
Packit 0848f5
	        if ($curfuncname eq "" && $lastState eq ":$state:") {
Packit 0848f5
		    $curfuncname = $lastFuncname;
Packit 0848f5
	        }
Packit 0848f5
		if ($curfuncname ne "") {
Packit 0848f5
		    $candidateLine .= " $curfuncname";
Packit 0848f5
		}
Packit 0848f5
		else {
Packit 0848f5
		    print STDERR "Warning: no FUNCNAME defined for $state in $file\n" if $showWarnings;
Packit 0848f5
		}
Packit 0848f5
		$lastState    .= ":$state:";
Packit 0848f5
		if ($curfuncname ne "") {
Packit 0848f5
		    $lastFuncname = $curfuncname;
Packit 0848f5
		}
Packit 0848f5
		# Save this state and the associated function name
Packit 0848f5
		if (!defined($knownStates{$state})) {
Packit 0848f5
		    $knownStates{$state} = $curfuncname;
Packit 0848f5
		}
Packit 0848f5
Packit 0848f5
		# Once we see the declaration of the state, set the
Packit 0848f5
		# state name to empty.  The source code must be organized
Packit 0848f5
		# so that the state declarations only appear once LEXICALLY
Packit 0848f5
		# in the code. 
Packit 0848f5
		if (! $showWarnings) {
Packit 0848f5
		    $curfuncname  = "";
Packit 0848f5
		}
Packit 0848f5
	    }
Packit 0848f5
	    if (!defined($knownLines{$candidateLine})) {
Packit 0848f5
		$info .= $candidateLine . "\n";
Packit 0848f5
		$knownLines{$candidateLine} = $linenum;
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	elsif (/FUNC_ENTER\((.*)\)/ && !/^\#\s*define\s/) {
Packit 0848f5
	    # Match with current state
Packit 0848f5
	    my $state = $1;
Packit 0848f5
	    $inDecls = 0;
Packit 0848f5
	    if (! ($lastState =~ /:$state:/) &&
Packit 0848f5
		! defined($exceptionState{$state}) ) {
Packit 0848f5
		print STDERR "Warning: State in FUNC_ENTER($state) does not match STATE_DECL($lastState) in $file\n" if $showWarnings;
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	elsif (/FUNC_EXIT\((.*)\)/ && !/^\#\s*define\s/) {
Packit 0848f5
	    # Match with current state
Packit 0848f5
	    my $state = $1;
Packit 0848f5
	    $inDecls = 0;
Packit 0848f5
	    if (! ($lastState =~ /:$state:/) && 
Packit 0848f5
		! defined($exceptionState{$state})) {
Packit 0848f5
		print STDERR "Warning: State in FUNC_EXIT($state) does not match STATE_DECL($lastState) in $file\n" if $showWarnings;
Packit 0848f5
	    }
Packit 0848f5
#	    else {
Packit 0848f5
#		# Remove this state from the defined states
Packit 0848f5
#		$lastState =~ s/:$state://;
Packit 0848f5
#	    }
Packit 0848f5
	}
Packit 0848f5
	
Packit 0848f5
    }
Packit 0848f5
    close FD;
Packit 0848f5
Packit 0848f5
    return $info;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Read the cache file and add the information to the hash allInfo
Packit 0848f5
# The key for allInfo is the specification line, the value is the location 
Packit 0848f5
# of the cache file where the value was found.
Packit 0848f5
# For entries from the exceptions file, the value is the location of the
Packit 0848f5
# exceptions file.
Packit 0848f5
sub catState {
Packit 0848f5
   my ($dir,$cachefile) = @_;
Packit 0848f5
   if (-s "$dir/$cachefile") {
Packit 0848f5
       my %f = &ReadCacheContents( $dir, $cachefile );
Packit 0848f5
       foreach my $key (keys(%f)) {
Packit 0848f5
	   foreach my $value (split/\n/,$f{$key}) {
Packit 0848f5
	       $allInfo{$value} = "$dir/$cachefile";
Packit 0848f5
	   }
Packit 0848f5
       }
Packit 0848f5
   }
Packit 0848f5
   if (-s "$dir/$exceptionsFile") {
Packit 0848f5
       print "Reading $dir/$exceptionsFile\n" if $gVerbose;
Packit 0848f5
       open CFD, "<$dir/$exceptionsFile" || 
Packit 0848f5
	   die "Could not open $dir/$exceptionsFile";
Packit 0848f5
       while (<CFD>) {
Packit 0848f5
	   s/#.*//;
Packit 0848f5
	   if (/^(\S+)\s+(\S+)\s*(.*)/) {
Packit 0848f5
	       # Found a conforming line. 
Packit 0848f5
	       my $key = $1;
Packit 0848f5
	       my $name = $2;
Packit 0848f5
	       my $color = $3;
Packit 0848f5
	       my $defaultKey = $1 . " " . $2;
Packit 0848f5
	       if (defined($allInfo{$defaultKey}) && $color ne "") {
Packit 0848f5
		   # Replace this entry
Packit 0848f5
		   delete $allInfo{$defaultKey};
Packit 0848f5
	       }
Packit 0848f5
	       $allInfo{$_} = "$dir/$exceptionsFile";
Packit 0848f5
	   }
Packit 0848f5
       }
Packit 0848f5
       close CFD;
Packit 0848f5
   }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# --------------------------------------------------------------------------
Packit 0848f5
# Make sure that there are no inconsistencies in the list by 
Packit 0848f5
# ensuring that all keys have the same descriptions.  Also
Packit 0848f5
# synthesize the function names here
Packit 0848f5
# Keys in allInfo are of the form "state [optional func]"
Packit 0848f5
# The value is the cache file in which the key was defined.
Packit 0848f5
# stateNames is used to keep track of all states, so that if the 
Packit 0848f5
# same state is defined in multiple cache files, but with different
Packit 0848f5
# values, we can detect the inconsistency.
Packit 0848f5
sub CheckAllInfo {
Packit 0848f5
    my %stateNames = ();
Packit 0848f5
    my %stateLoc   = ();
Packit 0848f5
    foreach my $key (sort(keys(%allInfo))) {
Packit 0848f5
	my $val = "";
Packit 0848f5
	my $color = "";
Packit 0848f5
	my $origkey = $key;
Packit 0848f5
	my $origval = "";
Packit 0848f5
	if ($key =~ /(\S+)\s+(.+)/) {
Packit 0848f5
	    $key = $1;
Packit 0848f5
	    $val = $2;
Packit 0848f5
	    $origval = $val;
Packit 0848f5
	}
Packit 0848f5
	elsif ($key =~ /\s/) {
Packit 0848f5
	    print STDERR "Key :$key: contains a blank, found in $allInfo{$origkey}\n";
Packit 0848f5
	}
Packit 0848f5
	
Packit 0848f5
	# If there is no value (no function name to go with the state,
Packit 0848f5
	# synthesize one
Packit 0848f5
	if ($val eq "") {
Packit 0848f5
	    $val = $key;
Packit 0848f5
	    if ($val =~ /^(MPID[A-Z]*_STATE_)+(MPI[A-Z]*)_(\w)(\S+)/) {
Packit 0848f5
		$val = "$2_$3" . lc($4);
Packit 0848f5
	    }
Packit 0848f5
	    print "Setting value for state $key to $val for entry found in $allInfo{$origkey}\n" if $gVerbose;
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
	if (defined($stateNames{$key})) {
Packit 0848f5
	    if ($stateNames{$key} ne $val) {
Packit 0848f5
		# There are two possibilities: 
Packit 0848f5
		# One of the values is cached and the other is an exception
Packit 0848f5
		# value, in which case we reject the cached value
Packit 0848f5
		# The other possiblity is a conflict, which we report.
Packit 0848f5
		
Packit 0848f5
		print STDERR "\nInconsistent value for state of $key:\n";
Packit 0848f5
		print STDERR "Old : $stateNames{$key} in $stateLoc{$key}\n";
Packit 0848f5
		print STDERR "New : $val in $allInfo{$origkey}\n";
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    $stateNames{$key} = $val;
Packit 0848f5
	    $stateLoc{$key}   = $allInfo{$origkey};
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
}