f40739593b664e8f6ddb7f097a4f4981d1e79d1a
[projects/chimara/chimara.git] / interpreters / frotz / files.c
1 /* files.c - Transscription, recording and playback
2  *      Copyright (c) 1995-1997 Stefan Jokisch
3  *
4  * This file is part of Frotz.
5  *
6  * Frotz is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Frotz is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include "frotz.h"
22 #include "glk.h"
23 #include "glkio.h"
24
25 extern void set_more_prompts (bool);
26
27 extern bool is_terminator (zchar);
28
29 extern bool read_yes_or_no (const char *);
30
31 static int script_width = 0;
32
33 static FILE *sfp = NULL;
34 static FILE *rfp = NULL;
35 static FILE *pfp = NULL;
36
37 /*
38  * script_open
39  *
40  * Open the transscript file. 'AMFV' makes this more complicated as it
41  * turns transscription on/off several times to exclude some text from
42  * the transscription file. This wasn't a problem for the original V4
43  * interpreters which always sent transscription to the printer, but it
44  * means a problem to modern interpreters that offer to open a new file
45  * every time transscription is turned on. Our solution is to append to
46  * the old transscription file in V1 to V4, and to ask for a new file
47  * name in V5+.
48  *
49  */
50
51 static bool script_valid = FALSE;
52
53 void script_open (void)
54 {
55
56         h_flags &= ~SCRIPTING_FLAG;
57
58         if (h_version < V5 && script_valid)
59                 sfp = frotzreopen(FILE_SCRIPT);
60         else
61                 sfp = frotzopenprompt(FILE_SCRIPT);
62
63         if (sfp != NULL)
64         {
65                 fseek (sfp, 0, SEEK_END);
66
67                 h_flags |= SCRIPTING_FLAG;
68
69                 script_valid = TRUE;
70                 ostream_script = TRUE;
71
72                 script_width = 0;
73
74         } else print_string ("Cannot open file\n");
75
76         SET_WORD (H_FLAGS, h_flags)
77
78 }/* script_open */
79
80 /*
81  * script_close
82  *
83  * Stop transscription.
84  *
85  */
86
87 void script_close (void)
88 {
89
90         h_flags &= ~SCRIPTING_FLAG;
91         SET_WORD (H_FLAGS, h_flags)
92
93                 fclose (sfp); ostream_script = FALSE;
94
95 }/* script_close */
96
97 /*
98  * script_new_line
99  *
100  * Write a newline to the transscript file.
101  *
102  */
103
104 void script_new_line (void)
105 {
106
107         if (fputc ('\n', sfp) == EOF)
108                 script_close ();
109
110         script_width = 0;
111
112 }/* script_new_line */
113
114 /*
115  * script_char
116  *
117  * Write a single character to the transscript file.
118  *
119  */
120
121 void script_char (zchar c)
122 {
123
124         if (c == ZC_INDENT && script_width != 0)
125                 c = ' ';
126
127         if (c == ZC_INDENT)
128         { script_char (' '); script_char (' '); script_char (' '); return; }
129         if (c == ZC_GAP)
130         { script_char (' '); script_char (' '); return; }
131
132         fputwc (c, sfp); script_width++;
133
134 }/* script_char */
135
136 /*
137  * script_word
138  *
139  * Write a string to the transscript file.
140  *
141  */
142
143 void script_word (const zchar *s)
144 {
145         int width;
146         int i;
147
148         if (*s == ZC_INDENT && script_width != 0)
149                 script_char (*s++);
150
151         for (i = 0, width = 0; s[i] != 0; i++)
152
153                 if (s[i] == ZC_NEW_STYLE || s[i] == ZC_NEW_FONT)
154                         i++;
155                 else if (s[i] == ZC_GAP)
156                         width += 3;
157                 else if (s[i] == ZC_INDENT)
158                         width += 2;
159                 else
160                         width += 1;
161
162         if (option_script_cols != 0 && script_width + width > option_script_cols) {
163
164                 if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
165                         s++;
166
167                 script_new_line ();
168
169         }
170
171         for (i = 0; s[i] != 0; i++)
172
173                 if (s[i] == ZC_NEW_FONT || s[i] == ZC_NEW_STYLE)
174                         i++;
175                 else
176                         script_char (s[i]);
177
178 }/* script_word */
179
180 /*
181  * script_write_input
182  *
183  * Send an input line to the transscript file.
184  *
185  */
186
187 void script_write_input (const zchar *buf, zchar key)
188 {
189         int width;
190         int i;
191
192         for (i = 0, width = 0; buf[i] != 0; i++)
193                 width++;
194
195         if (option_script_cols != 0 && script_width + width > option_script_cols)
196                 script_new_line ();
197
198         for (i = 0; buf[i] != 0; i++)
199                 script_char (buf[i]);
200
201         if (key == ZC_RETURN)
202                 script_new_line ();
203
204 }/* script_write_input */
205
206 /*
207  * script_erase_input
208  *
209  * Remove an input line from the transscript file.
210  *
211  */
212
213 void script_erase_input (const zchar *buf)
214 {
215         int width;
216         int i;
217
218         for (i = 0, width = 0; buf[i] != 0; i++)
219                 width++;
220
221         fseek (sfp, -width, SEEK_CUR); script_width -= width;
222
223 }/* script_erase_input */
224
225 /*
226  * script_mssg_on
227  *
228  * Start sending a "debugging" message to the transscript file.
229  *
230  */
231
232 void script_mssg_on (void)
233 {
234
235         if (script_width != 0)
236                 script_new_line ();
237
238         script_char (ZC_INDENT);
239
240 }/* script_mssg_on */
241
242 /*
243  * script_mssg_off
244  *
245  * Stop writing a "debugging" message.
246  *
247  */
248
249 void script_mssg_off (void)
250 {
251
252         script_new_line ();
253
254 }/* script_mssg_off */
255
256 /*
257  * record_open
258  *
259  * Open a file to record the player's input.
260  *
261  */
262
263 void record_open (void)
264 {
265         if ((rfp = frotzopenprompt(FILE_RECORD)) != NULL)
266                 ostream_record = TRUE;
267         else
268                 print_string ("Cannot open file\n");
269 }
270
271 /*
272  * record_close
273  *
274  * Stop recording the player's input.
275  *
276  */
277
278 void record_close (void)
279 {
280
281         fclose (rfp); ostream_record = FALSE;
282
283 }/* record_close */
284
285 /*
286  * record_code
287  *
288  * Helper function for record_char.
289  *
290  */
291
292 static void record_code (int c, bool force_encoding)
293 {
294
295         if (force_encoding || c == '[' || c < 0x20 || c > 0x7e) {
296
297                 int i;
298
299                 fputc ('[', rfp);
300
301                 for (i = 10000; i != 0; i /= 10)
302                         if (c >= i || i == 1)
303                                 fputc ('0' + (c / i) % 10, rfp);
304
305                 fputc (']', rfp);
306
307         } else fputc (c, rfp);
308
309 }/* record_code */
310
311 /*
312  * record_char
313  *
314  * Write a character to the command file.
315  *
316  */
317
318 static void record_char (zchar c)
319 {
320
321         if (c != ZC_RETURN) {
322                 if (c < ZC_HKEY_MIN || c > ZC_HKEY_MAX) {
323                         record_code (translate_to_zscii (c), FALSE);
324                         if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
325                                 record_code (mouse_x, TRUE);
326                                 record_code (mouse_y, TRUE);
327                         }
328                 } else record_code (1000 + c - ZC_HKEY_MIN, TRUE);
329         }
330
331 }/* record_char */
332
333 /*
334  * record_write_key
335  *
336  * Copy a keystroke to the command file.
337  *
338  */
339
340 void record_write_key (zchar key)
341 {
342
343         record_char (key);
344
345         if (fputc ('\n', rfp) == EOF)
346                 record_close ();
347
348 }/* record_write_key */
349
350 /*
351  * record_write_input
352  *
353  * Copy a line of input to a command file.
354  *
355  */
356
357 void record_write_input (const zchar *buf, zchar key)
358 {
359         zchar c;
360
361         while ((c = *buf++) != 0)
362                 record_char (c);
363
364         record_char (key);
365
366         if (fputc ('\n', rfp) == EOF)
367                 record_close ();
368
369 }/* record_write_input */
370
371 /*
372  * replay_open
373  *
374  * Open a file of commands for playback.
375  *
376  */
377
378 void replay_open (void)
379 {
380         if ((pfp = frotzopenprompt(FILE_PLAYBACK)) != NULL)
381                 istream_replay = TRUE;
382         else
383                 print_string ("Cannot open file\n");
384 }
385
386 /*
387  * replay_close
388  *
389  * Stop playback of commands.
390  *
391  */
392
393 void replay_close (void)
394 {
395         fclose (pfp); istream_replay = FALSE;
396 }
397
398 /*
399  * replay_code
400  *
401  * Helper function for replay_key and replay_line.
402  *
403  */
404
405 static int replay_code (void)
406 {
407         int c;
408
409         if ((c = fgetc (pfp)) == '[') {
410
411                 int c2;
412
413                 c = 0;
414
415                 while ((c2 = fgetc (pfp)) != EOF && c2 >= '0' && c2 <= '9')
416                         c = 10 * c + c2 - '0';
417
418                 return (c2 == ']') ? c : EOF;
419
420         } else return c;
421
422 }/* replay_code */
423
424 /*
425  * replay_char
426  *
427  * Read a character from the command file.
428  *
429  */
430
431 static zchar replay_char (void)
432 {
433         int c;
434
435         if ((c = replay_code ()) != EOF) {
436
437                 if (c != '\n') {
438
439                         if (c < 1000) {
440
441                                 c = translate_from_zscii (c);
442
443                                 if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
444                                         mouse_x = replay_code ();
445                                         mouse_y = replay_code ();
446                                 }
447
448                                 return c;
449
450                         } else return ZC_HKEY_MIN + c - 1000;
451                 }
452
453                 ungetc ('\n', pfp);
454
455                 return ZC_RETURN;
456
457         } else return ZC_BAD;
458
459 }/* replay_char */
460
461 /*
462  * replay_read_key
463  *
464  * Read a keystroke from a command file.
465  *
466  */
467
468 zchar replay_read_key (void)
469 {
470         zchar key;
471
472         key = replay_char ();
473
474         if (fgetc (pfp) != '\n') {
475
476                 replay_close ();
477                 return ZC_BAD;
478
479         } else return key;
480
481 }/* replay_read_key */
482
483 /*
484  * replay_read_input
485  *
486  * Read a line of input from a command file.
487  *
488  */
489
490 zchar replay_read_input (zchar *buf)
491 {
492         zchar c;
493
494         for (;;) {
495
496                 c = replay_char ();
497
498                 if (c == ZC_BAD || is_terminator (c))
499                         break;
500
501                 *buf++ = c;
502
503         }
504
505         *buf = 0;
506
507         if (fgetc (pfp) != '\n') {
508
509                 replay_close ();
510                 return ZC_BAD;
511
512         } else return c;
513
514 }/* replay_read_input */