~ubuntu-branches/ubuntu/saucy/jzip/saucy

« back to all changes in this revision

Viewing changes to .pc/zlib-update/fileio.c

  • Committer: Package Import Robot
  • Author(s): Niko Tyni
  • Date: 2012-03-25 22:42:35 UTC
  • Revision ID: package-import@ubuntu.com-20120325224235-aq5xki4sm298evr3
Tags: 210r20001005d-2
Adapt to zlib gzFile changes. (Closes: #664931)

Show diffs side-by-side

added added

removed removed

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