consultant.h

/* This is the header file for the Consultant module.  It is also included by
   the Cases and Adjuster modules. */

/* external functions */

extern int
Get_Option(
      string question,
      string options);

extern vector_element *
Get_Facts(
      file log_stream,
      case_law_specification case_law,
      area *area_pointer,
      boolean adjust,
      boolean echo,
      boolean inputable_latex,
      boolean verbose,
      cardinal hypothetical_reports,
      cardinal hypothetical_changes,
      cardinal level,
      string distances_filename,
      string weights_filename,
      string report_filename);

consultant.c

/* This is the implementation file for the Consultant module. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "shyster.h"
#include "cases.h"
#include "consultant.h"

static void
error_exit(
      file stream,
      const string message)
{
   Write_Error_Message_And_Exit(stream, "Consultant", message);
}

extern int
Get_Option(
      string question,
      string options)

/* Asks the user the question, and reads the user's response until a valid
   option - one of the characters in the options string, or Q (quit) - is
   chosen.  Treats lower-case alphabetic characters entered by the user as if
   they were upper-case.  Treats the end of the file as a Q. Returns the
   chosen character. */

{
   int ch,
      temp_ch;
   cardinal count;

   fprintf(stdout, "%s (%sQ)? ", question, options);

   for (;;) {

      if ((ch = getc(stdin)) == EOF)
         return Quit_Character;

      /* convert ch to upper-case if necessary */

      if ((ch >= Little_A_Character) && (ch <= Little_Z_Character))
         ch = Big_A_Character + ch - Little_A_Character;

      if (ch == Quit_Character) {

         /* skip over the rest of the line of input */

         for (temp_ch = getc(stdin);
               (temp_ch != Carriage_Return_Character) && (temp_ch != EOF);
               temp_ch = getc(stdin));

         return Quit_Character;
      }
      if (ch != Carriage_Return_Character) {

         /* skip over the rest of the line of input */

         for (temp_ch = getc(stdin);
               (temp_ch != Carriage_Return_Character) && (temp_ch != EOF);
               temp_ch = getc(stdin));

         if (temp_ch == EOF)
            return Quit_Character;
      }
      if (strchr(options, ch) != NULL)

         /* the user has entered a valid option */

         return ch;

      /* the user has entered an invalid option */

      fprintf(stdout, "Please enter `%c'", options[0]);
      for (count = 1; options[count] != Null_Character; count += sizeof(char))
         fprintf(stdout, ", `%c'", options[count]);
      fprintf(stdout, " or `%c'.\n%s? ", Quit_Character, question);
   }
}

static boolean
get_local_fact(
      file log_stream,
      attribute *attribute_pointer,
      vector_element *vector_pointer,
      boolean echo,
      cardinal level)

/* Interrogates the user as to the value, in the instant case, of the local
   attribute pointed to by attribute_pointer.  Puts the attribute value in
   the vector element pointed to by vector_pointer.  Returns FALSE, if the
   user chooses to quit. */

{
   char options[Max_Attribute_Options + 1],
      option;
   cardinal count = 0;

   /* determine which values are valid for this attribute */

   if (attribute_pointer->yes != NULL) {
      options[count] = Yes_Character;
      count += sizeof(char);
   }
   if (attribute_pointer->no != NULL) {
      options[count] = No_Character;
      count += sizeof(char);
   }
   if (attribute_pointer->unknown != NULL) {
      options[count] = Unknown_Character;
      count += sizeof(char);
   }
   if (attribute_pointer->details.local.help != NULL) {
      options[count] = Help_Character;
      count += sizeof(char);
   }
   options[count] = Null_Character;
   count += sizeof(char);

   /* prompt the user for one of the valid attribute values */

   do {
      if ((option = Get_Option(attribute_pointer->details.local.question, options)) ==
            Quit_Character) {
         Indent(log_stream, level);
         fprintf(log_stream, "Quitting consultation.\n\n");
         return FALSE;
      }
      if (option == Help_Character)
         fprintf(stdout, "%s\n", attribute_pointer->details.local.help);
   } while (option == Help_Character);

   /* set this attribute's value to that chosen */

   switch (option) {
      case Yes_Character:
         vector_pointer->attribute_value = YES;
         if (echo)
            fprintf(stdout, "Yes: %s.\n", attribute_pointer->yes);
         break;
      case No_Character:
         vector_pointer->attribute_value = NO;
         if (echo)
            fprintf(stdout, "No: %s.\n", attribute_pointer->no);
         break;
      case Unknown_Character:
         vector_pointer->attribute_value = UNKNOWN;
         if (echo)
            fprintf(stdout, "Unknown: %s.\n", attribute_pointer->unknown);
         break;
   }
   return TRUE;
}

static boolean
get_external_fact(
      file log_stream,
      case_law_specification case_law,
      boolean adjust,
      boolean echo,
      boolean inputable_latex,
      boolean verbose,
      cardinal hypothetical_reports,
      cardinal hypothetical_changes,
      cardinal level,
      string distances_filename,
      string weights_filename,
      string report_filename,
      attribute *attribute_pointer,
      cardinal attribute_number,
      vector_element *vector_pointer)

/* Resolves the value, in the instant case, of the external attribute pointed
   to by attribute_pointer (attribute attribute_number) by reference to the
   relevant area.  Puts the attribute value in the vector element pointed to
   by vector_pointer.  Returns FALSE, if the user chooses to quit. */

{
   string nearest_result_identifier;
   boolean found = FALSE;
   identifier_list_element *identifier_list_pointer;
   char message[Max_Error_Message_Length];

   Indent(log_stream, level);
   fprintf(log_stream, "A%u is external.\n\n", attribute_number);

   /* determine the identifier of the "likely result" of the instant case in
      the relevant area (attribute_pointer->details.external.area_identifier) */

   nearest_result_identifier = Case_Law(log_stream, case_law,
         attribute_pointer->details.external.area_identifier, adjust, echo,
         inputable_latex, verbose, hypothetical_reports, hypothetical_changes,
         level + 1, distances_filename, weights_filename, report_filename);

   if (nearest_result_identifier == NULL)

      /* quit */

      return FALSE;

   /* search for the result identifier in the list of external result
      identifiers for YES for this attribute */

   identifier_list_pointer = attribute_pointer->details.external.yes_identifier_head;
   vector_pointer->attribute_value = YES;
   while ((identifier_list_pointer != NULL) && !found) {
      found = !strcmp(identifier_list_pointer->identifier, nearest_result_identifier);
      if (!found)
         identifier_list_pointer = identifier_list_pointer->next;
   }

   if (!found) {

      /* search for the result identifier in the list of external result
         identifiers for NO for this attribute */

      identifier_list_pointer = attribute_pointer->details.external.no_identifier_head;
      vector_pointer->attribute_value = NO;
      while ((identifier_list_pointer != NULL) && !found) {
         found = !strcmp(identifier_list_pointer->identifier, nearest_result_identifier);
         if (!found)
            identifier_list_pointer = identifier_list_pointer->next;
      }
      if (!found) {

         /* search for the result identifier in the list of external result
            identifiers for UNKNOWN for this attribute */

         identifier_list_pointer = attribute_pointer->details.external.unknown_identifier_head;
         vector_pointer->attribute_value = UNKNOWN;
         while ((identifier_list_pointer != NULL) && !found) {
            found = !strcmp(identifier_list_pointer->identifier, nearest_result_identifier);
            if (!found)
               identifier_list_pointer = identifier_list_pointer->next;
         }
         if (!found) {
            sprintf(message, "Unexpected external result identifier \"%s\"",
                  nearest_result_identifier);
            error_exit(log_stream, message);
         }
      }
   }

   /* write details of the attribute value to the log file */

   Indent(log_stream, level);
   fprintf(log_stream, "Value of A%u is ", attribute_number);
   switch (vector_pointer->attribute_value) {
      case YES:
         fprintf(log_stream, "YES");
         break;
      case NO:
         fprintf(log_stream, "NO");
         break;
      case UNKNOWN:
         fprintf(log_stream, "UNKNOWN");
         break;
   }
   fprintf(log_stream, ".\n\n");

   return TRUE;
}

static vector_element *
get_fact(
      file log_stream,
      case_law_specification case_law,
      boolean adjust,
      boolean echo,
      boolean inputable_latex,
      boolean verbose,
      cardinal hypothetical_reports,
      cardinal hypothetical_changes,
      cardinal level,
      string distances_filename,
      string weights_filename,
      string report_filename,
      attribute *attribute_pointer,
      cardinal attribute_number)

/* Determines the value, in the instant case, of the attribute pointed to by
   attribute_pointer (attribute attribute_number). Interrogates the user, if
   the attribute is local; resolves the value by reference to the relevant
   area, if the attribute is external.  Returns a pointer to a single vector
   element containing the attribute value; or NULL, if the user chooses to
   quit. */

{
   vector_element *vector_pointer;

   /* allocate memory for this vector element */

   if ((vector_pointer = (vector_element *) malloc(sizeof(vector_element))) == NULL)
      error_exit(log_stream, "malloc failed during fact vector handling");

   if (attribute_pointer->external_attribute) {

      /* the attribute is external */

      if (!get_external_fact(log_stream, case_law, adjust, echo, inputable_latex, verbose,
                  hypothetical_reports, hypothetical_changes, level,
                  distances_filename, weights_filename, report_filename,
                  attribute_pointer, attribute_number, vector_pointer)) {

         /* quit */

         free(vector_pointer);
         return NULL;
      }

   } else {

      /* the attribute is local */

      if (!get_local_fact(log_stream, attribute_pointer, vector_pointer, echo, level)) {

         /* quit */

         free(vector_pointer);
         return NULL;
      }
   }
   vector_pointer->next = NULL;
   return vector_pointer;
}

extern vector_element *
Get_Facts(
      file log_stream,
      case_law_specification case_law,
      area *area_pointer,
      boolean adjust,
      boolean echo,
      boolean inputable_latex,
      boolean verbose,
      cardinal hypothetical_reports,
      cardinal hypothetical_changes,
      cardinal level,
      string distances_filename,
      string weights_filename,
      string report_filename)

/* Interrogates the user as to the values of local attributes, in the instant
   case, in the area pointed to by area_pointer.  Resolves the value of
   external attributes by reference to the relevant area, recursively
   invoking Case_Law().  Prompts the user by writing to stdout; reads the
   user's response from stdin.  Returns a pointer to a fact vector containing
   the facts of the instant case; or NULL, if the user chooses to quit. */

{
   attribute *attribute_pointer;
   vector_element *facts_head = NULL,
     *vector_pointer = NULL;
   cardinal count = 1;

   /* for every attribute ... */

   for (attribute_pointer = area_pointer->attribute_head; attribute_pointer != NULL;
         attribute_pointer = attribute_pointer->next)
      if (facts_head == NULL) {

         /* this is the first attribute */

         if ((facts_head = get_fact(log_stream, case_law, adjust, echo, inputable_latex,
                           verbose, hypothetical_reports, hypothetical_changes, level,
                           distances_filename, weights_filename, report_filename,
                           attribute_pointer, 1)) == NULL)

            /* quit */

            return NULL;

         vector_pointer = facts_head;

      } else {

         /* this is not the first attribute */

         count++;
         if ((vector_pointer->next =
                     get_fact(log_stream, case_law, adjust, echo, inputable_latex,
                           verbose, hypothetical_reports, hypothetical_changes, level,
                           distances_filename, weights_filename, report_filename,
                           attribute_pointer, count)) == NULL)

            /* quit */

            return NULL;

         vector_pointer = vector_pointer->next;
      }
   return facts_head;
}

Other SHYSTER modules: Shyster, Statutes, Cases, Tokenizer, Parser, Dumper, Checker, Scales, Adjuster, Odometer and Reporter.
Copyright notice
Home page:  <https://www.popple.net/james/>
E-mail:  <james@popple.net>
Last modified:  30 April 1995