home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume28 / ldb / part03 / save.c < prev   
Encoding:
C/C++ Source or Header  |  1992-03-15  |  14.4 KB  |  466 lines

  1. /*    save.c        8/4/91
  2.  *
  3.  * Copyright 1991  Perry R. Ross
  4.  *
  5.  * Permission to use, copy, modify, and distribute this software and its
  6.  * documentation without fee is hereby granted, subject to the restrictions
  7.  * detailed in the README file, which is included here by reference.
  8.  * Any other use requires written permission from the author.  This software
  9.  * is distributed "as is" without any warranty, including any implied
  10.  * warranties of merchantability or fitness for a particular purpose.
  11.  * The author shall not be liable for any damages resulting from the
  12.  * use of this software.  By using this software, the user agrees
  13.  * to these terms.
  14.  */
  15.  
  16. #include "ldb.h"
  17.  
  18. /*===========================================================================
  19.  * This file contains miscellaneous functions that save and load things.
  20.  *===========================================================================
  21.  */
  22.  
  23. /*---------------------------------------------------------------------------
  24.  *    save -- make a copy of a string
  25.  *
  26.  * This function makes a copy of a string in malloc memory, and returns
  27.  * a pointer to the copy.
  28.  *---------------------------------------------------------------------------
  29.  */
  30.  
  31. char *save(s)
  32. char *s;
  33. {
  34. char *n;
  35.  
  36. if ( (n = calloc(strlen(s)+1,1)) == NULL) {
  37.     FeFinishSession();
  38.     TFinishSession();    /* close down transport */
  39.     fprintf(stderr,"Out of memory!\n");
  40.     exit(1);
  41.     }
  42. strcpy(n,s);
  43. return(n);
  44. }
  45.  
  46.  
  47. /*---------------------------------------------------------------------------
  48.  *    readldbrc -- read in the .ldbrc file
  49.  *
  50.  * This function reads the .ldbrc file, which contains the setup info
  51.  * for this user.  If the HOME environment variable is set, we chdir to it.
  52.  * If the LDBRC environment variable is set, it is used as the file to
  53.  * read instead of .ldbrc.
  54.  *---------------------------------------------------------------------------
  55.  */
  56.  
  57. readldbrc()
  58. {
  59. FILE *fp;
  60. char *s, *n, *getenv();
  61. char buf[80];
  62.  
  63. if ( (s = getenv("HOME")) != NULL)    /* if we have a home */
  64.     chdir(s);            /* go there */
  65. if ( (s = getenv("LDBRC")) == NULL)    /* LDBRC not set */
  66.     s = ".ldbrc";            /* use default file name */
  67. if ( (fp = fopen(s,"r")) == NULL) {
  68.     printf("'%s' does not exist.  Do you want to create it?",s);
  69.     if ( (gets(buf) == NULL) || ( (*buf != 'y') && (*buf != 'Y') ) ) {
  70.         printf("ldb aborted.\n");
  71.         exit(1);
  72.         }
  73.     if ( (fp = fopen(s,"w")) == NULL) {
  74.         printf("Sorry, could not create %s.\n",s);
  75.         exit(1);
  76.         }
  77.     printf("Please enter your personal name: ");
  78.     if (gets(buf) == NULL) {
  79.         fclose(fp);
  80.         unlink(s);
  81.         printf("ldb aborted.\n");
  82.         exit(1);
  83.         }
  84.     fprintf(fp,"myname=%s\n",buf);
  85.     printf("Please enter your e-mail address: ");
  86.     if (gets(buf) == NULL) {
  87.         fclose(fp);
  88.         unlink(s);
  89.         printf("ldb aborted.\n");
  90.         exit(1);
  91.         }
  92.     fprintf(fp,"myaddr=%s\n",buf);
  93.     fprintf(fp,"gamefile=.ldbdata\n");
  94.     fprintf(fp,"backupfile=.oldldbdata\n");
  95.     fprintf(fp,"mailfile=ldb.rcv\n");
  96.     fprintf(fp,"sendcmd=mail -s '$s' $a < $f\n");
  97.     fprintf(fp,"tempfile=ldb.tmp\n");
  98.     fprintf(fp,"colors=rw\n");
  99.     fprintf(fp,"direction=up\n");
  100.     fprintf(fp,"initialboard=current\n");
  101.     fprintf(fp,"autoroll=yes\n");
  102.     fprintf(fp,"automove=no\n");
  103.     fprintf(fp,"autodouble=0\n");
  104.     fprintf(fp,"supercmd=sh\n");
  105.     fprintf(fp,"superkey=0\n");
  106.     fprintf(fp,"checkpoint=yes\n");
  107.     fclose(fp);
  108.     printf("\nYour %s file was created.  You may want to read the\n",s);
  109.     printf("manual for additional options available in this file.\n\n");
  110.     if ( (fp = fopen(s,"r")) == NULL) {
  111.         printf("I can't re-open your %s file!\n",s);
  112.         exit(1);
  113.         }
  114.     }
  115. rc.myname = NULL;        /* these fields are required */
  116. rc.myaddr = NULL;
  117. rc.gfile = ".ldbdata";    /* default game storage file */
  118. rc.gbackup = ".oldldbdata";    /* game backup file */
  119. rc.mfile = "ldb.rcv";    /* default file for received mail */
  120. rc.sendcmd = "mail -s '$s' $a < $f";    /* default mail command */
  121. rc.tempfile = "ldb.tmp";        /* default temp file */
  122. rc.defclrs = "rw";            /* "default" default colors */
  123. rc.defdir = "u";            /* and direction */
  124. rc.initboard = "c";            /* show current board by default */
  125. rc.autoroll = "y";            /* enable autoroll by default */
  126. rc.automove = "n";        /* disabled by default (it's really annoying */
  127. rc.autodouble = 0;        /* disable autodouble by default */
  128. rc.supercmd = "sh";        /* command to run when we have company */
  129. rc.superkey = 0;        /* key to activate supercmd (dflt=disabled) */
  130. rc.chkpt = "y";            /* checkpoint is enabled by default */
  131. if ( (n = nvscan(fp,nv_rcfile,&rc,opcodes)) != NULL) {
  132.     fprintf(stderr,"Invalid line in .ldbrc: %s\n",n);
  133.     exit(1);
  134.     }
  135. fclose(fp);
  136. if (rc.myname == NULL) {
  137.     fprintf(stderr,"ERROR: missing 'myname' line in %s\n",s);
  138.     exit(1);
  139.     }
  140. if (rc.myaddr == NULL) {
  141.     fprintf(stderr,"ERROR: missing 'myaddr' line in %s\n",s);
  142.     exit(1);
  143.     }
  144. if ( (strlen(rc.defclrs) != 2) ||
  145.      (strchr("rwb",rc.defclrs[0]) == NULL) ||
  146.      (strchr("rwb",rc.defclrs[1]) == NULL) ||
  147.      (rc.defclrs[0] == rc.defclrs[1]) ) {
  148.     fprintf(stderr,"ERROR: invalid color string in %s: %s",s,rc.defclrs);
  149.     exit(1);
  150.     }
  151. if (strchr("ud",*rc.defdir) == NULL) {
  152.     fprintf(stderr,"ERROR: direction must be 'up' or 'down' in %s\n",s);
  153.     exit(1);
  154.     }
  155. if (strchr("bac",*rc.initboard) == NULL) {
  156.     fprintf(stderr,
  157.      "ERROR: initialboard must be 'before', 'after', or 'current' in %s\n"
  158.      ,s);
  159.     exit(1);
  160.     }
  161. if (strchr("yn",*rc.autoroll) == NULL) {
  162.     fprintf(stderr,"ERROR: autoroll must be 'yes' or 'no' in %s\n",s);
  163.     exit(1);
  164.     }
  165. if (strchr("yn",*rc.automove) == NULL) {
  166.     fprintf(stderr,"ERROR: automove must be 'yes' or 'no' in %s\n",s);
  167.     exit(1);
  168.     }
  169. if (strchr("yn",*rc.chkpt) == NULL) {
  170.     fprintf(stderr,"ERROR: checkpoint must be 'yes' or 'no' in %s\n",s);
  171.     exit(1);
  172.     }
  173. }
  174.  
  175.  
  176. /*---------------------------------------------------------------------------
  177.  *    readgames -- read in games in progress
  178.  *
  179.  * This function reads the games file specified in .ldbrc and loads
  180.  * the games into the games list (ghead/gtail).
  181.  *---------------------------------------------------------------------------
  182.  */
  183.  
  184. readgames()
  185. {
  186. FILE *fp;
  187. char *s;
  188. struct game *g;
  189.  
  190. if ( (fp = fopen(rc.gfile,"r")) == NULL)
  191.     return;                /* no games */
  192. while (! feof(fp)) {
  193.     g = addgame();        /* insert a new game */
  194.     g->opaddr = NULL;
  195.     g->opname = NULL;
  196.     g->mycmt = NULL;
  197.     g->mycmt2 = NULL;
  198.     g->opcmt = NULL;
  199.     g->opcmt2 = NULL;
  200.     g->dispmsg = NULL;
  201.     g->hiused = 0;
  202.     g->maxused = 0;
  203.     clearmvs(g->opmvs);
  204.     clearmvs(g->mvs);
  205.     if ( (s = nvscan(fp,nv_gfile,g,opcodes)) != NULL) {    /* read game */
  206.         FeFinishSession();    /* close down front-end */
  207.         TFinishSession();    /* close down transport */
  208.         fprintf(stderr,"ERROR: invalid line in %s: %s\n", rc.gfile, s);
  209.         exit(1);
  210.         }
  211.     if (g->gameid == NULL)        /* empty game (prob. EOF) */
  212.         deletegame(g);
  213.     }
  214. fclose(fp);
  215. }
  216.  
  217.  
  218. /*----------------------------------------------------------------------
  219.  *    writegames -- save the game list to a file
  220.  *
  221.  * This function writes each game in the game list to the specified
  222.  * file.  Games with F_DELETE set in their flags are skipped, and
  223.  * are thus effectively deleted.  If the bkup arg is not NULL and
  224.  * is not an empty string, the old file is renamed to the string
  225.  * specified in bkup before the new file is created.
  226.  *----------------------------------------------------------------------
  227.  */
  228.  
  229. writegames(file,bkup)
  230. char *file, *bkup;
  231. {
  232. FILE *fp;
  233. struct game *g;
  234.  
  235. if ( (bkup != NULL) && (*bkup != '\0') )
  236.     rename(file,bkup);    /* save old game file */
  237. else
  238.     unlink(file);        /* prevent multiple versions on VMS */
  239. if ( (fp = fopen(file,"w")) == NULL) {
  240.     fprintf(stderr,"ERROR: can't save games in %s\n",file);
  241.     return;            /* should do something to save games... */
  242.     }
  243. for (g = ghead; g != NULL; g = g->next) {
  244.     if (g->flags & F_DELETE)
  245.         continue;            /* game is over, delete it */
  246.     nvwrite(fp,nv_gfile,g,opcodes);    /* write the struct */
  247.     }
  248. fclose(fp);
  249. }
  250.  
  251.  
  252.  
  253. /*----------------------------------------------------------------------
  254.  *    boardstr -- generate an ascii representation of a board
  255.  *
  256.  * This function produces a visible representation of a board.  Each point
  257.  * on the board takes two characters; the quantity is offset by 65,
  258.  * putting it in the range [A-P], and the color is unchanged since it
  259.  * is already a printable character.  This results in a string of
  260.  * 28 character pairs, one for each point on the board.  These are
  261.  * in the order:
  262.  *    0:    BAR point for upbound player
  263.  *    1-24:    board points
  264.  *    25:    BAR point for downbound player
  265.  *    26:    OFF point for upbound player
  266.  *    27:    OFF point for downbound player
  267.  *----------------------------------------------------------------------
  268.  */
  269.  
  270. char *boardstr(b)
  271. board b;
  272. {
  273. static char buf[BOARDSIZE*2+1];
  274. char *s, c;
  275. int i;
  276.  
  277. s = buf;
  278. for (i = 0; i < BOARDSIZE; i++) {
  279.     *s++ = b[i].qty + 'A';        /* offset qty into u.c. letters */
  280.     if ( ((c = b[i].color) < 'a') || (c > 'z') )
  281.         c = 'x';        /* use printing chars */
  282.     *s++ = c;
  283.     }
  284. *s = '\0';
  285. return(buf);
  286. }
  287.  
  288.  
  289.  
  290. /*----------------------------------------------------------------------
  291.  *    nvscan -- read name/value pairs from a file
  292.  *
  293.  * This function provides a generalized method for reading name/value
  294.  * pairs.  The names and value types are specified in an array of
  295.  * struct namevalue's, along with an offset which is used to store
  296.  * the value.  The offset is added to a base pointer, passed as the
  297.  * "st" argument, to form a pointer, which is then converted to the
  298.  * type indicated by the "type" field of the namevalue table using
  299.  * the "nvtypes" union, and used to store the value.  The legal
  300.  * value types are defined in ldb.h as T_*.  Name/value pairs are
  301.  * expected to be in the form "name=value\n", with no spaces before
  302.  * or after name, and with any spaces after the = or before the
  303.  * newline being part of the value string.  Comments are not allowed in
  304.  * the input file, although the caller can read any lines that precede
  305.  * the name/value list before calling nvscan.
  306.  *----------------------------------------------------------------------
  307.  */
  308.  
  309. char *nvscan(fp,t,st,strings)
  310. FILE *fp;        /* file to scan */
  311. struct namevalue *t;    /* table of name/value pairs */
  312. char *st;        /* really a pointer to a structure */
  313. char *strings[];    /* string table for FT_STRLKUP */
  314. {
  315. static char buf[128];
  316. char *s, **p;
  317. int i, j;
  318. union nvtypes u;
  319. long atol();
  320.  
  321. while (fgets(buf,sizeof(buf),fp) != NULL) {
  322.     buf[strlen(buf)-1] = '\0';        /* clobber the newline */
  323.     if ( (s = strchr(buf,'=')) == NULL)
  324.         return(buf);            /* bad line, return it */
  325.     *s++ = '\0';
  326.     for (i = 0; t[i].name != NULL; i++)
  327.         if (strcmp(t[i].name,buf) == 0)
  328.             break;
  329.     if (t[i].name == NULL)        /* got a name we don't recognize */
  330.         continue;        /* ignore it */
  331.     u.nvchar = st + t[i].offset;    /* put pointer into union */
  332.     switch (t[i].type) {
  333.     case FT_CHAR:            /* just store a single char */
  334.         *u.nvchar = atoi(s);    /* chars stored as ints in the file */
  335.         break;
  336.     case FT_INT:            /* store an int */
  337.         *u.nvint = atoi(s);
  338.         break;
  339.     case FT_STRING:            /* store a copy of a string */
  340.         *u.nvstring = save(s);
  341.         break;
  342.     case FT_MOVE:            /* store a struct mv */
  343.         str2mv(s,u.nvmove);
  344.         break;
  345.     case FT_BOARD:            /* store an entire board */
  346.         for (j = 0; j < BOARDSIZE; j++) {
  347.             u.nvboard[j].qty = *s++ - 'A';
  348.             u.nvboard[j].color = *s++;
  349.             }
  350.         break;
  351.     case FT_STRLKUP:        /* look up string & store index */
  352.         if (strings == NULL) {        /* choke... */
  353.             FeFinishSession();    /* close down front-end */
  354.             TFinishSession();    /* close down transport */
  355.             fprintf(stderr,"ERROR: NULL string table in nvscan\n");
  356.             exit(1);
  357.             }
  358.         for (j = 0, p = strings; *p; j++, p++)
  359.             if (strcmp(s,*p) == 0)
  360.                 break;
  361.         if (*p == NULL) {
  362.             FeFinishSession();    /* close down front-end */
  363.             TFinishSession();    /* close down transport */
  364.             fprintf(stderr,"ERROR: unknown opcode: %s\n",s);
  365.             exit(1);    /* shouldn't do this... */
  366.             }
  367.         *u.nvint = j;    /* store integer opcode */
  368.         break;
  369.     case FT_TIME:            /* read in a timestamp */
  370.         *u.nvtime = atol(s);
  371.         break;
  372.     case FT_END:            /* we hit the end marker */
  373.         return(NULL);        /* return success */
  374.     default:            /* we have a bad nv table */
  375.         *--s = '=';        /* restore the buffer */
  376.         return(buf);        /* return bad line */
  377.         }
  378.     }
  379. return(NULL);
  380. }
  381.  
  382.  
  383.  
  384. /*----------------------------------------------------------------------
  385.  *    nvwrite -- write name/value pairs into a file
  386.  *
  387.  * This function writes name/value pairs to a file in the same format
  388.  * used by nvscan.  Nvwrite is merely the inverse of nvscan, taking values
  389.  * out of the structure in the same manner nvscan used to store them
  390.  * there, and generating "name=value" lines.  One line is generated for
  391.  * each element in the namevalue table, except that elements of type
  392.  * FT_STRING whose value is NULL are skipped, as are elements of a
  393.  * move array whose "roll" field is <= 0.
  394.  *----------------------------------------------------------------------
  395.  */
  396.  
  397. nvwrite(fp,t,st,strings)
  398. FILE *fp;            /* file to write to */
  399. struct namevalue *t;        /* table of name/value pairs */
  400. char *st;            /* really a pointer to a structure */
  401. char *strings[];        /* table of strings for FT_STRLKUP */
  402. {
  403. struct namevalue *n;
  404. static char buf[128];
  405. int nstr = -1;
  406. union nvtypes u;
  407. long time();
  408.  
  409. for (n = t; n->name != NULL; n++) {
  410.     u.nvchar = st + n->offset;
  411.     switch (n->type) {
  412.     case FT_CHAR:            /* just store a single char */
  413.         fprintf(fp,"%s=%d\n",n->name,*u.nvchar);
  414.         break;
  415.     case FT_INT:            /* store an int */
  416.         fprintf(fp,"%s=%d\n",n->name,*u.nvint);
  417.         break;
  418.     case FT_STRING:            /* store a copy of a string */
  419.         if (*u.nvstring != NULL)    /* skip NULL strings */
  420.             fprintf(fp,"%s=%s\n",n->name,*u.nvstring);
  421.         break;
  422.     case FT_MOVE:            /* store a struct mv */
  423.         if (u.nvmove->roll > 0) {
  424.             mv2str(u.nvmove,buf);
  425.             fprintf(fp,"%s=%s\n",n->name,buf);
  426.             }
  427.         break;
  428.     case FT_BOARD:            /* store an entire board */
  429.         fprintf(fp,"%s=%s\n",n->name,boardstr(u.nvboard));
  430.         break;
  431.     case FT_STRLKUP:        /* look up string & store index */
  432.         if (nstr < 0) {
  433.             if (strings == NULL) {
  434.                 FeFinishSession();/* close down front-end */
  435.                 TFinishSession();/* close down transport */
  436.                 fprintf(stderr,
  437.                    "ERROR: NULL string table in nvwrite.\n");
  438.                 exit(1);
  439.                 }
  440.             for (nstr = 0; strings[nstr]; nstr++); /* # strings */
  441.             }
  442.         if ( (*u.nvint < 0) || (*u.nvint >= nstr) ) {
  443.             FeFinishSession();    /* close down front-end */
  444.             TFinishSession();    /* close down transport */
  445.             fprintf(stderr,"ERROR: invalid index: %s=%d\n",
  446.                 n->name,*u.nvint);
  447.             exit(1);    /* shouldn't do this... */
  448.             }
  449.         fprintf(fp,"%s=%s\n",n->name,strings[*u.nvint]);
  450.         break;
  451.     case FT_TIME:            /* generate a timestamp */
  452.         fprintf(fp,"%s=%lu\n",n->name,time(0));
  453.         break;
  454.     case FT_END:            /* we hit the end marker */
  455.         fprintf(fp,"%s=end\n",n->name);
  456.         break;
  457.     default:            /* we have a bad nv table */
  458.         FeFinishSession();    /* close down front-end */
  459.         TFinishSession();    /* close down transport */
  460.         fprintf(stderr,"ERROR: bad namevalue type: %s (%d)\n",
  461.             n->name,n->type);
  462.         exit(1);        /* should have saved games? */
  463.         }
  464.     }
  465. }
  466.