1 /*
2 * osdepend.c
3 *
4 * All non screen specific operating system dependent routines.
5 *
6 * Olaf Barthel 28-Jul-1992
7 *
8 */
9
10 #include "ztypes.h"
11 #include "arguments.h"
12 #include "version.h"
13
14 /* File names will be O/S dependent */
15
16 #if defined(AMIGA)
17 #define SAVE_NAME "Story.Save" /* Default save name */
18 #define SCRIPT_NAME "PRT:" /* Default script name */
19 #define RECORD_NAME "Story.Record" /* Default record name */
20 #else /* defined(AMIGA) */
21 #define SAVE_NAME "story.sav" /* Default save name */
22 #define SCRIPT_NAME "story.lis" /* Default script name */
23 #define RECORD_NAME "record.lis" /* Default record name */
24 #endif /* defined(AMIGA) */
25
26 static optionname optionnamelist[] = {
27 {"bindings", OPT_BINDINGS, TRUE},
28 {"strictz", OPT_STRICTZ, TRUE},
29 {"spec", OPT_SPEC, TRUE},
30 {"geometry", OPT_GEOMETRY, TRUE},
31 {"statgeometry", OPT_STATGEOMETRY, TRUE},
32 {"inputstyle", OPT_INPUTSTYLE, TRUE},
33 {"marginx", OPT_MARGINX, TRUE},
34 {"leading", OPT_LEADING, TRUE},
35 {"justify", OPT_JUSTIFY, TRUE},
36 {"autoresize", OPT_AUTORESIZE, TRUE},
37 {"resizeupward", OPT_RESIZEUPWARD, TRUE},
38 {"autoclear", OPT_AUTOCLEAR, TRUE},
39 {"history", OPT_HISTORY, TRUE},
40 {"buffer", OPT_BUFFER, TRUE},
41 {"background", OPT_BACKGROUND, TRUE},
42 {"foreground", OPT_FOREGROUND, TRUE},
43 {"bg", OPT_BACKGROUND, FALSE},
44 {"fg", OPT_FOREGROUND, FALSE},
45 {"greycolor", OPT_GREYCOLOR, TRUE},
46
47 {"n-color", OPT_STYLECOLOR+0, TRUE},
48 {"r-color", OPT_STYLECOLOR+1, TRUE},
49 {"b-color", OPT_STYLECOLOR+2, TRUE},
50 {"rb-color", OPT_STYLECOLOR+3, TRUE},
51 {"i-color", OPT_STYLECOLOR+4, TRUE},
52 {"ri-color", OPT_STYLECOLOR+5, TRUE},
53 {"bi-color", OPT_STYLECOLOR+6, TRUE},
54 {"rbi-color", OPT_STYLECOLOR+7, TRUE},
55 {"f-color", OPT_STYLECOLOR+8, TRUE},
56 {"rf-color", OPT_STYLECOLOR+9, TRUE},
57 {"bf-color", OPT_STYLECOLOR+10, TRUE},
58 {"rbf-color", OPT_STYLECOLOR+11, TRUE},
59 {"if-color", OPT_STYLECOLOR+12, TRUE},
60 {"rif-color", OPT_STYLECOLOR+13, TRUE},
61 {"bif-color", OPT_STYLECOLOR+14, TRUE},
62 {"rbif-color", OPT_STYLECOLOR+15, TRUE},
63
64 {"n-font", OPT_STYLEFONT+0, TRUE},
65 {"r-font", OPT_STYLEFONT+1, TRUE},
66 {"b-font", OPT_STYLEFONT+2, TRUE},
67 {"rb-font", OPT_STYLEFONT+3, TRUE},
68 {"i-font", OPT_STYLEFONT+4, TRUE},
69 {"ri-font", OPT_STYLEFONT+5, TRUE},
70 {"bi-font", OPT_STYLEFONT+6, TRUE},
71 {"rbi-font", OPT_STYLEFONT+7, TRUE},
72 {"f-font", OPT_STYLEFONT+8, TRUE},
73 {"rf-font", OPT_STYLEFONT+9, TRUE},
74 {"bf-font", OPT_STYLEFONT+10, TRUE},
75 {"rbf-font", OPT_STYLEFONT+11, TRUE},
76 {"if-font", OPT_STYLEFONT+12, TRUE},
77 {"rif-font", OPT_STYLEFONT+13, TRUE},
78 {"bif-font", OPT_STYLEFONT+14, TRUE},
79 {"rbif-font", OPT_STYLEFONT+15, TRUE},
80
81 {"help", OPT_HELP, TRUE},
82
83 {NULL, 0, FALSE}
84 };
85
86 unixoption unixoptionlist[NUMOPTIONS];
87
88 int strictz_declare_spec;
89
90 #ifdef STRICTZ
91
92 /* Define stuff for stricter Z-code error checking, for the generic
93 Unix/DOS/etc terminal-window interface. Feel free to change the way
94 player prefs are specified, or replace report_zstrict_error()
95 completely if you want to change the way errors are reported. */
96
97 /* There are four error reporting modes: never report errors;
98 report only the first time a given error type occurs; report
99 every time an error occurs; or treat all errors as fatal
100 errors, killing the interpreter. I strongly recommend
101 "report once" as the default. But you can compile in a
102 different default by changing the definition of
103 STRICTZ_DEFAULT_REPORT_MODE. In any case, the player can
104 specify a report mode on the command line by typing "-s 0"
105 through "-s 3". */
106
107 int strictz_report_mode;
108 static int strictz_error_count[STRICTZ_NUM_ERRORS];
109
110 #endif /* STRICTZ */
111
112
113 #if !defined(AMIGA)
114
115 /*
116 * process_arguments
117 *
118 * Do any argument preprocessing necessary before the game is
119 * started. This may include selecting a specific game file or
120 * setting interface-specific options.
121 *
122 */
123
124 #ifdef __STDC__
process_arguments(int argc,char * argv[])125 void process_arguments (int argc, char *argv[])
126 #else
127 void process_arguments (argc, argv)
128 int argc;
129 char *argv[];
130 #endif
131 {
132 int c, errflg = 0;
133 int num;
134 char *gamename = NULL;
135
136 {
137 zword_t zw;
138 int little_endian=0;
139
140 /* Find out if we are big-endian */
141 zw=0x0001;
142 if ( *(zbyte_t *)&zw ) {
143 little_endian=1;
144 }
145
146 #if defined(BIG_END_MODE) || defined(LITTLE_END_MODE)
147
148 #ifdef BIG_END_MODE
149 if (little_endian) {
150 fprintf (stderr, "%s: On this machine, this program must be compiled with LITTLE_END_MODE defined! Adjust the Makefile and recompile.\n", PROGRAMNAME);
151 exit(EXIT_FAILURE);
152 }
153 #else
154 if (!little_endian) {
155 fprintf (stderr, "%s: On this machine, this program must be compiled with BIG_END_MODE defined! Adjust the Makefile and recompile.\n", PROGRAMNAME);
156 exit(EXIT_FAILURE);
157 }
158 #endif
159
160 #else
161 fprintf (stderr, "%s: This program must be compiled with either BIG_END_MODE or LITTLE_END_MODE defined! Adjust the Makefile and recompile.\n", PROGRAMNAME);
162 exit(EXIT_FAILURE);
163
164 #endif
165 }
166
167 #ifdef STRICTZ
168 /* Initialize the STRICTZ variables. */
169 strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE;
170 for (num=0; num<STRICTZ_NUM_ERRORS; num++) {
171 strictz_error_count[num] = 0;
172 }
173 #endif /* STRICTZ */
174
175 /* Parse the options */
176 /* this is considerably changed --zarf */
177
178 num = 0;
179 for (c=0; c<NUMOPTIONS; c++) {
180 unixoptionlist[c].val = NULL;
181 unixoptionlist[c].name = NULL;
182 }
183 for (c=0; optionnamelist[c].name; c++) {
184 if (optionnamelist[c].canonical) {
185 unixoptionlist[optionnamelist[c].key].name = optionnamelist[c].name;
186 }
187 }
188
189 errflg = 0;
190 for (c=1; !errflg && c<argc; c++) {
191 if (argv[c][0]=='-') {
192 /* ### if I were clever, this would be a binary search */
193 for (num=0; optionnamelist[num].name; num++) {
194 if (!strcmp(optionnamelist[num].name, argv[c]+1)) {
195 break;
196 }
197 }
198 if (optionnamelist[num].name) {
199 num = optionnamelist[num].key;
200 if (num==OPT_HELP) {
201 errflg = 2;
202 }
203 else {
204 if (c+1 >= argc) {
205 fprintf(stderr, "%s: option %s requires a value to follow it\n", PROGRAMNAME, argv[c]);
206 errflg = 1;
207 }
208 else {
209 c++;
210 unixoptionlist[num].val = argv[c];
211 }
212 }
213 }
214 else {
215 fprintf(stderr, "%s: unknown option: %s\n", PROGRAMNAME, argv[c]);
216 errflg = 1;
217 }
218 }
219 else {
220 if (!gamename)
221 gamename = argv[c];
222 else {
223 fprintf(stderr, "%s: unknown option after story-file: %s\n", PROGRAMNAME, argv[c]);
224 errflg = 1;
225 }
226 }
227 }
228
229 /* Display usage */
230
231 if (errflg || !gamename) {
232 fprintf (stderr, "usage: %s [options...] story-file\n\n", argv[0]);
233 fprintf (stderr, "XZip - a Z-machine interpreter.\nVersion %s by Andrew Plotkin (erkyrath@eblong.com).\n", XZIPVERSION);
234 fprintf (stderr, "Based on ZIP Version 2.0 by Mark Howell.\n");
235 fprintf (stderr, "Plays Z-machine files of versions 1-5 and version 8.\n\n");
236 fprintf (stderr, "\t-help: display full list of options\n");
237 if (errflg==2) {
238 fprintf(stderr, "\n");
239 for (c=0; c<NUM_SIMPLE_OPTIONS; c++) {
240 if (unixoptionlist[c].name)
241 fprintf(stderr, "\t-%s\n", unixoptionlist[c].name);
242 }
243 /* sue me, this is hardwired */
244 fprintf(stderr, "\t-%s\n", "XXX-color");
245 fprintf(stderr, "\t-%s\n", "XXX-font");
246 fprintf(stderr, "\t(for XXX in n, r, b, rb, i, ri, bi, rbi, f, rf, bf, rbf, if, rif, bif, rbif)\n");
247 }
248 exit (EXIT_FAILURE);
249 }
250
251 /* Open the story file */
252
253 open_story (gamename);
254
255 }/* process_arguments */
256
257 #endif /* !defined(AMIGA) */
258
259 #if !defined(AMIGA)
260
261 /*
262 * file_cleanup
263 *
264 * Perform actions when a file is successfully closed. Flag can be one of:
265 * GAME_SAVE, GAME_RESTORE, GAME_SCRIPT.
266 *
267 */
268
269 #ifdef __STDC__
file_cleanup(const char * file_name,int flag)270 void file_cleanup (const char *file_name, int flag)
271 #else
272 void file_cleanup (file_name, flag)
273 const char *file_name;
274 int flag;
275 #endif
276 {
277
278 }/* file_cleanup */
279
280 #endif /* !defined(AMIGA) */
281
282 #if !defined(AMIGA)
283
284 /*
285 * sound
286 *
287 * Play a sound file or a note.
288 *
289 * argc = 1: argv[0] = note# (range 1 - 3)
290 *
291 * Play note.
292 *
293 * argc = 2: argv[0] = 0
294 * argv[1] = 3
295 *
296 * Stop playing current sound.
297 *
298 * argc = 2: argv[0] = 0
299 * argv[1] = 4
300 *
301 * Free allocated resources.
302 *
303 * argc = 3: argv[0] = ID# of sound file to replay.
304 * argv[1] = 2
305 * argv[2] = Volume to replay sound with, this value
306 * can range between 1 and 8.
307 *
308 * argc = 4: argv[0] = ID# of sound file to replay.
309 * argv[1] = 2
310 * argv[2] = Control information
311 * argv[3] = Volume information
312 *
313 * Volume information:
314 *
315 * 0x34FB -> Fade sound in
316 * 0x3507 -> Fade sound out
317 * other -> Replay sound at maximum volume
318 *
319 * Control information:
320 *
321 * This word is divided into two bytes,
322 * the upper byte determines the number of
323 * cycles to play the sound (e.g. how many
324 * times a clock chimes or a dog barks).
325 * The meaning of the lower byte is yet to
326 * be discovered :)
327 *
328 */
329
330 #ifdef __STDC__
sound(int argc,zword_t * argv)331 void sound (int argc, zword_t *argv)
332 #else
333 void sound (argc, argv)
334 int argc;
335 zword_t *argv;
336 #endif
337 {
338
339 /* Supply default parameters */
340
341 if (argc < 4)
342 argv[3] = 0;
343 if (argc < 3)
344 argv[2] = 0xff;
345 if (argc < 2)
346 argv[1] = 2;
347
348 /* Generic bell sounder */
349
350 if (argc == 1 || argv[1] == 2) {
351 xio_bell(); /* --zarf */
352 /* display_char ('\007'); */
353 }
354
355 }/* sound */
356
357 #endif /* !defined(AMIGA) */
358
359 /*
360 * get_file_name
361 *
362 * Return the name of a file. Flag can be one of:
363 * GAME_SAVE - Save file (write only)
364 * GAME_RESTORE - Save file (read only)
365 * GAME_SCRIPT - Script file (write only)
366 * GAME_RECORD - Keystroke record file (write only)
367 * GAME_PLABACK - Keystroke record file (read only)
368 *
369 */
370
371 #ifdef __STDC__
get_file_name(char * file_name,char * default_name,int flag)372 int get_file_name (char *file_name, char *default_name, int flag)
373 #else
374 int get_file_name (file_name, default_name, flag)
375 char *file_name;
376 char *default_name;
377 int flag;
378 #endif
379 {
380 char buffer[127 + 2]; /* 127 is the biggest positive char */
381 int status = 0;
382
383 /* If no default file name then supply the standard name */
384
385 if (default_name[0] == '\0') {
386 if (flag == GAME_SCRIPT)
387 strcpy (default_name, SCRIPT_NAME);
388 else if (flag == GAME_RECORD || flag == GAME_PLAYBACK)
389 strcpy (default_name, RECORD_NAME);
390 else /* (flag == GAME_SAVE || flag == GAME_RESTORE) */
391 strcpy (default_name, SAVE_NAME);
392 }
393
394 /* Prompt for the file name */
395
396 output_line ("Enter a file name.");
397 output_string ("(Default is \"");
398 output_string (default_name);
399 output_string ("\"): ");
400
401 buffer[0] = 127;
402 buffer[1] = 0;
403 (void) get_line (buffer, 0, 0);
404
405 /* Copy file name from the input buffer */
406
407 if (h_type > V4) {
408 unsigned char len = buffer[1];
409 memcpy (file_name, &buffer[2], len);
410 file_name[len] = '\0';
411 } else
412 strcpy (file_name, &buffer[1]);
413
414 /* If nothing typed then use the default name */
415
416 if (file_name[0] == '\0')
417 strcpy (file_name, default_name);
418
419 #if !defined(VMS) /* VMS has file version numbers, so cannot overwrite */
420
421 /* Check if we are going to overwrite the file */
422
423 if (flag == GAME_SAVE || flag == GAME_SCRIPT || flag == GAME_RECORD) {
424 FILE *tfp;
425 char c;
426
427 /* Try to access the file */
428
429 tfp = fopen (file_name, "r");
430 if (tfp != NULL) {
431 fclose (tfp);
432
433 /* If it succeeded then prompt to overwrite */
434
435 output_line ("You are about to write over an existing file.");
436 output_string ("Proceed? (Y/N) ");
437
438 do {
439 c = (char) input_character (0);
440 c = (char) toupper (c);
441 } while (c != 'Y' && c != 'N');
442
443 output_char (c);
444 output_new_line ();
445
446 /* If no overwrite then fail the routine */
447
448 if (c == 'N')
449 status = 1;
450 }
451 }
452 #endif /* !defined(VMS) */
453
454 /* Record the file name if it was OK */
455
456 if (status == 0)
457 record_line (file_name, strlen(file_name));
458
459 return (status);
460
461 }/* get_file_name */
462
463 #if !defined(AMIGA)
464
465 /*
466 * fatal
467 *
468 * Display message and stop interpreter.
469 *
470 */
471
472 #ifdef __STDC__
fatal(const char * s)473 void fatal (const char *s)
474 #else
475 void fatal (s)
476 const char *s;
477 #endif
478 {
479
480 reset_screen ();
481 printf ("\nFatal error: %s (PC = %lx)\n", s, pc);
482 exit (1);
483
484 }/* fatal */
485
486 #endif /* !defined(AMIGA) */
487
488 #if !defined(AMIGA)
489
490 /*
491 * report_strictz_error
492 *
493 * This handles Z-code error conditions which ought to be fatal errors,
494 * but which players might want to ignore for the sake of finishing the
495 * game.
496 *
497 * The error is provided as both a numeric code and a string. This allows
498 * us to print a warning the first time a particular error occurs, and
499 * ignore it thereafter.
500 *
501 * errnum : Numeric code for error (0 to STRICTZ_NUM_ERRORS-1)
502 * errstr : Text description of error
503 *
504 */
505
506 #ifdef STRICTZ
507
508 #ifdef __STDC__
report_strictz_error(int errnum,const char * errstr)509 void report_strictz_error (int errnum, const char *errstr)
510 #else /* __STDC__ */
511 void report_strictz_error (errnum, errstr)
512 int errnum;
513 const char *errstr;
514 #endif /* __STDC__ */
515 {
516 int wasfirst;
517
518 if (errnum <= 0 || errnum >= STRICTZ_NUM_ERRORS)
519 return;
520
521 if (strictz_report_mode == STRICTZ_REPORT_FATAL) {
522 fatal(errstr);
523 return;
524 }
525
526 wasfirst = (strictz_error_count[errnum] == 0);
527 strictz_error_count[errnum]++;
528
529 if ((strictz_report_mode == STRICTZ_REPORT_ALWAYS)
530 || (strictz_report_mode == STRICTZ_REPORT_ONCE && wasfirst)) {
531 char buf[256];
532 sprintf(buf, "Warning: %s (PC = %lx)", errstr, pc);
533 write_string(buf);
534
535 if (strictz_report_mode == STRICTZ_REPORT_ONCE) {
536 write_string(" (will ignore further occurrences)");
537 }
538 else {
539 sprintf(buf, " (occurrence %d)", strictz_error_count[errnum]);
540 write_string(buf);
541 }
542 new_line();
543 }
544
545 } /* report_strictz_error */
546
547 #endif /* STRICTZ */
548
549 #endif /* !defined(AMIGA) */
550
551 #if !defined(AMIGA)
552
553 /*
554 * fit_line
555 *
556 * This routine determines whether a line of text will still fit
557 * on the screen.
558 *
559 * line : Line of text to test.
560 * pos : Length of text line (in characters).
561 * max : Maximum number of characters to fit on the screen.
562 *
563 */
564
565 #ifdef __STDC__
fit_line(const char * line_buffer,int pos,int max)566 int fit_line (const char *line_buffer, int pos, int max)
567 #else
568 int fit_line (line_buffer, pos, max)
569 const char *line_buffer;
570 int pos;
571 int max;
572 #endif
573 {
574
575 return (pos < max);
576
577 }/* fit_line */
578
579 #endif /* !defined(AMIGA) */
580
581 #if !defined(AMIGA)
582
583 /*
584 * print_status
585 *
586 * Print the status line (type 3 games only).
587 *
588 * argv[0] : Location name
589 * argv[1] : Moves/Time
590 * argv[2] : Score
591 *
592 * Depending on how many arguments are passed to this routine
593 * it is to print the status line. The rendering attributes
594 * and the status line window will be have been activated
595 * when this routine is called. It is to return FALSE if it
596 * cannot render the status line in which case the interpreter
597 * will use display_char() to render it on its own.
598 *
599 * This routine has been provided in order to support
600 * proportional-spaced fonts.
601 *
602 */
603
604 #ifdef __STDC__
print_status(int argc,char * argv[])605 int print_status (int argc, char *argv[])
606 #else
607 int print_status (argc, argv)
608 int argc;
609 char *argv[];
610 #endif
611 {
612
613 return (FALSE);
614
615 }/* print_status */
616
617 #endif /* !defined(AMIGA) */
618
619 #if !defined(AMIGA)
620
621 /*
622 * set_font
623 *
624 * Set a new character font. Font can be either be:
625 *
626 * TEXT_FONT (1) = normal text character font
627 * GRAPHICS_FONT (3) = graphical character font
628 *
629 * Returns TRUE if succeeded, FALSE if failed.
630 */
631
632 #ifdef __STDC__
set_font(int font_type)633 int set_font (int font_type)
634 #else
635 int set_font (font_type)
636 int font_type;
637 #endif
638 {
639 if (font_type == 1)
640 return TRUE;
641 else
642 return FALSE;
643 }/* set_font */
644
645 #endif /* !defined(AMIGA) */
646
647 #if !defined(MSDOS) && !defined(AMIGA)
648
649 /*
650 * set_colours
651 *
652 * Sets screen foreground and background colours.
653 *
654 */
655
656 #ifdef __STDC__
set_colours(int foreground,int background)657 void set_colours (int foreground, int background)
658 #else
659 void set_colours (foreground, background)
660 int foreground;
661 int background;
662 #endif
663 {
664
665 }/* set_colours */
666
667 #endif /* !defined(MSDOS) && !defined(AMIGA) */
668
669 #if !defined(VMS) && !defined(MSDOS)
670
671 /*
672 * codes_to_text
673 *
674 * Translate Z-code characters to machine specific characters. These characters
675 * include line drawing characters and international characters.
676 *
677 * The routine takes one of the Z-code characters from the following table and
678 * writes the machine specific text replacement. The target replacement buffer
679 * is defined by MAX_TEXT_SIZE in ztypes.h. The replacement text should be in a
680 * normal C, zero terminated, string.
681 *
682 * Return 0 if a translation was available, otherwise 1.
683 *
684 * Arrow characters (0x18 - 0x1b):
685 *
686 * 0x18 Up arrow
687 * 0x19 Down arrow
688 * 0x1a Right arrow
689 * 0x1b Left arrow
690 *
691 * International characters (0x9b - 0xa3):
692 *
693 * 0x9b a umlaut (ae)
694 * 0x9c o umlaut (oe)
695 * 0x9d u umlaut (ue)
696 * 0x9e A umlaut (Ae)
697 * 0x9f O umlaut (Oe)
698 * 0xa0 U umlaut (Ue)
699 * 0xa1 sz (ss)
700 * 0xa2 open quote (>>)
701 * 0xa3 close quota (<<)
702 *
703 * Line drawing characters (0xb3 - 0xda):
704 *
705 * 0xb3 vertical line (|)
706 * 0xba double vertical line (#)
707 * 0xc4 horizontal line (-)
708 * 0xcd double horizontal line (=)
709 * all other are corner pieces (+)
710 *
711 */
712
713 #ifdef __STDC__
codes_to_text(int c,char * s)714 int codes_to_text (int c, char *s)
715 #else
716 int codes_to_text (c, s)
717 int c;
718 char *s;
719 #endif
720 {
721 if (c >= 220 && c <= 221) {
722 if (c == 220) {
723 s[0] = 'o';
724 s[1] = 'e';
725 }
726 else {
727 s[0] = 'O';
728 s[1] = 'E';
729 }
730 s[2] = '\0';
731 return 0;
732 }
733
734 if (c >= 155 && c <= 223) {
735 static char xlat[] = "\344\366\374\304\326\334\337\273\253\353\357\377\313\317\341\351\355\363\372\375\301\311\315\323\332\335\340\350\354\362\371\300\310\314\322\331\342\352\356\364\373\302\312\316\324\333\345\305\370\330\343\361\365\303\321\325\346\306\347\307\376\360\336\320\243oO\241\277";
736 s[0] = xlat[c - 155];
737 s[1] = '\0';
738 return 0;
739 }
740
741 return 1;
742
743 }/* codes_to_text */
744
745 #endif /* !defined(VMS) && !defined(MSDOS) */
746