Separated library source code from testing code, fixing #6
[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 <libchimara/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  * Alas, we cannot do this, since glk cannot give us the filename
50  * to reopen it again, and I dont want to mess with filerefs here.
51  *
52  */
53
54 void script_open (void)
55 {
56         static bool script_valid = FALSE;
57
58         h_flags &= ~SCRIPTING_FLAG;
59
60 #if 0
61         if (h_version >= V5 || !script_valid) {
62                 if (!os_read_file_name (new_name, script_name, FILE_SCRIPT))
63                         goto done;
64         }
65
66         /* Opening in "at" mode doesn't work for script_erase_input... */
67
68         if ((sfp = fopen (sfp = fopen (script_name, "r+t")) != NULL || (sfp = fopen (script_name, "w+t")) != NULL) {
69
70 #endif
71
72         if ((sfp = frotzopenprompt(FILE_SCRIPT)) != NULL)
73         {
74                 fseek (sfp, 0, SEEK_END);
75
76                 h_flags |= SCRIPTING_FLAG;
77
78                 script_valid = TRUE;
79                 ostream_script = TRUE;
80
81                 script_width = 0;
82
83         } else print_string ("Cannot open file\n");
84
85 /* done: */
86
87         SET_WORD (H_FLAGS, h_flags)
88
89 }/* script_open */
90
91 /*
92  * script_close
93  *
94  * Stop transscription.
95  *
96  */
97
98 void script_close (void)
99 {
100
101         h_flags &= ~SCRIPTING_FLAG;
102         SET_WORD (H_FLAGS, h_flags)
103
104                 fclose (sfp); ostream_script = FALSE;
105
106 }/* script_close */
107
108 /*
109  * script_new_line
110  *
111  * Write a newline to the transscript file.
112  *
113  */
114
115 void script_new_line (void)
116 {
117
118         if (fputc ('\n', sfp) == EOF)
119                 script_close ();
120
121         script_width = 0;
122
123 }/* script_new_line */
124
125 /*
126  * script_char
127  *
128  * Write a single character to the transscript file.
129  *
130  */
131
132 void script_char (zchar c)
133 {
134
135         if (c == ZC_INDENT && script_width != 0)
136                 c = ' ';
137
138         if (c == ZC_INDENT)
139         { script_char (' '); script_char (' '); script_char (' '); return; }
140         if (c == ZC_GAP)
141         { script_char (' '); script_char (' '); return; }
142
143         fputc (c, sfp); script_width++;
144
145 }/* script_char */
146
147 /*
148  * script_word
149  *
150  * Write a string to the transscript file.
151  *
152  */
153
154 void script_word (const zchar *s)
155 {
156         int width;
157         int i;
158
159         if (*s == ZC_INDENT && script_width != 0)
160                 script_char (*s++);
161
162         for (i = 0, width = 0; s[i] != 0; i++)
163
164                 if (s[i] == ZC_NEW_STYLE || s[i] == ZC_NEW_FONT)
165                         i++;
166                 else if (s[i] == ZC_GAP)
167                         width += 3;
168                 else if (s[i] == ZC_INDENT)
169                         width += 2;
170                 else
171                         width += 1;
172
173         if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols) {
174
175                 if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
176                         s++;
177
178                 script_new_line ();
179
180         }
181
182         for (i = 0; s[i] != 0; i++)
183
184                 if (s[i] == ZC_NEW_FONT || s[i] == ZC_NEW_STYLE)
185                         i++;
186                 else
187                         script_char (s[i]);
188
189 }/* script_word */
190
191 /*
192  * script_write_input
193  *
194  * Send an input line to the transscript file.
195  *
196  */
197
198 void script_write_input (const zchar *buf, zchar key)
199 {
200         int width;
201         int i;
202
203         for (i = 0, width = 0; buf[i] != 0; i++)
204                 width++;
205
206         if (f_setup.script_cols != 0 && script_width + width > f_setup.script_cols)
207                 script_new_line ();
208
209         for (i = 0; buf[i] != 0; i++)
210                 script_char (buf[i]);
211
212         if (key == ZC_RETURN)
213                 script_new_line ();
214
215 }/* script_write_input */
216
217 /*
218  * script_erase_input
219  *
220  * Remove an input line from the transscript file.
221  *
222  */
223
224 void script_erase_input (const zchar *buf)
225 {
226         int width;
227         int i;
228
229         for (i = 0, width = 0; buf[i] != 0; i++)
230                 width++;
231
232         fseek (sfp, -width, SEEK_CUR); script_width -= width;
233
234 }/* script_erase_input */
235
236 /*
237  * script_mssg_on
238  *
239  * Start sending a "debugging" message to the transscript file.
240  *
241  */
242
243 void script_mssg_on (void)
244 {
245
246         if (script_width != 0)
247                 script_new_line ();
248
249         script_char (ZC_INDENT);
250
251 }/* script_mssg_on */
252
253 /*
254  * script_mssg_off
255  *
256  * Stop writing a "debugging" message.
257  *
258  */
259
260 void script_mssg_off (void)
261 {
262
263         script_new_line ();
264
265 }/* script_mssg_off */
266
267 /*
268  * record_open
269  *
270  * Open a file to record the player's input.
271  *
272  */
273
274 void record_open (void)
275 {
276         if ((rfp = frotzopenprompt(FILE_RECORD)) != NULL)
277                 ostream_record = TRUE;
278         else
279                 print_string ("Cannot open file\n");
280 }
281
282 /*
283  * record_close
284  *
285  * Stop recording the player's input.
286  *
287  */
288
289 void record_close (void)
290 {
291
292         fclose (rfp); ostream_record = FALSE;
293
294 }/* record_close */
295
296 /*
297  * record_code
298  *
299  * Helper function for record_char.
300  *
301  */
302
303 static void record_code (int c, bool force_encoding)
304 {
305
306         if (force_encoding || c == '[' || c < 0x20 || c > 0x7e) {
307
308                 int i;
309
310                 fputc ('[', rfp);
311
312                 for (i = 10000; i != 0; i /= 10)
313                         if (c >= i || i == 1)
314                                 fputc ('0' + (c / i) % 10, rfp);
315
316                 fputc (']', rfp);
317
318         } else fputc (c, rfp);
319
320 }/* record_code */
321
322 /*
323  * record_char
324  *
325  * Write a character to the command file.
326  *
327  */
328
329 static void record_char (zchar c)
330 {
331
332         if (c != ZC_RETURN) {
333                 if (c < ZC_HKEY_MIN || c > ZC_HKEY_MAX) {
334                         record_code (translate_to_zscii (c), FALSE);
335                         if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
336                                 record_code (mouse_x, TRUE);
337                                 record_code (mouse_y, TRUE);
338                         }
339                 } else record_code (1000 + c - ZC_HKEY_MIN, TRUE);
340         }
341
342 }/* record_char */
343
344 /*
345  * record_write_key
346  *
347  * Copy a keystroke to the command file.
348  *
349  */
350
351 void record_write_key (zchar key)
352 {
353
354         record_char (key);
355
356         if (fputc ('\n', rfp) == EOF)
357                 record_close ();
358
359 }/* record_write_key */
360
361 /*
362  * record_write_input
363  *
364  * Copy a line of input to a command file.
365  *
366  */
367
368 void record_write_input (const zchar *buf, zchar key)
369 {
370         zchar c;
371
372         while ((c = *buf++) != 0)
373                 record_char (c);
374
375         record_char (key);
376
377         if (fputc ('\n', rfp) == EOF)
378                 record_close ();
379
380 }/* record_write_input */
381
382 /*
383  * replay_open
384  *
385  * Open a file of commands for playback.
386  *
387  */
388
389 void replay_open (void)
390 {
391         if ((pfp = frotzopenprompt(FILE_PLAYBACK)) != NULL)
392                 istream_replay = TRUE;
393         else
394                 print_string ("Cannot open file\n");
395 }
396
397 /*
398  * replay_close
399  *
400  * Stop playback of commands.
401  *
402  */
403
404 void replay_close (void)
405 {
406         fclose (pfp); istream_replay = FALSE;
407 }
408
409 /*
410  * replay_code
411  *
412  * Helper function for replay_key and replay_line.
413  *
414  */
415
416 static int replay_code (void)
417 {
418         int c;
419
420         if ((c = fgetc (pfp)) == '[') {
421
422                 int c2;
423
424                 c = 0;
425
426                 while ((c2 = fgetc (pfp)) != EOF && c2 >= '0' && c2 <= '9')
427                         c = 10 * c + c2 - '0';
428
429                 return (c2 == ']') ? c : EOF;
430
431         } else return c;
432
433 }/* replay_code */
434
435 /*
436  * replay_char
437  *
438  * Read a character from the command file.
439  *
440  */
441
442 static zchar replay_char (void)
443 {
444         int c;
445
446         if ((c = replay_code ()) != EOF) {
447
448                 if (c != '\n') {
449
450                         if (c < 1000) {
451
452                                 c = translate_from_zscii (c);
453
454                                 if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
455                                         mouse_x = replay_code ();
456                                         mouse_y = replay_code ();
457                                 }
458
459                                 return c;
460
461                         } else return ZC_HKEY_MIN + c - 1000;
462                 }
463
464                 ungetc ('\n', pfp);
465
466                 return ZC_RETURN;
467
468         } else return ZC_BAD;
469
470 }/* replay_char */
471
472 /*
473  * replay_read_key
474  *
475  * Read a keystroke from a command file.
476  *
477  */
478
479 zchar replay_read_key (void)
480 {
481         zchar key;
482
483         key = replay_char ();
484
485         if (fgetc (pfp) != '\n') {
486
487                 replay_close ();
488                 return ZC_BAD;
489
490         } else return key;
491
492 }/* replay_read_key */
493
494 /*
495  * replay_read_input
496  *
497  * Read a line of input from a command file.
498  *
499  */
500
501 zchar replay_read_input (zchar *buf)
502 {
503         zchar c;
504
505         for (;;) {
506
507                 c = replay_char ();
508
509                 if (c == ZC_BAD || is_terminator (c))
510                         break;
511
512                 *buf++ = c;
513
514         }
515
516         *buf = 0;
517
518         if (fgetc (pfp) != '\n') {
519
520                 replay_close ();
521                 return ZC_BAD;
522
523         } else return c;
524
525 }/* replay_read_input */