1 /*
2 * fileio.c
3 *
4 * File manipulation routines. Should be generic.
5 *
6 */
7
8 #include "ztypes.h"
9 #include "pickle.h"
10
11 /* A couple of definitions for constants used to access PICKLE files.
12 Both are Mac-style four-byte constants. You can read each as
13 four characters, MSB first. (Don't worry about whether your
14 system is big- or little-endian; the PICKLE library takes care
15 of that stuff.) */
16 /* The "use" of executable chunks */
17 #define PICKLETYPE_exec (0x65786563)
18 /* The "format" of executable chunks containing Z-code */
19 #define PICKLETYPE_zcod (0x7a636f64)
20
21 /* All of the following variables are set in open_story(). */
22
23 /* is_pickle is a boolean flag; it will be TRUE if the open zcode is
24 contained in a PICKLE file. It is not static because other modules
25 may wish to check its value. */
26 int is_pickle;
27
28 /* pickle_map is the opaque handle to the PICKLE file map in memory.
29 It is not static because other modules will need it in order
30 to load PICKLE chunks. */
31 pikMapPtr pickle_map;
32
33 /* zcode_length is the length of the zcode. If is_pickle is FALSE,
34 this is the actual file length. */
35 static unsigned long zcode_length;
36
37 /* zcode_offset is the starting position of the zcode in its file. If
38 is_pickle is FALSE, this is just 0. */
39 static unsigned long zcode_offset;
40
41 /* Static data */
42
43 static FILE *gfp = NULL; /* Game file pointer */
44 static FILE *sfp = NULL; /* Script file pointer */
45 static FILE *rfp = NULL; /* Record file pointer */
46 static char save_name[FILENAME_MAX + 1] = "";
47 static char savedata_name[FILENAME_MAX + 1] = "";
48 static char script_name[FILENAME_MAX + 1] = "";
49 static char record_name[FILENAME_MAX + 1] = "";
50
51 static int undo_valid = FALSE;
52 static zword_t undo_stack[STACK_SIZE];
53
54 static int script_file_valid = FALSE;
55
56 #ifdef __STDC__
57 static int save_restore (const char *, int);
58 static int save_restore_data (const char *, int, int, zword_t *);
59 static void set_names (const char *);
60 static void swap_bytes (zword_t *, int);
61 #else
62 static int save_restore ();
63 static int save_restore_data ();
64 static void set_names ();
65 static void swap_bytes ();
66 #endif
67
68 /*
69 * set_names
70 *
71 * Set up the story names intelligently.
72 * Taken from JZip, John Holder, 28 Sept 1995
73 */
74 #ifdef __STDC__
set_names(const char * storyname)75 static void set_names (const char *storyname)
76 #else
77 static void set_names (storyname)
78 const char *storyname;
79 #endif
80 {
81 char *per_pos=0;
82
83 /* experimental setting of save_name, added by John Holder 26 July 1995 */
84 per_pos = strrchr(storyname,'.'); /* find last '.' in storyname. */
85 if (per_pos) /* The story file looks like "Odius.dat" or "odieus.z3" */
86 {
87 strcpy(save_name, storyname);
88 per_pos=strrchr(save_name,'.');
89 *(per_pos) = '\0';
90 strcat(save_name,".sav");
91
92 strcpy(script_name, storyname);
93 per_pos=strrchr(script_name,'.');
94 *(per_pos) = '\0';
95 strcat(script_name,".scr");
96
97 strcpy(savedata_name, storyname);
98 per_pos=strrchr(savedata_name,'.');
99 *(per_pos) = '\0';
100 strcat(savedata_name,".dat");
101
102 strcpy(record_name, storyname);
103 per_pos=strrchr(record_name,'.');
104 *(per_pos) = '\0';
105 strcat(record_name,".rec");
106 }
107 else /* The story file looks like: "OdieusQuest" */
108 {
109 strcpy(save_name, storyname);
110 strcat(save_name,".sav");
111
112 strcpy(script_name, storyname);
113 strcat(script_name,".scr");
114
115 strcpy(savedata_name, storyname);
116 strcat(savedata_name,".dat");
117
118 strcpy(record_name, storyname);
119 strcat(record_name,".rec");
120 }
121 } /* set_names */
122
123 /*
124 * open_story
125 *
126 * Open game file for read.
127 *
128 */
129
130 #ifdef __STDC__
open_story(const char * storyname)131 void open_story (const char *storyname)
132 #else
133 void open_story (storyname)
134 const char *storyname;
135 #endif
136 {
137 /* Most of this function is new. --Z */
138 int ix;
139 char firstfour[4];
140 pikErr err;
141 pikChunkID chunkid;
142 pikChunk chunk;
143
144 /* This is the list of formats that the PICKLE library will check for.
145 You can extend it in the obvious way. */
146 #define NUMPICKLEFORMATS (4)
147 static pikFormat formatlist[NUMPICKLEFORMATS] = {
148 {PICKLETYPE_zcod, 3},
149 {PICKLETYPE_zcod, 4},
150 {PICKLETYPE_zcod, 5},
151 {PICKLETYPE_zcod, 8}
152 };
153
154 /* The following three lines are what used to here. --Z */
155 gfp = fopen (storyname, "rb");
156 if (gfp == NULL && storyname[0] != '/') {
157 /* Try the magic path variable. */
158 char *classpath = getenv("INFOCOM_PATH");
159 if (classpath && strlen(classpath) > 0) {
160 char *p;
161 p = strtok(classpath, ":");
162 while (p && !gfp) {
163 char classfile[FILENAME_MAX+1];
164 sprintf(classfile, "%s/%s", p, storyname);
165 gfp = fopen (classfile, "rb");
166 p = strtok(NULL, ":");
167 }
168 }
169 }
170 if (gfp == NULL)
171 fatal ("Game file not found");
172
173 set_names(storyname);
174
175 /* Now the new code... --Z */
176
177 for (ix = 0; ix < 4; ix++) {
178 firstfour[ix] = fgetc (gfp);
179 if (firstfour[ix] == EOF)
180 break;
181 }
182
183 /* The PICKLE library doesn't require the file to be rewound here,
184 and standard ZIP doesn't either, but it doesn't hurt to be sure. */
185 rewind(gfp);
186
187 is_pickle = FALSE;
188 zcode_length = 0;
189 zcode_offset = 0;
190
191 if (ix == 4) {
192 if (pikIsPickleHeader(firstfour)) {
193 /* Yes! It is indeed a PICKLE file! */
194 is_pickle = TRUE;
195 /* Open the PICKLE file and load the map into memory. */
196 err = pikCreateMap(gfp, &pickle_map);
197 if (err)
198 fatal ("Unable to open PICKLE file");
199 /* Find and load the Z-code chunk. */
200 err = pikFindChunk(pickle_map, PICKLETYPE_exec, 0, NUMPICKLEFORMATS,
201 formatlist, &chunkid);
202 if (err == pikerr_NotFound)
203 fatal ("There is no Z-code chunk in this PICKLE file");
204 if (err)
205 fatal ("Unable to search PICKLE file");
206 err = pikLoadChunk(pickle_map, chunkid, pikmethod_FilePos, &chunk);
207 if (err)
208 fatal ("Unable to read Z-code chunk from PICKLE file");
209 zcode_offset = chunk.data.startpos;
210 zcode_length = chunk.length;
211 }
212 }
213 }/* open_story */
214
215 /*
216 * close_story
217 *
218 * Close game file if open.
219 *
220 */
221
222 #ifdef __STDC__
close_story(void)223 void close_story (void)
224 #else
225 void close_story ()
226 #endif
227 {
228 if (is_pickle) { /* --Z */
229 pikDestroyMap(pickle_map);
230 } /* --Z */
231
232 /* The rest of this function is not changed. --Z */
233
234 if (gfp != NULL)
235 fclose (gfp);
236
237 }/* close_story */
238
239 /*
240 * get_story_size
241 *
242 * Calculate the size of the game file. Only used for very old games that do not
243 * have the game file size in the header.
244 *
245 */
246
247 #ifdef __STDC__
get_story_size(void)248 unsigned int get_story_size (void)
249 #else
250 unsigned int get_story_size ()
251 #endif
252 {
253 unsigned long file_length;
254
255 if (!is_pickle) { /* --Z */
256 /* Read whole file to calculate file size */
257
258 rewind (gfp);
259 for (file_length = 0; fgetc (gfp) != EOF; file_length++)
260 ;
261 rewind (gfp);
262 }
263 else {
264 /* Use the length loaded from the PICKLE file */
265 file_length = zcode_length;
266 } /* --Z */
267
268 /* The rest of this function is not changed. --Z */
269
270 /* Calculate length of file in game allocation units */
271
272 file_length = (file_length + (unsigned long) (story_scaler - 1)) / (unsigned long) story_scaler;
273
274 return ((unsigned int) file_length);
275
276 }/* get_story_size */
277
278 /*
279 * read_page
280 *
281 * Read one game file page.
282 *
283 */
284
285 #ifdef __STDC__
read_page(int page,void * buffer)286 void read_page (int page, void *buffer)
287 #else
288 void read_page (page, buffer)
289 int page;
290 void *buffer;
291 #endif
292 {
293 unsigned long file_size;
294 unsigned int pages, offset;
295
296 /* Seek to start of page */
297
298 fseek (gfp, zcode_offset + (long) page * PAGE_SIZE, SEEK_SET);
299
300 /* Read the page */
301
302 if (fread (buffer, PAGE_SIZE, 1, gfp) != 1) {
303
304 /* Read failed. Are we in the last page? */
305
306 file_size = (unsigned long) h_file_size * story_scaler;
307 pages = (unsigned int) ((unsigned long) file_size / PAGE_SIZE);
308 offset = (unsigned int) ((unsigned long) file_size & PAGE_MASK);
309 if ((unsigned int) page == pages) {
310
311 /* Read partial page if this is the last page in the game file */
312
313 fseek (gfp, zcode_offset + (long) page * PAGE_SIZE, SEEK_SET);
314 if (fread (buffer, offset, 1, gfp) == 1)
315 return;
316 }
317 fatal ("Game file read error");
318 }
319
320 }/* read_page */
321
322 /*
323 * verify
324 *
325 * Verify game ($verify verb). Add all bytes in game file except for bytes in
326 * the game file header.
327 *
328 */
329
330 #ifdef __STDC__
verify(void)331 void verify (void)
332 #else
333 void verify ()
334 #endif
335 {
336 unsigned long file_size;
337 unsigned int pages, offset;
338 unsigned int start, end, i, j;
339 zword_t checksum = 0;
340 zbyte_t buffer[PAGE_SIZE];
341
342 /* Print version banner */
343
344 if (h_type < V4) {
345 write_string ("ZIP Interpreter ");
346 print_number (get_byte (H_INTERPRETER));
347 write_string (", Version ");
348 write_char (get_byte (H_INTERPRETER_VERSION));
349 write_string (".");
350 new_line ();
351 }
352
353 /* Calculate game file dimensions */
354
355 file_size = (unsigned long) h_file_size * story_scaler;
356 pages = (unsigned int) ((unsigned long) file_size / PAGE_SIZE);
357 offset = (unsigned int) file_size & PAGE_MASK;
358
359 /* Sum all bytes in game file, except header bytes */
360
361 for (i = 0; i <= pages; i++) {
362 read_page (i, buffer);
363 start = (i == 0) ? 64 : 0;
364 end = (i == pages) ? offset : PAGE_SIZE;
365 for (j = start; j < end; j++)
366 checksum += buffer[j];
367 }
368
369 /* Make a conditional jump based on whether the checksum is equal */
370
371 conditional_jump (checksum == h_checksum);
372
373 }/* verify */
374
375 /*
376 * save
377 *
378 * Save game state to disk. Returns:
379 * 0 = save failed
380 * 1 = save succeeded
381 *
382 */
383
384 #ifdef __STDC__
save(int argc,zword_t * argv)385 int save (int argc, zword_t *argv)
386 #else
387 int save (argc, argv)
388 int argc;
389 zword_t *argv;
390 #endif
391 {
392 int status = 1; /* assume failure */
393 int storestatus = 0;
394
395 if (argc == 0) {
396
397 char new_save_name[FILENAME_MAX + 1];
398
399 /* Get the file name */
400 if (get_file_name (new_save_name, save_name, GAME_SAVE) == 0) {
401
402 /* Do a save operation */
403 if (save_restore (new_save_name, GAME_SAVE) == 0) {
404
405 /* Cleanup file */
406 file_cleanup (new_save_name, GAME_SAVE);
407
408 /* Save the new name as the default file name */
409 strcpy (save_name, new_save_name);
410
411 /* Indicate success */
412 status = 0;
413 }
414 }
415 storestatus = ((status == 0) ? 1 : 0);
416 }
417 else {
418
419 char new_savedata_name[FILENAME_MAX + 1];
420 char defname[FILENAME_MAX + 1];
421 char *defnameptr = NULL;
422
423 if (argc >= 3) {
424 unsigned char *cx = datap + argv[2];
425 int cxlen = cx[0];
426 memcpy(defname, cx+1, cxlen);
427 defname[cxlen] = '\0';
428 defnameptr = defname;
429 }
430
431 /* Get the file name ### defname */
432 if (get_file_name (new_savedata_name, savedata_name,
433 GAME_SAVEDATA) == 0) {
434
435 /* Do a save operation */
436 storestatus = save_restore_data (new_savedata_name,
437 GAME_SAVEDATA, argc, argv);
438 if (storestatus != 0) {
439
440 /* Cleanup file */
441 file_cleanup (new_savedata_name, GAME_SAVEDATA);
442
443 /* Save the new name as the default file name */
444 strcpy (savedata_name, new_savedata_name);
445
446 /* Indicate success */
447 status = 0;
448 }
449 }
450 }
451
452 /* Return result of save to Z-code */
453
454 if (h_type < V4)
455 conditional_jump (status == 0);
456 else
457 store_operand (storestatus);
458
459 return (status);
460
461 }/* save */
462
463 /*
464 * restore
465 *
466 * Restore game state from disk. Returns:
467 * 0 = restore failed
468 * 2 = restore succeeded
469 *
470 */
471
472 #ifdef __STDC__
restore(int argc,zword_t * argv)473 int restore (int argc, zword_t *argv)
474 #else
475 int restore (argc, argv)
476 int argc;
477 zword_t *argv;
478 #endif
479 {
480 int status = 1; /* assume failure */
481 int storestatus = 0;
482
483 if (argc == 0) {
484 char new_save_name[FILENAME_MAX + 1];
485
486 /* Get the file name */
487 if (get_file_name (new_save_name, save_name, GAME_RESTORE) == 0) {
488
489 /* Do the restore operation */
490 if (save_restore (new_save_name, GAME_RESTORE) == 0) {
491
492 /* Cleanup file */
493 file_cleanup (new_save_name, GAME_SAVE);
494
495 /* Save the new name as the default file name */
496 strcpy (save_name, new_save_name);
497
498 /* Indicate success */
499 status = 0;
500
501 }
502 }
503 storestatus = ((status == 0) ? 2 : 0);
504 }
505 else {
506 char new_savedata_name[FILENAME_MAX + 1];
507 char defname[FILENAME_MAX + 1];
508 char *defnameptr = NULL;
509
510 if (argc >= 3) {
511 unsigned char *cx = datap + argv[2];
512 int cxlen = cx[0];
513 memcpy(defname, cx+1, cxlen);
514 defname[cxlen] = '\0';
515 defnameptr = defname;
516 }
517
518 /* Get the file name ### defname */
519 if (get_file_name (new_savedata_name, savedata_name,
520 GAME_RESTOREDATA) == 0) {
521
522 /* Do the restore operation */
523 storestatus = save_restore_data (new_savedata_name,
524 GAME_RESTOREDATA, argc, argv);
525 if (storestatus != 0) {
526
527 /* Cleanup file */
528 file_cleanup (new_savedata_name, GAME_RESTOREDATA);
529
530 /* Save the new name as the default file name */
531 strcpy (savedata_name, new_savedata_name);
532
533 /* Indicate success */
534 status = 0;
535 }
536 }
537 }
538
539 /* Return result of save to Z-code */
540
541 if (h_type < V4)
542 conditional_jump (status == 0);
543 else
544 store_operand (storestatus);
545
546 return (status);
547
548 }/* restore */
549
550 /*
551 * undo_save
552 *
553 * Save the current Z machine state in memory for a future undo. Returns:
554 * -1 = feature unavailable
555 * 0 = save failed
556 * 1 = save succeeded
557 *
558 */
559
560 #ifdef __STDC__
undo_save(void)561 void undo_save (void)
562 #else
563 void undo_save ()
564 #endif
565 {
566
567 /* Check if undo is available first */
568
569 if (undo_datap != NULL) {
570
571 /* Save the undo data and return success */
572
573 save_restore (NULL, UNDO_SAVE);
574
575 undo_valid = TRUE;
576
577 store_operand (1);
578
579 } else
580
581 /* If no memory for data area then say undo is not available */
582
583 store_operand ((zword_t) -1);
584
585 }/* undo_save */
586
587 /*
588 * undo_restore
589 *
590 * Restore the current Z machine state from memory. Returns:
591 * -1 = feature unavailable
592 * 0 = restore failed
593 * 2 = restore succeeded
594 *
595 */
596
597 #ifdef __STDC__
undo_restore(void)598 void undo_restore (void)
599 #else
600 void undo_restore ()
601 #endif
602 {
603
604 /* Check if undo is available first */
605
606 if (undo_datap != NULL) {
607
608 /* If no undo save done then return an error */
609
610 if (undo_valid == TRUE) {
611
612 /* Restore the undo data and return success */
613
614 save_restore (NULL, UNDO_RESTORE);
615
616 store_operand (2);
617
618 } else
619
620 store_operand (0);
621
622 } else
623
624 /* If no memory for data area then say undo is not available */
625
626 store_operand ((zword_t) -1);
627
628 }/* undo_restore */
629
630 /*
631 * swap_bytes
632 *
633 * Swap the low and high bytes in every word of the specified array.
634 * The length is specified in BYTES!
635 *
636 * This routine added by Mark Phillips(msp@bnr.co.uk), Thanks Mark!
637 */
638
639 #ifdef __STDC__
swap_bytes(zword_t * ptr,int len)640 static void swap_bytes(zword_t *ptr, int len)
641 #else
642 static void swap_bytes(ptr, len)
643 zword_t *ptr;
644 int len;
645 #endif
646 {
647 unsigned char *pbyte;
648 unsigned char tmp;
649
650 len/=2; /* convert len into number of 2 byte words */
651
652 pbyte=(unsigned char*)ptr;
653
654 while (len)
655 {
656 tmp=pbyte[0];
657 pbyte[0]=pbyte[1];
658 pbyte[1]=tmp;
659 pbyte+=2;
660 len--;
661 }
662 return;
663 }
664
665 /*
666 * save_restore
667 *
668 * Common save and restore code. Just save or restore the game stack and the
669 * writeable data area.
670 *
671 */
672
673 #ifdef __STDC__
save_restore(const char * file_name,int flag)674 static int save_restore (const char *file_name, int flag)
675 #else
676 static int save_restore (file_name, flag)
677 const char *file_name;
678 int flag;
679 #endif
680 {
681 FILE *tfp = NULL;
682 int scripting_flag = 0, status = 0;
683 #ifdef BIG_END_MODE
684 int little_endian=0;
685 #else
686 int little_endian=1;
687 #endif
688
689 /* Open the save file and disable scripting */
690
691 if (flag == GAME_SAVE || flag == GAME_RESTORE) {
692 if ((tfp = fopen (file_name, (flag == GAME_SAVE) ? "wb" : "rb")) == NULL) {
693 output_line ("Cannot open SAVE file");
694 return (1);
695 }
696 scripting_flag = get_word (H_FLAGS) & SCRIPTING_FLAG;
697 set_word (H_FLAGS, get_word (H_FLAGS) & (~SCRIPTING_FLAG));
698 }
699
700 #if defined(USE_QUETZAL)
701 if (flag == GAME_SAVE)
702 status = !save_quetzal (tfp, gfp, zcode_offset);
703 else if (flag == GAME_RESTORE)
704 status = !restore_quetzal (tfp, gfp, zcode_offset);
705 else {
706 #endif /* defined(USE_QUETZAL) */
707
708 /* Push PC, FP, version and store SP in special location */
709
710 stack[--sp] = (zword_t) (pc / PAGE_SIZE);
711 stack[--sp] = (zword_t) (pc % PAGE_SIZE);
712 stack[--sp] = fp;
713 stack[--sp] = h_version;
714 stack[0] = sp;
715
716 /* Save or restore stack */
717
718 #if !defined(USE_QUETZAL)
719 if (flag == GAME_SAVE) {
720 if (little_endian) swap_bytes(stack, sizeof(stack));
721 if (status == 0 && fwrite (stack, sizeof (stack), 1, tfp) != 1)
722 status = 1;
723 if (little_endian) swap_bytes(stack, sizeof(stack));
724 } else if (flag == GAME_RESTORE) {
725 if (little_endian) swap_bytes(stack, sizeof(stack));
726 if (status == 0 && fread (stack, sizeof (stack), 1, tfp) != 1)
727 status = 1;
728 if (little_endian) swap_bytes(stack, sizeof(stack));
729 } else
730 #endif/* !defined(USE_QUETZAL) */
731 if (flag == UNDO_SAVE) {
732 memmove (undo_stack, stack, sizeof (stack));
733 } else /* if (flag == UNDO_RESTORE) */
734 memmove (stack, undo_stack, sizeof (stack));
735
736 /* Restore SP, check version, restore FP and PC */
737
738 sp = stack[0];
739 if (stack[sp++] != h_version)
740 fatal ("Wrong game or version");
741 fp = stack[sp++];
742 pc = stack[sp++];
743 pc += (unsigned long) stack[sp++] * PAGE_SIZE;
744
745 /* Save or restore writeable game data area */
746
747 #if !defined(USE_QUETZAL)
748 if (flag == GAME_SAVE) {
749 if (status == 0 && fwrite (datap, h_restart_size, 1, tfp) != 1)
750 status = 1;
751 } else if (flag == GAME_RESTORE) {
752 if (status == 0 && fread (datap, h_restart_size, 1, tfp) != 1)
753 status = 1;
754 } else
755 #endif /* !defined(USE_QUETZAL) */
756 if (flag == UNDO_SAVE) {
757 memmove (undo_datap, datap, h_restart_size);
758 } else /* if (flag == UNDO_RESTORE) */
759 memmove (datap, undo_datap, h_restart_size);
760
761 #if defined(USE_QUETZAL)
762 }
763 #endif /* defined(USE_QUETZAL) */
764
765 /* Close the save file and restore scripting */
766
767 if (flag == GAME_SAVE) {
768 fclose (tfp);
769 if (scripting_flag)
770 set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG);
771 }
772 else if (flag == GAME_RESTORE) {
773 fclose (tfp);
774 restart_screen();
775 restart_interp(scripting_flag);
776 }
777
778 /* Handle read or write errors */
779
780 if (status) {
781 if (flag == GAME_SAVE) {
782 output_line ("Write to SAVE file failed");
783 remove (file_name);
784 } else {
785 output_line ("Read from SAVE file failed");
786 }
787 }
788
789 return (status);
790
791 }/* save_restore */
792
793 /*
794 * open_script
795 *
796 * Open the scripting file.
797 *
798 */
799
800 #ifdef __STDC__
open_script(void)801 void open_script (void)
802 #else
803 void open_script ()
804 #endif
805 {
806 char new_script_name[FILENAME_MAX + 1];
807
808 /* Open scripting file if closed */
809
810 if (scripting == OFF) {
811
812 if (script_file_valid == TRUE) {
813
814 sfp = fopen (script_name, "a");
815
816 /* Turn on scripting if open succeeded */
817
818 if (sfp != NULL)
819 scripting = ON;
820 else
821 output_line ("Script file open failed");
822
823 } else {
824
825 /* Get scripting file name and record it */
826
827 if (get_file_name (new_script_name, script_name, GAME_SCRIPT) == 0) {
828
829 /* Open scripting file */
830
831 sfp = fopen (new_script_name, "w");
832
833 /* Turn on scripting if open succeeded */
834
835 if (sfp != NULL) {
836
837 script_file_valid = TRUE;
838
839 /* Make file name the default name */
840
841 strcpy (script_name, new_script_name);
842
843 /* Turn on scripting */
844
845 scripting = ON;
846
847 } else
848
849 output_line ("Script file create failed");
850
851 }
852
853 }
854
855 }
856
857 /* Set the scripting flag in the game file flags */
858
859 if (datap) {
860 if (scripting == ON)
861 set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG);
862 else
863 set_word (H_FLAGS, get_word (H_FLAGS) & (~SCRIPTING_FLAG));
864 }
865
866 }/* open_script */
867
868 /*
869 * close_script
870 *
871 * Close the scripting file.
872 *
873 */
874
875 #ifdef __STDC__
close_script(void)876 void close_script (void)
877 #else
878 void close_script ()
879 #endif
880 {
881
882 /* Close scripting file if open */
883
884 if (scripting == ON) {
885
886 fclose (sfp);
887 #if 0
888 /* Cleanup */
889
890 file_cleanup (script_name, GAME_SCRIPT);
891 #endif
892 /* Turn off scripting */
893
894 scripting = OFF;
895
896 }
897
898 /* Set the scripting flag in the game file flags */
899
900 if (datap) {
901 if (scripting == OFF)
902 set_word (H_FLAGS, get_word (H_FLAGS) & (~SCRIPTING_FLAG));
903 else
904 set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG);
905 }
906
907 }/* close_script */
908
909 /*
910 * script_char
911 *
912 * Write one character to scripting file.
913 *
914 * Check the state of the scripting flag first. Older games only set the
915 * scripting flag in the game flags instead of calling the set_print_modes
916 * function. This is because they expect a physically attached printer that
917 * doesn't need opening like a file.
918 */
919
920 #ifdef __STDC__
script_char(int c)921 void script_char (int c)
922 #else
923 void script_char (c)
924 int c;
925 #endif
926 {
927
928 /* Check the state of the scripting flag in the game flags. If it is on
929 then check to see if the scripting file is open as well */
930
931 if ((get_word (H_FLAGS) & SCRIPTING_FLAG) != 0 && scripting == OFF)
932 open_script ();
933
934 /* Check the state of the scripting flag in the game flags. If it is off
935 then check to see if the scripting file is closed as well */
936
937 if ((get_word (H_FLAGS) & SCRIPTING_FLAG) == 0 && scripting == ON)
938 close_script ();
939
940 /* If scripting file is open, we are in the text window and the character is
941 printable then write the character */
942
943 if (scripting == ON && scripting_disable == OFF && (c == '\n' || (isprint (c))))
944 putc (c, sfp);
945
946 }/* script_char */
947
948 /*
949 * script_string
950 *
951 * Write a string to the scripting file.
952 *
953 */
954
955 #ifdef __STDC__
script_string(const char * s)956 void script_string (const char *s)
957 #else
958 void script_string (s)
959 const char *s;
960 #endif
961 {
962
963 /* Write string */
964
965 while (*s)
966 script_char (*s++);
967
968 }/* script_string */
969
970 /*
971 * script_line
972 *
973 * Write a string followed by a new line to the scripting file.
974 *
975 */
976
977 #ifdef __STDC__
script_line(const char * s,int len)978 void script_line (const char *s, int len)
979 #else
980 void script_line (s, len)
981 const char *s;
982 int len;
983 #endif
984 {
985 int ix;
986
987 /* Write string */
988
989 for (ix=0; ix<len; ix++)
990 script_char(s[ix]);
991
992 /* Write new line */
993
994 script_new_line ();
995
996 }/* script_line */
997
998 /*
999 * script_new_line
1000 *
1001 * Write a new line to the scripting file.
1002 *
1003 */
1004
1005 #ifdef __STDC__
script_new_line(void)1006 void script_new_line (void)
1007 #else
1008 void script_new_line ()
1009 #endif
1010 {
1011
1012 script_char ('\n');
1013
1014 }/* script_new_line */
1015
1016 /*
1017 * open_record
1018 *
1019 * Turn on recording of all input to an output file.
1020 *
1021 */
1022
1023 #ifdef __STDC__
open_record(void)1024 void open_record (void)
1025 #else
1026 void open_record ()
1027 #endif
1028 {
1029 char new_record_name[FILENAME_MAX + 1];
1030
1031 /* If recording or playback is already on then complain */
1032
1033 if (recording == ON || replaying == ON) {
1034
1035 output_line ("Recording or playback are already active.");
1036
1037 } else {
1038
1039 /* Get recording file name */
1040
1041 if (get_file_name (new_record_name, record_name, GAME_RECORD) == 0) {
1042
1043 /* Open recording file */
1044
1045 rfp = fopen (new_record_name, "w");
1046
1047 /* Turn on recording if open succeeded */
1048
1049 if (rfp != NULL) {
1050
1051 /* Make file name the default name */
1052
1053 strcpy (record_name, new_record_name);
1054
1055 /* Set recording on */
1056
1057 recording = ON;
1058
1059 } else
1060
1061 output_line ("Record file create failed");
1062
1063 }
1064
1065 }
1066
1067 }/* open_record */
1068
1069 /*
1070 * record_line
1071 *
1072 * Write a string followed by a new line to the recording file.
1073 *
1074 */
1075
1076 #ifdef __STDC__
record_line(const char * s,int len)1077 void record_line (const char *s, int len)
1078 #else
1079 void record_line (s, len)
1080 const char *s;
1081 int len;
1082 #endif
1083 {
1084 int ix;
1085
1086 if (recording == ON && replaying == OFF) {
1087
1088 /* Write string */
1089 for (ix=0; ix<len; ix++)
1090 putc(s[ix], rfp);
1091
1092 putc('\n', rfp);
1093
1094 }
1095
1096 }/* record_line */
1097
1098 /*
1099 * record_key
1100 *
1101 * Write a key followed by a new line to the recording file.
1102 *
1103 */
1104
1105 #ifdef __STDC__
record_key(int c)1106 void record_key (int c)
1107 #else
1108 void record_key (c)
1109 int c;
1110 #endif
1111 {
1112
1113 if (recording == ON && replaying == OFF) {
1114
1115 /* Write the key */
1116
1117 fprintf (rfp, "<%0o>\n", c);
1118
1119 }
1120
1121 }/* record_key */
1122
1123 /*
1124 * close_record
1125 *
1126 * Turn off recording of all input to an output file.
1127 *
1128 */
1129
1130 #ifdef __STDC__
close_record(void)1131 void close_record (void)
1132 #else
1133 void close_record ()
1134 #endif
1135 {
1136
1137 /* Close recording file */
1138
1139 if (rfp != NULL) {
1140 fclose (rfp);
1141 rfp = NULL;
1142
1143 /* Cleanup */
1144
1145 if (recording == ON)
1146 file_cleanup (record_name, GAME_RECORD);
1147 else /* (replaying == ON) */
1148 file_cleanup (record_name, GAME_PLAYBACK);
1149 }
1150
1151 /* Set recording and replaying off */
1152
1153 recording = OFF;
1154 replaying = OFF;
1155
1156 }/* close_record */
1157
1158 /*
1159 * open_playback
1160 *
1161 * Take input from command file instead of keyboard.
1162 *
1163 */
1164
1165 #ifdef __STDC__
open_playback(int arg)1166 void open_playback (int arg)
1167 #else
1168 void open_playback (arg)
1169 int arg;
1170 #endif
1171 {
1172 char new_record_name[FILENAME_MAX + 1];
1173
1174 /* If recording or replaying is already on then complain */
1175
1176 if (recording == ON || replaying == ON) {
1177
1178 output_line ("Recording or replaying is already active.");
1179
1180 } else {
1181
1182 /* Get recording file name */
1183
1184 if (get_file_name (new_record_name, record_name, GAME_PLAYBACK) == 0) {
1185
1186 /* Open recording file */
1187
1188 rfp = fopen (new_record_name, "r");
1189
1190 /* Turn on recording if open succeeded */
1191
1192 if (rfp != NULL) {
1193
1194 /* Make file name the default name */
1195
1196 strcpy (record_name, new_record_name);
1197
1198 /* Set replaying on */
1199
1200 replaying = ON;
1201
1202 } else
1203
1204 output_line ("Record file open failed");
1205
1206 }
1207
1208 }
1209
1210 }/* open_playback */
1211
1212 /*
1213 * playback_line
1214 *
1215 * Get a line of input from the command file.
1216 *
1217 */
1218
1219 #ifdef __STDC__
playback_line(int buflen,char * buffer,int * read_size)1220 int playback_line (int buflen, char *buffer, int *read_size)
1221 #else
1222 int playback_line (buflen, buffer, read_size)
1223 int buflen;
1224 char *buffer;
1225 int *read_size;
1226 #endif
1227 {
1228 char *cp;
1229
1230 if (recording == ON || replaying == OFF)
1231 return (-1);
1232
1233 if (fgets (buffer, buflen, rfp) == NULL) {
1234 close_record ();
1235 return (-1);
1236 } else {
1237 cp = strrchr (buffer, '\n');
1238 if (cp != NULL)
1239 *cp = '\0';
1240 *read_size = strlen (buffer);
1241 output_line (buffer);
1242 }
1243
1244 return ('\n');
1245
1246 }/* playback_line */
1247
1248 /*
1249 * playback_key
1250 *
1251 * Get a key from the command file.
1252 *
1253 */
1254
1255 #ifdef __STDC__
playback_key(void)1256 int playback_key (void)
1257 #else
1258 int playback_key ()
1259 #endif
1260 {
1261 int c;
1262
1263 if (recording == ON || replaying == OFF)
1264 return (-1);
1265
1266 if (fscanf (rfp, "<%o>\n", &c) == EOF) {
1267 close_record ();
1268 c = -1;
1269 }
1270
1271 return (c);
1272
1273 }/* playback_key */
1274
1275 /*
1276 * save_restore_data. This returns the actual z-machine status: number of bytes
1277 * loaded for a restore; 0 for failure / 1 for success, for a save.
1278 *
1279 */
1280
1281 #ifdef __STDC__
save_restore_data(const char * file_name,int flag,int argc,zword_t * argv)1282 static int save_restore_data (const char *file_name, int flag, int argc, zword_t *argv)
1283 #else
1284 static int save_restore_data (file_name, flag, argc, argv)
1285 const char *file_name;
1286 int flag;
1287 int argc;
1288 zword_t *argv;
1289 #endif
1290 {
1291 FILE *tfp;
1292 long dat_begin, dat_len;
1293 int status, val;
1294 long lx;
1295 char *cx;
1296
1297 if (argc < 2)
1298 return (1);
1299
1300 dat_begin = argv[0];
1301 dat_len = argv[1];
1302
1303 /* Open the save file */
1304
1305 if (flag == GAME_SAVEDATA)
1306 tfp = fopen (file_name, "wb");
1307 else
1308 tfp = fopen (file_name, "rb");
1309
1310 if (tfp == NULL) {
1311 output_line ("Cannot open DATA file");
1312 return (1);
1313 }
1314
1315 /* Save or restore writeable game data area */
1316 if (flag == GAME_SAVEDATA) {
1317 lx = fwrite (datap+dat_begin, 1, dat_len, tfp);
1318 if (lx != dat_len) {
1319 output_line ("Write to DATA file failed");
1320 status = 0;
1321 }
1322 else {
1323 status = 1;
1324 }
1325 }
1326 else if (flag == GAME_RESTOREDATA) {
1327 lx = fread (datap+dat_begin, 1, dat_len, tfp);
1328 status = lx; /* number of bytes read */
1329 }
1330
1331 /* Close the save file */
1332
1333 fclose (tfp);
1334
1335 return (status);
1336
1337 } /* save_restore_data */
1338