/* This is the header file for the Shyster module. It is included by all
twelve modules. */
/* version and copyright information */
#define Shyster_Version "SHYSTER version 1.0"
#define Copyright_Message "Copyright James Popple 1993"
/* a string which is written to stderr if SHYSTER is invoked without
arguments */
#define usage_string\
"usage:\t" \
"shyster [ -a ] [ -c filename ] [ -d filename ] [ -D filename ] [ -e ]\n" \
"\t\t[ -h number number ] [ -i ] [ -l filename ] [ -p filename ]\n" \
"\t\t[ -q ] [ -r filename ] [ -w filename ]\n"
/* the versions of LaTeX and TeX for which SHYSTER has been developed */
#define LaTeX_Version "LaTeX version 2.09 <25 March 1992>"
#define TeX_Version "TeX version 3.141"
/* maxima */
#define Max_Filename_Length 256
#define Max_Error_Message_Length 256
#define Max_LaTeX_Line_Width 64
/* other constants */
#define Empty_String ""
#define Null_Character '\0'
#define Space_Character ' '
#define Carriage_Return_Character '\n'
#define Top_Level 0
#define No_Hang 0
#define Hang 1
/* functions whose returned values are always ignored */
#define fprintf (void) fprintf
#define free (void) free
#define gets (void) gets
#define sprintf (void) sprintf
/* simple types */
typedef unsigned int cardinal;
typedef float floating_point;
typedef char *string;
typedef FILE *file;
/* enumerated type */
typedef enum {
FALSE,
TRUE
} boolean;
/* external functions */
extern void
Indent(
file stream,
cardinal level);
extern void
Write(
file stream,
string write_string,
const string suffix,
const cardinal level,
const boolean hanging_indent);
extern void
Write_Error_Message_And_Exit(
file stream,
const string module_name,
string message);
extern void
Write_Warning_Message(
file stream,
const string module_name,
string message,
const cardinal level);
extern void
Write_LaTeX_Header(
file stream,
boolean inputable_latex);
extern void
Write_LaTeX_Trailer(
file stream,
boolean inputable_latex);
extern boolean
Is_Digit(
int ch);
/* This is the implementation file for the Shyster module. */
#include <stdio.h>
#include <stdlib.h>
#include "shyster.h"
#include "cases.h"
#include "statutes.h"
extern void
Indent(
file stream,
cardinal level)
/* Writes the equivalent of 4 x level spaces (1 tab = 8 spaces). */
{
while (level > 1) {
fprintf(stream, "\t");
level -= 2;
}
if (level == 1)
fprintf(stream, " ");
}
static void
write_line(
file stream,
string *write_string,
const cardinal level,
const boolean hanging_indent,
cardinal count)
/* Writes a line of characters from *write_string. Writes characters up to
the last space in the next count characters, then breaks the line and
indents the next line by 4 x level spaces (plus an extra two spaces if
hanging_indent is TRUE). Leaves *write_string pointing to the character
after the space at which the line was broken. */
{
/* find the last space that will fit on the line */
while ((*(*write_string + count) != Space_Character) && (count != 0))
count--;
if (count == 0) {
/* there is no convenient place to break this line, so write as much as
will fit, with a % character at the end of the line, and don't
indent the next line */
for (count = Max_LaTeX_Line_Width - level * 4 - 1; count != 0; count--)
fprintf(stream, "%c", *((*write_string)++));
fprintf(stream, "%%\n");
} else {
/* there is (at least) one space in this line, so write each of the
characters up to the last space, break the line, and indent the next
line */
while (count != 0) {
fprintf(stream, "%c", *((*write_string)++));
count--;
}
(*write_string)++;
fprintf(stream, "\n");
Indent(stream, level);
if (hanging_indent)
fprintf(stream, " ");
}
}
extern void
Write(
file stream,
string write_string,
const string suffix,
const cardinal level,
const boolean hanging_indent)
/* Writes write_string plus suffix. Breaks lines (at spaces) so that they
are no longer than Max_LaTeX_Line_Width characters. Indents lines by 4 x
level spaces. Indents lines after the first by a further two spaces, if
hanging_indent is TRUE. (Assumes that suffix is less than
Max_LaTeX_Line_Width - level x 4 characters long.) */
{
cardinal count = 0,
suffix_length = 0,
line_length = Max_LaTeX_Line_Width - level * 4;
boolean hanged = FALSE;
if (write_string == NULL)
/* there is no string to write */
fprintf(stream, "%s", Null_String);
else {
/* there is a string to write */
if (suffix != Null_String)
/* there is a suffix, so set suffix_length to the number of
characters in the suffix, up to (but not including) the first
carriage return (if there is one) */
while ((*(suffix + suffix_length) != Null_Character) &&
(*(suffix + suffix_length) != Carriage_Return_Character))
suffix_length++;
Indent(stream, level);
while (*(write_string + count) != Null_Character) {
if (count == line_length) {
/* there are more characters left in the string than will fit on
this line, so write as much as will fit */
write_line(stream, &write_string, level, hanging_indent, count);
if (!hanged && hanging_indent) {
line_length -= 2;
hanged = TRUE;
}
count = 0;
}
count++;
}
/* the rest of the string will fit on a line */
if (count + suffix_length > line_length) {
/* ... but the rest of the string plus the suffix will be too long
to fit on a line, so write as much as will fit */
write_line(stream, &write_string, level, hanging_indent, count);
/* the rest of the string plus the suffix will fit on the new line;
set count to be the number of characters still to be written */
count = 0;
while (*(write_string + count) != Null_Character)
count++;
}
/* write the rest of the string */
while (count != 0) {
fprintf(stream, "%c", *write_string++);
count--;
}
}
/* write the suffix */
fprintf(stream, "%s\n", suffix);
}
extern void
Write_Error_Message_And_Exit(
file stream,
const string module_name,
string message)
/* Writes "ERROR (module_name): message." to stderr and to stream. Exits with
a value of EXIT_FAILURE (defined in stdlib.h). */
{
static char full_message[Max_Error_Message_Length];
sprintf(full_message, "ERROR (%s): %s", module_name, message);
Write(stderr, full_message, ".\n", Top_Level, Hang);
/* write to stream only if stream is not stdout (the error message has
already been written to stderr) */
if ((stream != NULL) && (stream != stdout))
Write(stream, full_message, ".\n", Top_Level, Hang);
exit(EXIT_FAILURE);
}
extern void
Write_Warning_Message(
file stream,
const string module_name,
string message,
const cardinal level)
/* Writes "WARNING (module_name): message." to stderr and to stream. */
{
static char full_message[Max_Error_Message_Length];
if (stream != NULL) {
sprintf(full_message, "WARNING (%s): %s", module_name, message);
Write(stderr, full_message, ".\n", Top_Level, Hang);
/* write to stream only if stream is not stdout (the warning message
has already been written to stderr) */
if (stream != stdout)
Write(stream, full_message, ".\n", level, Hang);
}
}
extern void
Write_LaTeX_Header(
file stream,
boolean inputable_latex)
/* Writes LaTeX code to go at the start of a LaTeX document. Writes code
that can be included in another LaTeX document (i.e. not stand-alone
code), if inputable_latex is TRUE. */
{
fprintf(stream, "%% Produced by %s\n\n"
"%% %s\n\n", Shyster_Version, Copyright_Message);
if (!inputable_latex)
fprintf(stream, "%% This is a stand-alone LaTeX file.\n");
else
fprintf(stream, "%% This is not a stand-alone LaTeX file.\n"
"%% Include it in a LaTeX document using the \\input command.\n");
fprintf(stream, "%% Use %s and %s.\n\n", LaTeX_Version, TeX_Version);
if (!inputable_latex)
fprintf(stream, "\\documentstyle[12pt]{article}\n"
"\\oddsidemargin=-5.4mm\n"
"\\evensidemargin=-5.4mm\n"
"\\topmargin=-5.4mm\n"
"\\headheight=0mm\n"
"\\headsep=0mm\n"
"\\textheight=247mm\n"
"\\textwidth=170mm\n"
"\\footskip=15mm\n"
"\\pagestyle{plain}\n\n"
"\\begin{document}\n\n");
}
extern void
Write_LaTeX_Trailer(
file stream,
boolean inputable_latex)
/* Writes LaTeX code to go at the end of a LaTeX document. Writes code that
can be included in another LaTeX document (i.e. not stand-alone code), if
inputable_latex is TRUE. */
{
if (!inputable_latex)
fprintf(stream, "\\end{document}\n");
}
extern boolean
Is_Digit(
int ch)
/* Returns TRUE, iff ch is a digit (0 ... 9). */
{
return ((ch >= Zero_Character) && (ch <= Nine_Character));
}
static void
error_exit(
const string message)
{
Write_Error_Message_And_Exit(NULL, "Shyster", message);
}
static void
parse_arguments(
int argc,
string *argv,
boolean *adjust,
boolean *echo,
cardinal *hypothetical_reports,
cardinal *hypothetical_changes,
boolean *inputable_latex,
boolean *verbose,
string *specification_filename,
string *distances_filename,
string *log_filename,
string *probabilities_filename,
string *report_filename,
string *dump_filename,
string *weights_filename)
/* Parses the UNIX command line arguments (argv [1] ... argv [argc - 1]) and
stores the information in the variables pointed to by the 13 other
parameters. */
{
string argument;
char message[Max_Error_Message_Length];
if (argc < 2) {
/* no argument was provided, so write usage_string to stderr and exit
with a value of EXIT_FAILURE (defined in stdlib.h) */
fprintf(stderr, usage_string);
exit(EXIT_FAILURE);
}
/* skip over the first argument (the name by which SHYSTER was invoked) */
argc--;
argv++;
/* while there are still arguments to parse ... */
while (argc > 0) {
argument = *argv;
if (*argument++ != '-')
/* this argument is not a switch */
break;
switch (*argument++) {
case 'a':
/* -a: enable weight adjustment */
*adjust = TRUE;
break;
case 'c':
/* -c specification: read the case law specification from
"specification.cls" */
if (argc > 1) {
argc--;
argv++;
*specification_filename = *argv;
} else
error_exit("must supply a filename with -c");
break;
case 'd':
/* -d distances: write distances to "distances-area.tex" */
if (argc > 1) {
argc--;
argv++;
*distances_filename = *argv;
} else
error_exit("must supply a filename with -d");
break;
case 'D':
/* -D dump: write dump to "dump.tex" */
if (argc > 1) {
argc--;
argv++;
*dump_filename = *argv;
} else
error_exit("must supply a filename with -D");
break;
case 'e':
/* -e: enable echo mode */
*echo = TRUE;
break;
case 'h':
/* -h r c: hypothesize, reporting on r hypotheticals per result
with a limit of c changes */
if (argc > 2) {
argc--;
argv++;
while (**argv != Null_Character) {
if (!Is_Digit(**argv))
error_exit("argument to -h must be two numbers");
*hypothetical_reports = (10 * *hypothetical_reports) +
(cardinal) **argv - (cardinal) Zero_Character;
(*argv)++;
}
argc--;
argv++;
*hypothetical_changes = 0;
while (**argv != Null_Character) {
if (!Is_Digit(**argv))
error_exit("argument to -h must be two numbers");
*hypothetical_changes = (10 * *hypothetical_changes) +
(cardinal) **argv - (cardinal) Zero_Character;
(*argv)++;
}
} else
error_exit("must supply two numbers with -h");
break;
case 'i':
/* -i: write LaTeX code that can be included in another LaTeX
document (i.e. not stand-alone code) */
*inputable_latex = TRUE;
break;
case 'l':
/* -l log: write log to "log.log" */
if (argc > 1) {
argc--;
argv++;
*log_filename = *argv;
} else
error_exit("must supply a filename with -l");
break;
case 'p':
/* -p probabilities: write probabilities to "probabilities.tex" */
if (argc > 1) {
argc--;
argv++;
*probabilities_filename = *argv;
} else
error_exit("must supply a filename with -p");
break;
case 'q':
/* -q: enable quiet mode (don't summarize cases, etc.) */
*verbose = FALSE;
break;
case 'r':
/* -r report: write report to "report-area.tex" */
if (argc > 1) {
argc--;
argv++;
*report_filename = *argv;
} else
error_exit("must supply a filename with -r");
break;
case 'w':
/* -w weights: write weights to "weights.tex" */
if (argc > 1) {
argc--;
argv++;
*weights_filename = *argv;
} else
error_exit("must supply a filename with -w");
break;
default:
sprintf(message, "unrecognized option -%s", argument - 1);
error_exit(message);
break;
}
argc--;
argv++;
}
}
extern int
main(
int argc,
string *argv)
/* Extracts the options and arguments from the UNIX command line, initializes
the rule-based system and the case-based system, then invokes the
rule-based system. */
{
char filename[Max_Filename_Length],
message[Max_Error_Message_Length];
statute_law_specification statute_law;
case_law_specification case_law;
file log_stream;
boolean adjust = FALSE,
echo = FALSE,
inputable_latex = FALSE,
verbose = TRUE;
cardinal hypothetical_reports = 0,
hypothetical_changes;
string specification_filename = NULL,
distances_filename = NULL,
log_filename = NULL,
probabilities_filename = NULL,
report_filename = NULL,
dump_filename = NULL,
weights_filename = NULL;
/* extract the options and arguments from the UNIX command line */
parse_arguments(argc, argv, &adjust, &echo, &hypothetical_reports, &hypothetical_changes,
&inputable_latex, &verbose, &specification_filename, &distances_filename,
&log_filename, &probabilities_filename, &report_filename, &dump_filename,
&weights_filename);
/* write version and copyright information to stdout */
fprintf(stdout, "%s\n\n%s\n\n", Shyster_Version, Copyright_Message);
if (log_filename == NULL)
/* no log filename was specified, so log information will be written to
stdout */
log_stream = stdout;
else {
/* open the log file */
sprintf(filename, "%s%s", log_filename, Log_File_Extension);
if ((log_stream = fopen(filename, "w")) == NULL) {
sprintf(message, "can't open log file \"%s\"", filename);
error_exit(message);
}
/* write version and copyright information to the log file */
fprintf(log_stream, "%s\n\n"
"%s\n\n", Shyster_Version, Copyright_Message);
}
/* initialize the rule-based system */
statute_law = Initialize_Statutes();
/* initialize the case-based system */
case_law = Initialize_Cases(log_stream, inputable_latex, verbose, specification_filename,
dump_filename, probabilities_filename, weights_filename);
/* invoke the rule-based system */
Statute_Law(log_stream, statute_law, case_law, adjust, echo, inputable_latex, verbose,
hypothetical_reports, hypothetical_changes, distances_filename, weights_filename,
report_filename);
/* write "Finished." to the log file (if there is one) and to stdout */
if (log_filename != NULL)
fprintf(log_stream, "Finished.\n");
fprintf(stdout, "Finished.\n");
/* close the log file */
if (fclose(log_stream) == EOF) {
sprintf(message, "can't close log file \"%s\"", filename);
error_exit(message);
}
/* everything worked, so exit with a value of EXIT_SUCCESS (defined in
stdlib.h) */
return EXIT_SUCCESS;
}
Other SHYSTER modules: Statutes, Cases, Tokenizer, Parser, Dumper, Checker, Scales, Adjuster, Consultant, Odometer and Reporter.