1 /*
2 ** os_glk.c - Definitions which are specific to the Glk 'platform'
3 **
4 ** Notes:
5 ** 10 Jan 99: SRG Initial creation
6 ** 3 Dec 01: SRG Added os_build_full_path
7 ** 20 Dec 01: SRG Added os_get_exe_filename and os_get_special_path
8 ** 10 Mar 02: SRG Added os_more_prompt routine (thanks to D.J. Picton)
9 ** 13 Jul 04: Nikos Added os_nonstop_mode dummy implementation
10 */
11
12 #include "run.h"
13 #include "os_glk.h"
14 #include "oss_glk.h"
15 #include <unistd.h>
16 #include <stdlib.h>
17
18
19 /* ------------------------------------------------------------------------ */
20 /*
21 ** Some machines are missing memmove, so we use our own memcpy/memmove
22 ** routine instead.
23 */
our_memcpy(void * destp,const void * srcp,size_t size)24 void *our_memcpy(void *destp, const void *srcp, size_t size)
25 {
26 char *dest = (char *)destp;
27 char *src = (char *)srcp;
28 size_t n;
29
30 n = size;
31 if (dest < src) {
32 while (n > 0) {
33 *dest = *src;
34 dest++;
35 src++;
36 n--;
37 }
38 }
39 else if (dest > src) {
40 for (src += n, dest += n; n > 0; n--) {
41 dest--;
42 src--;
43 *dest = *src;
44 }
45 }
46
47 return destp;
48 }
49
50
51 /* ------------------------------------------------------------------------ */
52 /*
53 ** File handling
54 */
55
56 /* Ask the user for a filename. Return 0 if successful, non-zero otherwise */
os_askfile(const char * prompt,char * fname_buf,int fname_buf_len,int prompt_type,int file_type)57 int os_askfile(const char *prompt, char *fname_buf, int fname_buf_len,
58 int prompt_type, int file_type)
59 {
60 frefid_t fileref;
61 glui32 glk_prompt_type, glk_file_type;
62
63 glk_prompt_type = oss_convert_prompt_type(prompt_type);
64 glk_file_type = oss_convert_file_type(file_type) |
65 fileusage_TextMode;
66
67 fileref = glk_fileref_create_by_prompt(glk_file_type, glk_prompt_type, 0);
68 if (fileref == NULL)
69 return OS_AFE_CANCEL;
70 return (oss_convert_fileref_to_string(fileref, fname_buf, fname_buf_len)
71 == FALSE ? OS_AFE_FAILURE : OS_AFE_SUCCESS);
72 }
73
74 /* Create and open a temporary file. Theoretically I should use the
75 filename in swapname or generate my own and put it in buf */
os_create_tempfile(const char * swapname,char * buf)76 osfildef *os_create_tempfile(const char *swapname, char *buf)
77 {
78 frefid_t fileref;
79 strid_t stream;
80
81 fileref = glk_fileref_create_temp(fileusage_Data | fileusage_BinaryMode,
82 0);
83 stream = glk_stream_open_file(fileref, filemode_ReadWrite, 0);
84 glk_fileref_destroy(fileref);
85 return stream;
86 }
87
88 /* Delete a temp file that was created by os_create_tempfile. Since
89 Glk automatically deletes temporary files, I have no need of this */
osfdel_temp(const char * fname)90 int osfdel_temp(const char *fname)
91 {
92 return TRUE;
93 }
94
95 /* Get a path to put a temp file--too bad we don't use paths...most of
96 the time */
os_get_tmp_path(char * buf)97 void os_get_tmp_path(char *buf)
98 {
99 buf[0] = 0;
100 }
101
102 /* Locate a file and, if the search is successful, store the resulting
103 name in the given buffer. Return TRUE if the file was found, FALSE
104 otherwise. Since Glk doesn't concern itself with paths, this is an
105 easy check */
os_locate(const char * fname,int flen,const char * arg0,char * buf,size_t bufsiz)106 int os_locate(const char *fname, int flen, const char *arg0, char *buf,
107 size_t bufsiz)
108 {
109 if (!osfacc(fname)) {
110 memcpy(buf, fname, flen);
111 buf[flen] = 0;
112 return TRUE;
113 }
114 return FALSE;
115 }
116
117 /* open text file for reading; returns NULL on error */
osfoprt(char * fname,glui32 typ)118 osfildef *osfoprt(char *fname, glui32 typ)
119 {
120 return (oss_open_stream(fname, typ, fileusage_TextMode,
121 filemode_Read, 0));
122 }
123
124 /* open text file for writing; returns NULL on error */
osfopwt(char * fname,glui32 typ)125 osfildef *osfopwt(char *fname, glui32 typ)
126 {
127 return (oss_open_stream(fname, typ, fileusage_TextMode,
128 filemode_Write, 0));
129 }
130
131 /* open text file for reading and writing; returns NULL on error */
osfoprwt(char * fname,glui32 typ)132 osfildef *osfoprwt(char *fname, glui32 typ)
133 {
134 return (oss_open_stream(fname, typ, fileusage_TextMode,
135 filemode_ReadWrite, 0));
136 }
137
138 /* open text file for reading/writing; truncate; returns NULL on error */
osfoprwtt(char * fname,glui32 typ)139 osfildef *osfoprwtt(char *fname, glui32 typ)
140 {
141 return (oss_open_stream(fname, typ, fileusage_TextMode,
142 filemode_ReadWrite, 0));
143 }
144
145 /* open binary file for writing; returns NULL on error */
osfopwb(char * fname,glui32 typ)146 osfildef *osfopwb(char *fname, glui32 typ)
147 {
148 return (oss_open_stream(fname, typ, fileusage_BinaryMode,
149 filemode_Write, 0));
150 }
151
152 /* open source file for reading */
osfoprs(char * fname,glui32 typ)153 osfildef *osfoprs(char *fname, glui32 typ)
154 {
155 return (oss_open_stream(fname, typ, fileusage_BinaryMode,
156 filemode_Read, 0));
157 }
158
159 /* open binary file for reading; returns NULL on erorr */
osfoprb(char * fname,glui32 typ)160 osfildef *osfoprb(char *fname, glui32 typ)
161 {
162 return (oss_open_stream(fname, typ, fileusage_BinaryMode,
163 filemode_Read, 0));
164 }
165
166 /* open binary file for reading/writing; don't truncate */
osfoprwb(char * fname,glui32 typ)167 osfildef *osfoprwb(char *fname, glui32 typ)
168 {
169 return (oss_open_stream(fname, typ, fileusage_BinaryMode,
170 filemode_ReadWrite, 0));
171 }
172
173 /* open binary file for reading/writing; truncate; returns NULL on error */
osfoprwtb(char * fname,glui32 typ)174 osfildef *osfoprwtb(char *fname, glui32 typ)
175 {
176 return (oss_open_stream(fname, typ, fileusage_BinaryMode,
177 filemode_ReadWrite, 0));
178 }
179
180 /* delete a file - TRUE if error */
osfdel(char * fname)181 int osfdel(char *fname)
182 {
183 frefid_t fileref;
184 int changed_dirs;
185
186 fileref = oss_convert_string_to_fileref(fname, fileusage_BinaryMode);
187 changed_dirs = oss_check_path(fname);
188 glk_fileref_delete_file(fileref);
189 glk_fileref_destroy(fileref);
190 if (changed_dirs)
191 oss_revert_path();
192 return FALSE;
193 }
194
195 /* access a file - 0 if file exists */
osfacc(const char * fname)196 int osfacc(const char *fname)
197 {
198 frefid_t fileref;
199 int result, changed_dirs;
200
201 fileref = oss_convert_string_to_fileref(fname, fileusage_BinaryMode);
202 changed_dirs = oss_check_path(fname);
203 result = (int)glk_fileref_does_file_exist(fileref);
204 if (changed_dirs)
205 oss_revert_path();
206 return (result != TRUE);
207 }
208
209
210 /* build a full path name given a path and a filename */
211 /* (NB much of this comes from osnoui.c) */
os_build_full_path(char * fullpathbuf,size_t fullpathbuflen,const char * path,const char * filename)212 void os_build_full_path(char *fullpathbuf, size_t fullpathbuflen,
213 const char *path, const char *filename)
214 {
215 size_t plen, flen;
216 int add_sep;
217
218 /* I'm defining this just for the Unix version of GLK */
219 #ifdef GLKUNIX
220
221 /*
222 * Note whether we need to add a separator. If the path prefix ends
223 * in a separator, don't add another; otherwise, add the standard
224 * system separator character.
225 *
226 * Do not add a separator if the path is completely empty, since this
227 * simply means that we want to use the current directory.
228 */
229 plen = strlen(path);
230 add_sep = (plen != 0
231 && path[plen-1] != OSPATHCHAR
232 && strchr(OSPATHALT, path[plen-1]) == 0);
233
234 /* copy the path to the full path buffer, limiting to the buffer length */
235 if (plen > fullpathbuflen - 1)
236 plen = fullpathbuflen - 1;
237 memcpy(fullpathbuf, path, plen);
238
239 /* add the path separator if necessary (and if there's room) */
240 if (add_sep && plen + 2 < fullpathbuflen)
241 fullpathbuf[plen++] = OSPATHCHAR;
242
243 /* add the filename after the path, if there's room */
244 flen = strlen(filename);
245 if (flen > fullpathbuflen - plen - 1)
246 flen = fullpathbuflen - plen - 1;
247 memcpy(fullpathbuf + plen, filename, flen);
248
249 /* add a null terminator */
250 fullpathbuf[plen + flen] = '\0';
251 #endif /* GLKUNIX */
252 }
253
254 /*
255 * Given argv[0], what's the executable's full pathname? The problem under
256 * Unix is that we don't necessarily know. If the interpreter is invoked
257 * using an alias, argv[0] will (under many shells) contain that alias. So
258 * we're going to return failure regardless. The good news is that we only
259 * lose the ability to create bound games, which I don't expect to be an
260 * issue under Unix. If you port Glk TADS to another platform where this
261 * is not the case, feel free to adjust this routine appropriately.
262 */
os_get_exe_filename(char * buf,size_t buflen,const char * argv0)263 int os_get_exe_filename(char *buf, size_t buflen, const char *argv0)
264 {
265 buf[0] = 0;
266 return FALSE;
267 }
268
269 /*
270 * Get a special path (e.g. path to standard include files or libraries).
271 * Valid id values include OS_GSP_T3_RES, OS_GSP_T3_LIB, and
272 * OS_GSP_T3_INC. If certain compiler variables are set, use those
273 * hardcoded paths. Otherwise, check for environment variables; if those
274 * aren't set, return argv0's path. Note that this is only for Unix Glk
275 */
os_get_special_path(char * buf,size_t buflen,const char * argv0,int id)276 void os_get_special_path(char *buf, size_t buflen, const char *argv0, int id)
277 {
278 const char *str;
279 char *p;
280
281 #ifdef GLKUNIX
282 switch(id) {
283 #ifdef DEFINEDIRS
284 case OS_GSP_T3_RES:
285 str = RESDIR;
286 break;
287 case OS_GSP_T3_LIB:
288 str = LIBDIR;
289 break;
290 case OS_GSP_T3_INC:
291 str = INCDIR;
292 break;
293 #else /* DEFINEDIRS */
294 case OS_GSP_T3_RES:
295 str = getenv("TADS3_RESDIR");
296 break;
297 case OS_GSP_T3_LIB:
298 str = getenv("TADS3_LIBDIR");
299 break;
300 case OS_GSP_T3_INC:
301 str = getenv("TADS3_INCLUDEDIR");
302 break;
303 #endif /* DEFINEDIRS */
304 default:
305 /*
306 * If we're called with another identifier, it must mean that
307 * we're out of date. Fail with an assertion.
308 */
309 assert(FALSE);
310 }
311
312 #ifndef DEFINEDIRS
313 if (str == NULL) {
314 strcpy(buf, argv0);
315 p = buf + strlen(argv0) - 1;
316 /* Move backwards until we find a slash in argv0 or its beginning */
317 while (p != buf && *p != '/') {
318 p--;
319 }
320 if (*p == '/' && p != buf) {
321 *p = (char)NULL;
322 }
323 }
324 #endif /* DEFINEDIRS */
325
326 if (strlen(str) >= buflen)
327 assert(FALSE);
328 strcpy(buf, str);
329 #endif /* GLKUNIX */
330 }
331
332
333 /* ------------------------------------------------------------------------ */
334 /*
335 ** File extension and path fiddling
336 */
337
338 /* I'm defining these functions for the Unix Glk libraries. Your port may
339 not need them at all */
340
os_defext(char * fname,const char * ext)341 void os_defext(char *fname, const char *ext)
342 {
343 #ifdef GLKUNIX
344 os_addext(fname, ext);
345 #endif /* GLKUNIX */
346 }
347
os_addext(char * fname,const char * ext)348 void os_addext(char *fname, const char *ext)
349 {
350 #ifdef GLKUNIX
351 char buf[5], *p;
352
353 /* Don't do any fiddling if the passed string is a hashed fileref or
354 if there is already an extension on the file */
355 if (oss_is_string_a_fileref(fname))
356 return;
357 p = fname + strlen(fname) - 1;
358 while (p > fname && *p != '.' && *p != '/')
359 p--;
360 if (*p == '.')
361 return;
362
363 strcat(fname, "."); /* Append a dot and the extension */
364 strcpy(buf, ext); /* Make the extension lower-case by default */
365 os_strlwr(buf);
366 strcat(fname, buf);
367 #endif /* GLKUNIX */
368 }
369
os_remext(char * fname)370 void os_remext(char *fname)
371 {
372 #ifdef GLKUNIX
373 char *p;
374
375 /* Don't do any fiddling if the passed string is a hashed fileref */
376 if (oss_is_string_a_fileref(fname))
377 return;
378
379 p = fname + strlen(fname);
380 while (p != fname) {
381 p--;
382 if (*p == '.') {
383 *p = 0;
384 return;
385 }
386 /* If we run into a directory separator, return */
387 if (*p == '/' || *p == '\\' || *p == ':')
388 return;
389 }
390 #endif /* GLKUNIX */
391 }
392
393 /* Get a pointer to the root name portion of a filename */
os_get_root_name(char * buf)394 char *os_get_root_name(char *buf)
395 {
396 char *p = buf;
397
398 #ifdef GLKUNIX
399 p += strlen(buf) - 1;
400 while (*p != '/' && p > buf)
401 p--;
402 if (p != buf) p++;
403 #endif /* GLKUNIX */
404 return p;
405 }
406
407
408 /* ------------------------------------------------------------------------ */
409 /*
410 ** Text handling and I/O
411 */
412
413 /*
414 ** The main text area print routines
415 */
os_printz(const char * str)416 void os_printz(const char *str)
417 {
418 /* print the string through the base counted-length print routine */
419 os_print(str, strlen(str));
420 }
421
os_print(const char * str,size_t len)422 void os_print(const char *str, size_t len)
423 {
424 int current_status_mode;
425
426 /* Decide what to do based on our status mode */
427 current_status_mode = os_get_status();
428 if (current_status_mode == OSS_STATUS_MODE_STORY) {
429 oss_put_string_with_hilite(story_win, str, len);
430 }
431 else if (current_status_mode == OSS_STATUS_MODE_STATUS) {
432 const char *p;
433 size_t rem;
434
435 /* The string requires some fiddling for the status window */
436 for (p = str, rem = len ; rem != 0 && *p == '\n'; p++, --rem) ;
437 if (rem != 0 && p[rem-1] == '\n')
438 --rem;
439
440 /* if that leaves anything, update the statusline */
441 if (rem != 0)
442 oss_change_status_left(p, rem);
443 }
444 }
445
os_fprintz(osfildef * fp,const char * str)446 void os_fprintz(osfildef *fp, const char *str)
447 {
448 glk_put_string_stream(fp, str);
449 }
450
os_fprint(osfildef * fp,const char * str,size_t len)451 void os_fprint(osfildef *fp, const char *str, size_t len)
452 {
453 glk_put_buffer_stream(fp, str, len);
454 }
455
456 /* Convert a string to all-lowercase */
os_strlwr(char * s)457 char *os_strlwr(char *s)
458 {
459 char *sptr;
460
461 sptr = s;
462 while (*sptr != 0) {
463 *sptr = glk_char_to_lower((unsigned char)*sptr);
464 sptr++;
465 }
466 return s;
467 }
468
469 /* Show a [MORE] prompt */
os_more_prompt(void)470 void os_more_prompt(void)
471 {
472 int done;
473
474 /* display the "MORE" prompt */
475 os_printz("[More]");
476 os_flush();
477
478 /* wait for a keystroke */
479 for (done = FALSE; !done; )
480 {
481 os_event_info_t evt;
482
483 /* get an event */
484 switch(os_get_event(0, FALSE, &evt))
485 {
486 case OS_EVT_KEY:
487 /* stop waiting, show one page */
488 done = TRUE;
489 break;
490
491 case OS_EVT_EOF:
492 /* end of file - there's nothing to wait for now */
493 done = TRUE;
494 break;
495
496 default:
497 /* ignore other events */
498 break;
499 }
500 }
501 os_printz("\n");
502 os_flush();
503 }
504
505 /* Set non-stop mode */
os_nonstop_mode(int flag)506 void os_nonstop_mode(int flag)
507 {
508 /* Dummy; someone please implement it. */
509 }
510
511 /* ------------------------------------------------------------------------ */
512 /*
513 ** Keyboard I/O
514 */
515
516 /* Read in a line of text from the keyboard */
os_gets(unsigned char * buf,size_t bufl)517 unsigned char *os_gets(unsigned char *buf, size_t bufl)
518 {
519 event_t ev;
520
521 glk_request_line_event(story_win, buf, (glui32) bufl - 1, 0);
522 do {
523 glk_select(&ev);
524 if (ev.type == evtype_Arrange)
525 oss_draw_status_line();
526 } while (ev.type != evtype_LineInput);
527 buf[ev.val1] = 0; /* Don't forget the trailing NULL */
528
529 return buf;
530 }
531
532 /* Get a character from the keyboard. For extended characters, return 0,
533 then return the extended key at the next call to this function */
os_getc(void)534 int os_getc(void)
535 {
536 return (oss_getc_from_window(story_win));
537 }
538
539 /* Get a character from the keyboard, returning low-level, untranslated
540 key codes. Since we don't deal with anything but low-level codes,
541 this is exactly the same as os_getc. */
os_getc_raw(void)542 int os_getc_raw(void)
543 {
544 return os_getc();
545 }
546
547 /* Wait for a key to be hit */
os_waitc(void)548 void os_waitc(void)
549 {
550 os_getc();
551 }
552
553 /* Here's the biggie. Get an input event, which may or may not be timed
554 out. timeout is in milliseconds */
os_get_event(unsigned long timeout,int use_timeout,os_event_info_t * info)555 int os_get_event(unsigned long timeout, int use_timeout,
556 os_event_info_t *info)
557 {
558 event_t ev;
559
560 glk_request_char_event(story_win);
561 if (flag_timer_supported && use_timeout)
562 glk_request_timer_events((glui32)timeout);
563 do {
564 glk_select(&ev);
565 if (ev.type == evtype_Arrange)
566 oss_draw_status_line();
567 } while (ev.type != evtype_Timer && ev.type != evtype_CharInput);
568 glk_cancel_char_event(story_win); /* Just in case */
569 if (flag_timer_supported) /* If we support timers, stop 'em */
570 glk_request_timer_events(0);
571 if (ev.type == evtype_Timer)
572 return OS_EVT_TIMEOUT;
573 if (ev.val1 == keycode_Return)
574 ev.val1 = '\n';
575 else if (ev.val1 == keycode_Tab)
576 ev.val1 = '\t';
577 if (ev.val1 <= 255)
578 info->key[0] = (int)(ev.val1);
579 else {
580 info->key[0] = 0;
581 info->key[1] = (int)(oss_convert_keystroke_to_tads(ev.val1));
582 }
583 return OS_EVT_KEY;
584 }
585
586
587 /* ------------------------------------------------------------------------ */
588 /*
589 ** Status line functions
590 */
591
592 /* Set the status mode */
os_status(int stat)593 void os_status(int stat)
594 {
595 status_mode = stat;
596 }
597
598 /* Query the status mode */
os_get_status()599 int os_get_status()
600 {
601 return status_mode;
602 }
603
604 /* Display a string in the score area (rightmost) of the status line */
os_strsc(const char * p)605 void os_strsc(const char *p)
606 {
607 if (p == NULL) /* NULL means simply refresh the status */
608 oss_draw_status_line();
609 else oss_change_status_right(p);
610 }
611
612 /* Set the score. If score == -1, use the last score */
os_score(int cur,int turncount)613 void os_score(int cur, int turncount)
614 {
615 char buf[20];
616
617 if (turncount == -1) /* -1 means simply refresh the status */
618 oss_draw_status_line();
619 else {
620 sprintf(buf, "%d/%d", cur, turncount);
621 oss_change_status_right(buf);
622 }
623 }
624
625
626 /* ------------------------------------------------------------------------ */
627 /*
628 ** Other misc functions
629 */
630
os_rand(long * seed)631 void os_rand(long *seed)
632 {
633 time_t t;
634
635 time(&t);
636 *seed = (long)t;
637 }
638
os_get_sys_clock_ms(void)639 long os_get_sys_clock_ms(void)
640 {
641 if (time_zero == 0)
642 time_zero = time(0);
643 return ((time(0) - time_zero) * 1000);
644 }
645
os_sleep_ms(long delay_in_ms)646 void os_sleep_ms(long delay_in_ms)
647 {
648 glk_tick();
649 usleep(delay_in_ms);
650 glk_tick();
651 }
652
os_set_text_attr(int attr)653 void os_set_text_attr(int attr)
654 {
655 /* ensure that we are acting on the story window */
656 glk_set_window(story_win);
657
658 /* map highlighting/bold/emphasized to "emphasized" style */
659 if ((attr & (OS_ATTR_HILITE | OS_ATTR_BOLD | OS_ATTR_EM)) != 0)
660 glk_set_style(style_Emphasized);
661 else
662 glk_set_style(style_Normal);
663 }
664
os_set_text_color(os_color_t fg,os_color_t bg)665 void os_set_text_color(os_color_t fg, os_color_t bg)
666 {
667 /* glk does not have a way to set colors explicitly */
668 }
669
oscls(void)670 void oscls(void)
671 {
672 glk_window_clear(story_win);
673 }
674
675 /* Flush the output */
os_flush(void)676 void os_flush(void)
677 {
678 glk_tick();
679 }
680
681 /* update the display - process any painting events immediately */
os_update_display()682 void os_update_display()
683 {
684 glk_tick();
685 }
686
os_yield(void)687 int os_yield(void)
688 {
689 glk_tick();
690 return FALSE;
691 }
692
os_expause(void)693 void os_expause(void)
694 {
695 #ifdef USE_EXPAUSE
696 os_printz("(Strike any key to exit...)");
697 os_flush();
698 os_waitc();
699 #endif /* USE_EXPAUSE */
700 }
701
os_get_sysinfo(int code,void * parm,long * result)702 int os_get_sysinfo(int code, void *parm, long *result)
703 {
704 switch(code) {
705 case SYSINFO_TEXT_HILITE:
706 /* we do support text highlighting */
707 *result = 1;
708 return TRUE;
709
710 case SYSINFO_HTML:
711 case SYSINFO_JPEG:
712 case SYSINFO_PNG:
713 case SYSINFO_WAV:
714 case SYSINFO_MIDI:
715 case SYSINFO_WAV_MIDI_OVL:
716 case SYSINFO_WAV_OVL:
717 case SYSINFO_PREF_IMAGES:
718 case SYSINFO_PREF_SOUNDS:
719 case SYSINFO_PREF_MUSIC:
720 case SYSINFO_PREF_LINKS:
721 case SYSINFO_MPEG:
722 case SYSINFO_MPEG1:
723 case SYSINFO_MPEG2:
724 case SYSINFO_MPEG3:
725 case SYSINFO_LINKS_HTTP:
726 case SYSINFO_LINKS_FTP:
727 case SYSINFO_LINKS_NEWS:
728 case SYSINFO_LINKS_MAILTO:
729 case SYSINFO_LINKS_TELNET:
730 case SYSINFO_PNG_TRANS:
731 case SYSINFO_PNG_ALPHA:
732 case SYSINFO_OGG:
733 case SYSINFO_BANNERS:
734 /* Since we support none of these, set result to 0 */
735 *result = 0;
736 return TRUE; /* We recognized the code */
737 case SYSINFO_INTERP_CLASS:
738 /* we're a text-only character-mode interpreter */
739 /*
740 * $$$ we might want to be more specific: if it's possible to
741 * determine whether we're running on a character-mode or GUI
742 * platform, we should indicate type TEXT or TEXTGUI as
743 * appropriate. There's no practical difference between these
744 * classes at the moment, though, so it's not very important to
745 * distinguish them.
746 */
747 *result = SYSINFO_ICLASS_TEXT;
748 return TRUE;
749 default:
750 return FALSE;
751 }
752 }
753
os_xlat_html4(unsigned int html4_char,char * result,size_t result_len)754 void os_xlat_html4(unsigned int html4_char, char *result, size_t result_len)
755 {
756 /* Return all standard Latin-1 characters as-is */
757 if (html4_char <= 128 || (html4_char >= 160 && html4_char <= 255))
758 result[0] = (unsigned char)html4_char;
759 else {
760 switch (html4_char) {
761 case 130: /* single back quote */
762 result[0] = '`'; break;
763 case 132: /* double back quote */
764 result[0] = '\"'; break;
765 case 153: /* trade mark */
766 strcpy(result, "(tm)"); return;
767 case 140: /* OE ligature */
768 case 338: /* OE ligature */
769 strcpy(result, "OE"); return;
770 case 339: /* oe ligature */
771 strcpy(result, "oe"); return;
772 case 159: /* Yuml */
773 result[0] = 255;
774 case 376: /* Y with diaresis */
775 result[0] = 'Y'; break;
776 case 352: /* S with caron */
777 result[0] = 'S'; break;
778 case 353: /* s with caron */
779 result[0] = 's'; break;
780 case 150: /* en dash */
781 case 8211: /* en dash */
782 result[0] = '-'; break;
783 case 151: /* em dash */
784 case 8212: /* em dash */
785 strcpy(result, "--"); return;
786 case 145: /* left single quote */
787 case 8216: /* left single quote */
788 result[0] = '`'; break;
789 case 146: /* right single quote */
790 case 8217: /* right single quote */
791 case 8218: /* single low-9 quote */
792 result[0] = '\''; break;
793 case 147: /* left double quote */
794 case 148: /* right double quote */
795 case 8220: /* left double quote */
796 case 8221: /* right double quote */
797 case 8222: /* double low-9 quote */
798 result[0] = '\"'; break;
799 case 8224: /* dagger */
800 case 8225: /* double dagger */
801 case 8240: /* per mille sign */
802 result[0] = ' '; break;
803 case 139: /* single left-pointing angle quote */
804 case 8249: /* single left-pointing angle quote */
805 result[0] = '<'; break;
806 case 155: /* single right-pointing angle quote */
807 case 8250: /* single right-pointing angle quote */
808 result[0] = '>'; break;
809 case 8482: /* small tilde */
810 result[0] = '~'; break;
811
812 default:
813 /* unmappable character - return space */
814 result[0] = (unsigned char)' ';
815 }
816 }
817 result[1] = 0;
818 }
819
os_gen_charmap_filename(char * filename,char * internal_id,char * argv0)820 void os_gen_charmap_filename(char *filename, char *internal_id, char *argv0)
821 {
822 filename[0] = 0;
823 }
824
825 /* ------------------------------------------------------------------------ */
826 /*
827 ** Some empty routines that we have to have just because
828 */
829 /* Set the title of the story window */
os_set_title(const char * title)830 void os_set_title(const char *title) {}
831
832 /* Seek to the game file embedded in the given executable file */
os_exeseek(const char * exefile,const char * typ)833 osfildef *os_exeseek(const char *exefile, const char *typ) { return NULL; }
834
835 /* Load an external function from a file, given the name of the file */
os_exfil(const char * name)836 int (*os_exfil(const char *name))(void *) { return (int (*)(void *))NULL; }
837
838 /* Load an external function from an open file */
os_exfld(osfildef * fp,unsigned len)839 int (*os_exfld(osfildef *fp, unsigned len))(void *)
840 {
841 return (int (*)(void *))NULL;
842 }
843
844 /* Call an external function */
os_excall(int (* extfn)(void *),void * arg)845 int os_excall(int (*extfn)(void *), void *arg) { return 0; }
846
847 /* Check for user break */
os_break(void)848 int os_break(void) { return FALSE; }
849
850 /* Get a filename from a startup parameter, if possible. Which it isn't */
os_paramfile(char * buf)851 int os_paramfile(char *buf) { return FALSE; }
852
853 /* Set the terminal into "plain" mode */
os_plain(void)854 void os_plain(void) {}
855
856 /* Set the saved game extension. Sha, as if. */
os_set_save_ext(const char * ext)857 void os_set_save_ext(const char *ext) {}
858
859 /* Set a file's filetype */
os_settype(const char * f,int t)860 void os_settype(const char *f, int t) {}
861
862 /* Find the first file in a directory, given a wildcard pattern */
os_find_first_file(const char * dir,const char * pattern,char * outbuf,size_t outbufsiz,int * isdir,char * outpathbuf,size_t outpathbufsiz)863 void *os_find_first_file(const char *dir, const char *pattern,
864 char *outbuf, size_t outbufsiz, int *isdir,
865 char *outpathbuf, size_t outpathbufsiz) {}
866
867 /* Find the next file */
os_find_next_file(void * ctx0,char * outbuf,size_t outbufsize,int * isdir,char * outpathbuf,size_t outpathbufsiz)868 void *os_find_next_file(void *ctx0, char *outbuf, size_t outbufsize,
869 int *isdir, char *outpathbuf, size_t outpathbufsiz) {}
870
871 /* Cancel a search */
os_find_close(void * ctx0)872 void os_find_close(void *ctx0) {}
873
874 /* Character map loading */
os_advise_load_charmap(char * id,char * ldesc,char * sysinfo)875 void os_advise_load_charmap(char *id, char *ldesc, char *sysinfo) {}
876
877 /* TK I should be able to remove these eventually, when Glk is updated */
osfwb(osfildef * fp,unsigned char * buf,int bufl)878 int osfwb(osfildef *fp, unsigned char *buf, int bufl)
879 {
880 glk_put_buffer_stream(fp, buf, (glui32)bufl);
881 return FALSE;
882 }
osfseek(osfildef * fp,long pos,int mode)883 int osfseek(osfildef *fp, long pos, int mode)
884 {
885 glk_stream_set_position(fp, (glsi32)pos, mode);
886 return FALSE;
887 }
osfputs(char * buf,osfildef * fp)888 int osfputs(char *buf, osfildef *fp)
889 {
890 glk_put_string_stream(fp, buf);
891 return 1;
892 }
893