home *** CD-ROM | disk | FTP | other *** search
- /* save.c 8/4/91
- *
- * Copyright 1991 Perry R. Ross
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation without fee is hereby granted, subject to the restrictions
- * detailed in the README file, which is included here by reference.
- * Any other use requires written permission from the author. This software
- * is distributed "as is" without any warranty, including any implied
- * warranties of merchantability or fitness for a particular purpose.
- * The author shall not be liable for any damages resulting from the
- * use of this software. By using this software, the user agrees
- * to these terms.
- */
-
- #include "ldb.h"
-
- /*===========================================================================
- * This file contains miscellaneous functions that save and load things.
- *===========================================================================
- */
-
- /*---------------------------------------------------------------------------
- * save -- make a copy of a string
- *
- * This function makes a copy of a string in malloc memory, and returns
- * a pointer to the copy.
- *---------------------------------------------------------------------------
- */
-
- char *save(s)
- char *s;
- {
- char *n;
-
- if ( (n = calloc(strlen(s)+1,1)) == NULL) {
- FeFinishSession();
- TFinishSession(); /* close down transport */
- fprintf(stderr,"Out of memory!\n");
- exit(1);
- }
- strcpy(n,s);
- return(n);
- }
-
-
- /*---------------------------------------------------------------------------
- * readldbrc -- read in the .ldbrc file
- *
- * This function reads the .ldbrc file, which contains the setup info
- * for this user. If the HOME environment variable is set, we chdir to it.
- * If the LDBRC environment variable is set, it is used as the file to
- * read instead of .ldbrc.
- *---------------------------------------------------------------------------
- */
-
- readldbrc()
- {
- FILE *fp;
- char *s, *n, *getenv();
- char buf[80];
-
- if ( (s = getenv("HOME")) != NULL) /* if we have a home */
- chdir(s); /* go there */
- if ( (s = getenv("LDBRC")) == NULL) /* LDBRC not set */
- s = ".ldbrc"; /* use default file name */
- if ( (fp = fopen(s,"r")) == NULL) {
- printf("'%s' does not exist. Do you want to create it?",s);
- if ( (gets(buf) == NULL) || ( (*buf != 'y') && (*buf != 'Y') ) ) {
- printf("ldb aborted.\n");
- exit(1);
- }
- if ( (fp = fopen(s,"w")) == NULL) {
- printf("Sorry, could not create %s.\n",s);
- exit(1);
- }
- printf("Please enter your personal name: ");
- if (gets(buf) == NULL) {
- fclose(fp);
- unlink(s);
- printf("ldb aborted.\n");
- exit(1);
- }
- fprintf(fp,"myname=%s\n",buf);
- printf("Please enter your e-mail address: ");
- if (gets(buf) == NULL) {
- fclose(fp);
- unlink(s);
- printf("ldb aborted.\n");
- exit(1);
- }
- fprintf(fp,"myaddr=%s\n",buf);
- fprintf(fp,"gamefile=.ldbdata\n");
- fprintf(fp,"backupfile=.oldldbdata\n");
- fprintf(fp,"mailfile=ldb.rcv\n");
- fprintf(fp,"sendcmd=mail -s '$s' $a < $f\n");
- fprintf(fp,"tempfile=ldb.tmp\n");
- fprintf(fp,"colors=rw\n");
- fprintf(fp,"direction=up\n");
- fprintf(fp,"initialboard=current\n");
- fprintf(fp,"autoroll=yes\n");
- fprintf(fp,"automove=no\n");
- fprintf(fp,"autodouble=0\n");
- fprintf(fp,"supercmd=sh\n");
- fprintf(fp,"superkey=0\n");
- fprintf(fp,"checkpoint=yes\n");
- fclose(fp);
- printf("\nYour %s file was created. You may want to read the\n",s);
- printf("manual for additional options available in this file.\n\n");
- if ( (fp = fopen(s,"r")) == NULL) {
- printf("I can't re-open your %s file!\n",s);
- exit(1);
- }
- }
- rc.myname = NULL; /* these fields are required */
- rc.myaddr = NULL;
- rc.gfile = ".ldbdata"; /* default game storage file */
- rc.gbackup = ".oldldbdata"; /* game backup file */
- rc.mfile = "ldb.rcv"; /* default file for received mail */
- rc.sendcmd = "mail -s '$s' $a < $f"; /* default mail command */
- rc.tempfile = "ldb.tmp"; /* default temp file */
- rc.defclrs = "rw"; /* "default" default colors */
- rc.defdir = "u"; /* and direction */
- rc.initboard = "c"; /* show current board by default */
- rc.autoroll = "y"; /* enable autoroll by default */
- rc.automove = "n"; /* disabled by default (it's really annoying */
- rc.autodouble = 0; /* disable autodouble by default */
- rc.supercmd = "sh"; /* command to run when we have company */
- rc.superkey = 0; /* key to activate supercmd (dflt=disabled) */
- rc.chkpt = "y"; /* checkpoint is enabled by default */
- if ( (n = nvscan(fp,nv_rcfile,&rc,opcodes)) != NULL) {
- fprintf(stderr,"Invalid line in .ldbrc: %s\n",n);
- exit(1);
- }
- fclose(fp);
- if (rc.myname == NULL) {
- fprintf(stderr,"ERROR: missing 'myname' line in %s\n",s);
- exit(1);
- }
- if (rc.myaddr == NULL) {
- fprintf(stderr,"ERROR: missing 'myaddr' line in %s\n",s);
- exit(1);
- }
- if ( (strlen(rc.defclrs) != 2) ||
- (strchr("rwb",rc.defclrs[0]) == NULL) ||
- (strchr("rwb",rc.defclrs[1]) == NULL) ||
- (rc.defclrs[0] == rc.defclrs[1]) ) {
- fprintf(stderr,"ERROR: invalid color string in %s: %s",s,rc.defclrs);
- exit(1);
- }
- if (strchr("ud",*rc.defdir) == NULL) {
- fprintf(stderr,"ERROR: direction must be 'up' or 'down' in %s\n",s);
- exit(1);
- }
- if (strchr("bac",*rc.initboard) == NULL) {
- fprintf(stderr,
- "ERROR: initialboard must be 'before', 'after', or 'current' in %s\n"
- ,s);
- exit(1);
- }
- if (strchr("yn",*rc.autoroll) == NULL) {
- fprintf(stderr,"ERROR: autoroll must be 'yes' or 'no' in %s\n",s);
- exit(1);
- }
- if (strchr("yn",*rc.automove) == NULL) {
- fprintf(stderr,"ERROR: automove must be 'yes' or 'no' in %s\n",s);
- exit(1);
- }
- if (strchr("yn",*rc.chkpt) == NULL) {
- fprintf(stderr,"ERROR: checkpoint must be 'yes' or 'no' in %s\n",s);
- exit(1);
- }
- }
-
-
- /*---------------------------------------------------------------------------
- * readgames -- read in games in progress
- *
- * This function reads the games file specified in .ldbrc and loads
- * the games into the games list (ghead/gtail).
- *---------------------------------------------------------------------------
- */
-
- readgames()
- {
- FILE *fp;
- char *s;
- struct game *g;
-
- if ( (fp = fopen(rc.gfile,"r")) == NULL)
- return; /* no games */
- while (! feof(fp)) {
- g = addgame(); /* insert a new game */
- g->opaddr = NULL;
- g->opname = NULL;
- g->mycmt = NULL;
- g->mycmt2 = NULL;
- g->opcmt = NULL;
- g->opcmt2 = NULL;
- g->dispmsg = NULL;
- g->hiused = 0;
- g->maxused = 0;
- clearmvs(g->opmvs);
- clearmvs(g->mvs);
- if ( (s = nvscan(fp,nv_gfile,g,opcodes)) != NULL) { /* read game */
- FeFinishSession(); /* close down front-end */
- TFinishSession(); /* close down transport */
- fprintf(stderr,"ERROR: invalid line in %s: %s\n", rc.gfile, s);
- exit(1);
- }
- if (g->gameid == NULL) /* empty game (prob. EOF) */
- deletegame(g);
- }
- fclose(fp);
- }
-
-
- /*----------------------------------------------------------------------
- * writegames -- save the game list to a file
- *
- * This function writes each game in the game list to the specified
- * file. Games with F_DELETE set in their flags are skipped, and
- * are thus effectively deleted. If the bkup arg is not NULL and
- * is not an empty string, the old file is renamed to the string
- * specified in bkup before the new file is created.
- *----------------------------------------------------------------------
- */
-
- writegames(file,bkup)
- char *file, *bkup;
- {
- FILE *fp;
- struct game *g;
-
- if ( (bkup != NULL) && (*bkup != '\0') )
- rename(file,bkup); /* save old game file */
- else
- unlink(file); /* prevent multiple versions on VMS */
- if ( (fp = fopen(file,"w")) == NULL) {
- fprintf(stderr,"ERROR: can't save games in %s\n",file);
- return; /* should do something to save games... */
- }
- for (g = ghead; g != NULL; g = g->next) {
- if (g->flags & F_DELETE)
- continue; /* game is over, delete it */
- nvwrite(fp,nv_gfile,g,opcodes); /* write the struct */
- }
- fclose(fp);
- }
-
-
-
- /*----------------------------------------------------------------------
- * boardstr -- generate an ascii representation of a board
- *
- * This function produces a visible representation of a board. Each point
- * on the board takes two characters; the quantity is offset by 65,
- * putting it in the range [A-P], and the color is unchanged since it
- * is already a printable character. This results in a string of
- * 28 character pairs, one for each point on the board. These are
- * in the order:
- * 0: BAR point for upbound player
- * 1-24: board points
- * 25: BAR point for downbound player
- * 26: OFF point for upbound player
- * 27: OFF point for downbound player
- *----------------------------------------------------------------------
- */
-
- char *boardstr(b)
- board b;
- {
- static char buf[BOARDSIZE*2+1];
- char *s, c;
- int i;
-
- s = buf;
- for (i = 0; i < BOARDSIZE; i++) {
- *s++ = b[i].qty + 'A'; /* offset qty into u.c. letters */
- if ( ((c = b[i].color) < 'a') || (c > 'z') )
- c = 'x'; /* use printing chars */
- *s++ = c;
- }
- *s = '\0';
- return(buf);
- }
-
-
-
- /*----------------------------------------------------------------------
- * nvscan -- read name/value pairs from a file
- *
- * This function provides a generalized method for reading name/value
- * pairs. The names and value types are specified in an array of
- * struct namevalue's, along with an offset which is used to store
- * the value. The offset is added to a base pointer, passed as the
- * "st" argument, to form a pointer, which is then converted to the
- * type indicated by the "type" field of the namevalue table using
- * the "nvtypes" union, and used to store the value. The legal
- * value types are defined in ldb.h as T_*. Name/value pairs are
- * expected to be in the form "name=value\n", with no spaces before
- * or after name, and with any spaces after the = or before the
- * newline being part of the value string. Comments are not allowed in
- * the input file, although the caller can read any lines that precede
- * the name/value list before calling nvscan.
- *----------------------------------------------------------------------
- */
-
- char *nvscan(fp,t,st,strings)
- FILE *fp; /* file to scan */
- struct namevalue *t; /* table of name/value pairs */
- char *st; /* really a pointer to a structure */
- char *strings[]; /* string table for FT_STRLKUP */
- {
- static char buf[128];
- char *s, **p;
- int i, j;
- union nvtypes u;
- long atol();
-
- while (fgets(buf,sizeof(buf),fp) != NULL) {
- buf[strlen(buf)-1] = '\0'; /* clobber the newline */
- if ( (s = strchr(buf,'=')) == NULL)
- return(buf); /* bad line, return it */
- *s++ = '\0';
- for (i = 0; t[i].name != NULL; i++)
- if (strcmp(t[i].name,buf) == 0)
- break;
- if (t[i].name == NULL) /* got a name we don't recognize */
- continue; /* ignore it */
- u.nvchar = st + t[i].offset; /* put pointer into union */
- switch (t[i].type) {
- case FT_CHAR: /* just store a single char */
- *u.nvchar = atoi(s); /* chars stored as ints in the file */
- break;
- case FT_INT: /* store an int */
- *u.nvint = atoi(s);
- break;
- case FT_STRING: /* store a copy of a string */
- *u.nvstring = save(s);
- break;
- case FT_MOVE: /* store a struct mv */
- str2mv(s,u.nvmove);
- break;
- case FT_BOARD: /* store an entire board */
- for (j = 0; j < BOARDSIZE; j++) {
- u.nvboard[j].qty = *s++ - 'A';
- u.nvboard[j].color = *s++;
- }
- break;
- case FT_STRLKUP: /* look up string & store index */
- if (strings == NULL) { /* choke... */
- FeFinishSession(); /* close down front-end */
- TFinishSession(); /* close down transport */
- fprintf(stderr,"ERROR: NULL string table in nvscan\n");
- exit(1);
- }
- for (j = 0, p = strings; *p; j++, p++)
- if (strcmp(s,*p) == 0)
- break;
- if (*p == NULL) {
- FeFinishSession(); /* close down front-end */
- TFinishSession(); /* close down transport */
- fprintf(stderr,"ERROR: unknown opcode: %s\n",s);
- exit(1); /* shouldn't do this... */
- }
- *u.nvint = j; /* store integer opcode */
- break;
- case FT_TIME: /* read in a timestamp */
- *u.nvtime = atol(s);
- break;
- case FT_END: /* we hit the end marker */
- return(NULL); /* return success */
- default: /* we have a bad nv table */
- *--s = '='; /* restore the buffer */
- return(buf); /* return bad line */
- }
- }
- return(NULL);
- }
-
-
-
- /*----------------------------------------------------------------------
- * nvwrite -- write name/value pairs into a file
- *
- * This function writes name/value pairs to a file in the same format
- * used by nvscan. Nvwrite is merely the inverse of nvscan, taking values
- * out of the structure in the same manner nvscan used to store them
- * there, and generating "name=value" lines. One line is generated for
- * each element in the namevalue table, except that elements of type
- * FT_STRING whose value is NULL are skipped, as are elements of a
- * move array whose "roll" field is <= 0.
- *----------------------------------------------------------------------
- */
-
- nvwrite(fp,t,st,strings)
- FILE *fp; /* file to write to */
- struct namevalue *t; /* table of name/value pairs */
- char *st; /* really a pointer to a structure */
- char *strings[]; /* table of strings for FT_STRLKUP */
- {
- struct namevalue *n;
- static char buf[128];
- int nstr = -1;
- union nvtypes u;
- long time();
-
- for (n = t; n->name != NULL; n++) {
- u.nvchar = st + n->offset;
- switch (n->type) {
- case FT_CHAR: /* just store a single char */
- fprintf(fp,"%s=%d\n",n->name,*u.nvchar);
- break;
- case FT_INT: /* store an int */
- fprintf(fp,"%s=%d\n",n->name,*u.nvint);
- break;
- case FT_STRING: /* store a copy of a string */
- if (*u.nvstring != NULL) /* skip NULL strings */
- fprintf(fp,"%s=%s\n",n->name,*u.nvstring);
- break;
- case FT_MOVE: /* store a struct mv */
- if (u.nvmove->roll > 0) {
- mv2str(u.nvmove,buf);
- fprintf(fp,"%s=%s\n",n->name,buf);
- }
- break;
- case FT_BOARD: /* store an entire board */
- fprintf(fp,"%s=%s\n",n->name,boardstr(u.nvboard));
- break;
- case FT_STRLKUP: /* look up string & store index */
- if (nstr < 0) {
- if (strings == NULL) {
- FeFinishSession();/* close down front-end */
- TFinishSession();/* close down transport */
- fprintf(stderr,
- "ERROR: NULL string table in nvwrite.\n");
- exit(1);
- }
- for (nstr = 0; strings[nstr]; nstr++); /* # strings */
- }
- if ( (*u.nvint < 0) || (*u.nvint >= nstr) ) {
- FeFinishSession(); /* close down front-end */
- TFinishSession(); /* close down transport */
- fprintf(stderr,"ERROR: invalid index: %s=%d\n",
- n->name,*u.nvint);
- exit(1); /* shouldn't do this... */
- }
- fprintf(fp,"%s=%s\n",n->name,strings[*u.nvint]);
- break;
- case FT_TIME: /* generate a timestamp */
- fprintf(fp,"%s=%lu\n",n->name,time(0));
- break;
- case FT_END: /* we hit the end marker */
- fprintf(fp,"%s=end\n",n->name);
- break;
- default: /* we have a bad nv table */
- FeFinishSession(); /* close down front-end */
- TFinishSession(); /* close down transport */
- fprintf(stderr,"ERROR: bad namevalue type: %s (%d)\n",
- n->name,n->type);
- exit(1); /* should have saved games? */
- }
- }
- }
-