1 1.22 dholland /* $NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $ */ 2 1.3 cgd 3 1.1 cgd /* 4 1.3 cgd * Copyright (c) 1980, 1993 5 1.3 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.10 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.4 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.3 cgd #if 0 35 1.3 cgd static char sccsid[] = "@(#)execute.c 8.1 (Berkeley) 5/31/93"; 36 1.3 cgd #else 37 1.22 dholland __RCSID("$NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $"); 38 1.3 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.4 christos #include <fcntl.h> 42 1.4 christos #include <stdlib.h> 43 1.4 christos #include <unistd.h> 44 1.15 dholland #include <limits.h> 45 1.4 christos #include <sys/types.h> 46 1.4 christos #include <sys/stat.h> 47 1.4 christos #include <sys/time.h> 48 1.8 jsm #include <time.h> 49 1.15 dholland #include <errno.h> 50 1.1 cgd 51 1.17 dholland #include "deck.h" 52 1.17 dholland #include "monop.h" 53 1.17 dholland 54 1.15 dholland #define MIN_FORMAT_VERSION 1 55 1.15 dholland #define CUR_FORMAT_VERSION 1 56 1.15 dholland #define MAX_FORMAT_VERSION 1 57 1.1 cgd 58 1.1 cgd typedef struct stat STAT; 59 1.1 cgd typedef struct tm TIME; 60 1.1 cgd 61 1.4 christos static char buf[257]; 62 1.1 cgd 63 1.4 christos static bool new_play; /* set if move on to new player */ 64 1.1 cgd 65 1.11 jsm static void show_move(void); 66 1.1 cgd 67 1.15 dholland static void restore_reset(void); 68 1.15 dholland static int restore_parseline(char *txt); 69 1.15 dholland static int restore_toplevel_attr(const char *attribute, char *txt); 70 1.15 dholland static int restore_player_attr(const char *attribute, char *txt); 71 1.15 dholland static int restore_deck_attr(const char *attribute, char *txt); 72 1.15 dholland static int restore_square_attr(const char *attribute, char *txt); 73 1.15 dholland static int getnum(const char *what, char *txt, int min, int max, int *ret); 74 1.15 dholland static int getnum_withbrace(const char *what, char *txt, int min, int max, 75 1.15 dholland int *ret); 76 1.15 dholland 77 1.1 cgd /* 78 1.1 cgd * This routine executes the given command by index number 79 1.1 cgd */ 80 1.4 christos void 81 1.22 dholland execute(int com_num) 82 1.4 christos { 83 1.1 cgd new_play = FALSE; /* new_play is true if fixing */ 84 1.1 cgd (*func[com_num])(); 85 1.1 cgd notify(); 86 1.1 cgd force_morg(); 87 1.1 cgd if (new_play) 88 1.1 cgd next_play(); 89 1.1 cgd else if (num_doub) 90 1.1 cgd printf("%s rolled doubles. Goes again\n", cur_p->name); 91 1.1 cgd } 92 1.6 simonb 93 1.1 cgd /* 94 1.1 cgd * This routine moves a piece around. 95 1.1 cgd */ 96 1.4 christos void 97 1.22 dholland do_move(void) 98 1.4 christos { 99 1.6 simonb int r1, r2; 100 1.6 simonb bool was_jail; 101 1.1 cgd 102 1.1 cgd new_play = was_jail = FALSE; 103 1.1 cgd printf("roll is %d, %d\n", r1=roll(1, 6), r2=roll(1, 6)); 104 1.1 cgd if (cur_p->loc == JAIL) { 105 1.1 cgd was_jail++; 106 1.1 cgd if (!move_jail(r1, r2)) { 107 1.1 cgd new_play++; 108 1.1 cgd goto ret; 109 1.1 cgd } 110 1.1 cgd } 111 1.1 cgd else { 112 1.1 cgd if (r1 == r2 && ++num_doub == 3) { 113 1.1 cgd printf("That's 3 doubles. You go to jail\n"); 114 1.1 cgd goto_jail(); 115 1.1 cgd new_play++; 116 1.1 cgd goto ret; 117 1.1 cgd } 118 1.1 cgd move(r1+r2); 119 1.1 cgd } 120 1.1 cgd if (r1 != r2 || was_jail) 121 1.1 cgd new_play++; 122 1.1 cgd ret: 123 1.1 cgd return; 124 1.1 cgd } 125 1.6 simonb 126 1.1 cgd /* 127 1.1 cgd * This routine moves a normal move 128 1.1 cgd */ 129 1.4 christos void 130 1.22 dholland move(int rl) 131 1.4 christos { 132 1.6 simonb int old_loc; 133 1.1 cgd 134 1.1 cgd old_loc = cur_p->loc; 135 1.1 cgd cur_p->loc = (cur_p->loc + rl) % N_SQRS; 136 1.1 cgd if (cur_p->loc < old_loc && rl > 0) { 137 1.1 cgd cur_p->money += 200; 138 1.1 cgd printf("You pass %s and get $200\n", board[0].name); 139 1.1 cgd } 140 1.1 cgd show_move(); 141 1.1 cgd } 142 1.6 simonb 143 1.1 cgd /* 144 1.1 cgd * This routine shows the results of a move 145 1.1 cgd */ 146 1.4 christos static void 147 1.22 dholland show_move(void) 148 1.4 christos { 149 1.6 simonb SQUARE *sqp; 150 1.1 cgd 151 1.1 cgd sqp = &board[cur_p->loc]; 152 1.1 cgd printf("That puts you on %s\n", sqp->name); 153 1.1 cgd switch (sqp->type) { 154 1.1 cgd case SAFE: 155 1.1 cgd printf("That is a safe place\n"); 156 1.1 cgd break; 157 1.1 cgd case CC: 158 1.14 dholland cc(); 159 1.14 dholland break; 160 1.1 cgd case CHANCE: 161 1.14 dholland chance(); 162 1.14 dholland break; 163 1.1 cgd case INC_TAX: 164 1.14 dholland inc_tax(); 165 1.14 dholland break; 166 1.1 cgd case GOTO_J: 167 1.14 dholland goto_jail(); 168 1.14 dholland break; 169 1.1 cgd case LUX_TAX: 170 1.14 dholland lux_tax(); 171 1.14 dholland break; 172 1.1 cgd case PRPTY: 173 1.1 cgd case RR: 174 1.1 cgd case UTIL: 175 1.1 cgd if (sqp->owner < 0) { 176 1.1 cgd printf("That would cost $%d\n", sqp->cost); 177 1.1 cgd if (getyn("Do you want to buy? ") == 0) { 178 1.1 cgd buy(player, sqp); 179 1.1 cgd cur_p->money -= sqp->cost; 180 1.1 cgd } 181 1.1 cgd else if (num_play > 2) 182 1.4 christos bid(); 183 1.1 cgd } 184 1.1 cgd else if (sqp->owner == player) 185 1.1 cgd printf("You own it.\n"); 186 1.1 cgd else 187 1.1 cgd rent(sqp); 188 1.1 cgd } 189 1.1 cgd } 190 1.6 simonb 191 1.1 cgd /* 192 1.15 dholland * Reset the game state. 193 1.15 dholland */ 194 1.15 dholland static void 195 1.15 dholland reset_game(void) 196 1.15 dholland { 197 1.15 dholland int i; 198 1.15 dholland 199 1.15 dholland for (i = 0; i < N_SQRS; i++) { 200 1.15 dholland board[i].owner = -1; 201 1.15 dholland if (board[i].type == PRPTY) { 202 1.15 dholland board[i].desc->morg = 0; 203 1.15 dholland board[i].desc->houses = 0; 204 1.15 dholland } else if (board[i].type == RR || board[i].type == UTIL) { 205 1.15 dholland board[i].desc->morg = 0; 206 1.15 dholland } 207 1.15 dholland } 208 1.15 dholland 209 1.15 dholland for (i = 0; i < 2; i++) { 210 1.15 dholland deck[i].top_card = 0; 211 1.15 dholland deck[i].gojf_used = FALSE; 212 1.15 dholland } 213 1.15 dholland 214 1.15 dholland if (play) { 215 1.15 dholland for (i = 0; i < num_play; i++) { 216 1.15 dholland free(play[i].name); 217 1.15 dholland play[i].name = NULL; 218 1.15 dholland } 219 1.15 dholland free(play); 220 1.15 dholland play = NULL; 221 1.15 dholland } 222 1.15 dholland 223 1.15 dholland for (i = 0; i < MAX_PL+2; i++) { 224 1.15 dholland name_list[i] = NULL; 225 1.15 dholland } 226 1.15 dholland 227 1.15 dholland cur_p = NULL; 228 1.15 dholland num_play = 0; 229 1.15 dholland player = 0; 230 1.15 dholland num_doub = 0; 231 1.15 dholland fixing = FALSE; 232 1.15 dholland trading = FALSE; 233 1.15 dholland told_em = FALSE; 234 1.15 dholland spec = FALSE; 235 1.15 dholland } 236 1.15 dholland 237 1.15 dholland 238 1.15 dholland /* 239 1.1 cgd * This routine saves the current game for use at a later date 240 1.1 cgd */ 241 1.4 christos void 242 1.22 dholland save(void) 243 1.4 christos { 244 1.6 simonb char *sp; 245 1.15 dholland FILE *outf; 246 1.6 simonb time_t t; 247 1.6 simonb struct stat sb; 248 1.15 dholland int i, j; 249 1.1 cgd 250 1.1 cgd printf("Which file do you wish to save it in? "); 251 1.15 dholland fgets(buf, sizeof(buf), stdin); 252 1.15 dholland if (feof(stdin)) 253 1.15 dholland return; 254 1.15 dholland sp = strchr(buf, '\n'); 255 1.15 dholland if (sp) 256 1.15 dholland *sp = '\0'; 257 1.1 cgd 258 1.1 cgd /* 259 1.1 cgd * check for existing files, and confirm overwrite if needed 260 1.1 cgd */ 261 1.1 cgd 262 1.15 dholland if (stat(buf, &sb) == 0 263 1.4 christos && getyn("File exists. Do you wish to overwrite? ") > 0) 264 1.1 cgd return; 265 1.1 cgd 266 1.15 dholland outf = fopen(buf, "w"); 267 1.15 dholland if (outf == NULL) { 268 1.13 dholland warn("%s", buf); 269 1.1 cgd return; 270 1.1 cgd } 271 1.1 cgd printf("\"%s\" ", buf); 272 1.1 cgd time(&t); /* get current time */ 273 1.15 dholland 274 1.15 dholland /* Header */ 275 1.15 dholland fprintf(outf, "NetBSD monop format v%d\n", CUR_FORMAT_VERSION); 276 1.15 dholland fprintf(outf, "time %s", ctime(&t)); /* ctime includes a \n */ 277 1.15 dholland fprintf(outf, "numplayers %d\n", num_play); 278 1.15 dholland fprintf(outf, "currentplayer %d\n", player); 279 1.15 dholland fprintf(outf, "doubles %d\n", num_doub); 280 1.15 dholland 281 1.15 dholland /* Players */ 282 1.15 dholland for (i = 0; i < num_play; i++) { 283 1.15 dholland fprintf(outf, "player %d {\n", i); 284 1.15 dholland fprintf(outf, " name %s\n", name_list[i]); 285 1.15 dholland fprintf(outf, " money %d\n", play[i].money); 286 1.15 dholland fprintf(outf, " loc %d\n", play[i].loc); 287 1.15 dholland fprintf(outf, " num_gojf %d\n", play[i].num_gojf); 288 1.15 dholland fprintf(outf, " in_jail %d\n", play[i].in_jail); 289 1.15 dholland fprintf(outf, "}\n"); 290 1.15 dholland } 291 1.15 dholland 292 1.15 dholland /* Decks */ 293 1.15 dholland for (i = 0; i < 2; i++) { 294 1.15 dholland fprintf(outf, "deck %d {\n", i); 295 1.15 dholland fprintf(outf, " numcards %d\n", deck[i].num_cards); 296 1.15 dholland fprintf(outf, " topcard %d\n", deck[i].top_card); 297 1.15 dholland fprintf(outf, " gojf_used %d\n", deck[i].gojf_used); 298 1.18 dholland fprintf(outf, " cards"); 299 1.15 dholland for (j = 0; j < deck[i].num_cards; j++) 300 1.18 dholland fprintf(outf, " %d", deck[i].cards[j]); 301 1.15 dholland fprintf(outf, "\n"); 302 1.15 dholland fprintf(outf, "}\n"); 303 1.15 dholland } 304 1.15 dholland 305 1.15 dholland /* Board */ 306 1.15 dholland for (i = 0; i < N_SQRS; i++) { 307 1.15 dholland fprintf(outf, "square %d {\n", i); 308 1.15 dholland fprintf(outf, "owner %d\n", board[i].owner); 309 1.15 dholland if (board[i].owner < 0) { 310 1.15 dholland /* nothing */ 311 1.15 dholland } else if (board[i].type == PRPTY) { 312 1.15 dholland fprintf(outf, "morg %d\n", board[i].desc->morg); 313 1.15 dholland fprintf(outf, "houses %d\n", board[i].desc->houses); 314 1.15 dholland } else if (board[i].type == RR || board[i].type == UTIL) { 315 1.15 dholland fprintf(outf, "morg %d\n", board[i].desc->morg); 316 1.15 dholland } 317 1.15 dholland fprintf(outf, "}\n"); 318 1.15 dholland } 319 1.15 dholland if (ferror(outf) || fflush(outf)) 320 1.15 dholland warnx("write error"); 321 1.15 dholland fclose(outf); 322 1.15 dholland 323 1.1 cgd strcpy(buf, ctime(&t)); 324 1.1 cgd for (sp = buf; *sp != '\n'; sp++) 325 1.1 cgd continue; 326 1.1 cgd *sp = '\0'; 327 1.1 cgd printf("[%s]\n", buf); 328 1.1 cgd } 329 1.6 simonb 330 1.1 cgd /* 331 1.1 cgd * This routine restores an old game from a file 332 1.1 cgd */ 333 1.4 christos void 334 1.20 dholland restore(void) 335 1.4 christos { 336 1.6 simonb char *sp; 337 1.1 cgd 338 1.20 dholland for (;;) { 339 1.20 dholland printf("Which file do you wish to restore from? "); 340 1.20 dholland fgets(buf, sizeof(buf), stdin); 341 1.20 dholland if (feof(stdin)) 342 1.20 dholland return; 343 1.20 dholland sp = strchr(buf, '\n'); 344 1.20 dholland if (sp) 345 1.20 dholland *sp = '\0'; 346 1.20 dholland if (rest_f(buf) == 0) 347 1.20 dholland break; 348 1.20 dholland } 349 1.1 cgd } 350 1.6 simonb 351 1.1 cgd /* 352 1.20 dholland * This does the actual restoring. It returns zero on success, 353 1.20 dholland * and -1 on failure. 354 1.1 cgd */ 355 1.4 christos int 356 1.20 dholland rest_f(const char *file) 357 1.4 christos { 358 1.6 simonb char *sp; 359 1.15 dholland FILE *inf; 360 1.12 dholland char xbuf[80]; 361 1.6 simonb STAT sbuf; 362 1.15 dholland char readbuf[512]; 363 1.21 dholland int ret = 0; 364 1.1 cgd 365 1.15 dholland inf = fopen(file, "r"); 366 1.15 dholland if (inf == NULL) { 367 1.13 dholland warn("%s", file); 368 1.20 dholland return -1; 369 1.1 cgd } 370 1.1 cgd printf("\"%s\" ", file); 371 1.15 dholland if (fstat(fileno(inf), &sbuf) < 0) { 372 1.13 dholland err(1, "%s: fstat", file); 373 1.1 cgd } 374 1.15 dholland 375 1.15 dholland /* Clear the game state to prevent brokenness on misordered files. */ 376 1.15 dholland reset_game(); 377 1.15 dholland 378 1.15 dholland /* Reset the parser */ 379 1.15 dholland restore_reset(); 380 1.15 dholland 381 1.15 dholland /* Note: can't use buf[], file might point at it. (Lame...) */ 382 1.15 dholland while (fgets(readbuf, sizeof(readbuf), inf)) { 383 1.15 dholland /* 384 1.15 dholland * The input buffer is long enough to handle anything 385 1.15 dholland * that's supposed to be in the output buffer, so if 386 1.15 dholland * we get a partial line, complain. 387 1.15 dholland */ 388 1.15 dholland sp = strchr(readbuf, '\n'); 389 1.15 dholland if (sp == NULL) { 390 1.15 dholland printf("file is corrupt: long lines.\n"); 391 1.21 dholland ret = -1; 392 1.15 dholland break; 393 1.15 dholland } 394 1.15 dholland *sp = '\0'; 395 1.15 dholland 396 1.15 dholland if (restore_parseline(readbuf)) { 397 1.21 dholland ret = -1; 398 1.15 dholland break; 399 1.15 dholland } 400 1.1 cgd } 401 1.15 dholland 402 1.15 dholland if (ferror(inf)) 403 1.15 dholland warnx("%s: read error", file); 404 1.15 dholland fclose(inf); 405 1.15 dholland 406 1.21 dholland if (ret < 0) 407 1.21 dholland return -1; 408 1.21 dholland 409 1.15 dholland name_list[num_play] = "done"; 410 1.15 dholland 411 1.21 dholland if (play == NULL || cur_p == NULL || num_play < 2) { 412 1.21 dholland printf("save file is incomplete.\n"); 413 1.21 dholland return -1; 414 1.21 dholland } 415 1.21 dholland 416 1.15 dholland /* 417 1.15 dholland * We could at this point crosscheck the following: 418 1.15 dholland * - there are only two GOJF cards floating around 419 1.15 dholland * - total number of houses and hotels does not exceed maximums 420 1.15 dholland * - no props are both built and mortgaged 421 1.15 dholland * but for now we don't. 422 1.15 dholland */ 423 1.15 dholland 424 1.12 dholland strcpy(xbuf, ctime(&sbuf.st_mtime)); 425 1.12 dholland for (sp = xbuf; *sp != '\n'; sp++) 426 1.1 cgd continue; 427 1.1 cgd *sp = '\0'; 428 1.12 dholland printf("[%s]\n", xbuf); 429 1.20 dholland return 0; 430 1.1 cgd } 431 1.15 dholland 432 1.15 dholland /* 433 1.15 dholland * State of the restore parser 434 1.15 dholland */ 435 1.15 dholland static int restore_version; 436 1.15 dholland static enum { 437 1.15 dholland RI_NONE, 438 1.15 dholland RI_PLAYER, 439 1.15 dholland RI_DECK, 440 1.19 christos RI_SQUARE 441 1.15 dholland } restore_item; 442 1.15 dholland static int restore_itemnum; 443 1.15 dholland 444 1.15 dholland /* 445 1.15 dholland * Reset the restore parser 446 1.15 dholland */ 447 1.15 dholland static void 448 1.15 dholland restore_reset(void) 449 1.15 dholland { 450 1.15 dholland restore_version = -1; 451 1.15 dholland restore_item = RI_NONE; 452 1.15 dholland restore_itemnum = -1; 453 1.15 dholland } 454 1.15 dholland 455 1.15 dholland /* 456 1.15 dholland * Handle one line of the save file 457 1.15 dholland */ 458 1.15 dholland static int 459 1.15 dholland restore_parseline(char *txt) 460 1.15 dholland { 461 1.15 dholland char *attribute; 462 1.15 dholland char *s; 463 1.15 dholland 464 1.15 dholland if (restore_version < 0) { 465 1.15 dholland /* Haven't seen the header yet. Demand it right away. */ 466 1.15 dholland if (!strncmp(txt, "NetBSD monop format v", 21)) { 467 1.15 dholland return getnum("format version", txt+21, 468 1.15 dholland MIN_FORMAT_VERSION, 469 1.15 dholland MAX_FORMAT_VERSION, 470 1.15 dholland &restore_version); 471 1.15 dholland } 472 1.15 dholland printf("file is not a monop save file.\n"); 473 1.15 dholland return -1; 474 1.15 dholland } 475 1.15 dholland 476 1.15 dholland /* Check for lines that are right braces. */ 477 1.15 dholland if (!strcmp(txt, "}")) { 478 1.15 dholland if (restore_item == RI_NONE) { 479 1.15 dholland printf("mismatched close brace.\n"); 480 1.15 dholland return -1; 481 1.15 dholland } 482 1.15 dholland restore_item = RI_NONE; 483 1.15 dholland restore_itemnum = -1; 484 1.15 dholland return 0; 485 1.15 dholland } 486 1.15 dholland 487 1.15 dholland /* Any other line must begin with a word, which is the attribute. */ 488 1.15 dholland s = txt; 489 1.15 dholland while (*s==' ') 490 1.15 dholland s++; 491 1.15 dholland attribute = s; 492 1.15 dholland s = strchr(attribute, ' '); 493 1.15 dholland if (s == NULL) { 494 1.15 dholland printf("file is corrupt: attribute %s lacks value.\n", 495 1.15 dholland attribute); 496 1.15 dholland return -1; 497 1.15 dholland } 498 1.15 dholland *(s++) = '\0'; 499 1.15 dholland while (*s==' ') 500 1.15 dholland s++; 501 1.15 dholland /* keep the remaining text for further handling */ 502 1.15 dholland txt = s; 503 1.15 dholland 504 1.15 dholland switch (restore_item) { 505 1.15 dholland case RI_NONE: 506 1.15 dholland /* toplevel attributes */ 507 1.15 dholland return restore_toplevel_attr(attribute, txt); 508 1.15 dholland 509 1.15 dholland case RI_PLAYER: 510 1.15 dholland /* player attributes */ 511 1.15 dholland return restore_player_attr(attribute, txt); 512 1.15 dholland 513 1.15 dholland case RI_DECK: 514 1.15 dholland /* deck attributes */ 515 1.15 dholland return restore_deck_attr(attribute, txt); 516 1.15 dholland 517 1.15 dholland case RI_SQUARE: 518 1.15 dholland /* board square attributes */ 519 1.15 dholland return restore_square_attr(attribute, txt); 520 1.15 dholland } 521 1.15 dholland /* NOTREACHED */ 522 1.15 dholland printf("internal logic error\n"); 523 1.15 dholland return -1; 524 1.15 dholland } 525 1.15 dholland 526 1.15 dholland static int 527 1.15 dholland restore_toplevel_attr(const char *attribute, char *txt) 528 1.15 dholland { 529 1.15 dholland if (!strcmp(attribute, "time")) { 530 1.15 dholland /* nothing */ 531 1.15 dholland } else if (!strcmp(attribute, "numplayers")) { 532 1.15 dholland if (getnum("numplayers", txt, 2, MAX_PL, &num_play) < 0) { 533 1.15 dholland return -1; 534 1.15 dholland } 535 1.15 dholland if (play != NULL) { 536 1.15 dholland printf("numplayers: multiple settings\n"); 537 1.15 dholland return -1; 538 1.15 dholland } 539 1.19 christos play = calloc((size_t)num_play, sizeof(play[0])); 540 1.15 dholland if (play == NULL) { 541 1.15 dholland err(1, "calloc"); 542 1.15 dholland } 543 1.15 dholland } else if (!strcmp(attribute, "currentplayer")) { 544 1.15 dholland if (getnum("currentplayer", txt, 0, num_play-1, &player) < 0) { 545 1.15 dholland return -1; 546 1.15 dholland } 547 1.15 dholland if (play == NULL) { 548 1.15 dholland printf("currentplayer: before numplayers\n"); 549 1.15 dholland return -1; 550 1.15 dholland } 551 1.15 dholland cur_p = &play[player]; 552 1.15 dholland } else if (!strcmp(attribute, "doubles")) { 553 1.15 dholland if (getnum("doubles", txt, 0, 2, &num_doub) < 0) { 554 1.15 dholland return -1; 555 1.15 dholland } 556 1.15 dholland } else if (!strcmp(attribute, "player")) { 557 1.15 dholland if (getnum_withbrace("player", txt, 0, num_play-1, 558 1.15 dholland &restore_itemnum) < 0) { 559 1.15 dholland return -1; 560 1.15 dholland } 561 1.15 dholland restore_item = RI_PLAYER; 562 1.15 dholland } else if (!strcmp(attribute, "deck")) { 563 1.15 dholland if (getnum_withbrace("deck", txt, 0, 1, 564 1.15 dholland &restore_itemnum) < 0) { 565 1.15 dholland return -1; 566 1.15 dholland } 567 1.15 dholland restore_item = RI_DECK; 568 1.15 dholland } else if (!strcmp(attribute, "square")) { 569 1.15 dholland if (getnum_withbrace("square", txt, 0, N_SQRS-1, 570 1.15 dholland &restore_itemnum) < 0) { 571 1.15 dholland return -1; 572 1.15 dholland } 573 1.15 dholland restore_item = RI_SQUARE; 574 1.15 dholland } else { 575 1.15 dholland printf("unknown attribute %s\n", attribute); 576 1.15 dholland return -1; 577 1.15 dholland } 578 1.15 dholland return 0; 579 1.15 dholland } 580 1.15 dholland 581 1.15 dholland static int 582 1.15 dholland restore_player_attr(const char *attribute, char *txt) 583 1.15 dholland { 584 1.15 dholland PLAY *pp; 585 1.15 dholland int tmp; 586 1.15 dholland 587 1.15 dholland if (play == NULL) { 588 1.15 dholland printf("player came before numplayers.\n"); 589 1.15 dholland return -1; 590 1.15 dholland } 591 1.15 dholland pp = &play[restore_itemnum]; 592 1.15 dholland 593 1.15 dholland if (!strcmp(attribute, "name")) { 594 1.15 dholland if (pp->name != NULL) { 595 1.15 dholland printf("player has multiple names.\n"); 596 1.15 dholland return -1; 597 1.15 dholland } 598 1.15 dholland /* XXX should really systematize the max name length */ 599 1.15 dholland if (strlen(txt) > 256) { 600 1.15 dholland txt[256] = 0; 601 1.15 dholland } 602 1.15 dholland pp->name = strdup(txt); 603 1.15 dholland if (pp->name == NULL) 604 1.15 dholland err(1, "strdup"); 605 1.15 dholland name_list[restore_itemnum] = pp->name; 606 1.15 dholland } else if (!strcmp(attribute, "money")) { 607 1.15 dholland if (getnum(attribute, txt, 0, INT_MAX, &pp->money) < 0) { 608 1.15 dholland return -1; 609 1.15 dholland } 610 1.15 dholland } else if (!strcmp(attribute, "loc")) { 611 1.15 dholland /* note: not N_SQRS-1 */ 612 1.15 dholland if (getnum(attribute, txt, 0, N_SQRS, &tmp) < 0) { 613 1.15 dholland return -1; 614 1.15 dholland } 615 1.15 dholland pp->loc = tmp; 616 1.15 dholland } else if (!strcmp(attribute, "num_gojf")) { 617 1.15 dholland if (getnum(attribute, txt, 0, 2, &tmp) < 0) { 618 1.15 dholland return -1; 619 1.15 dholland } 620 1.15 dholland pp->num_gojf = tmp; 621 1.15 dholland } else if (!strcmp(attribute, "in_jail")) { 622 1.15 dholland if (getnum(attribute, txt, 0, 3, &tmp) < 0) { 623 1.15 dholland return -1; 624 1.15 dholland } 625 1.15 dholland pp->in_jail = tmp; 626 1.15 dholland if (pp->in_jail > 0 && pp->loc != JAIL) { 627 1.15 dholland printf("player escaped from jail?\n"); 628 1.15 dholland return -1; 629 1.15 dholland } 630 1.15 dholland } else { 631 1.15 dholland printf("unknown attribute %s\n", attribute); 632 1.15 dholland return -1; 633 1.15 dholland } 634 1.15 dholland return 0; 635 1.15 dholland } 636 1.15 dholland 637 1.15 dholland static int 638 1.15 dholland restore_deck_attr(const char *attribute, char *txt) 639 1.15 dholland { 640 1.15 dholland int tmp, j; 641 1.15 dholland char *s; 642 1.15 dholland DECK *dp; 643 1.15 dholland 644 1.15 dholland dp = &deck[restore_itemnum]; 645 1.15 dholland 646 1.15 dholland if (!strcmp(attribute, "numcards")) { 647 1.15 dholland if (getnum(attribute, txt, dp->num_cards, dp->num_cards, 648 1.15 dholland &tmp) < 0) { 649 1.15 dholland return -1; 650 1.15 dholland } 651 1.15 dholland } else if (!strcmp(attribute, "topcard")) { 652 1.15 dholland if (getnum(attribute, txt, 0, dp->num_cards, 653 1.15 dholland &dp->top_card) < 0) { 654 1.15 dholland return -1; 655 1.15 dholland } 656 1.15 dholland } else if (!strcmp(attribute, "gojf_used")) { 657 1.15 dholland if (getnum(attribute, txt, 0, 1, &tmp) < 0) { 658 1.15 dholland return -1; 659 1.15 dholland } 660 1.15 dholland dp->gojf_used = tmp; 661 1.18 dholland } else if (!strcmp(attribute, "cards")) { 662 1.15 dholland errno = 0; 663 1.15 dholland s = txt; 664 1.15 dholland for (j = 0; j<dp->num_cards; j++) { 665 1.18 dholland tmp = strtol(s, &s, 10); 666 1.18 dholland if (tmp < 0 || tmp >= dp->num_cards) { 667 1.18 dholland printf("cards: out of range value\n"); 668 1.18 dholland return -1; 669 1.18 dholland } 670 1.18 dholland dp->cards[j] = tmp; 671 1.15 dholland } 672 1.15 dholland if (errno) { 673 1.18 dholland printf("cards: invalid values\n"); 674 1.15 dholland return -1; 675 1.15 dholland } 676 1.15 dholland } else { 677 1.15 dholland printf("unknown attribute %s\n", attribute); 678 1.15 dholland return -1; 679 1.15 dholland } 680 1.15 dholland return 0; 681 1.15 dholland } 682 1.15 dholland 683 1.15 dholland static int 684 1.15 dholland restore_square_attr(const char *attribute, char *txt) 685 1.15 dholland { 686 1.15 dholland SQUARE *sp = &board[restore_itemnum]; 687 1.15 dholland int tmp; 688 1.15 dholland 689 1.15 dholland if (!strcmp(attribute, "owner")) { 690 1.15 dholland if (getnum(attribute, txt, -1, num_play-1, &tmp) < 0) { 691 1.15 dholland return -1; 692 1.15 dholland } 693 1.15 dholland sp->owner = tmp; 694 1.15 dholland if (tmp >= 0) 695 1.15 dholland add_list(tmp, &play[tmp].own_list, restore_itemnum); 696 1.15 dholland } else if (!strcmp(attribute, "morg")) { 697 1.15 dholland if (sp->type != PRPTY && sp->type != RR && sp->type != UTIL) { 698 1.15 dholland printf("unownable property is mortgaged.\n"); 699 1.15 dholland return -1; 700 1.15 dholland } 701 1.15 dholland if (getnum(attribute, txt, 0, 1, &tmp) < 0) { 702 1.15 dholland return -1; 703 1.15 dholland } 704 1.15 dholland sp->desc->morg = tmp; 705 1.15 dholland } else if (!strcmp(attribute, "houses")) { 706 1.15 dholland if (sp->type != PRPTY) { 707 1.15 dholland printf("unbuildable property has houses.\n"); 708 1.15 dholland return -1; 709 1.15 dholland } 710 1.15 dholland if (getnum(attribute, txt, 0, 5, &tmp) < 0) { 711 1.15 dholland return -1; 712 1.15 dholland } 713 1.15 dholland sp->desc->houses = tmp; 714 1.15 dholland } else { 715 1.15 dholland printf("unknown attribute %s\n", attribute); 716 1.15 dholland return -1; 717 1.15 dholland } 718 1.15 dholland return 0; 719 1.15 dholland } 720 1.15 dholland 721 1.15 dholland static int 722 1.15 dholland getnum(const char *what, char *txt, int min, int max, int *ret) 723 1.15 dholland { 724 1.15 dholland char *s; 725 1.15 dholland long l; 726 1.15 dholland 727 1.15 dholland errno = 0; 728 1.15 dholland l = strtol(txt, &s, 10); 729 1.15 dholland if (errno || strlen(s)>0) { 730 1.15 dholland printf("%s: not a number.\n", what); 731 1.15 dholland return -1; 732 1.15 dholland } 733 1.15 dholland if (l < min || l > max) { 734 1.15 dholland printf("%s: out of range.\n", what); 735 1.15 dholland } 736 1.15 dholland *ret = l; 737 1.15 dholland return 0; 738 1.15 dholland } 739 1.15 dholland 740 1.15 dholland static int 741 1.15 dholland getnum_withbrace(const char *what, char *txt, int min, int max, int *ret) 742 1.15 dholland { 743 1.15 dholland char *s; 744 1.15 dholland s = strchr(txt, ' '); 745 1.15 dholland if (s == NULL) { 746 1.15 dholland printf("%s: expected open brace\n", what); 747 1.15 dholland return -1; 748 1.15 dholland } 749 1.15 dholland *(s++) = '\0'; 750 1.15 dholland while (*s == ' ') 751 1.15 dholland s++; 752 1.15 dholland if (*s != '{') { 753 1.15 dholland printf("%s: expected open brace\n", what); 754 1.15 dholland return -1; 755 1.15 dholland } 756 1.15 dholland if (s[1] != 0) { 757 1.15 dholland printf("%s: garbage after open brace\n", what); 758 1.15 dholland return -1; 759 1.15 dholland } 760 1.15 dholland return getnum(what, txt, min, max, ret); 761 1.15 dholland } 762