/* 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);
/* 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.