1 #ifdef RCSID
2 static char RCSid[] =
3 "$Header: d:/cvsroot/tads/TADS2/OSGEN.C,v 1.3 1999/07/11 00:46:30 MJRoberts Exp $";
4 #endif
5
6 /*
7 * Copyright (c) 1990, 2002 Michael J. Roberts. All Rights Reserved.
8 *
9 * Please see the accompanying license file, LICENSE.TXT, for information
10 * on using and copying this software.
11 */
12 /*
13 Name
14 osgen - Operating System dependent functions, general implementation
15 Function
16 This module contains certain OS-dependent functions that are common
17 between several systems. Routines in this file are selectively enabled
18 according to macros defined in os.h:
19
20 USE_STDIO - implement os_print, os_flush, os_gets with stdio functions
21 USE_DOSEXT - implement os_remext, os_defext using MSDOS-like filename
22 conventions
23 USE_NULLINIT - implement os_init and os_term as do-nothing routines
24 USE_NULLPAUSE - implement os_expause as a do-nothing routine
25 USE_EXPAUSE - use an os_expause that prints a 'strike any key' message
26 and calls os_waitc
27 USE_TIMERAND - implement os_rand using localtime() as a seed
28 USE_NULLSTAT - use a do-nothing os_status function
29 USE_NULLSCORE - use a do-nothing os_score function
30 RUNTIME - enable character-mode console implementation
31 USE_STATLINE - implement os_status and os_score using character-mode
32 status line implementation
33 USE_OVWCHK - implements default saved file overwrite check
34 USE_NULLSTYPE - use a dummy os_settype routine
35 USE_NULL_SET_TITLE - use an empty os_set_title() implementation
36
37 If USE_STDIO is defined, we'll implicitly define USE_STDIO_INPDLG.
38
39 If USE_STATLINE is defined, certain subroutines must be provided for
40 your platform that handle the character-mode console:
41 ossclr - clears a portion of the screen
42 ossdsp - displays text in a given color at a given location
43 ossscr - scroll down (i.e., moves a block of screen up)
44 ossscu - scroll up (i.e., moves a block of screen down)
45 ossloc - locate cursor
46
47 If USE_STATLINE is defined, certain sub-options can be enabled:
48 USE_SCROLLBACK - include output buffer capture in console system
49 USE_HISTORY - include command editing and history in console system
50 Notes
51
52 Modified
53 01/01/98 MJRoberts - moved certain osgen.c routines to osnoui.c
54 04/24/93 JEras - add os_locate() for locating tads-related files
55 04/12/92 MJRoberts - add os_strsc (string score) function
56 03/26/92 MJRoberts - add os_setcolor function
57 09/26/91 MJRoberts - os/2 user exit support
58 09/04/91 MJRoberts - stop reading resources if we find '$eof' resource
59 08/28/91 MJRoberts - debugger bug fix
60 08/01/91 MJRoberts - make runstat work correctly
61 07/30/91 MJRoberts - add debug active/inactive visual cue
62 05/23/91 MJRoberts - add user exit reader
63 04/08/91 MJRoberts - add full-screen debugging support
64 03/10/91 MJRoberts - integrate John's qa-scripter mods
65 11/27/90 MJRoberts - use time() not localtime() in os_rand; cast time_t
66 11/15/90 MJRoberts - created (split off from os.c)
67 */
68
69 #define OSGEN_INIT
70 # include "os.h"
71 #undef OSGEN_INIT
72
73 #include "osgen.h"
74
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include <stdarg.h>
79 #include <ctype.h>
80 #include <assert.h>
81
82 #include "run.h"
83
84 #if defined(TURBO) || defined(DJGPP)
85 #include "io.h"
86 #endif
87
88 #include "lib.h"
89 #include "tio.h"
90
91 /* global "plain mode" flag */
92 int os_f_plain = 0;
93
94 #ifdef RUNTIME
95 # ifdef USE_SCROLLBACK
96 int osssbmode();
97 void scrpgup();
98 void scrpgdn();
99 void scrlnup();
100 void scrlndn();
101 static void ossdosb();
102
103 /*
104 * Screen size variables. The underlying system-specific "oss" code must
105 * initialize these during startup and must keep them up-to-date if the
106 * screen size ever changes.
107 */
108 int G_oss_screen_width = 80;
109 int G_oss_screen_height = 24;
110
111 # endif /* USE_SCROLLBACK */
112 #endif /* RUNTIME */
113
114 /* forward declare the low-level display routine */
115 void ossdspn(int y, int x, int color, char *p);
116
117 /*
118 * The special character codes for controlling color.
119 */
120
121 /*
122 * Set text attributes: the next byte has the new text attributes value,
123 * with 1 added to it to ensure it's never zero. (A zero in the buffer has
124 * a special meaning, so we want to ensure we never have an incidental
125 * zero. Zero happens to be a valid attribute value, though, so we have to
126 * encode attributes to avoid this possibility. Our simple "plus one"
127 * encoding ensures we satisfy the never-equals-zero rule.)
128 */
129 #define OSGEN_ATTR 1
130
131 /*
132 * explicit colored text: this is followed by two bytes giving the
133 * foreground and background colors as OSGEN_COLOR_xxx codes
134 */
135 #define OSGEN_COLOR 2
136
137
138 /*
139 * If this port is to use the default saved file overwrite check, define
140 * USE_OVWCHK. This routine tries to open the file; if successful, the
141 * file is closed and we ask the user if they're sure they want to overwrite
142 * the file.
143 */
144 #ifdef USE_OVWCHK
os_chkovw(char * filename)145 int os_chkovw(char *filename)
146 {
147 FILE *fp;
148
149 if ((fp = fopen( filename, "r" )) != 0)
150 {
151 char buf[128];
152
153 fclose(fp);
154 os_printz("That file already exists. Overwrite it? (y/n) >");
155 os_gets((uchar *)buf, sizeof(buf));
156 if (buf[0] != 'y' && buf[0] != 'Y')
157 return 1;
158 }
159 return 0;
160 }
161 #endif /* USE_OVWCHK */
162
163 /*
164 * non-stop mode does nothing in character-mode implementations, since the
165 * portable console layer handles MORE mode
166 */
os_nonstop_mode(int flag)167 void os_nonstop_mode(int flag)
168 {
169 }
170
171 /* ------------------------------------------------------------------------ */
172 /*
173 * Ports can implement os_flush and os_gets as calls to the stdio routines
174 * of the same name, and os_printz and os_print using the stdio routine
175 * printf, by defining USE_STDIO. These definitions can be used for any
176 * port for which the standard C run-time library is available.
177 */
178
179 #ifdef USE_STDIO
180
181 /*
182 * print a null-terminated string the console
183 */
os_printz(const char * str)184 void os_printz(const char *str)
185 {
186 /* write the string to stdout */
187 fputs(str, stdout);
188 }
189
190 /*
191 * print a counted-length string, which isn't necessarily null-terminated
192 */
os_print(const char * str,size_t len)193 void os_print(const char *str, size_t len)
194 {
195 /* write the string to stdout, limiting the length */
196 printf("%.*s", (int)len, str);
197 }
198
199 /*
200 * os_flush forces output of anything buffered for standard output. It
201 * is generally used prior to waiting for a key (so the normal flushing
202 * may not occur, as it does when asking for a line of input).
203 */
os_flush(void)204 void os_flush(void)
205 {
206 fflush( stdout );
207 }
208
209 /*
210 * update the display - since we're using text mode, there's nothing we
211 * need to do
212 */
os_update_display(void)213 void os_update_display(void)
214 {
215 }
216
217 /*
218 * os_gets performs the same function as gets(). It should get a
219 * string from the keyboard, echoing it and allowing any editing
220 * appropriate to the system, and return the null-terminated string as
221 * the function's value. The closing newline should NOT be included in
222 * the string.
223 */
os_gets(uchar * s,size_t bufl)224 uchar *os_gets(uchar *s, size_t bufl)
225 {
226 return((uchar *)fgets((char *)s, bufl, stdin));
227 }
228
229 /*
230 * The default stdio implementation does not support reading a line of
231 * text with timeout.
232 */
os_gets_timeout(unsigned char * buf,size_t bufl,unsigned long timeout,int resume_editing)233 int os_gets_timeout(unsigned char *buf, size_t bufl,
234 unsigned long timeout, int resume_editing)
235 {
236 /* tell the caller this operation is not supported */
237 return OS_EVT_NOTIMEOUT;
238 }
239
240 /*
241 * since we don't support os_gets_timeout(), we don't need to do anything
242 * in the cancel routine
243 */
os_gets_cancel(int reset)244 void os_gets_cancel(int reset)
245 {
246 /* os_gets_timeout doesn't do anything, so neither do we */
247 }
248
249 /*
250 * Get an event - stdio version. This version does not accept a timeout
251 * value, and can only get a keystroke.
252 */
os_get_event(unsigned long timeout,int use_timeout,os_event_info_t * info)253 int os_get_event(unsigned long timeout, int use_timeout,
254 os_event_info_t *info)
255 {
256 /* if there's a timeout, return an error indicating we don't allow it */
257 if (use_timeout)
258 return OS_EVT_NOTIMEOUT;
259
260 /* get a key the normal way */
261 info->key[0] = os_getc();
262
263 /* if it's an extended key, get the other key */
264 if (info->key[0] == 0)
265 {
266 /* get the extended key code */
267 info->key[1] = os_getc();
268
269 /* if it's EOF, return an EOF event rather than a key event */
270 if (info->key[1] == CMD_EOF)
271 return OS_EVT_EOF;
272 }
273
274 /* return the keyboard event */
275 return OS_EVT_KEY;
276 }
277
278 #endif /* USE_STDIO */
279
280 /******************************************************************************
281 * Ports without any special initialization/termination requirements can define
282 * USE_NULLINIT to pick up the default definitions below. These do nothing, so
283 * ports requiring special handling at startup and/or shutdown time must define
284 * their own versions of these routines.
285 ******************************************************************************/
286
287 #ifdef USE_NULLINIT
288 /* os_init returns 0 for success, 1 for failure. The arguments are &argc, the
289 * address of the count of arguments to the program, and argv, the address of
290 * an array of up to 10 pointers to those arguments. For systems which don't
291 * pass a standard command line (such as the Mac Finder), the arguments should
292 * be read here using some alternate mechanism (an alert box, for instance),
293 * and the values of argc and argv[] updated accordingly. Note that a maximum
294 * of 10 arguments are allowed to be stored in the argv[] array. The command
295 * line itself can be stored in buf, which is a buffer passed by the caller
296 * guaranteed to be bufsiz bytes long.
297 *
298 * Unix conventions are followed, so argc is 1 when no arguments are present.
299 * The final argument is a prompt string which can be used to ask the user for
300 * a command line; its use is not required, but may be desirable for producing
301 * a relevant prompt message. See the Mac implementation for a detailed
302 * example of how this mechanism is used.
303 */
os_init(int * argc,char * argv[],const char * prompt,char * buf,int bufsiz)304 int os_init(int *argc, char *argv[], const char *prompt,
305 char *buf, int bufsiz)
306 {
307 return 0;
308 }
309
310 /*
311 * uninitialize
312 */
os_uninit(void)313 void os_uninit(void)
314 {
315 }
316
317 /*
318 * os_term should perform any necessary cleaning up, then terminate the
319 * program. The int argument is a return code to be passed to the
320 * caller, generally 0 for success and other for failure.
321 */
os_term(int rc)322 void os_term(int rc)
323 {
324 exit(rc);
325 }
326 #endif /* USE_NULLINIT */
327
328 /* ------------------------------------------------------------------------ */
329 /*
330 * Ports can define USE_NULLPAUSE if no pause is required on exit.
331 *
332 * Ports needing an exit pause, and can simply print a message (with
333 * os_print) and wait for a key (with os_getc) can define USE_EXPAUSE.
334 */
335
336 #ifdef USE_NULLPAUSE
os_expause(void)337 void os_expause(void)
338 {
339 /* does nothing */
340 }
341 #endif /* USE_NULLPAUSE */
342
343 #ifdef USE_EXPAUSE
os_expause(void)344 void os_expause(void)
345 {
346 os_printz("(Strike any key to exit...)");
347 os_flush();
348 os_waitc();
349 }
350 #endif /* USE_EXPAUSE */
351
352
353 #ifdef USE_NULLSTAT
354 /*
355 * USE_NULLSTAT defines a do-nothing version of os_status.
356 */
os_status(int stat)357 void os_status(int stat)
358 {
359 /* ignore the new status */
360 }
361
os_get_status()362 int os_get_status()
363 {
364 return 0;
365 }
366 #endif /* USE_NULLSTAT */
367
368 #ifdef USE_NULLSCORE
369 /*
370 * USE_NULLSCORE defines a do-nothing version of os_score.
371 */
os_score(int cur,int turncount)372 void os_score(int cur, int turncount)
373 {
374 /* ignore the score information */
375 }
376
os_strsc(const char * p)377 void os_strsc(const char *p)
378 {
379 /* ignore */
380 }
381 #endif /* USE_NULLSCORE */
382
383 #ifdef USE_STATLINE
384
385 /* saved main text area column when drawing in status line */
386 static osfar_t int S_statline_savecol;
387
388 /* saved text column when we're drawing in status line */
389 static osfar_t int text_lastcol;
390
391 /*
392 * first line of text area - the status line is always one line high, so
393 * this is always simply 1
394 */
395 static osfar_t int text_line = 1;
396
397 /* the column in the status line for the score part of the display */
398 static osfar_t int score_column = 0;
399
400 /*
401 * Define some macros in terms of "oss" globals that tell us the size of
402 * the screen.
403 *
404 * max_line is the maximum row number of the text area, as a zero-based row
405 * number. The text area goes from the second row (row 1) to the bottom of
406 * the screen, so this is simply the screen height minus one.
407 *
408 * max_column is the maximum column number of the text area, as a
409 * zero-based column number. The text area goes from the first column
410 * (column 0) to the rightmost column, so this is simply the screen width
411 * minus one.
412 *
413 * text_line and text_column are the starting row and column number of the
414 * text area. These are always row 1, column 0.
415 *
416 * sdesc_line and sdesc_column are the starting row and column of the
417 * status line. These are always row 0, column 0.
418 */
419 #define max_line ((G_oss_screen_height) - 1)
420 #define max_column ((G_oss_screen_width) - 1)
421 #define text_line 1
422 #define text_column 0
423 #define sdesc_line 0
424 #define sdesc_column 0
425
426 /*
427 * Status line buffer. Each time we display text to the status line,
428 * we'll keep track of the text here. This allows us to refresh the
429 * status line whenever we overwrite it (during scrollback mode, for
430 * example).
431 */
432 static osfar_t char S_statbuf[OS_MAXWIDTH + 1];
433
434 /* pointer to the next free character of the status line buffer */
435 static osfar_t char *S_statptr = S_statbuf;
436
437
438 /*
439 * The special run-time version displays a status line and the ldesc before
440 * each command line is read. To accomplish these functions, we need to
441 * redefine os_gets and os_print with our own special functions.
442 *
443 * Note that os_init may have to modify some of these values to suit, and
444 * should set up the screen appropriately.
445 */
os_status(int stat)446 void os_status(int stat)
447 {
448 /* if we're leaving the status line, restore the old main text column */
449 if (stat != status_mode && (status_mode == 1 || status_mode == 2))
450 {
451 /*
452 * we're leaving status-line (or post-status-line) mode - restore
453 * the main text column that was in effect before we drew the
454 * status line
455 */
456 text_lastcol = S_statline_savecol;
457 }
458
459 /* switch to the new mode */
460 status_mode = stat;
461
462 /* check the mode */
463 if (status_mode == 1)
464 {
465 /*
466 * we're entering the status line - start writing at the start
467 * of the status line
468 */
469 S_statptr = S_statbuf;
470
471 /*
472 * clear out any previously-saved status line text, since we're
473 * starting a new status line
474 */
475 *S_statptr = '\0';
476
477 /*
478 * remember the current text area display column so that we can
479 * restore it when we finish with the status line
480 */
481 S_statline_savecol = text_lastcol;
482 }
483 else if (status_mode == 2)
484 {
485 /*
486 * entering post-status-line mode - remember the text column so
487 * that we can restore it when we return to normal mode
488 */
489 S_statline_savecol = text_lastcol;
490 }
491 }
492
os_get_status()493 int os_get_status()
494 {
495 return status_mode;
496 }
497
498 /* Set score to a string value provided by the caller */
os_strsc(const char * p)499 void os_strsc(const char *p)
500 {
501 static osfar_t char lastbuf[135];
502 int i;
503 int x;
504
505 /* ignore score strings in plain mode, there's no status line */
506 if (os_f_plain)
507 return;
508
509 /* presume the score column will be ten spaces left of the right edge */
510 score_column = max_column - 10;
511
512 /* start out in the initial score column */
513 x = score_column;
514
515 /*
516 * if we have a string, save the new value; if the string pointer is
517 * null, it means that we should redraw the string with the previous
518 * value
519 */
520 if (p != 0)
521 strcpy(lastbuf, p);
522 else
523 p = lastbuf;
524
525 /* display enough spaces to right-justify the value */
526 for (i = strlen(p) ; i + score_column <= max_column ; ++i)
527 ossdsp(sdesc_line, x++, sdesc_color, " ");
528 if (x + strlen(p) > (size_t)max_column)
529 score_column = x = max_column - strlen(p);
530 ossdsp(sdesc_line, x, sdesc_color, p);
531 ossdsp(sdesc_line, max_column, sdesc_color, " ");
532 }
533
534 /*
535 * Set the score. If cur == -1, the LAST score set with a non-(-1)
536 * cur is displayed; this is used to refresh the status line without
537 * providing a new score (for example, after exiting scrollback mode).
538 * Otherwise, the given current score (cur) and turncount are displayed,
539 * and saved in case cur==-1 on the next call.
540 */
os_score(int cur,int turncount)541 void os_score(int cur, int turncount)
542 {
543 char buf[20];
544
545 /* check for the special -1 turn count */
546 if (turncount == -1)
547 {
548 /* it's turn "-1" - we're simply redrawing the score */
549 os_strsc((char *)0);
550 }
551 else
552 {
553 /* format the score */
554 sprintf(buf, "%d/%d", cur, turncount);
555
556 /* display the score string */
557 os_strsc(buf);
558 }
559 }
560
561
562 /* ------------------------------------------------------------------------ */
563 /*
564 * Scrollback
565 */
566 # ifdef USE_SCROLLBACK
567
568 /*
569 * Pointers for scrollback buffers.
570 *
571 * We store the text that has been displayed to the screen in a fixed
572 * buffer. We allocate out of the buffer circularly; when we reach the end
573 * of the buffer, we wrap around and allocate out of the beginning of the
574 * buffer, freeing old records as necessary to make space.
575 *
576 * 'scrbuf' is a pointer to the buffer. 'scrbuf_free' is a pointer to the
577 * next byte of the buffer available to be allocated.
578 */
579 static osfar_t char *scrbuf;
580 static osfar_t unsigned scrbufl;
581
582 /*
583 * Head/tail of linked list of scrollback lines. Lines are separated by
584 * null bytes. Note that 'scrbuf_tail' is a pointer to the START of the
585 * last line in the buffer (which is usually the line still under
586 * construction).
587 */
588 static char *scrbuf_head;
589 static char *scrbuf_tail;
590
591 /* allocation head */
592 static osfar_t char *scrbuf_free;
593
594 /* number of lines in scrollback buffer */
595 static osfar_t int os_line_count;
596
597 /* line number of top line on the screen */
598 static osfar_t int os_top_line;
599
600 /* current column in the scrollback buffer */
601 static osfar_t int sb_column;
602
603 /*
604 * Current screen color - this is the color to use for the blank areas of
605 * the screen. We use this to clear areas of the screen, to fill in blank
606 * areas left over after scrolling, and as the default background color to
607 * display for characters with a "transparent" background.
608 *
609 * Note that osssb_screen_color is an OSGEN_COLOR_xxx value, and
610 * osssb_oss_screen_color is the corresponding ossxxx color code for a
611 * character with that background color. We keep both values for
612 * efficiency.
613 */
614 static osfar_t int osssb_screen_color;
615 static osfar_t int osssb_oss_screen_color;
616
617 /* current color/attribute setting */
618 static osfar_t int osssb_cur_fg;
619 static osfar_t int osssb_cur_bg;
620 static osfar_t int osssb_cur_attrs;
621
622 /* color/attribute settings at start of current scrollback line */
623 static osfar_t int osssb_sol_fg;
624 static osfar_t int osssb_sol_bg;
625 static osfar_t int osssb_sol_attrs;
626
627 /*
628 * Receive notification of a screen size change.
629 */
osssb_on_resize_screen()630 void osssb_on_resize_screen()
631 {
632 /*
633 * Note the page length of the main text area - this is the distance
634 * between 'more' prompts. Use the screen height, minus one for the
635 * status line, minus two extra lines so we keep a line of context at
636 * the top of the screen while leaving a line for a "more" prompt at
637 * the bottom.
638 */
639 G_os_pagelength = (G_oss_screen_height > 3
640 ? G_oss_screen_height - 3
641 : G_oss_screen_height);
642
643 /* the main text area gets the full screen width */
644 G_os_linewidth = G_oss_screen_width;
645 }
646
647 /*
648 * Initialize the scrollback buffer - allocates memory for the buffer.
649 *
650 * Important: when this routine is called, the text_color global variable
651 * MUST be initialized to the ossdsp-style color code to use for the
652 * default text area.
653 */
osssbini(unsigned int size)654 void osssbini(unsigned int size)
655 {
656 /* calculate the page size and width based on the screen size */
657 osssb_on_resize_screen();
658
659 /* remember the size of the buffer */
660 scrbufl = size;
661
662 /* allocate the scrollback buffer */
663 if ((scrbuf = calloc(scrbufl, 1)) != 0)
664 {
665 /* set up the first and only (and thus last) line pointers */
666 scrbuf_head = scrbuf_tail = scrbuf;
667
668 /* set up the free pointer */
669 scrbuf_free = scrbuf;
670
671 /* we have one line in the buffer now */
672 os_line_count = 1;
673
674 /* start out in normal text color */
675 osssb_cur_fg = OSGEN_COLOR_TEXT;
676 osssb_cur_bg = OSGEN_COLOR_TRANSPARENT;
677 osssb_cur_attrs = 0;
678
679 /* the start of the scrollback buffer line is the same */
680 osssb_sol_fg = OSGEN_COLOR_TEXT;
681 osssb_sol_bg = OSGEN_COLOR_TRANSPARENT;
682 osssb_sol_attrs = 0;
683
684 /* set the base screen color to the normal text background color */
685 osssb_screen_color = OSGEN_COLOR_TEXTBG;
686 osssb_oss_screen_color = ossgetcolor(OSGEN_COLOR_TEXT,
687 OSGEN_COLOR_TEXTBG, 0, 0);
688 }
689 else
690 {
691 /* mention the problem */
692 os_printz("\nSorry, there is not enough memory available "
693 "for review mode.\n\n");
694
695 /* we have no line records */
696 scrbuf_head = 0;
697 scrbuf_tail = 0;
698 }
699
700 /* clear the status line area */
701 ossclr(sdesc_line, sdesc_column, sdesc_line, max_column, sdesc_color);
702 }
703
704 /*
705 * delete the scrollback buffer
706 */
osssbdel(void)707 void osssbdel(void)
708 {
709 /* free the screen buffer */
710 if (scrbuf != 0)
711 free(scrbuf);
712 }
713
714 /*
715 * advance to the next byte of the scrollback buffer
716 */
ossadvsp(char * p)717 static char *ossadvsp(char *p)
718 {
719 /* move to the next byte */
720 ++p;
721
722 /* if we've passed the end of the buffer, wrap to the beginning */
723 if (p >= scrbuf + scrbufl)
724 p = scrbuf;
725
726 /* return the pointer */
727 return p;
728 }
729
730 /*
731 * decrement to the previous byte of the buffer
732 */
ossdecsp(char * p)733 static char *ossdecsp(char *p)
734 {
735 /* if we're at the start of the buffer, wrap to just past the end */
736 if (p == scrbuf)
737 p = scrbuf + scrbufl;
738
739 /* move to the previous byte */
740 --p;
741
742 /* return the pointer */
743 return p;
744 }
745
746 /*
747 * Add a byte to the scrollback buffer
748 */
osssb_add_byte(char c)749 static void osssb_add_byte(char c)
750 {
751 /* add the character to the buffer */
752 *scrbuf_free = c;
753
754 /* advance the free pointer */
755 scrbuf_free = ossadvsp(scrbuf_free);
756
757 /*
758 * if the free pointer has just collided with the start of the oldest
759 * line, delete the oldest line
760 */
761 if (scrbuf_free == scrbuf_head)
762 {
763 /*
764 * delete the oldest line to make room for the new data, by
765 * advancing the head pointer to just after the next null byte
766 */
767 while (*scrbuf_head != '\0')
768 scrbuf_head = ossadvsp(scrbuf_head);
769
770 /* skip the null pointer that marks the end of the old first line */
771 scrbuf_head = ossadvsp(scrbuf_head);
772
773 /* note the loss of a line */
774 --os_line_count;
775 }
776 }
777
778 /*
779 * Add an appropriate color code to the scrollback buffer to yield the
780 * current color setting.
781 */
osssb_add_color_code()782 static void osssb_add_color_code()
783 {
784 /* if we have any attributes, add an attribute code */
785 if (osssb_cur_attrs != 0)
786 {
787 /*
788 * add the attribute, encoded with our plus-one rule (to avoid
789 * storing zero bytes as attribute arguments)
790 */
791 osssb_add_byte(OSGEN_ATTR);
792 osssb_add_byte((char)(osssb_cur_attrs + 1));
793 }
794
795 /* if we're using the plain text color, add a color code */
796 if (osssb_cur_fg != OSGEN_COLOR_TEXT
797 || osssb_cur_bg != OSGEN_COLOR_TRANSPARENT)
798 {
799 /* add the explicit color code */
800 osssb_add_byte(OSGEN_COLOR);
801 osssb_add_byte((char)osssb_cur_fg);
802 osssb_add_byte((char)osssb_cur_bg);
803 }
804 }
805
806 /*
807 * Scan a character, counting its contribution to the display column in the
808 * scrollback.
809 */
osssb_scan_char(char ** p,int * col)810 static void osssb_scan_char(char **p, int *col)
811 {
812 /* see what we have */
813 switch(**p)
814 {
815 case '\n':
816 case '\r':
817 case '\0':
818 /*
819 * these are all one-byte character sequences that don't contribute
820 * to the display column - simply skip the input byte
821 */
822 ++(*p);
823 break;
824
825 case OSGEN_ATTR:
826 /* this is a two-byte non-printing escape sequence */
827 *p += 2;
828 break;
829
830 case OSGEN_COLOR:
831 /* this is a three-byte non-printing escape sequence */
832 *p += 3;
833 break;
834
835 default:
836 /*
837 * anything else is a one-byte display character, so count its
838 * contribution to the display column and skip the byte
839 */
840 ++(*col);
841 ++(*p);
842 break;
843 }
844 }
845
846 /*
847 * Start a new line in the scrollback buffer
848 */
osssb_new_line()849 static void osssb_new_line()
850 {
851 /* add a null byte to mark the end of the current line */
852 osssb_add_byte(0);
853
854 /* remember the new final line - it starts at the free pointer */
855 scrbuf_tail = scrbuf_free;
856
857 /* count the added line */
858 ++os_line_count;
859
860 /* the new line starts at the first column */
861 sb_column = 0;
862
863 /* add a color code to the start of the new line, if necessary */
864 osssb_add_color_code();
865
866 /* remember the text color at the start of this line */
867 osssb_sol_fg = osssb_cur_fg;
868 osssb_sol_bg = osssb_cur_bg;
869 osssb_sol_attrs = osssb_cur_attrs;
870 }
871
872 /*
873 * Add text to the scrollback buffer. Returns the number of lines that the
874 * added text spans.
875 */
ossaddsb(const char * p,size_t len)876 static int ossaddsb(const char *p, size_t len)
877 {
878 int line_cnt;
879
880 /* if there's no scrollback buffer, ignore it */
881 if (scrbuf == 0)
882 return 0;
883
884 /* presume the text will all fit on one line */
885 line_cnt = 1;
886
887 /*
888 * Copy the text into the screen buffer, respecting the circular nature
889 * of the screen buffer. If the given text wraps lines, enter an
890 * explicit carriage return into the text to ensure that users can
891 * correctly count lines.
892 */
893 while(len != 0)
894 {
895 /* check for color control codes */
896 switch(*p)
897 {
898 case OSGEN_ATTR:
899 /*
900 * switch to the new attributes (decoding from the plus-one
901 * storage code)
902 */
903 osssb_cur_attrs = ((unsigned char)*(p+1)) - 1;
904 break;
905
906 case OSGEN_COLOR:
907 /* switch to the explicit colors */
908 osssb_cur_fg = (unsigned char)*(p+1);
909 osssb_cur_bg = (unsigned char)*(p+2);
910 break;
911 }
912
913 /* check for special characters */
914 switch(*p)
915 {
916 case '\n':
917 /* add the new line */
918 osssb_new_line();
919
920 /* skip this character */
921 ++p;
922 --len;
923
924 /* count the new line */
925 ++line_cnt;
926
927 /* done */
928 break;
929
930 case '\r':
931 /*
932 * We have a plain carriage return, which indicates that we
933 * should go back to the start of the current line and
934 * overwrite it. (This is most likely to occur for the
935 * "[More]" prompt.) Go back to the first column.
936 */
937 sb_column = 0;
938
939 /* set the free pointer back to the start of the current line */
940 scrbuf_free = scrbuf_tail;
941
942 /* switch back to the color as of the start of the line */
943 osssb_cur_fg = osssb_sol_fg;
944 osssb_cur_bg = osssb_sol_bg;
945 osssb_cur_attrs = osssb_sol_attrs;
946
947 /*
948 * since we're back at the start of the line, add a color code
949 * if necessary
950 */
951 osssb_add_color_code();
952
953 /* skip this character */
954 ++p;
955 --len;
956
957 /* done */
958 break;
959
960 case OSGEN_ATTR:
961 /* it's a two-byte attribute sequence - add the bytes */
962 osssb_add_byte(*p);
963 osssb_add_byte(*(p+1));
964
965 /* skip the sequence */
966 p += 2;
967 len -= 2;
968
969 /* done (since this doesn't print) */
970 break;
971
972 case OSGEN_COLOR:
973 /* it's a three-byte color sequence - add the bytes */
974 osssb_add_byte(*p);
975 osssb_add_byte(*(p+1));
976 osssb_add_byte(*(p+2));
977
978 /* skip the sequence */
979 p += 3;
980 len -= 3;
981
982 /*
983 * done (this doesn't print, so it has no effect on the column
984 * position or wrapping)
985 */
986 break;
987
988 default:
989 /* for anything else, simply store the byte in the buffer */
990 osssb_add_byte(*p);
991
992 /* skip the character */
993 ++p;
994 --len;
995
996 /* advance to the next column */
997 ++sb_column;
998
999 /* check for wrapping */
1000 if (sb_column > max_column)
1001 {
1002 /* start a new line */
1003 osssb_new_line();
1004
1005 /* count the new line */
1006 ++line_cnt;
1007 }
1008
1009 /* done */
1010 break;
1011 }
1012 }
1013
1014 /*
1015 * Always make sure we have a null terminator after each addition, in
1016 * case we need to look at the buffer before this line is finished.
1017 * However, since we're just tentatively writing the null terminator,
1018 * back up the free pointer to point to it after we write it, so that
1019 * the next character we write will go here.
1020 */
1021 osssb_add_byte(0);
1022 scrbuf_free = ossdecsp(scrbuf_free);
1023
1024 /* return the number of lines we added */
1025 return line_cnt;
1026 }
1027
1028 /*
1029 * A slight complication: if we're not on the very bottom line, and we
1030 * don't even have any text displayed on the bottom line (example: the
1031 * input line grew to over 80 characters, scrolling up a line, but shrunk
1032 * again due to deletions), we must add blank lines to fill out the unused
1033 * space, so that the scrollback line counter doesn't get confused (it
1034 * counts backwards from the bottom of the screen, where it assumes we are
1035 * right now). Figure out if the current buffer will go to the end of the
1036 * screen.
1037 *
1038 * This routine adds the given text to the screen buffer, then adds as many
1039 * blank lines as are necessary to fill the screen to the bottom line. buf
1040 * is the buffer to add; p is a pointer into the buffer corresponding to
1041 * screen position (x,y).
1042 */
ossaddsbe(char * buf,char * p,int x,int y)1043 static void ossaddsbe(char *buf, char *p, int x, int y)
1044 {
1045 int extra_lines;
1046 int actual_lines;
1047
1048 /*
1049 * compute the number of blank lines we need to add - we need one blank
1050 * line for each line on the screen beyond the display position
1051 */
1052 extra_lines = max_line - y;
1053
1054 /* add the text */
1055 actual_lines = ossaddsb(buf, strlen(buf));
1056
1057 /*
1058 * if we added more than one line already, those count against the
1059 * extra lines we need to add
1060 */
1061 extra_lines -= (actual_lines - 1);
1062
1063 /* add the extra blank lines */
1064 for ( ; extra_lines > 0 ; --extra_lines)
1065 osssb_new_line();
1066
1067 /* add a tentative null terminator */
1068 osssb_add_byte(0);
1069 scrbuf_free = ossdecsp(scrbuf_free);
1070 }
1071
1072 /*
1073 * Scrollback mode variables. These track the current position while
1074 * in scrollback mode.
1075 */
1076 char osfar_t *scrtop; /* first line displayed on the screen */
1077 static osfar_t char *scrbot; /* last line displayed on sreen */
1078 static osfar_t char *scrlast; /* first line of last screenful */
1079
1080 /*
1081 * scrdsp - display a line of text from the scrollback buffer on the
1082 * screen. It is the responsibility of the caller to ensure that the
1083 * line on the screen has been cleared beforehand.
1084 */
scrdsp(char * p,int y)1085 static void scrdsp(char *p, int y)
1086 {
1087 char buf[127];
1088 char *q = buf;
1089 int x = text_column;
1090 int fg;
1091 int bg;
1092 int attrs;
1093 int oss_color;
1094
1095 /* start out in normal text color */
1096 fg = OSGEN_COLOR_TEXT;
1097 bg = OSGEN_COLOR_TRANSPARENT;
1098 attrs = 0;
1099 oss_color = ossgetcolor(fg, bg, attrs, osssb_screen_color);
1100
1101 /* keep going until we reach the end of the line */
1102 while (*p != '\0')
1103 {
1104 /* check the character */
1105 switch(*p)
1106 {
1107 case OSGEN_ATTR:
1108 /* set the new attributes (decoding from the plus-one value) */
1109 attrs = (unsigned char)*(p = ossadvsp(p)) - 1;
1110
1111 /* handle it via the common color-switching code */
1112 goto change_color;
1113
1114 case OSGEN_COLOR:
1115 /* explicit color code - read the two extra bytes */
1116 fg = *(p = ossadvsp(p));
1117 bg = *(p = ossadvsp(p));
1118
1119 /* handle it via the common color-switching code */
1120 goto change_color;
1121
1122 change_color:
1123 /* null-terminate the buffer and display it in the old color */
1124 *q = '\0';
1125 ossdsp(y, x, oss_color, buf);
1126
1127 /* switch to the new color */
1128 oss_color = ossgetcolor(fg, bg, attrs, osssb_screen_color);
1129
1130 /* advance the column counter */
1131 x += strlen(buf);
1132
1133 /* go back to start of buffer */
1134 q = buf;
1135 break;
1136
1137 default:
1138 /* add this byte to our buffer */
1139 *q++ = *p;
1140 break;
1141 }
1142
1143 /* advance to next character no matter what happened */
1144 p = ossadvsp(p);
1145
1146 /* if the buffer's full, flush it */
1147 if (q == buf + sizeof(buf) - 1)
1148 {
1149 /* flush out the buffer */
1150 *q = '\0';
1151 ossdsp(y, x, oss_color, buf);
1152
1153 /* advance the column counter */
1154 x += strlen(buf);
1155
1156 /* go back to start of buffer */
1157 q = buf;
1158 }
1159 }
1160
1161 /* flush out what's left in the buffer */
1162 *q = '\0';
1163 ossdsp(y, x, oss_color, buf);
1164 }
1165
1166 /*
1167 * scrdspscr - display a screenful of text starting at a given location
1168 * in the scrollback buffer.
1169 */
scrdspscr(char * p)1170 static void scrdspscr(char *p)
1171 {
1172 int y;
1173
1174 /* clear the screen area of our display */
1175 ossclr(text_line, text_column, max_line, max_column,
1176 osssb_oss_screen_color);
1177
1178 /* display each line of this area */
1179 for (y = text_line ; y <= max_line ; ++y)
1180 {
1181 /* display this line */
1182 scrdsp(p, y);
1183
1184 /* if we just displayed the last line, we're done */
1185 if (p == scrbuf_tail)
1186 break;
1187
1188 /* advance to the next line */
1189 while (*p != '\0')
1190 p = ossadvsp(p);
1191
1192 /* skip the line separator */
1193 p = ossadvsp(p);
1194 }
1195 }
1196
1197 /*
1198 * Advance a buffer pointer until it's pointing to the start of the next
1199 * line. Returns true if we advanced the pointer, false if we were already
1200 * at the end of the buffer.
1201 */
osssb_next_line(char ** p)1202 static int osssb_next_line(char **p)
1203 {
1204 /* if we're at the last line already, there's nothing to do */
1205 if (*p == scrbuf_tail)
1206 return FALSE;
1207
1208 /* advance until we find the current line's terminating null byte */
1209 while (**p != '\0')
1210 *p = ossadvsp(*p);
1211
1212 /* skip the null byte */
1213 *p = ossadvsp(*p);
1214
1215 /* we did advance by a line */
1216 return TRUE;
1217 }
1218
1219 /*
1220 * Move a buffer pointer backward to the start of the current line.
1221 */
osssb_to_start(char * p)1222 static char *osssb_to_start(char *p)
1223 {
1224 /* keep going as long as we don't reach the start of the first line */
1225 while (p != scrbuf_head)
1226 {
1227 /* move back a byte */
1228 p = ossdecsp(p);
1229
1230 /* if it's a null byte, we've found the end of the previous line */
1231 if (*p == '\0')
1232 return ossadvsp(p);
1233 }
1234
1235 /*
1236 * return the pointer (which is at the start of the first line if we
1237 * got here)
1238 */
1239 return p;
1240 }
1241
1242 /*
1243 * Move a buffer pointer backward to the start of the previous line.
1244 * Returns true if we moved the pointer, false if we were already in the
1245 * first line.
1246 */
osssb_prev_line(char ** p)1247 static int osssb_prev_line(char **p)
1248 {
1249 /* first, make sure we're at the start of the current line */
1250 *p = osssb_to_start(*p);
1251
1252 /* if we're at the start of the first line, we can't go back */
1253 if (*p == scrbuf_head)
1254 return FALSE;
1255
1256 /* move back to the null byte at the end of the previous line */
1257 *p = ossdecsp(*p);
1258
1259 /* go back to the start of this line */
1260 *p = osssb_to_start(*p);
1261
1262 /* we moved the pointer */
1263 return TRUE;
1264 }
1265
1266 /*
1267 * move forward by a number of lines, and redisplays the sreen
1268 */
scrfwd(int n)1269 static void scrfwd(int n)
1270 {
1271 /* if we're already on the last screen, there's nothing to do */
1272 if (scrtop == scrlast)
1273 return;
1274
1275 /*
1276 * Move forward by the requested amount. Stop if we reach the top of
1277 * the bottom-most screen.
1278 */
1279 while (n != 0)
1280 {
1281 /* move to the next line at the bottom */
1282 if (!osssb_next_line(&scrbot))
1283 break;
1284
1285 /* move to the next line at the top as well */
1286 osssb_next_line(&scrtop);
1287
1288 /* update our display counter */
1289 ++os_top_line;
1290
1291 /* that's one less line to advance by */
1292 --n;
1293
1294 }
1295
1296 /* re-display the screen with the new top line */
1297 scrdspscr(scrtop);
1298 }
1299
1300 /*
1301 * move back by a number of lines, redisplaying the screen
1302 */
scrback(int n)1303 static void scrback(int n)
1304 {
1305 /* if we can't go back any further, we're done */
1306 if (scrtop == scrbuf_head)
1307 return;
1308
1309 /* keep going until we satisfy the request */
1310 while (n != 0 && scrtop != scrbuf_head)
1311 {
1312 /*
1313 * back up one line - if we can't (because we're already at the
1314 * first line), stop trying
1315 */
1316 if (!osssb_prev_line(&scrtop))
1317 break;
1318
1319 /* back up one at the bottom */
1320 osssb_prev_line(&scrbot);
1321
1322 /* that's one less to look for */
1323 --n;
1324
1325 /* adjust our line position */
1326 --os_top_line;
1327 }
1328
1329 /* redisplay the screen */
1330 scrdspscr(scrtop);
1331 }
1332
1333 /*
1334 * scrto moves to a selected line
1335 */
scrto(int lin)1336 void scrto(int lin)
1337 {
1338 if (lin > os_top_line)
1339 scrfwd(lin - os_top_line);
1340 else if (lin < os_top_line)
1341 scrback(os_top_line - lin);
1342 }
1343
1344 /*
1345 * scrpgup scrolls back a page
1346 */
scrpgup(void)1347 void scrpgup(void)
1348 {
1349 scrback(max_line - text_line);
1350 }
1351
1352 /*
1353 * scrpgdn scrolls forward a page
1354 */
scrpgdn(void)1355 void scrpgdn(void)
1356 {
1357 scrfwd(max_line - text_line);
1358 }
1359
1360 /*
1361 * scrlnup scrolls up one line
1362 */
scrlnup(void)1363 void scrlnup(void)
1364 {
1365 /* move the top pointer back a line */
1366 if (osssb_prev_line(&scrtop))
1367 {
1368 /* success - move the bottom pointer back a line as well */
1369 osssb_prev_line(&scrbot);
1370
1371 /* adjust our line counter */
1372 --os_top_line;
1373
1374 /* scroll the display area */
1375 ossscu(text_line, text_column, max_line, max_column,
1376 osssb_oss_screen_color);
1377
1378 /* redisplay the top line */
1379 scrdsp(scrtop, text_line);
1380 }
1381 }
1382
1383 /*
1384 * scrlndn scrolls down one line
1385 */
scrlndn(void)1386 void scrlndn(void)
1387 {
1388 /* if we're already at the last screenful, there's nothing to do */
1389 if (scrtop == scrlast)
1390 return;
1391
1392 /* move the bottom pointer up a line */
1393 if (osssb_next_line(&scrbot))
1394 {
1395 /* success - move the top pointer up a line as well */
1396 osssb_next_line(&scrtop);
1397
1398 /* adjust our line counter */
1399 ++os_top_line;
1400
1401 /* scroll the display area */
1402 ossscr(text_line, text_column, max_line, max_column,
1403 osssb_oss_screen_color);
1404
1405 /* redisplay the bottom line */
1406 scrdsp(scrbot, max_line);
1407 }
1408 }
1409
1410 /* redraw the screen's text region */
os_redraw(void)1411 void os_redraw(void)
1412 {
1413 int y;
1414 char *p;
1415
1416 /* clear the area */
1417 ossclr(text_line, text_column, max_line, max_column,
1418 osssb_oss_screen_color);
1419
1420 /* find the top line in the display area */
1421 p = scrbuf_tail;
1422 for (y = max_line ; y >= text_line ; --y)
1423 {
1424 /* display the current line at the current position */
1425 scrdsp(p, y);
1426
1427 /* move back a line if possible */
1428 if (!osssb_prev_line(&p))
1429 break;
1430 }
1431 }
1432
1433 /*
1434 * osssbmode toggles scrollback mode. Once in scrollback mode, calls
1435 * can be made to osssbup, osssbdn, osssbpgup, and osspgdn to scroll
1436 * through the saved text. We also put up a scrollback-mode version of
1437 * the status line, showing keys that should be used for scrollback.
1438 * When the user wants to exit scrollback mode, this routine should
1439 * be called again.
1440 *
1441 * Returns: 0 if scrollback mode is entered/exited successfully, 1 if
1442 * an error occurs. Note that it may not be possible to enter scrollback
1443 * mode, since insufficient saved text may have been accumulated.
1444 */
osssbmode(int mode_line)1445 int osssbmode(int mode_line)
1446 {
1447 /* if there's no buffer, we can't enter scrollback mode */
1448 if (scrbuf == 0)
1449 return 1;
1450
1451 /*
1452 * if we're not in scrollback mode, enter scrollback mode; otherwise,
1453 * return to normal mode
1454 */
1455 if (scrtop == 0)
1456 {
1457 int y;
1458 int i;
1459 char buf[135];
1460
1461 /*
1462 * Enter scrollback mode. Figure out what scrtop should be, and
1463 * put up the scrollback status line. If insufficient saved text
1464 * is around for scrollback mode, return 1.
1465 */
1466 for (os_top_line = os_line_count, scrtop = scrbuf_tail,
1467 y = max_line ; y > text_line ; --y, --os_top_line)
1468 {
1469 /* back up one line */
1470 if (!osssb_prev_line(&scrtop))
1471 {
1472 /* there wasn't enough text, so abort and return failure */
1473 scrtop = 0;
1474 return 1;
1475 }
1476 }
1477
1478 /*
1479 * if the top of the screen is the very first line in the buffer,
1480 * there's still not enough scrollback information
1481 */
1482 if (scrtop == scrbuf_head)
1483 {
1484 /* no point in scrollback when we have exactly one screen */
1485 scrtop = 0;
1486 return 1;
1487 }
1488
1489 /* remember where current screen starts and ends */
1490 scrlast = scrtop;
1491 scrbot = scrbuf_tail;
1492
1493 /* display instructions if we have a status line */
1494 if (mode_line)
1495 {
1496 strcpy(buf, OS_SBSTAT);
1497 for (i = strlen(buf) ; i < max_column ; buf[i++] = ' ') ;
1498 buf[i] = '\0';
1499 ossdsp(sdesc_line, sdesc_column+1, sdesc_color, buf);
1500 }
1501
1502 /* successfully entered scrollback mode */
1503 return 0;
1504 }
1505 else
1506 {
1507 /*
1508 * Exit scrollback mode. Show the last page of text, and put
1509 * up the normal status bar. Also clear our scrollback mode
1510 * variables.
1511 */
1512 if (scrlast != scrtop)
1513 scrdspscr(scrlast);
1514
1515 /* re-display the status line, if appropriate */
1516 if (mode_line)
1517 {
1518 /* display the last status line buffer */
1519 ossdspn(sdesc_line, sdesc_column, sdesc_color, " ");
1520 ossdspn(sdesc_line, sdesc_column + 1, sdesc_color, S_statbuf);
1521
1522 /*
1523 * refresh the right-hand side with the score part - do this
1524 * by drawing the score with a special turn counter of -1 to
1525 * indicate that we just want to refresh the previous score
1526 * value
1527 */
1528 os_score(-1, -1);
1529 }
1530 scrtop = 0;
1531 return( 0 );
1532 }
1533 }
1534
1535 /*
1536 * ossdosb runs a scrollback session. When entered, osssbmode()
1537 * must already have been called. When we're done, we'll be out
1538 * of scrollback mode.
1539 */
ossdosb(void)1540 static void ossdosb(void)
1541 {
1542 for ( ;; )
1543 {
1544 if (!os_getc())
1545 {
1546 switch(os_getc())
1547 {
1548 case CMD_SCR:
1549 case CMD_KILL: /* leave scrollback via 'escape' as well */
1550 case CMD_EOF: /* stop on end of file */
1551 osssbmode(1);
1552 return;
1553 case CMD_UP:
1554 scrlnup();
1555 break;
1556 case CMD_DOWN:
1557 scrlndn();
1558 break;
1559 case CMD_PGUP:
1560 scrpgup();
1561 break;
1562 case CMD_PGDN:
1563 scrpgdn();
1564 break;
1565 }
1566 }
1567 }
1568 }
1569
1570 # else /* USE_SCROLLBACK */
ossaddsb(char * p,size_t len)1571 static void ossaddsb(char *p, size_t len)
1572 {
1573 /* We're not saving output - do nothing */
1574 }
1575 # endif /* USE_SCROLLBACK */
1576
1577 /* display with no highlighting - intercept and ignore highlight codes */
ossdspn(int y,int x,int color,char * p)1578 void ossdspn(int y, int x, int color, char *p)
1579 {
1580 char *q;
1581 int esc_len;
1582
1583 /* scan the string */
1584 for (q = p ; *q ; ++q)
1585 {
1586 switch(*q)
1587 {
1588 case OSGEN_COLOR:
1589 /* three-byte escape sequence */
1590 esc_len = 3;
1591 goto skip_esc;
1592
1593 case OSGEN_ATTR:
1594 /* two-byte escape sequence */
1595 esc_len = 2;
1596 goto skip_esc;
1597
1598 skip_esc:
1599 /* end the buffer here and display what we have so far */
1600 *q = '\0';
1601 ossdsp(y, x, color, p);
1602
1603 /* adjust the column position for the display */
1604 x += strlen(p);
1605
1606 /* advance past what we've displayed plus the escape sequence */
1607 p = q + esc_len;
1608 break;
1609
1610 default:
1611 /* ordinary character - keep going */
1612 break;
1613 }
1614 }
1615
1616 /* display the remainder of the buffer, if there's anything left */
1617 if (q != p)
1618 ossdsp(y, x, color, p);
1619 }
1620
1621 /* display with highlighting enabled */
ossdsph(int y,int x,int color,char * p)1622 int ossdsph(int y, int x, int color, char *p)
1623 {
1624 char *q;
1625 int len;
1626 int esc_len;
1627
1628 /* get length of entire string */
1629 len = strlen(p);
1630
1631 /* scan the input string */
1632 for (q = p ; *q != '\0' ; ++q)
1633 {
1634 /* check for special escape codes */
1635 switch(*q)
1636 {
1637 case OSGEN_ATTR:
1638 /* set text attributes (decoding from the plus-one code) */
1639 osssb_cur_attrs = (unsigned char)*(q+1) - 1;
1640 esc_len = 2;
1641 goto change_color;
1642
1643 case OSGEN_COLOR:
1644 /* set explicit color */
1645 osssb_cur_fg = *(q+1);
1646 osssb_cur_bg = *(q+2);
1647 esc_len = 3;
1648 goto change_color;
1649
1650 change_color:
1651 /* display the part up to the escape code in the old color */
1652 *q = '\0';
1653 ossdsp(y, x, text_color, p);
1654
1655 /* adjust the column position for the display */
1656 x += strlen(p);
1657
1658 /* note the new text color */
1659 text_color = ossgetcolor(osssb_cur_fg, osssb_cur_bg,
1660 osssb_cur_attrs, osssb_screen_color);
1661
1662 /* move past the escape sequence */
1663 p = q + esc_len;
1664 q += esc_len - 1;
1665
1666 /* don't count the escape character in the length displayed */
1667 len -= esc_len;
1668 break;
1669
1670 default:
1671 break;
1672 }
1673 }
1674
1675 /* display the last portion of the line if anything's left */
1676 if (q != p)
1677 ossdsp(y, x, text_color, p);
1678
1679 /* return the length */
1680 return len;
1681 }
1682
1683 /*
1684 * Set the terminal into 'plain' mode: disables status line,
1685 * scrollback, command editing.
1686 */
os_plain(void)1687 void os_plain(void)
1688 {
1689 /* set the 'plain' mode flag */
1690 os_f_plain = 1;
1691 }
1692
os_printz(const char * str)1693 void os_printz(const char *str)
1694 {
1695 /* use our base counted-length routine */
1696 os_print(str, strlen(str));
1697 }
1698
os_print(const char * str,size_t len)1699 void os_print(const char *str, size_t len)
1700 {
1701 /*
1702 * save the output in the scrollback buffer if we're displaying to
1703 * the main text area (status_mode == 0) and we're not in plain
1704 * stdio mode (in which case there's no scrollback support)
1705 */
1706 if (status_mode == 0 && !os_f_plain)
1707 ossaddsb(str, len);
1708
1709 /* determine what to do based on the status mode */
1710 switch(status_mode)
1711 {
1712 case 2:
1713 /* we're in the post-status-line mode - suppress all output */
1714 break;
1715
1716 case 0:
1717 /* normal main text area mode */
1718 {
1719 const char *p;
1720 size_t rem;
1721 char *dst;
1722 char buf[128];
1723
1724 /* scan the buffer */
1725 for (p = str, rem = len, dst = buf ; ; ++p, --rem)
1726 {
1727 /*
1728 * if we're out of text, or the buffer is full, or we're at
1729 * a newline or carriage return, flush the buffer
1730 */
1731 if (rem == 0
1732 || dst == buf + sizeof(buf) - 2
1733 || *p == '\n' || *p == '\r')
1734 {
1735 /* write out the buffer */
1736 if (os_f_plain)
1737 {
1738 /* write the buffer, INCLUDING the LF/CR */
1739 if (*p == '\n' || *p == '\r')
1740 *dst++ = *p;
1741 *dst = '\0';
1742 fputs(buf, stdout);
1743 }
1744 else
1745 {
1746 size_t len;
1747
1748 /* display the buffer */
1749 *dst = '\0';
1750 len = ossdsph(max_line, text_lastcol,
1751 text_color, buf);
1752
1753 /* move the cursor right */
1754 text_lastcol += len;
1755
1756 /* scroll on a newline */
1757 if (*p == '\n')
1758 {
1759 /* scroll up a line */
1760 ossscr(text_line, text_column,
1761 max_line, max_column,
1762 osssb_oss_screen_color);
1763 }
1764
1765 /* move the cursor to the left column on LF/CR */
1766 if (*p == '\n' || *p == '\r')
1767 text_lastcol = text_column;
1768 }
1769
1770 /* reset the buffer */
1771 dst = buf;
1772
1773 /* if we're out of source text, we're done */
1774 if (rem == 0)
1775 break;
1776 }
1777
1778 /* see what we have */
1779 switch(*p)
1780 {
1781 case '\n':
1782 case '\r':
1783 /* don't buffer newlines/carriage returns */
1784 break;
1785
1786 default:
1787 /* buffer this character */
1788 *dst++ = *p;
1789 break;
1790 }
1791 }
1792
1793 /* put the cursor at the end of the text */
1794 if (status_mode == 0 && !os_f_plain)
1795 ossloc(max_line, text_lastcol);
1796 }
1797
1798 /* done */
1799 break;
1800
1801 case 1:
1802 /* status-line mode - ignore in 'plain' mode */
1803 if (!os_f_plain)
1804 {
1805 size_t rem;
1806 const char *p;
1807 int i;
1808
1809 /*
1810 * Skip leading newlines at the start of the statusline output.
1811 * Only do this if we don't already have anything buffered,
1812 * since a newline after some other text indicates the end of
1813 * the status line and thus can't be ignored.
1814 */
1815 p = str;
1816 rem = len;
1817 if (S_statptr == S_statbuf)
1818 {
1819 /* the buffer is empty, so skip leading newlines */
1820 for ( ; rem != 0 && *p == '\n' ; ++p, --rem) ;
1821 }
1822
1823 /*
1824 * Add this text to our private copy, so that we can refresh
1825 * the display later if necessary. If we reach a newline,
1826 * stop.
1827 */
1828 for ( ; (rem != 0 && *p != '\n'
1829 && S_statptr < S_statbuf + sizeof(S_statbuf)) ;
1830 ++p, --rem)
1831 {
1832 /* omit special characters from the status buffer */
1833 if (*p == OSGEN_ATTR)
1834 {
1835 /* skip an extra byte for the attribute code */
1836 ++p;
1837 continue;
1838 }
1839 else if (*p == OSGEN_COLOR)
1840 {
1841 /* skip two extra bytes for the color codes */
1842 p += 2;
1843 continue;
1844 }
1845
1846 /* copy this character */
1847 *S_statptr++ = *p;
1848 }
1849
1850 /* if we reached a newline, we're done with the status line */
1851 if (rem != 0 && *p == '\n')
1852 os_status(2);
1853
1854 /* add spaces up to the score location */
1855 for (i = S_statptr - S_statbuf ; i < score_column - 1 ; ++i)
1856 S_statbuf[i] = ' ';
1857
1858 /* null-terminate the buffer */
1859 S_statbuf[i] = '\0';
1860
1861 /* display a leading space */
1862 ossdspn(sdesc_line, sdesc_column, sdesc_color, " ");
1863
1864 /* display the string */
1865 ossdspn(sdesc_line, sdesc_column + 1, sdesc_color, S_statbuf);
1866 }
1867
1868 /* done */
1869 break;
1870 }
1871 }
1872
os_flush(void)1873 void os_flush(void)
1874 {
1875 /* we don't buffer our output, so there's nothing to do here */
1876 }
1877
os_update_display(void)1878 void os_update_display(void)
1879 {
1880 /* there's nothing we need to do */
1881 }
1882
1883 # ifdef USE_HISTORY
1884 /*
1885 * For command line history, we must have some buffer space to store
1886 * past command lines. We will use a circular buffer: when we move
1887 * the pointer past the end of the buffer, it wraps back to the start
1888 * of the buffer. A "tail" indicates the oldest line in the buffer;
1889 * when we need more room for new text, we advance the tail and thereby
1890 * lose the oldest text in the buffer.
1891 */
1892 static osfar_t unsigned char *histbuf = 0;
1893 static osfar_t unsigned char *histhead = 0;
1894 static osfar_t unsigned char *histtail = 0;
1895
1896 /*
1897 * ossadvhp advances a history pointer, and returns the new pointer.
1898 * This function takes the circular nature of the buffer into account
1899 * by wrapping back to the start of the buffer when it hits the end.
1900 */
ossadvhp(uchar * p)1901 uchar *ossadvhp(uchar *p)
1902 {
1903 if (++p >= histbuf + HISTBUFSIZE)
1904 p = histbuf;
1905 return p;
1906 }
1907
1908 /*
1909 * ossdechp decrements a history pointer, wrapping the pointer back
1910 * to the top of the buffer when it reaches the bottom.
1911 */
ossdechp(uchar * p)1912 uchar *ossdechp(uchar *p)
1913 {
1914 if (p == histbuf)
1915 p = histbuf + HISTBUFSIZE;
1916 return p - 1;
1917 }
1918
1919 /*
1920 * osshstcpy copies from a history buffer into a contiguous destination
1921 * buffer, wrapping the history pointer if need be. One null-terminated
1922 * string is copied.
1923 */
osshstcpy(uchar * dst,uchar * hst)1924 void osshstcpy(uchar *dst, uchar *hst)
1925 {
1926 while( *hst )
1927 {
1928 *dst++ = *hst;
1929 hst = ossadvhp( hst );
1930 }
1931 *dst = '\0';
1932 }
1933
1934 /*
1935 * ossprvcmd returns a pointer to the previous history command, given
1936 * a pointer to a history command. It returns a null pointer if the
1937 * given history command is the first in the buffer.
1938 */
ossprvcmd(uchar * hst)1939 uchar *ossprvcmd(uchar *hst)
1940 {
1941 if (hst == histtail)
1942 return 0; /* no more previous commands */
1943 hst = ossdechp( hst ); /* back onto nul */
1944 do
1945 {
1946 hst = ossdechp( hst ); /* back one character */
1947 } while (*hst && hst != histtail); /* go until previous command */
1948 if (*hst == 0)
1949 hst = ossadvhp(hst); /* step over null byte */
1950 return hst;
1951 }
1952
1953 /*
1954 * ossnxtcmd returns a pointer to the next history command, given
1955 * a pointer to a history command. It returns a null pointer if the
1956 * given command is already past the last command.
1957 */
ossnxtcmd(uchar * hst)1958 uchar *ossnxtcmd(uchar *hst)
1959 {
1960 if ( hst == histhead ) return( 0 ); /* past the last one already */
1961 while( *hst ) hst = ossadvhp( hst ); /* scan forward to null */
1962 hst = ossadvhp( hst ); /* scan past null onto new command */
1963 return( hst );
1964 }
1965 # endif /* USE_HISTORY */
1966
1967 /* ------------------------------------------------------------------------ */
1968 /*
1969 * Input buffer state. This information is defined statically because
1970 * os_gets_timeout() can carry the information from invocation to
1971 * invocation when input editing is interrupted by a tmieout.
1972 */
1973 static osfar_t char S_gets_internal_buf[256]; /* internal save buffer */
1974 static osfar_t char *S_gets_buf = S_gets_internal_buf; /* current save buf */
1975 static osfar_t size_t S_gets_buf_siz = sizeof(S_gets_internal_buf); /* size */
1976 static osfar_t int S_gets_ofs; /* offset in buffer of insertion point */
1977 static osfar_t unsigned char *S_gets_curhist; /* current history pointer */
1978 static osfar_t int S_gets_x, S_gets_y; /* saved cursor position */
1979
1980 # ifdef USE_HISTORY
1981 /* save buffer for line being edited before history recall began */
1982 static osfar_t char S_hist_sav_internal[256];
1983 static osfar_t char *S_hist_sav = S_hist_sav_internal;
1984 static osfar_t size_t S_hist_sav_siz = sizeof(S_hist_sav_internal);
1985 # endif /* USE_HISTORY */
1986
1987 /*
1988 * Flag: input is already in progress. When os_gets_timeout() returns
1989 * with OS_EVT_TIMEOUT, it sets this flag to true. os_gets_cancel() sets
1990 * this flag to false.
1991 *
1992 * When os_gets_timeout() is called again, it checks this flag to see if
1993 * the input session was cancelled; if not, the routine knows that the
1994 * partially-edited input line is already displayed where it left off,
1995 * because the display has not been modified since the interrupted call to
1996 * os_gets_timeout() returned.
1997 */
1998 static osfar_t int S_gets_in_progress = FALSE;
1999
2000 /* ------------------------------------------------------------------------ */
2001 /*
2002 * Display a string from the given character position. This does NOT
2003 * scroll the screen.
2004 */
ossdsp_str(int y,int x,int color,unsigned char * str,size_t len)2005 static void ossdsp_str(int y, int x, int color,
2006 unsigned char *str, size_t len)
2007 {
2008 /* keep going until we exhaust the string */
2009 while (len != 0)
2010 {
2011 size_t cur;
2012 unsigned char oldc;
2013
2014 /* display as much as will fit on the current line */
2015 cur = max_column - x + 1;
2016 if (cur > len)
2017 cur = len;
2018
2019 /* null-terminate the chunk, but save the original character */
2020 oldc = str[cur];
2021 str[cur] = '\0';
2022
2023 /* display this chunk */
2024 ossdsp(y, x, color, (char *)str);
2025
2026 /* restore the character where we put our null */
2027 str[cur] = oldc;
2028
2029 /* move our string counters past this chunk */
2030 str += cur;
2031 len -= cur;
2032
2033 /* advance the x position */
2034 x += cur;
2035 if (x > max_column)
2036 {
2037 x = 0;
2038 ++y;
2039 }
2040 }
2041 }
2042
2043 /*
2044 * Display a string from the given character position, scrolling the
2045 * screen if necessary.
2046 */
ossdsp_str_scr(int * y,int * x,int color,unsigned char * str,size_t len)2047 static void ossdsp_str_scr(int *y, int *x, int color,
2048 unsigned char *str, size_t len)
2049 {
2050 /* keep going until we exhaust the string */
2051 while (len != 0)
2052 {
2053 size_t cur;
2054 unsigned char oldc;
2055
2056 /* display as much as will fit on the current line */
2057 cur = max_column - *x + 1;
2058 if (cur > len)
2059 cur = len;
2060
2061 /* null-terminate the chunk, but save the original character */
2062 oldc = str[cur];
2063 str[cur] = '\0';
2064
2065 /* display this chunk */
2066 ossdsp(*y, *x, color, (char *)str);
2067
2068 /* restore the character where we put our null */
2069 str[cur] = oldc;
2070
2071 /* move our string counters past this chunk */
2072 str += cur;
2073 len -= cur;
2074
2075 /* advance the x position */
2076 *x += cur;
2077 if (*x > max_column)
2078 {
2079 /* reset to the first column */
2080 *x = 0;
2081
2082 /* scroll the screen if necessary */
2083 if (*y == max_line)
2084 ossscr(text_line, text_column,
2085 max_line, max_column, osssb_oss_screen_color);
2086 else
2087 ++*y;
2088 }
2089 }
2090 }
2091
2092 /*
2093 * Delete a character in the buffer, updating the display.
2094 */
oss_gets_delchar(unsigned char * buf,unsigned char * p,unsigned char ** eol,int x,int y)2095 static void oss_gets_delchar(unsigned char *buf, unsigned char *p,
2096 unsigned char **eol, int x, int y)
2097 {
2098 if (p < *eol)
2099 {
2100 /* delete the character and close the gap */
2101 --*eol;
2102 if (p != *eol)
2103 memmove(p, p + 1, *eol - p);
2104
2105 /*
2106 * replace the last character with a blank, so that we overwrite
2107 * its presence on the display
2108 */
2109 **eol = ' ';
2110
2111 /* re-display the changed part of the string */
2112 ossdsp_str(y, x, text_color, p, *eol - p + 1);
2113
2114 /* null-terminate the shortened buffer */
2115 **eol = '\0';
2116 }
2117 }
2118
2119 /*
2120 * Backspace in the buffer, updating the display and adjusting the cursor
2121 * position.
2122 */
oss_gets_backsp(unsigned char * buf,unsigned char ** p,unsigned char ** eol,int * x,int * y)2123 static void oss_gets_backsp(unsigned char *buf, unsigned char **p,
2124 unsigned char **eol, int *x, int *y)
2125 {
2126 /* if we can back up, do so */
2127 if (*p > buf)
2128 {
2129 /* move our insertion point back one position */
2130 --*p;
2131
2132 /* the line is now one character shorter */
2133 --*eol;
2134
2135 /* shift all of the characters down one position */
2136 if (*p != *eol)
2137 memmove(*p, *p + 1, *eol - *p);
2138
2139 /* move the cursor back, wrapping if at the first column */
2140 if (--*x < 0)
2141 {
2142 *x = max_column;
2143 --*y;
2144 }
2145
2146 /*
2147 * replace the trailing character with a space, so that we
2148 * overwrite its screen position with a blank
2149 */
2150 **eol = ' ';
2151
2152 /*
2153 * display the string from the current position, so that we update
2154 * the display for the moved characters
2155 */
2156 ossdsp_str(*y, *x, text_color, *p, *eol - *p + 1);
2157
2158 /* null-terminate the shortened buffer */
2159 **eol = '\0';
2160 }
2161 }
2162
2163 /*
2164 * Move the cursor left by the number of characters.
2165 */
oss_gets_csrleft(int * y,int * x,size_t len)2166 static void oss_gets_csrleft(int *y, int *x, size_t len)
2167 {
2168 for ( ; len != 0 ; --len)
2169 {
2170 /* move left one character, wrapping at the end of the line */
2171 if (--*x < 0)
2172 {
2173 /* move up a line */
2174 --*y;
2175
2176 /* move to the end of the line */
2177 *x = max_column;
2178 }
2179 }
2180 }
2181
2182 /*
2183 * Move the cursor right by the number of characters.
2184 */
oss_gets_csrright(int * y,int * x,size_t len)2185 static void oss_gets_csrright(int *y, int *x, size_t len)
2186 {
2187 for ( ; len != 0 ; --len)
2188 {
2189 /* move right one character, wrapping at the end of the line */
2190 if (++*x > max_column)
2191 {
2192 /* move down a line */
2193 ++*y;
2194
2195 /* move to the left column */
2196 *x = 0;
2197 }
2198 }
2199 }
2200
2201 /* ------------------------------------------------------------------------ */
2202 /*
2203 * cancel interrupted input
2204 */
os_gets_cancel(int reset)2205 void os_gets_cancel(int reset)
2206 {
2207 int x, y;
2208
2209 /*
2210 * if we interrupted a previous line, apply display effects as though
2211 * the user had pressed return
2212 */
2213 if (S_gets_in_progress)
2214 {
2215 /* move to the end of the input line */
2216 x = S_gets_x;
2217 y = S_gets_y;
2218 oss_gets_csrright(&y, &x, strlen(S_gets_buf + S_gets_ofs));
2219
2220 /* add a newline, scrolling if necessary */
2221 if (y == max_line)
2222 ossscr(text_line, text_column, max_line, max_column,
2223 osssb_oss_screen_color);
2224
2225 /* set the cursor to the new position */
2226 ossloc(y, x);
2227
2228 /* move to the left column for the next display */
2229 text_lastcol = 0;
2230
2231 /* copy the buffer to the screen save buffer, adding a newline */
2232 ossaddsbe(S_gets_buf, S_gets_buf + strlen(S_gets_buf), x, y);
2233 if (y == max_line)
2234 ossaddsb("\n", 1);
2235
2236 /* we no longer have an input in progress */
2237 S_gets_in_progress = FALSE;
2238 }
2239
2240 /* if we're resetting, clear our saved buffer */
2241 if (reset)
2242 S_gets_buf[0] = '\0';
2243 }
2244
2245 /* ------------------------------------------------------------------------ */
2246 /*
2247 * Common routine to read a command from the keyboard. This
2248 * implementation provides command editing and history, as well as timeout
2249 * capabilities.
2250 */
os_gets_timeout(unsigned char * buf,size_t bufl,unsigned long timeout,int use_timeout)2251 int os_gets_timeout(unsigned char *buf, size_t bufl,
2252 unsigned long timeout, int use_timeout)
2253 {
2254 unsigned char *p;
2255 unsigned char *eol;
2256 unsigned char *eob = buf + bufl - 1;
2257 int x;
2258 int y;
2259 int origx;
2260 long end_time;
2261
2262 /* if we're in 'plain' mode, simply use stdio input */
2263 if (os_f_plain)
2264 {
2265 size_t len;
2266
2267 /* we don't support the timeout feature in plain mode */
2268 if (use_timeout)
2269 return OS_EVT_NOTIMEOUT;
2270
2271 /*
2272 * get input from stdio, and translate the result code - if gets()
2273 * returns null, it indicates an error of some kind, so return an
2274 * end-of-file indication
2275 */
2276 if (fgets((char *)buf, bufl, stdin) == 0)
2277 return OS_EVT_EOF;
2278
2279 /* remove the trailing newline from the buffer, if present */
2280 if ((len = strlen((char *)buf)) != 0 && buf[len-1] == '\n')
2281 buf[len-1] = '\0';
2282
2283 /* indicate that we read a line */
2284 return OS_EVT_LINE;
2285 }
2286
2287 # ifdef USE_HISTORY
2288 /* allocate the history buffer if it's not already allocated */
2289 if (histbuf == 0)
2290 {
2291 histbuf = (unsigned char *)osmalloc(HISTBUFSIZE);
2292 histhead = histtail = histbuf;
2293 S_gets_curhist = histhead;
2294 }
2295 # endif /* USE_HISTORY */
2296
2297 /*
2298 * If we have a timeout, calculate the system clock time at which the
2299 * timeout expires. This is simply the current system clock time plus
2300 * the timeout interval. Since we might need to process a series of
2301 * events, we'll need to know how much time remains at each point we
2302 * get a new event.
2303 */
2304 end_time = os_get_sys_clock_ms() + timeout;
2305
2306 /* set up at the last output position, after the prompt */
2307 x = text_lastcol;
2308 y = max_line;
2309 origx = x;
2310
2311 /*
2312 * If we have saved input state from a previous interrupted call,
2313 * restore it now. Otherwise, initialize everything.
2314 */
2315 if (S_gets_buf[0] != '\0' || S_gets_in_progress)
2316 {
2317 size_t len;
2318
2319 /* limit the restoration length to the new buffer length */
2320 len = strlen((char *)buf);
2321 if (len > bufl - 1)
2322 len = bufl - 1;
2323
2324 /* copy the saved buffer to the caller's buffer */
2325 memcpy(buf, S_gets_buf, len);
2326
2327 /* set up our pointer to the end of the text */
2328 eol = buf + len;
2329
2330 /* null-terminate the text */
2331 *eol = '\0';
2332
2333 /*
2334 * if we cancelled the previous input, we must re-display the
2335 * buffer under construction, since we have displayed something
2336 * else in between and have re-displayed the prompt
2337 */
2338 if (!S_gets_in_progress)
2339 {
2340 /* re-display the buffer */
2341 ossdsp_str_scr(&y, &x, text_color, buf, len);
2342
2343 /*
2344 * move back to the original insertion point, limiting the
2345 * move to the available buffer size for the new caller
2346 */
2347 if (S_gets_ofs < (int)len)
2348 oss_gets_csrleft(&y, &x, len - S_gets_ofs);
2349 else
2350 S_gets_ofs = len;
2351 }
2352 else
2353 {
2354 /*
2355 * input is still in progress, so the old text is still on the
2356 * screen - simply move to the original cursor position
2357 */
2358 x = S_gets_x;
2359 y = S_gets_y;
2360 }
2361
2362 /* get our pointer into the buffer */
2363 p = buf + S_gets_ofs;
2364 }
2365 else
2366 {
2367 /* set up our buffer pointers */
2368 p = buf;
2369 eol = buf;
2370
2371 /* initialize our history recall pointer */
2372 S_gets_curhist = histhead;
2373
2374 /* clear out the buffer */
2375 buf[0] = '\0';
2376 }
2377
2378 /* process keystrokes until we're done entering the command */
2379 for ( ;; )
2380 {
2381 unsigned char c;
2382 os_event_info_t event_info;
2383 int event_type;
2384
2385 /* move to the proper position on the screen */
2386 ossloc(y, x);
2387
2388 /* if we're using a timeout, check for expiration */
2389 if (use_timeout)
2390 {
2391 long cur_clock;
2392
2393 /* note the current system clock time */
2394 cur_clock = os_get_sys_clock_ms();
2395
2396 /*
2397 * if we're past the timeout expiration time already,
2398 * interrupt with timeout now
2399 */
2400 if (cur_clock >= end_time)
2401 goto timeout_expired;
2402
2403 /* note the interval remaining to the timeout expiration */
2404 timeout = end_time - cur_clock;
2405 }
2406
2407 /* get an event */
2408 event_type = os_get_event(timeout, use_timeout, &event_info);
2409
2410 /* handle the event according to the event type */
2411 switch(event_type)
2412 {
2413 case OS_EVT_KEY:
2414 /*
2415 * Keystroke event. First, translate the key from the "raw"
2416 * keystroke that os_get_event() returns to the "processed"
2417 * (CMD_xxx) representation. This lets the oss layer map
2418 * special keystrokes to generic editing commands in a
2419 * system-specific manner.
2420 */
2421 oss_raw_key_to_cmd(&event_info);
2422
2423 /* get the primary character from the event */
2424 c = event_info.key[0];
2425 break;
2426
2427 case OS_EVT_TIMEOUT:
2428 timeout_expired:
2429 /*
2430 * The timeout expired. Copy the current input state into the
2431 * save area so that we can resume the input later if desired.
2432 */
2433 strcpy(S_gets_buf, (char *)buf);
2434 S_gets_ofs = p - buf;
2435 S_gets_x = x;
2436 S_gets_y = y;
2437
2438 /* note that input was interrupted */
2439 S_gets_in_progress = TRUE;
2440
2441 /* return the timeout status to the caller */
2442 return OS_EVT_TIMEOUT;
2443
2444 case OS_EVT_NOTIMEOUT:
2445 /*
2446 * we can't handle events with timeouts, so we can't provide
2447 * line reading with timeouts, either
2448 */
2449 return OS_EVT_NOTIMEOUT;
2450
2451 case OS_EVT_EOF:
2452 /* end of file - return the same error to our caller */
2453 return OS_EVT_EOF;
2454
2455 default:
2456 /* ignore any other events */
2457 continue;
2458 }
2459
2460 /*
2461 * Check the character we got. Note that we must interpret
2462 * certain control characters explicitly, because os_get_event()
2463 * returns raw keycodes (untranslated into CMD_xxx codes) for
2464 * control characters.
2465 */
2466 switch(c)
2467 {
2468 case 8:
2469 /* backspace one character */
2470 oss_gets_backsp(buf, &p, &eol, &x, &y);
2471 break;
2472
2473 case 13:
2474 /* null-terminate the input */
2475 *eol = '\0';
2476
2477 /* move to the end of the line */
2478 oss_gets_csrright(&y, &x, eol - p);
2479 p = eol;
2480
2481 /*
2482 * Scroll the screen to account for the carriage return,
2483 * position the cursor at the end of the new line, and
2484 * null-terminate the line.
2485 */
2486 ossloc(y, x);
2487 if (y == max_line)
2488 ossscr(text_line, text_column, max_line, max_column,
2489 osssb_oss_screen_color);
2490
2491 /* move to the left column for the next display */
2492 text_lastcol = 0;
2493
2494 # ifdef USE_HISTORY
2495 /*
2496 * Save the line in our history buffer. If we don't have
2497 * enough room, lose some old text by advancing the tail
2498 * pointer far enough. Don't save it if it's a blank line,
2499 * though, or if it duplicates the most recent previous
2500 * command.
2501 */
2502 if (strlen((char *)buf) != 0)
2503 {
2504 uchar *q;
2505 int advtail;
2506 int saveflag = 1; /* assume we will be saving it */
2507
2508 if (q = ossprvcmd(histhead))
2509 {
2510 uchar *p = buf;
2511
2512 while (*p == *q && *p != '\0' && *q != '\0')
2513 {
2514 ++p;
2515 q = ossadvhp(q);
2516 }
2517 if (*p == *q) /* is this a duplicate command? */
2518 saveflag = 0; /* if so, don't save it */
2519 }
2520
2521 if (saveflag)
2522 {
2523 for (q = buf, advtail = 0 ; q <= eol ; ++q)
2524 {
2525 *histhead = *q;
2526 histhead = ossadvhp(histhead);
2527 if (histhead == histtail)
2528 {
2529 histtail = ossadvhp(histtail);
2530 advtail = 1;
2531 }
2532 }
2533
2534 /*
2535 * If we have encroached on space that was already
2536 * occupied, throw away the entire command we have
2537 * partially trashed; to do so, advance the tail
2538 * pointer to the next null byte.
2539 */
2540 if (advtail)
2541 {
2542 while(*histtail)
2543 histtail = ossadvhp(histtail);
2544 histtail = ossadvhp(histtail);
2545 }
2546 }
2547 }
2548 # endif /* USE_HISTORY */
2549
2550 /*
2551 * Finally, copy the buffer to the screen save buffer (if
2552 * applicable), and return the contents of the buffer. Note
2553 * that we add an extra carriage return if we were already
2554 * on the max_line, since we scrolled the screen in this
2555 * case; otherwise, ossaddsbe will add all the blank lines
2556 * that are necessary.
2557 */
2558 ossaddsbe((char *)buf, (char *)p, x, y);
2559 if (y == max_line)
2560 ossaddsb("\n", 1);
2561
2562 /* input is no longer in progress */
2563 S_gets_in_progress = FALSE;
2564 S_gets_buf[0] = '\0';
2565
2566 /* return success */
2567 return OS_EVT_LINE;
2568
2569 case 0:
2570 /* extended key code - get the second half of the code */
2571 c = event_info.key[1];
2572
2573 /* handle the command key code */
2574 switch(c)
2575 {
2576 # ifdef USE_SCROLLBACK
2577 case CMD_SCR:
2578 {
2579 char *old_scrbuf_free;
2580
2581 /*
2582 * Add the contents of the line buffer, plus any blank
2583 * lines, to the screen buffer, filling the screen to
2584 * the bottom. Before we do, though, save the current
2585 * scrollback buffer free pointer, so we can take our
2586 * buffer back out of the scrollback buffer when we're
2587 * done - this is just temporary so that the current
2588 * command shows up in the buffer while we're in
2589 * scrollback mode and is redrawn when we're done.
2590 */
2591 old_scrbuf_free = scrbuf_free;
2592 ossaddsbe((char *)buf, (char *)p, x, y);
2593
2594 /* run scrollback mode */
2595 if (!osssbmode(1))
2596 ossdosb();
2597
2598 /* restore the old free pointer */
2599 scrbuf_free = old_scrbuf_free;
2600 *scrbuf_free = '\0';
2601
2602 /* go back to our original column */
2603 sb_column = origx;
2604 break;
2605 }
2606 # endif /* USE_SCROLLBACK */
2607
2608 case CMD_LEFT:
2609 if (p > buf)
2610 {
2611 --p;
2612 --x;
2613 if (x < 0)
2614 {
2615 x = max_column;
2616 --y;
2617 }
2618 }
2619 break;
2620
2621 case CMD_WORD_LEFT:
2622 if (p > buf)
2623 {
2624 --p;
2625 --x;
2626 if (x < 0)
2627 x = max_column, --y;
2628 while (p > buf && t_isspace(*p))
2629 {
2630 --p, --x;
2631 if (x < 0)
2632 x = max_column, --y;
2633 }
2634 while (p > buf && !t_isspace(*(p-1)))
2635 {
2636 --p, --x;
2637 if (x < 0)
2638 x = max_column, --y;
2639 }
2640 }
2641 break;
2642
2643 case CMD_RIGHT:
2644 if (p < eol)
2645 {
2646 ++p;
2647 ++x;
2648 if (x > max_column)
2649 {
2650 x = 0;
2651 ++y;
2652 }
2653 }
2654 break;
2655
2656 case CMD_WORD_RIGHT:
2657 while (p < eol && !t_isspace(*p))
2658 {
2659 ++p, ++x;
2660 if (x > max_column)
2661 x = 0, ++y;
2662 }
2663 while (p < eol && t_isspace(*p))
2664 {
2665 ++p, ++x;
2666 if (x > max_column)
2667 x = 0, ++y;
2668 }
2669 break;
2670
2671 case CMD_DEL:
2672 /* delete a character */
2673 oss_gets_delchar(buf, p, &eol, x, y);
2674 break;
2675
2676 #ifdef UNIX
2677 case CMD_WORDKILL:
2678 {
2679 /* remove spaces preceding word */
2680 while (p >= buf && *p <= ' ')
2681 oss_gets_backsp(buf, &p, &eol, &x, &y);
2682
2683 /* remove previous word (i.e., until we get a space) */
2684 while (p >= buf && *p > ' ')
2685 oss_gets_backsp(buf, &p, &eol, &x, &y);
2686
2687 /* that's it */
2688 break;
2689 }
2690 #endif /* UNIX */
2691
2692 case CMD_KILL:
2693 case CMD_HOME:
2694 # ifdef USE_HISTORY
2695 case CMD_UP:
2696 case CMD_DOWN:
2697 if (c == CMD_UP && !ossprvcmd(S_gets_curhist))
2698 break; /* no more history - ignore arrow */
2699 if (c == CMD_DOWN && !ossnxtcmd(S_gets_curhist))
2700 break; /* no more history - ignore arrow */
2701 if (c == CMD_UP && !ossnxtcmd(S_gets_curhist))
2702 {
2703 /* first Up arrow - save current buffer */
2704 strcpy(S_hist_sav, (char *)buf);
2705 }
2706 # endif /* USE_HISTORY */
2707 while(p > buf)
2708 {
2709 --p;
2710 if (--x < 0)
2711 {
2712 x = max_column;
2713 --y;
2714 }
2715 }
2716 if (c == CMD_HOME)
2717 break;
2718
2719 /*
2720 * We're at the start of the line now; fall through for
2721 * KILL, UP, and DOWN to the code which deletes to the
2722 * end of the line.
2723 */
2724 case CMD_DEOL:
2725 if (p < eol)
2726 {
2727 /*
2728 * write spaces to the end of the line, to clear out
2729 * the screen display of the old characters
2730 */
2731 if (p != eol)
2732 {
2733 memset(p, ' ', eol - p);
2734 ossdsp_str(y, x, text_color, p, eol - p);
2735 }
2736
2737 /* truncate the buffer at the insertion point */
2738 eol = p;
2739 *p = '\0';
2740 }
2741 # ifdef USE_HISTORY
2742 if (c == CMD_UP)
2743 {
2744 S_gets_curhist = ossprvcmd(S_gets_curhist);
2745 osshstcpy(buf, S_gets_curhist);
2746 }
2747 else if (c == CMD_DOWN)
2748 {
2749 if (!ossnxtcmd(S_gets_curhist))
2750 break; /* no more */
2751 S_gets_curhist = ossnxtcmd(S_gets_curhist);
2752 if (ossnxtcmd(S_gets_curhist)) /* on a valid command */
2753 osshstcpy(buf, S_gets_curhist); /* ... so use it */
2754 else
2755 {
2756 /* no more history - restore original line */
2757 strcpy((char *)buf, S_hist_sav);
2758 }
2759 }
2760 if ((c == CMD_UP || c == CMD_DOWN)
2761 && strlen((char *)buf) != 0)
2762 {
2763 /* get the end pointer based on null termination */
2764 eol = buf + strlen((char *)buf);
2765
2766 /* display the string */
2767 ossdsp_str_scr(&y, &x, text_color, p, eol - p);
2768
2769 /* move to the end of the line */
2770 p = eol;
2771 }
2772 # endif /* USE_HISTORY */
2773 break;
2774 case CMD_END:
2775 while (p < eol)
2776 {
2777 ++p;
2778 if (++x > max_column)
2779 {
2780 x = 0;
2781 ++y;
2782 }
2783 }
2784 break;
2785
2786 case CMD_EOF:
2787 /* on end of file, return null */
2788 return OS_EVT_EOF;
2789 }
2790 break;
2791
2792 default:
2793 if (c >= ' ' && eol < eob)
2794 {
2795 /* open up the line and insert the character */
2796 if (p != eol)
2797 memmove(p + 1, p, eol - p);
2798 ++eol;
2799 *p = c;
2800 *eol = '\0';
2801
2802 /* write the updated part of the line */
2803 ossdsp_str_scr(&y, &x, text_color, p, eol - p);
2804
2805 /* move the cursor back to the insertion point */
2806 ++p;
2807 oss_gets_csrleft(&y, &x, eol - p);
2808 }
2809 break;
2810 }
2811 }
2812 }
2813
2814 /*
2815 * Read a line of input. We implement this in terms of the timeout input
2816 * line reader, passing an infinite timeout to that routine.
2817 */
os_gets(unsigned char * buf,size_t bufl)2818 uchar *os_gets(unsigned char *buf, size_t bufl)
2819 {
2820 int evt;
2821
2822 /* cancel any previous input, clearing the buffer */
2823 os_gets_cancel(TRUE);
2824
2825 /* get a line of input, with no timeout */
2826 evt = os_gets_timeout(buf, bufl, 0, FALSE);
2827
2828 /* translate the event code to the appropriate return value */
2829 switch(evt)
2830 {
2831 case OS_EVT_LINE:
2832 /* we got a line of input - return a pointer to our buffer */
2833 return buf;
2834
2835 case OS_EVT_EOF:
2836 /* end of file - return null */
2837 return 0;
2838
2839 default:
2840 /* we don't expect any other results */
2841 assert(FALSE);
2842 return 0;
2843 }
2844 }
2845
2846 #else /* USE_STATLINE */
2847
2848 #endif /* USE_STATLINE */
2849
2850 /* ------------------------------------------------------------------------ */
2851 /*
2852 * Highlighting and colors
2853 */
2854
2855 #ifdef STD_OS_HILITE
2856
2857 #ifdef RUNTIME
2858 /*
2859 * Set text attributes
2860 */
os_set_text_attr(int attr)2861 void os_set_text_attr(int attr)
2862 {
2863 char buf[3];
2864
2865 /* if we're in plain mode, ignore it */
2866 if (os_f_plain)
2867 return;
2868
2869 /* if the attributes aren't changing, do nothing */
2870 if (osssb_cur_attrs == attr)
2871 return;
2872
2873 /*
2874 * add the attribute sequence to the scrollback buffer (encoding with
2875 * our plus-one code, to avoid storing null bytes)
2876 */
2877 buf[0] = OSGEN_ATTR;
2878 buf[1] = (char)(attr + 1);
2879 buf[2] = '\0';
2880 ossaddsb(buf, 2);
2881
2882 /* translate the codes to an internal ossdsp color */
2883 text_color = ossgetcolor(osssb_cur_fg, osssb_cur_bg, attr,
2884 osssb_screen_color);
2885 }
2886
2887 /*
2888 * Translate a color from the os_color_t encoding to an OSGEN_xxx color.
2889 */
osgen_xlat_color_t(os_color_t color)2890 static char osgen_xlat_color_t(os_color_t color)
2891 {
2892 size_t i;
2893 struct color_map_t
2894 {
2895 /* the OSGEN_COLOR_xxx value */
2896 char id;
2897
2898 /* the RGB components for the color */
2899 unsigned char rgb[3];
2900 };
2901 struct color_map_t *p;
2902 struct color_map_t *bestp;
2903 static struct color_map_t color_map[] =
2904 {
2905 { OSGEN_COLOR_BLACK, { 0x00, 0x00, 0x00 } },
2906 { OSGEN_COLOR_WHITE, { 0xFF, 0xFF, 0xFF } },
2907 { OSGEN_COLOR_RED, { 0xFF, 0x00, 0x00 } },
2908 { OSGEN_COLOR_BLUE, { 0x00, 0x00, 0xFF } },
2909 { OSGEN_COLOR_GREEN, { 0x00, 0x80, 0x00 } },
2910 { OSGEN_COLOR_YELLOW, { 0xFF, 0xFF, 0x00 } },
2911 { OSGEN_COLOR_CYAN, { 0x00, 0xFF, 0xFF } },
2912 { OSGEN_COLOR_SILVER, { 0xC0, 0xC0, 0xC0 } },
2913 { OSGEN_COLOR_GRAY, { 0x80, 0x80, 0x80 } },
2914 { OSGEN_COLOR_MAROON, { 0x80, 0x00, 0x00 } },
2915 { OSGEN_COLOR_PURPLE, { 0x80, 0x00, 0x80 } },
2916 { OSGEN_COLOR_MAGENTA, { 0xFF, 0x00, 0xFF } },
2917 { OSGEN_COLOR_LIME, { 0x00, 0xFF, 0x00 } },
2918 { OSGEN_COLOR_OLIVE, { 0x80, 0x80, 0x00 } },
2919 { OSGEN_COLOR_NAVY, { 0x00, 0x00, 0x80 } },
2920 { OSGEN_COLOR_TEAL, { 0x00, 0x80, 0x80 } }
2921 };
2922 unsigned char r, g, b;
2923 unsigned long best_dist;
2924
2925 /*
2926 * If it's parameterized, map it by shifting the parameter code (in
2927 * the high-order 8 bits of the os_color_t) to our single-byte code,
2928 * which is defined as exactly the same code as the os_color_t values
2929 * but shifted into the low-order 8 bits.
2930 */
2931 if (os_color_is_param(color))
2932 return (char)((color >> 24) & 0xFF);
2933
2934 /* break the color into its components */
2935 r = os_color_get_r(color);
2936 g = os_color_get_g(color);
2937 b = os_color_get_b(color);
2938
2939 /* search for the closest match among our 16 ANSI colors */
2940 for (i = 0, p = color_map, bestp = 0, best_dist = 0xFFFFFFFF ;
2941 i < sizeof(color_map)/sizeof(color_map[0]) ; ++i, ++p)
2942 {
2943 unsigned long dist;
2944 int rd, gd, bd;
2945
2946 /* calculate the delta for each component */
2947 rd = r - p->rgb[0];
2948 gd = g - p->rgb[1];
2949 bd = b - p->rgb[2];
2950
2951 /* calculate the "distance" in RGB space */
2952 dist = rd*rd + gd*gd + bd*bd;
2953
2954 /* if it's an exact match, we need look no further */
2955 if (dist == 0)
2956 return p->id;
2957
2958 /* if it's the smallest distance so far, note it */
2959 if (dist < best_dist)
2960 {
2961 best_dist = dist;
2962 bestp = p;
2963 }
2964 }
2965
2966 /* return the OSGEN_COLOR_xxx ID of the best match we found */
2967 return bestp->id;
2968 }
2969
2970 /*
2971 * Set the text colors.
2972 *
2973 * The foreground and background colors apply to subsequent characters
2974 * displayed via os_print() (etc). If the background color is set to zero,
2975 * it indicates "transparent" drawing: subsequent text is displayed with
2976 * the "screen" color.
2977 */
os_set_text_color(os_color_t fg,os_color_t bg)2978 void os_set_text_color(os_color_t fg, os_color_t bg)
2979 {
2980 char buf[4];
2981
2982 /* if we're in plain mode, ignore it */
2983 if (os_f_plain)
2984 return;
2985
2986 /* add the color sequence to the scrollback buffer */
2987 buf[0] = OSGEN_COLOR;
2988 buf[1] = osgen_xlat_color_t(fg);
2989 buf[2] = osgen_xlat_color_t(bg);
2990 buf[3] = '\0';
2991 ossaddsb(buf, 3);
2992
2993 /* translate the codes to an internal ossdsp color */
2994 text_color = ossgetcolor(fg, bg, osssb_cur_attrs, osssb_screen_color);
2995 }
2996
2997 /*
2998 * Set the screen color
2999 */
os_set_screen_color(os_color_t color)3000 void os_set_screen_color(os_color_t color)
3001 {
3002 /* if we're in plain mode, ignore it */
3003 if (os_f_plain)
3004 return;
3005
3006 /* set the new background color */
3007 osssb_screen_color = color;
3008 osssb_oss_screen_color = ossgetcolor(OSGEN_COLOR_TEXT,
3009 osgen_xlat_color_t(color), 0, 0);
3010
3011 /*
3012 * recalculate the current text color, since it will be affected by the
3013 * background change if its background is transparent
3014 */
3015 text_color = ossgetcolor(osssb_cur_fg, osssb_cur_bg, osssb_cur_attrs,
3016 osssb_screen_color);
3017
3018 /* redraw the screen in the new background color */
3019 os_redraw();
3020 }
3021
3022 /* redraw the screen if necessary */
osssb_redraw_if_needed()3023 void osssb_redraw_if_needed()
3024 {
3025 /* this implementation never defers redrawing - do nothing */
3026 }
3027
3028 /* set the default cursor position */
osssb_cursor_to_default_pos()3029 void osssb_cursor_to_default_pos()
3030 {
3031 /* we don't need to do anything special here */
3032 }
3033
3034 #else /* RUNTIME */
3035
os_set_text_attr(int attr)3036 void os_set_text_attr(int attr)
3037 {
3038 /* attributes are not supported in non-RUNTIME mode */
3039 }
3040
os_set_text_color(os_color_t fg,os_color_t bg)3041 void os_set_text_color(os_color_t fg, os_color_t bg)
3042 {
3043 /* colors aren't supported in non-RUNTIME mode - ignore it */
3044 }
3045
os_set_screen_color(os_color_t color)3046 void os_set_screen_color(os_color_t color)
3047 {
3048 /* colors aren't supported in non-RUNTIME mode - ignore it */
3049 }
3050
3051 #endif /* RUNTIME */
3052
3053 #endif /* STD_OS_HILITE */
3054
3055 /* ------------------------------------------------------------------------ */
3056 /*
3057 * clear the screen, deleting all scrollback information
3058 */
3059 #ifdef STD_OSCLS
3060
oscls(void)3061 void oscls(void)
3062 {
3063 #ifdef RUNTIME
3064 /* do nothing in 'plain' mode */
3065 if (os_f_plain)
3066 return;
3067
3068 /* forget the scrollback buffer's contents */
3069 scrbuf_free = scrbuf;
3070 scrbuf_head = scrbuf_tail = scrbuf;
3071 scrtop = scrbot = scrlast = 0;
3072 os_line_count = 1;
3073 memset(scrbuf, 0, (size_t)scrbufl);
3074 os_redraw();
3075 #endif
3076 }
3077
3078 #endif /* STD_OSCLS */
3079
3080 /* ------------------------------------------------------------------------ */
3081 /*
3082 * Simple implementation of os_get_sysinfo. This can be used for any
3083 * non-HTML version of the system, since all sysinfo codes currently
3084 * pertain to HTML features. Note that new sysinfo codes may be added
3085 * in the future which may be relevant to non-html versions, so the
3086 * sysinfo codes should be checked from time to time to ensure that new
3087 * codes relevant to this system version are handled correctly here.
3088 */
os_get_sysinfo(int code,void * param,long * result)3089 int os_get_sysinfo(int code, void *param, long *result)
3090 {
3091 #ifdef RUNTIME
3092 /* if the oss layer recognizes the code, defer to its judgment */
3093 if (oss_get_sysinfo(code, param, result))
3094 return TRUE;
3095 #endif
3096
3097 /* check the type of information they're requesting */
3098 switch(code)
3099 {
3100 case SYSINFO_INTERP_CLASS:
3101 /* we're a character-mode text-only interpreter */
3102 *result = SYSINFO_ICLASS_TEXT;
3103 return TRUE;
3104
3105 case SYSINFO_HTML:
3106 case SYSINFO_JPEG:
3107 case SYSINFO_PNG:
3108 case SYSINFO_WAV:
3109 case SYSINFO_MIDI:
3110 case SYSINFO_WAV_MIDI_OVL:
3111 case SYSINFO_WAV_OVL:
3112 case SYSINFO_MPEG:
3113 case SYSINFO_MPEG1:
3114 case SYSINFO_MPEG2:
3115 case SYSINFO_MPEG3:
3116 case SYSINFO_PREF_IMAGES:
3117 case SYSINFO_PREF_SOUNDS:
3118 case SYSINFO_PREF_MUSIC:
3119 case SYSINFO_PREF_LINKS:
3120 case SYSINFO_LINKS_HTTP:
3121 case SYSINFO_LINKS_FTP:
3122 case SYSINFO_LINKS_NEWS:
3123 case SYSINFO_LINKS_MAILTO:
3124 case SYSINFO_LINKS_TELNET:
3125 case SYSINFO_PNG_TRANS:
3126 case SYSINFO_PNG_ALPHA:
3127 case SYSINFO_OGG:
3128 case SYSINFO_MNG:
3129 case SYSINFO_MNG_TRANS:
3130 case SYSINFO_MNG_ALPHA:
3131 case SYSINFO_BANNERS:
3132 /*
3133 * we don't support any of these features - set the result to 0
3134 * to indicate this
3135 */
3136 *result = 0;
3137
3138 /* return true to indicate that we recognized the code */
3139 return TRUE;
3140
3141 default:
3142 /* not recognized */
3143 return FALSE;
3144 }
3145 }
3146
3147 /* ------------------------------------------------------------------------ */
3148 /*
3149 * Set the saved-game extension. Most platforms don't need to do
3150 * anything with this information, and in fact most platforms won't even
3151 * have a way of letting the game author set the saved game extension,
3152 * so this trivial implementation is suitable for most systems.
3153 *
3154 * The purpose of setting a saved game extension is to support platforms
3155 * (such as Windows) where the filename suffix is used to associate
3156 * document files with applications. Each stand-alone executable
3157 * generated on such platforms must have a unique saved game extension,
3158 * so that the system can associate each game's saved position files
3159 * with that game's executable.
3160 */
os_set_save_ext(const char * ext)3161 void os_set_save_ext(const char *ext)
3162 {
3163 /* ignore the setting */
3164 }
3165
3166
3167 /* ------------------------------------------------------------------------ */
3168 /*
3169 * Set the game title. Most platforms have no use for this information,
3170 * so they'll just ignore it. This trivial implementation simply
3171 * ignores the title.
3172 */
3173 #ifdef USE_NULL_SET_TITLE
3174
os_set_title(const char * title)3175 void os_set_title(const char *title)
3176 {
3177 /* ignore the information */
3178 }
3179
3180 #endif /* USE_NULL_SET_TITLE */
3181
3182 /* ------------------------------------------------------------------------ */
3183 /*
3184 * The "banner" window functions are not supported in this implementation.
3185 */
os_banner_create(void * parent,int where,void * other,int wintype,int align,int siz,int siz_units,unsigned long style)3186 void *os_banner_create(void *parent, int where, void *other, int wintype,
3187 int align, int siz, int siz_units, unsigned long style)
3188 {
3189 return 0;
3190 }
3191
os_banner_delete(void * banner_handle)3192 void os_banner_delete(void *banner_handle)
3193 {
3194 }
3195
os_banner_orphan(void * banner_handle)3196 void os_banner_orphan(void *banner_handle)
3197 {
3198 }
3199
os_banner_disp(void * banner_handle,const char * txt,size_t len)3200 void os_banner_disp(void *banner_handle, const char *txt, size_t len)
3201 {
3202 }
3203
os_banner_set_attr(void * banner_handle,int attr)3204 void os_banner_set_attr(void *banner_handle, int attr)
3205 {
3206 }
3207
os_banner_set_color(void * banner_handle,os_color_t fg,os_color_t bg)3208 void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg)
3209 {
3210 }
3211
os_banner_set_screen_color(void * banner_handle,os_color_t color)3212 void os_banner_set_screen_color(void *banner_handle, os_color_t color)
3213 {
3214 }
3215
os_banner_flush(void * banner_handle)3216 void os_banner_flush(void *banner_handle)
3217 {
3218 }
3219
os_banner_set_size(void * banner_handle,int siz,int siz_units,int is_advisory)3220 void os_banner_set_size(void *banner_handle, int siz, int siz_units,
3221 int is_advisory)
3222 {
3223 }
3224
os_banner_size_to_contents(void * banner_handle)3225 void os_banner_size_to_contents(void *banner_handle)
3226 {
3227 }
3228
os_banner_start_html(void * banner_handle)3229 void os_banner_start_html(void *banner_handle)
3230 {
3231 }
3232
os_banner_end_html(void * banner_handle)3233 void os_banner_end_html(void *banner_handle)
3234 {
3235 }
3236
os_banner_goto(void * banner_handle,int row,int col)3237 void os_banner_goto(void *banner_handle, int row, int col)
3238 {
3239 }
3240