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

« back to all changes in this revision

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