home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume13 / okbridge / part03 / startup.c < prev   
C/C++ Source or Header  |  1992-01-12  |  11KB  |  419 lines

  1. /* startup.c
  2.  ! 
  3.  ! Copyright (C) 1991 by Matthew Clegg
  4.  ! 
  5.  ! This program may be copied and distributed freely.  Please do not
  6.  ! charge money for this program or for any program derived from it.
  7.  ! If you modify this program, then include a notice stating plainly
  8.  ! that your program is derived from the okbridge program and is not
  9.  ! the same as the official okbridge program.
  10.  !
  11.  ! I welcome any suggestions for improvement to okbridge, and 
  12.  ! I would be especially happy to receive improved source code.
  13.  ! If you have comments or suggestions, or if you would like to
  14.  ! join the okbridge mailing list, then write to
  15.  !
  16.  !   mclegg@cs.ucsd.edu
  17.  !
  18.  *
  19.  * This file contains procedures for reading the okbridge startup
  20.  * file .okbridgerc.  Each line in this file is either a comment line
  21.  * or a (field, value) pair.  Comment lines begin with the pound sign
  22.  * '#' character.  Field, value pairs are of the format
  23.  *    <Field-name>    <value>
  24.  *
  25.  * The fields which are currently recognized are as follows:
  26.  *
  27.  * BELL        ON | OFF
  28.  *    When requesting input (a bid or a play), the terminal's
  29.  *    bell is rung by default.  However, this can be disabled
  30.  *    by specifying 'BELL OFF'.  This has the same effect as the
  31.  *    '/BELL OFF' command.
  32.  *
  33.  * DEFAULT      ON | OFF
  34.  *      This controls whether or not default inputs will be provided for
  35.  *      bids, plays and questions.
  36.  *
  37.  * HELPFILE    <directory-name>
  38.  *    This field specifies the directory to be used for reading
  39.  *    the okbridge help files.
  40.  *
  41.  * LOAD         <email-duplicate-filename>
  42.  *      This field is only valid if the position is north and the
  43.  *      scoring mode is email duplicate.  In this case, okbridge will
  44.  *      automatically read a set of email duplicate boards from the
  45.  *      named file.
  46.  *
  47.  * LOG        <filename>
  48.  *    If this statement is present in the startup file, then
  49.  *    the hands will automatically be logged to the given filename.
  50.  *      If the first character of <filename> is '+', then logs the
  51.  *      hands to the end of the file rather than erasing the old file.
  52.  *
  53.  * NAME        <local-player-name>
  54.  *    This field specifies the name that will be used to identify
  55.  *    the local player to the other players.
  56.  *
  57.  * POSITION    NORTH | EAST | SOUTH | WEST
  58.  *    This field specifies the local player's position.
  59.  *
  60.  * PORT        <positive-integer>
  61.  *    This field specifies the internet port number that will be
  62.  *    used for communications with the server.
  63.  *
  64.  * PROMPT     NO | YES
  65.  *    The value of this field is only relevant in hands where the
  66.  *    local player is the dummy.  In this case, the dummy is
  67.  *    ordinarily prompted to press RETURN at the end of each trick.
  68.  *    This allows the dummy to see the cards that are played as they
  69.  *    are played.  However, if 'PROMPT NO' is specified, then the
  70.  *    dummy will not be prompted.
  71.  *
  72.  * REPLAY       <email-duplicate-filename>
  73.  *      This field is only valid if the position is north and the
  74.  *      scoring mode is email duplicate.  In this case, a set of
  75.  *      boards will automatically be read from the named file.
  76.  *      After they have been played, the results will automatically
  77.  *      be written back to the file from which the boards were read.
  78.  *
  79.  * SCORING    RUBBER | CHICAGO | DUPLICATE | EMAIL | IMP
  80.  *    This field is only relevant if the local player is north.
  81.  *    In this case, the SCORING field determines the type of scoring
  82.  *    that will be used by default in the game.
  83.  *
  84.  * SERVER    ME | <internet-name-or-number>
  85.  *    If the value of this field is 'ME', then the local player
  86.  *    will assume the role of server.  If the value of this field
  87.  *    is anything else, then it is interpreted as an internet name
  88.  *    or number of the machine where the server is running.
  89.  *
  90. */
  91.  
  92. #include <ctype.h>
  93. #include <stdio.h>
  94. #include <string.h>
  95.  
  96. #include "globals.h"
  97.  
  98. extern char *getenv ();
  99. extern char *strdup ();
  100.  
  101. #ifdef HPUX
  102. #define index(X,Y) strchr(X,Y)
  103. #else 
  104. #ifndef index
  105. extern char *index ();
  106. #endif
  107. #endif
  108.  
  109. #define    MAX_LENGTH    100
  110.  
  111. typedef void (*field_handler) ();
  112.  
  113. typedef struct Field_Descriptor_struct {
  114.     char *field_name;
  115.     char *parameter_type;
  116.     field_handler    handler;
  117. } Field_Descriptor;
  118.  
  119. void Bell_Field (), Default_Field (), Helpfile_Field (), Load_Field (), 
  120.      Log_Field (), Name_Field (), Position_Field (), Port_Field (), 
  121.      Prompt_Field (), Replay_Field (), Scoring_Field (), Server_Field ();
  122.  
  123. static Field_Descriptor Fields [] = {
  124.     {"BELL",    "OFF,ON",            Bell_Field},
  125.     {"DEFAULT",    "OFF,ON",            Default_Field},
  126.     {"HELPFILE",    "*",                Helpfile_Field},
  127.     {"LOAD",        "*",                            Load_Field},
  128.     {"LOG",        "*",                Log_Field},
  129.     {"NAME",    "*",                Name_Field},
  130.     {"POSITION",    "NORTH,EAST,SOUTH,WEST",    Position_Field},
  131.     {"PORT",    "#",                Port_Field},
  132.     {"PROMPT",    "NO,YES",            Prompt_Field},
  133.         {"REPLAY",      "*",                            Replay_Field},
  134.     {"SCORING",    "RUBBER,CHICAGO,DUPLICATE,EMAIL,IMP",     Scoring_Field},
  135.     {"SERVER",    "*",                Server_Field},
  136.     {NULL,        NULL,                NULL}
  137.   };
  138.  
  139. static char line_buffer [MAX_LENGTH];
  140. static int  current_char, last_pos;
  141. static int  line_length;
  142. static int  line_no;
  143. static FILE *init_file;
  144. static int  error_flag;
  145.  
  146. extern int errno;
  147. extern char *sys_errlist[];
  148.  
  149. extern int ring_my_bell;
  150. extern char *help_file_name;
  151. extern FILE *logfile;
  152. extern int local_player;
  153. extern int network_port;
  154. extern int server_mode;
  155. extern char *server_name;
  156. extern char *local_player_name;
  157. extern char *autoload_file, *autosave_file;
  158.  
  159. static Field_Error (error_msg)
  160.     char *error_msg;
  161. /* Prints out the current line from the field file along with an error
  162.    message.
  163. */
  164. {
  165.     int i;
  166.  
  167.     fprintf (stderr, "line %2d: %s\n", line_no, line_buffer);
  168.     for (i = 0; i < last_pos + 9; i++) 
  169.         fprintf (stderr, " ");
  170.     fprintf (stderr, "^ %s\n", error_msg);
  171.     error_flag = 1;
  172. };
  173.  
  174. static void Bell_Field (i)
  175.     int i;
  176. {
  177.     ring_my_bell = i;
  178. };
  179.  
  180. static void Default_Field (i)
  181.      int i;
  182. {
  183.   default_plays = i;
  184. };
  185.  
  186. static void Helpfile_Field (s)
  187.     char *s;
  188. {
  189.     help_file_name = strdup (s);
  190. };
  191.  
  192. static void Load_Field (s)
  193.      char *s;
  194. {
  195.   autoload_file = strdup (s);
  196. };
  197.  
  198. static void Log_Field (s)
  199.     char *s;
  200. {
  201.     char error_buf [80];
  202.     char *filename;
  203.  
  204.     if (s[0] == '+') {
  205.       filename = s + 1;
  206.       logfile = fopen (filename, "a");
  207.     } else {
  208.       filename = s;
  209.       logfile = fopen (filename, "w");
  210.     };
  211.     if (logfile == NULL) {
  212.         sprintf (error_buf, "Error opening %s: %s", filename,
  213.             sys_errlist[errno]);
  214.         Field_Error (error_buf);
  215.     };
  216. };
  217.  
  218. static void Name_Field (s)
  219.     char *s;
  220. {
  221.     local_player_name = strdup (s);
  222. };
  223.  
  224. static void Position_Field (i)
  225.     int i;
  226. {
  227.     local_player = i;
  228. };
  229.  
  230. static void Port_Field (i)
  231.     int i;
  232. {
  233.     network_port = i;
  234. };
  235.  
  236. static void Prompt_Field (i)
  237.     int i;
  238. {
  239.     prompt_dummy = i;
  240. };
  241.  
  242. static void Replay_Field (s)
  243.      char *s;
  244. {
  245.   autoload_file = strdup (s);
  246.   autosave_file = strdup (s);
  247. };
  248.  
  249. static void Scoring_Field (i)
  250.     int i;
  251. {
  252.     scoring_mode = i;
  253. };
  254.  
  255. static void Server_Field (s)
  256.     char *s;
  257. {
  258.     if (!strcasecmp(s, "ME"))
  259.         server_mode = 1;
  260.     else {
  261.         server_mode = 0;
  262.         server_name = strdup (s);
  263.     };
  264. };
  265.  
  266. static int Read_Field_Line ()
  267. /* Reads a line from initialization file init_file and copies it into
  268.    line_buffer.  Returns 1 if data is returned, or 0 if the end of file
  269.    is reached.  Skips comment lines.  Strips trailing blanks from the
  270.    end of the line.
  271. */
  272. {
  273.     int ch;
  274.  
  275.     do {
  276.         line_length = 0;
  277.         ch = getc (init_file);
  278.         while ((ch != EOF) && (ch != '\n')) {
  279.             if (line_length < MAX_LENGTH)
  280.                 line_buffer [line_length++] = ch;
  281.             ch = getc(init_file);
  282.         };
  283.         if (ch == EOF)
  284.             return (0);
  285.         line_no++;
  286.         while (line_buffer[line_length-1] == ' ')
  287.             line_length--;
  288.     } while ((line_length == 0) || (line_buffer[0] == '#'));
  289.  
  290.     current_char = 0;
  291.     line_buffer[line_length] = '\0';
  292.     return (1);
  293. };
  294.  
  295. static int Read_Keyword (buf, buflen)
  296.     char *buf; int buflen;
  297. /* Reads a whitespace delimited sequence of characters from the current
  298.    input line into the buffer.  Returns the number of characters
  299.    transferred.
  300. */
  301. {
  302.     int i;
  303.  
  304.     i = 0;
  305.     while ((current_char < line_length) && 
  306.        isspace (line_buffer[current_char])) 
  307.         current_char++;
  308.  
  309.     last_pos = current_char;
  310.     while ((current_char < line_length) && 
  311.       !isspace(line_buffer[current_char])) {
  312.         if (i < buflen-1)
  313.             buf[i++] = line_buffer[current_char++];
  314.         else
  315.             current_char++;
  316.     };
  317.     buf[i] = '\0';
  318.     return (i);
  319. };
  320.  
  321. static int Lookup_Keyword (lookup_string, keyword)
  322.     char *lookup_string, *keyword;
  323. /* Assumes that lookup_string is a comma-delimited sequence of keywords.
  324.    Looks for the keyword in lookup_string which matches the given keyword.
  325.    If the keyword is found, then returns its index in lookup_string,
  326.    i.e.,  Lookup_Keyword ("OFF,ON", "OFF") = 0, 
  327.       Lookup_Keyword ("OFF,ON", "ON") = 1.
  328.    If the keyword is not found, then returns -1.
  329. */
  330. {
  331.     int i, n;
  332.  
  333.     i = 0;
  334.     n = strlen (keyword);
  335.     while (lookup_string != NULL) {
  336.         if (!strncasecmp(lookup_string, keyword, n)) {
  337.             if ((lookup_string[n] == '\0') || 
  338.                 (lookup_string[n] == ','))
  339.                 return (i);
  340.         };
  341.         i += 1;
  342.         lookup_string = index (lookup_string, ',');
  343.         if (lookup_string != NULL) lookup_string++;
  344.     };
  345.     return (-1);
  346.         
  347. };
  348.  
  349. static int all_digits (s)
  350.     char *s;
  351. {
  352.     while (*s)
  353.         if (!isdigit(*(s++)))
  354.             return (0);
  355.     return (1);
  356. };
  357.  
  358. void Read_Initialization_File ()
  359. {
  360.     char *home_dir, filename_buf[128];
  361.     char name [20], value [80], message_buf[80];
  362.     int i, j;
  363.  
  364.     init_file = fopen (".okbridgerc", "r");
  365.     home_dir = getenv ("HOME");
  366.  
  367.     if ((init_file == NULL) && (home_dir != NULL)) {
  368.         sprintf (filename_buf, "%s/.okbridgerc", home_dir);
  369.         init_file = fopen (filename_buf, "r");
  370.     };
  371.  
  372.     if (init_file == NULL) {
  373.         /* couldn't find an initialization file. */
  374.         return;
  375.     };
  376.  
  377.     error_flag = 0;
  378.     while (Read_Field_Line()) {
  379.         Read_Keyword (name, 20);
  380.         i = 0;
  381.         while ((Fields[i].field_name != NULL) &&
  382.            strcmp(Fields[i].field_name, name))
  383.             i++;
  384.         if (Fields[i].field_name == NULL)
  385.             Field_Error ("Error in field name");
  386.         else {
  387.           Read_Keyword (value, 80);
  388.           if (current_char < line_length)
  389.             Field_Error ("Extra data at end of line");
  390.           if (Fields[i].parameter_type[0] == '*')
  391.             Fields[i].handler (value);
  392.           else if (Fields[i].parameter_type[0] == '#') {
  393.             if (all_digits(value))
  394.                 Fields[i].handler (atoi(value));
  395.             else
  396.                 Field_Error ("Expected a positive integer");
  397.           } else {
  398.             j = Lookup_Keyword (Fields[i].parameter_type, value);
  399.             if (j < 0) {
  400.                 sprintf (message_buf, "Expected keyword: %s",
  401.                     Fields[i].parameter_type);
  402.                 Field_Error (message_buf);
  403.             } else
  404.                 Fields[i].handler (j);
  405.           };
  406.         };
  407.     };
  408.  
  409.     fclose (init_file);
  410.  
  411.     if (error_flag) {
  412.         fprintf (stderr, "\n%s -- %s\n",
  413.             "Errors in .okbridgerc initialization file",
  414.             "Program terminating");
  415.         exit (1);
  416.     };
  417.     
  418. };
  419.