3
"$Header: d:/cvsroot/tads/TADS2/OSGEN.C,v 1.3 1999/07/11 00:46:30 MJRoberts Exp $";
7
* Copyright (c) 1990, 2002 Michael J. Roberts. All Rights Reserved.
9
* Please see the accompanying license file, LICENSE.TXT, for information
10
* on using and copying this software.
14
osgen - Operating System dependent functions, general implementation
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:
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
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
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
37
If USE_STDIO is defined, we'll implicitly define USE_STDIO_INPDLG.
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
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
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)
84
#if defined(TURBO) || defined(DJGPP)
91
/* global "plain mode" flag */
95
# ifdef USE_SCROLLBACK
101
static void ossdosb();
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.
108
int G_oss_screen_width = 80;
109
int G_oss_screen_height = 24;
111
# endif /* USE_SCROLLBACK */
114
/* forward declare the low-level display routine */
115
void ossdspn(int y, int x, int color, char *p);
118
* The special character codes for controlling color.
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.)
132
* explicit colored text: this is followed by two bytes giving the
133
* foreground and background colors as OSGEN_COLOR_xxx codes
135
#define OSGEN_COLOR 2
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
145
int os_chkovw(char *filename)
149
if ((fp = fopen( filename, "r" )) != 0)
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')
161
#endif /* USE_OVWCHK */
164
* non-stop mode does nothing in character-mode implementations, since the
165
* portable console layer handles MORE mode
167
void os_nonstop_mode(int flag)
171
/* ------------------------------------------------------------------------ */
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.
182
* print a null-terminated string the console
184
void os_printz(const char *str)
186
/* write the string to stdout */
191
* print a counted-length string, which isn't necessarily null-terminated
193
void os_print(const char *str, size_t len)
195
/* write the string to stdout, limiting the length */
196
printf("%.*s", (int)len, str);
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).
210
* update the display - since we're using text mode, there's nothing we
213
void os_update_display(void)
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
224
uchar *os_gets(uchar *s, size_t bufl)
226
return((uchar *)fgets((char *)s, bufl, stdin));
230
* The default stdio implementation does not support reading a line of
233
int os_gets_timeout(unsigned char *buf, size_t bufl,
234
unsigned long timeout, int resume_editing)
236
/* tell the caller this operation is not supported */
237
return OS_EVT_NOTIMEOUT;
241
* since we don't support os_gets_timeout(), we don't need to do anything
242
* in the cancel routine
244
void os_gets_cancel(int reset)
246
/* os_gets_timeout doesn't do anything, so neither do we */
250
* Get an event - stdio version. This version does not accept a timeout
251
* value, and can only get a keystroke.
253
int os_get_event(unsigned long timeout, int use_timeout,
254
os_event_info_t *info)
256
/* if there's a timeout, return an error indicating we don't allow it */
258
return OS_EVT_NOTIMEOUT;
260
/* get a key the normal way */
261
info->key[0] = os_getc();
263
/* if it's an extended key, get the other key */
264
if (info->key[0] == 0)
266
/* get the extended key code */
267
info->key[1] = os_getc();
269
/* if it's EOF, return an EOF event rather than a key event */
270
if (info->key[1] == CMD_EOF)
274
/* return the keyboard event */
278
#endif /* USE_STDIO */
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
******************************************************************************/
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.
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.
304
int os_init(int *argc, char *argv[], const char *prompt,
305
char *buf, int bufsiz)
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.
326
#endif /* USE_NULLINIT */
328
/* ------------------------------------------------------------------------ */
330
* Ports can define USE_NULLPAUSE if no pause is required on exit.
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.
337
void os_expause(void)
341
#endif /* USE_NULLPAUSE */
344
void os_expause(void)
346
os_printz("(Strike any key to exit...)");
350
#endif /* USE_EXPAUSE */
355
* USE_NULLSTAT defines a do-nothing version of os_status.
357
void os_status(int stat)
359
/* ignore the new status */
366
#endif /* USE_NULLSTAT */
370
* USE_NULLSCORE defines a do-nothing version of os_score.
372
void os_score(int cur, int turncount)
374
/* ignore the score information */
377
void os_strsc(const char *p)
381
#endif /* USE_NULLSCORE */
385
/* saved main text area column when drawing in status line */
386
static osfar_t int S_statline_savecol;
388
/* saved text column when we're drawing in status line */
389
static osfar_t int text_lastcol;
392
* first line of text area - the status line is always one line high, so
393
* this is always simply 1
395
static osfar_t int text_line = 1;
397
/* the column in the status line for the score part of the display */
398
static osfar_t int score_column = 0;
401
* Define some macros in terms of "oss" globals that tell us the size of
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.
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
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.
416
* sdesc_line and sdesc_column are the starting row and column of the
417
* status line. These are always row 0, column 0.
419
#define max_line ((G_oss_screen_height) - 1)
420
#define max_column ((G_oss_screen_width) - 1)
422
#define text_column 0
424
#define sdesc_column 0
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
432
static osfar_t char S_statbuf[OS_MAXWIDTH + 1];
434
/* pointer to the next free character of the status line buffer */
435
static osfar_t char *S_statptr = S_statbuf;
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.
443
* Note that os_init may have to modify some of these values to suit, and
444
* should set up the screen appropriately.
446
void os_status(int stat)
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))
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
456
text_lastcol = S_statline_savecol;
459
/* switch to the new mode */
463
if (status_mode == 1)
466
* we're entering the status line - start writing at the start
469
S_statptr = S_statbuf;
472
* clear out any previously-saved status line text, since we're
473
* starting a new status line
478
* remember the current text area display column so that we can
479
* restore it when we finish with the status line
481
S_statline_savecol = text_lastcol;
483
else if (status_mode == 2)
486
* entering post-status-line mode - remember the text column so
487
* that we can restore it when we return to normal mode
489
S_statline_savecol = text_lastcol;
498
/* Set score to a string value provided by the caller */
499
void os_strsc(const char *p)
501
static osfar_t char lastbuf[135];
505
/* ignore score strings in plain mode, there's no status line */
509
/* presume the score column will be ten spaces left of the right edge */
510
score_column = max_column - 10;
512
/* start out in the initial score column */
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
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, " ");
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.
541
void os_score(int cur, int turncount)
545
/* check for the special -1 turn count */
548
/* it's turn "-1" - we're simply redrawing the score */
553
/* format the score */
554
sprintf(buf, "%d/%d", cur, turncount);
556
/* display the score string */
562
/* ------------------------------------------------------------------------ */
566
# ifdef USE_SCROLLBACK
569
* Pointers for scrollback buffers.
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.
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.
579
static osfar_t char *scrbuf;
580
static osfar_t unsigned scrbufl;
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
588
static char *scrbuf_head;
589
static char *scrbuf_tail;
591
/* allocation head */
592
static osfar_t char *scrbuf_free;
594
/* number of lines in scrollback buffer */
595
static osfar_t int os_line_count;
597
/* line number of top line on the screen */
598
static osfar_t int os_top_line;
600
/* current column in the scrollback buffer */
601
static osfar_t int sb_column;
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.
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
614
static osfar_t int osssb_screen_color;
615
static osfar_t int osssb_oss_screen_color;
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;
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;
628
* Receive notification of a screen size change.
630
void osssb_on_resize_screen()
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
639
G_os_pagelength = (G_oss_screen_height > 3
640
? G_oss_screen_height - 3
641
: G_oss_screen_height);
643
/* the main text area gets the full screen width */
644
G_os_linewidth = G_oss_screen_width;
648
* Initialize the scrollback buffer - allocates memory for the buffer.
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
654
void osssbini(unsigned int size)
656
/* calculate the page size and width based on the screen size */
657
osssb_on_resize_screen();
659
/* remember the size of the buffer */
662
/* allocate the scrollback buffer */
663
if ((scrbuf = calloc(scrbufl, 1)) != 0)
665
/* set up the first and only (and thus last) line pointers */
666
scrbuf_head = scrbuf_tail = scrbuf;
668
/* set up the free pointer */
669
scrbuf_free = scrbuf;
671
/* we have one line in the buffer now */
674
/* start out in normal text color */
675
osssb_cur_fg = OSGEN_COLOR_TEXT;
676
osssb_cur_bg = OSGEN_COLOR_TRANSPARENT;
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;
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);
691
/* mention the problem */
692
os_printz("\nSorry, there is not enough memory available "
693
"for review mode.\n\n");
695
/* we have no line records */
700
/* clear the status line area */
701
ossclr(sdesc_line, sdesc_column, sdesc_line, max_column, sdesc_color);
705
* delete the scrollback buffer
709
/* free the screen buffer */
715
* advance to the next byte of the scrollback buffer
717
static char *ossadvsp(char *p)
719
/* move to the next byte */
722
/* if we've passed the end of the buffer, wrap to the beginning */
723
if (p >= scrbuf + scrbufl)
726
/* return the pointer */
731
* decrement to the previous byte of the buffer
733
static char *ossdecsp(char *p)
735
/* if we're at the start of the buffer, wrap to just past the end */
737
p = scrbuf + scrbufl;
739
/* move to the previous byte */
742
/* return the pointer */
747
* Add a byte to the scrollback buffer
749
static void osssb_add_byte(char c)
751
/* add the character to the buffer */
754
/* advance the free pointer */
755
scrbuf_free = ossadvsp(scrbuf_free);
758
* if the free pointer has just collided with the start of the oldest
759
* line, delete the oldest line
761
if (scrbuf_free == scrbuf_head)
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
767
while (*scrbuf_head != '\0')
768
scrbuf_head = ossadvsp(scrbuf_head);
770
/* skip the null pointer that marks the end of the old first line */
771
scrbuf_head = ossadvsp(scrbuf_head);
773
/* note the loss of a line */
779
* Add an appropriate color code to the scrollback buffer to yield the
780
* current color setting.
782
static void osssb_add_color_code()
784
/* if we have any attributes, add an attribute code */
785
if (osssb_cur_attrs != 0)
788
* add the attribute, encoded with our plus-one rule (to avoid
789
* storing zero bytes as attribute arguments)
791
osssb_add_byte(OSGEN_ATTR);
792
osssb_add_byte((char)(osssb_cur_attrs + 1));
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)
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);
807
* Scan a character, counting its contribution to the display column in the
810
static void osssb_scan_char(char **p, int *col)
812
/* see what we have */
819
* these are all one-byte character sequences that don't contribute
820
* to the display column - simply skip the input byte
826
/* this is a two-byte non-printing escape sequence */
831
/* this is a three-byte non-printing escape sequence */
837
* anything else is a one-byte display character, so count its
838
* contribution to the display column and skip the byte
847
* Start a new line in the scrollback buffer
849
static void osssb_new_line()
851
/* add a null byte to mark the end of the current line */
854
/* remember the new final line - it starts at the free pointer */
855
scrbuf_tail = scrbuf_free;
857
/* count the added line */
860
/* the new line starts at the first column */
863
/* add a color code to the start of the new line, if necessary */
864
osssb_add_color_code();
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;
873
* Add text to the scrollback buffer. Returns the number of lines that the
876
static int ossaddsb(const char *p, size_t len)
880
/* if there's no scrollback buffer, ignore it */
884
/* presume the text will all fit on one line */
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.
895
/* check for color control codes */
900
* switch to the new attributes (decoding from the plus-one
903
osssb_cur_attrs = ((unsigned char)*(p+1)) - 1;
907
/* switch to the explicit colors */
908
osssb_cur_fg = (unsigned char)*(p+1);
909
osssb_cur_bg = (unsigned char)*(p+2);
913
/* check for special characters */
917
/* add the new line */
920
/* skip this character */
924
/* count the new line */
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.
939
/* set the free pointer back to the start of the current line */
940
scrbuf_free = scrbuf_tail;
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;
948
* since we're back at the start of the line, add a color code
951
osssb_add_color_code();
953
/* skip this character */
961
/* it's a two-byte attribute sequence - add the bytes */
963
osssb_add_byte(*(p+1));
965
/* skip the sequence */
969
/* done (since this doesn't print) */
973
/* it's a three-byte color sequence - add the bytes */
975
osssb_add_byte(*(p+1));
976
osssb_add_byte(*(p+2));
978
/* skip the sequence */
983
* done (this doesn't print, so it has no effect on the column
984
* position or wrapping)
989
/* for anything else, simply store the byte in the buffer */
992
/* skip the character */
996
/* advance to the next column */
999
/* check for wrapping */
1000
if (sb_column > max_column)
1002
/* start a new line */
1005
/* count the new line */
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.
1022
scrbuf_free = ossdecsp(scrbuf_free);
1024
/* return the number of lines we added */
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
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).
1043
static void ossaddsbe(char *buf, char *p, int x, int y)
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
1052
extra_lines = max_line - y;
1055
actual_lines = ossaddsb(buf, strlen(buf));
1058
* if we added more than one line already, those count against the
1059
* extra lines we need to add
1061
extra_lines -= (actual_lines - 1);
1063
/* add the extra blank lines */
1064
for ( ; extra_lines > 0 ; --extra_lines)
1067
/* add a tentative null terminator */
1069
scrbuf_free = ossdecsp(scrbuf_free);
1073
* Scrollback mode variables. These track the current position while
1074
* in scrollback mode.
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 */
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.
1085
static void scrdsp(char *p, int y)
1089
int x = text_column;
1095
/* start out in normal text color */
1096
fg = OSGEN_COLOR_TEXT;
1097
bg = OSGEN_COLOR_TRANSPARENT;
1099
oss_color = ossgetcolor(fg, bg, attrs, osssb_screen_color);
1101
/* keep going until we reach the end of the line */
1104
/* check the character */
1108
/* set the new attributes (decoding from the plus-one value) */
1109
attrs = (unsigned char)*(p = ossadvsp(p)) - 1;
1111
/* handle it via the common color-switching code */
1115
/* explicit color code - read the two extra bytes */
1116
fg = *(p = ossadvsp(p));
1117
bg = *(p = ossadvsp(p));
1119
/* handle it via the common color-switching code */
1123
/* null-terminate the buffer and display it in the old color */
1125
ossdsp(y, x, oss_color, buf);
1127
/* switch to the new color */
1128
oss_color = ossgetcolor(fg, bg, attrs, osssb_screen_color);
1130
/* advance the column counter */
1133
/* go back to start of buffer */
1138
/* add this byte to our buffer */
1143
/* advance to next character no matter what happened */
1146
/* if the buffer's full, flush it */
1147
if (q == buf + sizeof(buf) - 1)
1149
/* flush out the buffer */
1151
ossdsp(y, x, oss_color, buf);
1153
/* advance the column counter */
1156
/* go back to start of buffer */
1161
/* flush out what's left in the buffer */
1163
ossdsp(y, x, oss_color, buf);
1167
* scrdspscr - display a screenful of text starting at a given location
1168
* in the scrollback buffer.
1170
static void scrdspscr(char *p)
1174
/* clear the screen area of our display */
1175
ossclr(text_line, text_column, max_line, max_column,
1176
osssb_oss_screen_color);
1178
/* display each line of this area */
1179
for (y = text_line ; y <= max_line ; ++y)
1181
/* display this line */
1184
/* if we just displayed the last line, we're done */
1185
if (p == scrbuf_tail)
1188
/* advance to the next line */
1192
/* skip the line separator */
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.
1202
static int osssb_next_line(char **p)
1204
/* if we're at the last line already, there's nothing to do */
1205
if (*p == scrbuf_tail)
1208
/* advance until we find the current line's terminating null byte */
1212
/* skip the null byte */
1215
/* we did advance by a line */
1220
* Move a buffer pointer backward to the start of the current line.
1222
static char *osssb_to_start(char *p)
1224
/* keep going as long as we don't reach the start of the first line */
1225
while (p != scrbuf_head)
1227
/* move back a byte */
1230
/* if it's a null byte, we've found the end of the previous line */
1236
* return the pointer (which is at the start of the first line if we
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
1247
static int osssb_prev_line(char **p)
1249
/* first, make sure we're at the start of the current line */
1250
*p = osssb_to_start(*p);
1252
/* if we're at the start of the first line, we can't go back */
1253
if (*p == scrbuf_head)
1256
/* move back to the null byte at the end of the previous line */
1259
/* go back to the start of this line */
1260
*p = osssb_to_start(*p);
1262
/* we moved the pointer */
1267
* move forward by a number of lines, and redisplays the sreen
1269
static void scrfwd(int n)
1271
/* if we're already on the last screen, there's nothing to do */
1272
if (scrtop == scrlast)
1276
* Move forward by the requested amount. Stop if we reach the top of
1277
* the bottom-most screen.
1281
/* move to the next line at the bottom */
1282
if (!osssb_next_line(&scrbot))
1285
/* move to the next line at the top as well */
1286
osssb_next_line(&scrtop);
1288
/* update our display counter */
1291
/* that's one less line to advance by */
1296
/* re-display the screen with the new top line */
1301
* move back by a number of lines, redisplaying the screen
1303
static void scrback(int n)
1305
/* if we can't go back any further, we're done */
1306
if (scrtop == scrbuf_head)
1309
/* keep going until we satisfy the request */
1310
while (n != 0 && scrtop != scrbuf_head)
1313
* back up one line - if we can't (because we're already at the
1314
* first line), stop trying
1316
if (!osssb_prev_line(&scrtop))
1319
/* back up one at the bottom */
1320
osssb_prev_line(&scrbot);
1322
/* that's one less to look for */
1325
/* adjust our line position */
1329
/* redisplay the screen */
1334
* scrto moves to a selected line
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);
1345
* scrpgup scrolls back a page
1349
scrback(max_line - text_line);
1353
* scrpgdn scrolls forward a page
1357
scrfwd(max_line - text_line);
1361
* scrlnup scrolls up one line
1365
/* move the top pointer back a line */
1366
if (osssb_prev_line(&scrtop))
1368
/* success - move the bottom pointer back a line as well */
1369
osssb_prev_line(&scrbot);
1371
/* adjust our line counter */
1374
/* scroll the display area */
1375
ossscu(text_line, text_column, max_line, max_column,
1376
osssb_oss_screen_color);
1378
/* redisplay the top line */
1379
scrdsp(scrtop, text_line);
1384
* scrlndn scrolls down one line
1388
/* if we're already at the last screenful, there's nothing to do */
1389
if (scrtop == scrlast)
1392
/* move the bottom pointer up a line */
1393
if (osssb_next_line(&scrbot))
1395
/* success - move the top pointer up a line as well */
1396
osssb_next_line(&scrtop);
1398
/* adjust our line counter */
1401
/* scroll the display area */
1402
ossscr(text_line, text_column, max_line, max_column,
1403
osssb_oss_screen_color);
1405
/* redisplay the bottom line */
1406
scrdsp(scrbot, max_line);
1410
/* redraw the screen's text region */
1411
void os_redraw(void)
1416
/* clear the area */
1417
ossclr(text_line, text_column, max_line, max_column,
1418
osssb_oss_screen_color);
1420
/* find the top line in the display area */
1422
for (y = max_line ; y >= text_line ; --y)
1424
/* display the current line at the current position */
1427
/* move back a line if possible */
1428
if (!osssb_prev_line(&p))
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
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.
1445
int osssbmode(int mode_line)
1447
/* if there's no buffer, we can't enter scrollback mode */
1452
* if we're not in scrollback mode, enter scrollback mode; otherwise,
1453
* return to normal mode
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.
1466
for (os_top_line = os_line_count, scrtop = scrbuf_tail,
1467
y = max_line ; y > text_line ; --y, --os_top_line)
1469
/* back up one line */
1470
if (!osssb_prev_line(&scrtop))
1472
/* there wasn't enough text, so abort and return failure */
1479
* if the top of the screen is the very first line in the buffer,
1480
* there's still not enough scrollback information
1482
if (scrtop == scrbuf_head)
1484
/* no point in scrollback when we have exactly one screen */
1489
/* remember where current screen starts and ends */
1491
scrbot = scrbuf_tail;
1493
/* display instructions if we have a status line */
1496
strcpy(buf, OS_SBSTAT);
1497
for (i = strlen(buf) ; i < max_column ; buf[i++] = ' ') ;
1499
ossdsp(sdesc_line, sdesc_column+1, sdesc_color, buf);
1502
/* successfully entered scrollback mode */
1508
* Exit scrollback mode. Show the last page of text, and put
1509
* up the normal status bar. Also clear our scrollback mode
1512
if (scrlast != scrtop)
1515
/* re-display the status line, if appropriate */
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);
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
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.
1540
static void ossdosb(void)
1549
case CMD_KILL: /* leave scrollback via 'escape' as well */
1550
case CMD_EOF: /* stop on end of file */
1570
# else /* USE_SCROLLBACK */
1571
static void ossaddsb(char *p, size_t len)
1573
/* We're not saving output - do nothing */
1575
# endif /* USE_SCROLLBACK */
1577
/* display with no highlighting - intercept and ignore highlight codes */
1578
void ossdspn(int y, int x, int color, char *p)
1583
/* scan the string */
1584
for (q = p ; *q ; ++q)
1589
/* three-byte escape sequence */
1594
/* two-byte escape sequence */
1599
/* end the buffer here and display what we have so far */
1601
ossdsp(y, x, color, p);
1603
/* adjust the column position for the display */
1606
/* advance past what we've displayed plus the escape sequence */
1611
/* ordinary character - keep going */
1616
/* display the remainder of the buffer, if there's anything left */
1618
ossdsp(y, x, color, p);
1621
/* display with highlighting enabled */
1622
int ossdsph(int y, int x, int color, char *p)
1628
/* get length of entire string */
1631
/* scan the input string */
1632
for (q = p ; *q != '\0' ; ++q)
1634
/* check for special escape codes */
1638
/* set text attributes (decoding from the plus-one code) */
1639
osssb_cur_attrs = (unsigned char)*(q+1) - 1;
1644
/* set explicit color */
1645
osssb_cur_fg = *(q+1);
1646
osssb_cur_bg = *(q+2);
1651
/* display the part up to the escape code in the old color */
1653
ossdsp(y, x, text_color, p);
1655
/* adjust the column position for the display */
1658
/* note the new text color */
1659
text_color = ossgetcolor(osssb_cur_fg, osssb_cur_bg,
1660
osssb_cur_attrs, osssb_screen_color);
1662
/* move past the escape sequence */
1666
/* don't count the escape character in the length displayed */
1675
/* display the last portion of the line if anything's left */
1677
ossdsp(y, x, text_color, p);
1679
/* return the length */
1684
* Set the terminal into 'plain' mode: disables status line,
1685
* scrollback, command editing.
1689
/* set the 'plain' mode flag */
1693
* if we're running without a stdin, turn off pagination - since the
1694
* user won't be able to respond to [more] prompts, there's no reason
1697
if (oss_eof_on_stdin())
1698
G_os_moremode = FALSE;
1701
void os_printz(const char *str)
1703
/* use our base counted-length routine */
1704
os_print(str, strlen(str));
1707
void os_print(const char *str, size_t len)
1710
* save the output in the scrollback buffer if we're displaying to
1711
* the main text area (status_mode == 0) and we're not in plain
1712
* stdio mode (in which case there's no scrollback support)
1714
if (status_mode == 0 && !os_f_plain)
1717
/* determine what to do based on the status mode */
1721
/* we're in the post-status-line mode - suppress all output */
1725
/* normal main text area mode */
1732
/* scan the buffer */
1733
for (p = str, rem = len, dst = buf ; ; ++p, --rem)
1736
* if we're out of text, or the buffer is full, or we're at
1737
* a newline or carriage return, flush the buffer
1740
|| dst == buf + sizeof(buf) - 2
1741
|| *p == '\n' || *p == '\r')
1743
/* write out the buffer */
1746
/* write the buffer, INCLUDING the LF/CR */
1747
if (*p == '\n' || *p == '\r')
1756
/* display the buffer */
1758
len = ossdsph(max_line, text_lastcol,
1761
/* move the cursor right */
1762
text_lastcol += len;
1764
/* scroll on a newline */
1767
/* scroll up a line */
1768
ossscr(text_line, text_column,
1769
max_line, max_column,
1770
osssb_oss_screen_color);
1773
/* move the cursor to the left column on LF/CR */
1774
if (*p == '\n' || *p == '\r')
1775
text_lastcol = text_column;
1778
/* reset the buffer */
1781
/* if we're out of source text, we're done */
1786
/* see what we have */
1791
/* don't buffer newlines/carriage returns */
1795
/* buffer this character */
1801
/* put the cursor at the end of the text */
1802
if (status_mode == 0 && !os_f_plain)
1803
ossloc(max_line, text_lastcol);
1810
/* status-line mode - ignore in 'plain' mode */
1818
* Skip leading newlines at the start of the statusline output.
1819
* Only do this if we don't already have anything buffered,
1820
* since a newline after some other text indicates the end of
1821
* the status line and thus can't be ignored.
1825
if (S_statptr == S_statbuf)
1827
/* the buffer is empty, so skip leading newlines */
1828
for ( ; rem != 0 && *p == '\n' ; ++p, --rem) ;
1832
* Add this text to our private copy, so that we can refresh
1833
* the display later if necessary. If we reach a newline,
1836
for ( ; (rem != 0 && *p != '\n'
1837
&& S_statptr < S_statbuf + sizeof(S_statbuf)) ;
1840
/* omit special characters from the status buffer */
1841
if (*p == OSGEN_ATTR)
1843
/* skip an extra byte for the attribute code */
1847
else if (*p == OSGEN_COLOR)
1849
/* skip two extra bytes for the color codes */
1854
/* copy this character */
1858
/* if we reached a newline, we're done with the status line */
1859
if (rem != 0 && *p == '\n')
1862
/* add spaces up to the score location */
1863
for (i = S_statptr - S_statbuf ; i < score_column - 1 ; ++i)
1866
/* null-terminate the buffer */
1867
S_statbuf[i] = '\0';
1869
/* display a leading space */
1870
ossdspn(sdesc_line, sdesc_column, sdesc_color, " ");
1872
/* display the string */
1873
ossdspn(sdesc_line, sdesc_column + 1, sdesc_color, S_statbuf);
1883
/* we don't buffer our output, so there's nothing to do here */
1886
void os_update_display(void)
1888
/* there's nothing we need to do */
1893
* For command line history, we must have some buffer space to store
1894
* past command lines. We will use a circular buffer: when we move
1895
* the pointer past the end of the buffer, it wraps back to the start
1896
* of the buffer. A "tail" indicates the oldest line in the buffer;
1897
* when we need more room for new text, we advance the tail and thereby
1898
* lose the oldest text in the buffer.
1900
static osfar_t unsigned char *histbuf = 0;
1901
static osfar_t unsigned char *histhead = 0;
1902
static osfar_t unsigned char *histtail = 0;
1905
* ossadvhp advances a history pointer, and returns the new pointer.
1906
* This function takes the circular nature of the buffer into account
1907
* by wrapping back to the start of the buffer when it hits the end.
1909
uchar *ossadvhp(uchar *p)
1911
if (++p >= histbuf + HISTBUFSIZE)
1917
* ossdechp decrements a history pointer, wrapping the pointer back
1918
* to the top of the buffer when it reaches the bottom.
1920
uchar *ossdechp(uchar *p)
1923
p = histbuf + HISTBUFSIZE;
1928
* osshstcpy copies from a history buffer into a contiguous destination
1929
* buffer, wrapping the history pointer if need be. One null-terminated
1932
void osshstcpy(uchar *dst, uchar *hst)
1937
hst = ossadvhp( hst );
1943
* ossprvcmd returns a pointer to the previous history command, given
1944
* a pointer to a history command. It returns a null pointer if the
1945
* given history command is the first in the buffer.
1947
uchar *ossprvcmd(uchar *hst)
1949
if (hst == histtail)
1950
return 0; /* no more previous commands */
1951
hst = ossdechp( hst ); /* back onto nul */
1954
hst = ossdechp( hst ); /* back one character */
1955
} while (*hst && hst != histtail); /* go until previous command */
1957
hst = ossadvhp(hst); /* step over null byte */
1962
* ossnxtcmd returns a pointer to the next history command, given
1963
* a pointer to a history command. It returns a null pointer if the
1964
* given command is already past the last command.
1966
uchar *ossnxtcmd(uchar *hst)
1968
if ( hst == histhead ) return( 0 ); /* past the last one already */
1969
while( *hst ) hst = ossadvhp( hst ); /* scan forward to null */
1970
hst = ossadvhp( hst ); /* scan past null onto new command */
1973
# endif /* USE_HISTORY */
1975
/* ------------------------------------------------------------------------ */
1977
* Input buffer state. This information is defined statically because
1978
* os_gets_timeout() can carry the information from invocation to
1979
* invocation when input editing is interrupted by a tmieout.
1981
static osfar_t char S_gets_internal_buf[256]; /* internal save buffer */
1982
static osfar_t char *S_gets_buf = S_gets_internal_buf; /* current save buf */
1983
static osfar_t size_t S_gets_buf_siz = sizeof(S_gets_internal_buf); /* size */
1984
static osfar_t int S_gets_ofs; /* offset in buffer of insertion point */
1985
static osfar_t unsigned char *S_gets_curhist; /* current history pointer */
1986
static osfar_t int S_gets_x, S_gets_y; /* saved cursor position */
1989
/* save buffer for line being edited before history recall began */
1990
static osfar_t char S_hist_sav_internal[256];
1991
static osfar_t char *S_hist_sav = S_hist_sav_internal;
1992
static osfar_t size_t S_hist_sav_siz = sizeof(S_hist_sav_internal);
1993
# endif /* USE_HISTORY */
1996
* Flag: input is already in progress. When os_gets_timeout() returns
1997
* with OS_EVT_TIMEOUT, it sets this flag to true. os_gets_cancel() sets
1998
* this flag to false.
2000
* When os_gets_timeout() is called again, it checks this flag to see if
2001
* the input session was cancelled; if not, the routine knows that the
2002
* partially-edited input line is already displayed where it left off,
2003
* because the display has not been modified since the interrupted call to
2004
* os_gets_timeout() returned.
2006
static osfar_t int S_gets_in_progress = FALSE;
2008
/* ------------------------------------------------------------------------ */
2010
* Display a string from the given character position. This does NOT
2011
* scroll the screen.
2013
static void ossdsp_str(int y, int x, int color,
2014
unsigned char *str, size_t len)
2016
/* keep going until we exhaust the string */
2022
/* display as much as will fit on the current line */
2023
cur = max_column - x + 1;
2027
/* null-terminate the chunk, but save the original character */
2031
/* display this chunk */
2032
ossdsp(y, x, color, (char *)str);
2034
/* restore the character where we put our null */
2037
/* move our string counters past this chunk */
2041
/* advance the x position */
2052
* Display a string from the given character position, scrolling the
2053
* screen if necessary.
2055
static void ossdsp_str_scr(int *y, int *x, int color,
2056
unsigned char *str, size_t len)
2058
/* keep going until we exhaust the string */
2064
/* display as much as will fit on the current line */
2065
cur = max_column - *x + 1;
2069
/* null-terminate the chunk, but save the original character */
2073
/* display this chunk */
2074
ossdsp(*y, *x, color, (char *)str);
2076
/* restore the character where we put our null */
2079
/* move our string counters past this chunk */
2083
/* advance the x position */
2085
if (*x > max_column)
2087
/* reset to the first column */
2090
/* scroll the screen if necessary */
2092
ossscr(text_line, text_column,
2093
max_line, max_column, osssb_oss_screen_color);
2101
* Delete a character in the buffer, updating the display.
2103
static void oss_gets_delchar(unsigned char *buf, unsigned char *p,
2104
unsigned char **eol, int x, int y)
2108
/* delete the character and close the gap */
2111
memmove(p, p + 1, *eol - p);
2114
* replace the last character with a blank, so that we overwrite
2115
* its presence on the display
2119
/* re-display the changed part of the string */
2120
ossdsp_str(y, x, text_color, p, *eol - p + 1);
2122
/* null-terminate the shortened buffer */
2128
* Backspace in the buffer, updating the display and adjusting the cursor
2131
static void oss_gets_backsp(unsigned char *buf, unsigned char **p,
2132
unsigned char **eol, int *x, int *y)
2134
/* if we can back up, do so */
2137
/* move our insertion point back one position */
2140
/* the line is now one character shorter */
2143
/* shift all of the characters down one position */
2145
memmove(*p, *p + 1, *eol - *p);
2147
/* move the cursor back, wrapping if at the first column */
2155
* replace the trailing character with a space, so that we
2156
* overwrite its screen position with a blank
2161
* display the string from the current position, so that we update
2162
* the display for the moved characters
2164
ossdsp_str(*y, *x, text_color, *p, *eol - *p + 1);
2166
/* null-terminate the shortened buffer */
2172
* Move the cursor left by the number of characters.
2174
static void oss_gets_csrleft(int *y, int *x, size_t len)
2176
for ( ; len != 0 ; --len)
2178
/* move left one character, wrapping at the end of the line */
2181
/* move up a line */
2184
/* move to the end of the line */
2191
* Move the cursor right by the number of characters.
2193
static void oss_gets_csrright(int *y, int *x, size_t len)
2195
for ( ; len != 0 ; --len)
2197
/* move right one character, wrapping at the end of the line */
2198
if (++*x > max_column)
2200
/* move down a line */
2203
/* move to the left column */
2209
/* ------------------------------------------------------------------------ */
2211
* cancel interrupted input
2213
void os_gets_cancel(int reset)
2218
* if we interrupted a previous line, apply display effects as though
2219
* the user had pressed return
2221
if (S_gets_in_progress)
2223
/* move to the end of the input line */
2226
oss_gets_csrright(&y, &x, strlen(S_gets_buf + S_gets_ofs));
2228
/* add a newline, scrolling if necessary */
2230
ossscr(text_line, text_column, max_line, max_column,
2231
osssb_oss_screen_color);
2233
/* set the cursor to the new position */
2236
/* move to the left column for the next display */
2239
/* copy the buffer to the screen save buffer, adding a newline */
2240
ossaddsbe(S_gets_buf, S_gets_buf + strlen(S_gets_buf), x, y);
2244
/* we no longer have an input in progress */
2245
S_gets_in_progress = FALSE;
2248
/* if we're resetting, clear our saved buffer */
2250
S_gets_buf[0] = '\0';
2253
/* ------------------------------------------------------------------------ */
2255
* Common routine to read a command from the keyboard. This
2256
* implementation provides command editing and history, as well as timeout
2259
int os_gets_timeout(unsigned char *buf, size_t bufl,
2260
unsigned long timeout, int use_timeout)
2264
unsigned char *eob = buf + bufl - 1;
2270
/* if we're in 'plain' mode, simply use stdio input */
2275
/* we don't support the timeout feature in plain mode */
2277
return OS_EVT_NOTIMEOUT;
2280
* get input from stdio, and translate the result code - if gets()
2281
* returns null, it indicates an error of some kind, so return an
2282
* end-of-file indication
2284
if (fgets((char *)buf, bufl, stdin) == 0)
2287
/* remove the trailing newline from the buffer, if present */
2288
if ((len = strlen((char *)buf)) != 0 && buf[len-1] == '\n')
2291
/* indicate that we read a line */
2296
/* allocate the history buffer if it's not already allocated */
2299
histbuf = (unsigned char *)osmalloc(HISTBUFSIZE);
2300
histhead = histtail = histbuf;
2301
S_gets_curhist = histhead;
2303
# endif /* USE_HISTORY */
2306
* If we have a timeout, calculate the system clock time at which the
2307
* timeout expires. This is simply the current system clock time plus
2308
* the timeout interval. Since we might need to process a series of
2309
* events, we'll need to know how much time remains at each point we
2312
end_time = os_get_sys_clock_ms() + timeout;
2314
/* set up at the last output position, after the prompt */
2320
* If we have saved input state from a previous interrupted call,
2321
* restore it now. Otherwise, initialize everything.
2323
if (S_gets_buf[0] != '\0' || S_gets_in_progress)
2327
/* limit the restoration length to the new buffer length */
2328
len = strlen((char *)buf);
2332
/* copy the saved buffer to the caller's buffer */
2333
memcpy(buf, S_gets_buf, len);
2335
/* set up our pointer to the end of the text */
2338
/* null-terminate the text */
2342
* if we cancelled the previous input, we must re-display the
2343
* buffer under construction, since we have displayed something
2344
* else in between and have re-displayed the prompt
2346
if (!S_gets_in_progress)
2348
/* re-display the buffer */
2349
ossdsp_str_scr(&y, &x, text_color, buf, len);
2352
* move back to the original insertion point, limiting the
2353
* move to the available buffer size for the new caller
2355
if (S_gets_ofs < (int)len)
2356
oss_gets_csrleft(&y, &x, len - S_gets_ofs);
2363
* input is still in progress, so the old text is still on the
2364
* screen - simply move to the original cursor position
2370
/* get our pointer into the buffer */
2371
p = buf + S_gets_ofs;
2375
/* set up our buffer pointers */
2379
/* initialize our history recall pointer */
2380
S_gets_curhist = histhead;
2382
/* clear out the buffer */
2386
/* process keystrokes until we're done entering the command */
2390
os_event_info_t event_info;
2393
/* move to the proper position on the screen */
2396
/* if we're using a timeout, check for expiration */
2401
/* note the current system clock time */
2402
cur_clock = os_get_sys_clock_ms();
2405
* if we're past the timeout expiration time already,
2406
* interrupt with timeout now
2408
if (cur_clock >= end_time)
2409
goto timeout_expired;
2411
/* note the interval remaining to the timeout expiration */
2412
timeout = end_time - cur_clock;
2416
event_type = os_get_event(timeout, use_timeout, &event_info);
2418
/* handle the event according to the event type */
2423
* Keystroke event. First, translate the key from the "raw"
2424
* keystroke that os_get_event() returns to the "processed"
2425
* (CMD_xxx) representation. This lets the oss layer map
2426
* special keystrokes to generic editing commands in a
2427
* system-specific manner.
2429
oss_raw_key_to_cmd(&event_info);
2431
/* get the primary character from the event */
2432
c = event_info.key[0];
2435
case OS_EVT_TIMEOUT:
2438
* The timeout expired. Copy the current input state into the
2439
* save area so that we can resume the input later if desired.
2441
strcpy(S_gets_buf, (char *)buf);
2442
S_gets_ofs = p - buf;
2446
/* note that input was interrupted */
2447
S_gets_in_progress = TRUE;
2449
/* return the timeout status to the caller */
2450
return OS_EVT_TIMEOUT;
2452
case OS_EVT_NOTIMEOUT:
2454
* we can't handle events with timeouts, so we can't provide
2455
* line reading with timeouts, either
2457
return OS_EVT_NOTIMEOUT;
2460
/* end of file - return the same error to our caller */
2464
/* ignore any other events */
2469
* Check the character we got. Note that we must interpret
2470
* certain control characters explicitly, because os_get_event()
2471
* returns raw keycodes (untranslated into CMD_xxx codes) for
2472
* control characters.
2477
/* backspace one character */
2478
oss_gets_backsp(buf, &p, &eol, &x, &y);
2482
/* null-terminate the input */
2485
/* move to the end of the line */
2486
oss_gets_csrright(&y, &x, eol - p);
2490
* Scroll the screen to account for the carriage return,
2491
* position the cursor at the end of the new line, and
2492
* null-terminate the line.
2496
ossscr(text_line, text_column, max_line, max_column,
2497
osssb_oss_screen_color);
2499
/* move to the left column for the next display */
2504
* Save the line in our history buffer. If we don't have
2505
* enough room, lose some old text by advancing the tail
2506
* pointer far enough. Don't save it if it's a blank line,
2507
* though, or if it duplicates the most recent previous
2510
if (strlen((char *)buf) != 0)
2514
int saveflag = 1; /* assume we will be saving it */
2516
if (q = ossprvcmd(histhead))
2520
while (*p == *q && *p != '\0' && *q != '\0')
2525
if (*p == *q) /* is this a duplicate command? */
2526
saveflag = 0; /* if so, don't save it */
2531
for (q = buf, advtail = 0 ; q <= eol ; ++q)
2534
histhead = ossadvhp(histhead);
2535
if (histhead == histtail)
2537
histtail = ossadvhp(histtail);
2543
* If we have encroached on space that was already
2544
* occupied, throw away the entire command we have
2545
* partially trashed; to do so, advance the tail
2546
* pointer to the next null byte.
2551
histtail = ossadvhp(histtail);
2552
histtail = ossadvhp(histtail);
2556
# endif /* USE_HISTORY */
2559
* Finally, copy the buffer to the screen save buffer (if
2560
* applicable), and return the contents of the buffer. Note
2561
* that we add an extra carriage return if we were already
2562
* on the max_line, since we scrolled the screen in this
2563
* case; otherwise, ossaddsbe will add all the blank lines
2564
* that are necessary.
2566
ossaddsbe((char *)buf, (char *)p, x, y);
2570
/* input is no longer in progress */
2571
S_gets_in_progress = FALSE;
2572
S_gets_buf[0] = '\0';
2574
/* return success */
2578
/* extended key code - get the second half of the code */
2579
c = event_info.key[1];
2581
/* handle the command key code */
2584
# ifdef USE_SCROLLBACK
2587
char *old_scrbuf_free;
2590
* Add the contents of the line buffer, plus any blank
2591
* lines, to the screen buffer, filling the screen to
2592
* the bottom. Before we do, though, save the current
2593
* scrollback buffer free pointer, so we can take our
2594
* buffer back out of the scrollback buffer when we're
2595
* done - this is just temporary so that the current
2596
* command shows up in the buffer while we're in
2597
* scrollback mode and is redrawn when we're done.
2599
old_scrbuf_free = scrbuf_free;
2600
ossaddsbe((char *)buf, (char *)p, x, y);
2602
/* run scrollback mode */
2606
/* restore the old free pointer */
2607
scrbuf_free = old_scrbuf_free;
2608
*scrbuf_free = '\0';
2610
/* go back to our original column */
2614
# endif /* USE_SCROLLBACK */
2635
x = max_column, --y;
2636
while (p > buf && t_isspace(*p))
2640
x = max_column, --y;
2642
while (p > buf && !t_isspace(*(p-1)))
2646
x = max_column, --y;
2664
case CMD_WORD_RIGHT:
2665
while (p < eol && !t_isspace(*p))
2671
while (p < eol && t_isspace(*p))
2680
/* delete a character */
2681
oss_gets_delchar(buf, p, &eol, x, y);
2687
/* remove spaces preceding word */
2688
while (p >= buf && *p <= ' ')
2689
oss_gets_backsp(buf, &p, &eol, &x, &y);
2691
/* remove previous word (i.e., until we get a space) */
2692
while (p >= buf && *p > ' ')
2693
oss_gets_backsp(buf, &p, &eol, &x, &y);
2705
if (c == CMD_UP && !ossprvcmd(S_gets_curhist))
2706
break; /* no more history - ignore arrow */
2707
if (c == CMD_DOWN && !ossnxtcmd(S_gets_curhist))
2708
break; /* no more history - ignore arrow */
2709
if (c == CMD_UP && !ossnxtcmd(S_gets_curhist))
2711
/* first Up arrow - save current buffer */
2712
strcpy(S_hist_sav, (char *)buf);
2714
# endif /* USE_HISTORY */
2728
* We're at the start of the line now; fall through for
2729
* KILL, UP, and DOWN to the code which deletes to the
2736
* write spaces to the end of the line, to clear out
2737
* the screen display of the old characters
2741
memset(p, ' ', eol - p);
2742
ossdsp_str(y, x, text_color, p, eol - p);
2745
/* truncate the buffer at the insertion point */
2752
S_gets_curhist = ossprvcmd(S_gets_curhist);
2753
osshstcpy(buf, S_gets_curhist);
2755
else if (c == CMD_DOWN)
2757
if (!ossnxtcmd(S_gets_curhist))
2758
break; /* no more */
2759
S_gets_curhist = ossnxtcmd(S_gets_curhist);
2760
if (ossnxtcmd(S_gets_curhist)) /* on a valid command */
2761
osshstcpy(buf, S_gets_curhist); /* ... so use it */
2764
/* no more history - restore original line */
2765
strcpy((char *)buf, S_hist_sav);
2768
if ((c == CMD_UP || c == CMD_DOWN)
2769
&& strlen((char *)buf) != 0)
2771
/* get the end pointer based on null termination */
2772
eol = buf + strlen((char *)buf);
2774
/* display the string */
2775
ossdsp_str_scr(&y, &x, text_color, p, eol - p);
2777
/* move to the end of the line */
2780
# endif /* USE_HISTORY */
2786
if (++x > max_column)
2795
/* on end of file, return null */
2801
if (c >= ' ' && eol < eob)
2803
/* open up the line and insert the character */
2805
memmove(p + 1, p, eol - p);
2810
/* write the updated part of the line */
2811
ossdsp_str_scr(&y, &x, text_color, p, eol - p);
2813
/* move the cursor back to the insertion point */
2815
oss_gets_csrleft(&y, &x, eol - p);
2823
* Read a line of input. We implement this in terms of the timeout input
2824
* line reader, passing an infinite timeout to that routine.
2826
uchar *os_gets(unsigned char *buf, size_t bufl)
2830
/* cancel any previous input, clearing the buffer */
2831
os_gets_cancel(TRUE);
2833
/* get a line of input, with no timeout */
2834
evt = os_gets_timeout(buf, bufl, 0, FALSE);
2836
/* translate the event code to the appropriate return value */
2840
/* we got a line of input - return a pointer to our buffer */
2844
/* end of file - return null */
2848
/* we don't expect any other results */
2854
#else /* USE_STATLINE */
2856
#endif /* USE_STATLINE */
2858
/* ------------------------------------------------------------------------ */
2860
* Highlighting and colors
2863
#ifdef STD_OS_HILITE
2867
* Set text attributes
2869
void os_set_text_attr(int attr)
2873
/* if we're in plain mode, ignore it */
2877
/* if the attributes aren't changing, do nothing */
2878
if (osssb_cur_attrs == attr)
2882
* add the attribute sequence to the scrollback buffer (encoding with
2883
* our plus-one code, to avoid storing null bytes)
2885
buf[0] = OSGEN_ATTR;
2886
buf[1] = (char)(attr + 1);
2890
/* translate the codes to an internal ossdsp color */
2891
text_color = ossgetcolor(osssb_cur_fg, osssb_cur_bg, attr,
2892
osssb_screen_color);
2896
* Translate a color from the os_color_t encoding to an OSGEN_xxx color.
2898
static char osgen_xlat_color_t(os_color_t color)
2903
/* the OSGEN_COLOR_xxx value */
2906
/* the RGB components for the color */
2907
unsigned char rgb[3];
2909
struct color_map_t *p;
2910
struct color_map_t *bestp;
2911
static struct color_map_t color_map[] =
2913
{ OSGEN_COLOR_BLACK, { 0x00, 0x00, 0x00 } },
2914
{ OSGEN_COLOR_WHITE, { 0xFF, 0xFF, 0xFF } },
2915
{ OSGEN_COLOR_RED, { 0xFF, 0x00, 0x00 } },
2916
{ OSGEN_COLOR_BLUE, { 0x00, 0x00, 0xFF } },
2917
{ OSGEN_COLOR_GREEN, { 0x00, 0x80, 0x00 } },
2918
{ OSGEN_COLOR_YELLOW, { 0xFF, 0xFF, 0x00 } },
2919
{ OSGEN_COLOR_CYAN, { 0x00, 0xFF, 0xFF } },
2920
{ OSGEN_COLOR_SILVER, { 0xC0, 0xC0, 0xC0 } },
2921
{ OSGEN_COLOR_GRAY, { 0x80, 0x80, 0x80 } },
2922
{ OSGEN_COLOR_MAROON, { 0x80, 0x00, 0x00 } },
2923
{ OSGEN_COLOR_PURPLE, { 0x80, 0x00, 0x80 } },
2924
{ OSGEN_COLOR_MAGENTA, { 0xFF, 0x00, 0xFF } },
2925
{ OSGEN_COLOR_LIME, { 0x00, 0xFF, 0x00 } },
2926
{ OSGEN_COLOR_OLIVE, { 0x80, 0x80, 0x00 } },
2927
{ OSGEN_COLOR_NAVY, { 0x00, 0x00, 0x80 } },
2928
{ OSGEN_COLOR_TEAL, { 0x00, 0x80, 0x80 } }
2930
unsigned char r, g, b;
2931
unsigned long best_dist;
2934
* If it's parameterized, map it by shifting the parameter code (in
2935
* the high-order 8 bits of the os_color_t) to our single-byte code,
2936
* which is defined as exactly the same code as the os_color_t values
2937
* but shifted into the low-order 8 bits.
2939
if (os_color_is_param(color))
2940
return (char)((color >> 24) & 0xFF);
2942
/* break the color into its components */
2943
r = os_color_get_r(color);
2944
g = os_color_get_g(color);
2945
b = os_color_get_b(color);
2947
/* search for the closest match among our 16 ANSI colors */
2948
for (i = 0, p = color_map, bestp = 0, best_dist = 0xFFFFFFFF ;
2949
i < sizeof(color_map)/sizeof(color_map[0]) ; ++i, ++p)
2954
/* calculate the delta for each component */
2959
/* calculate the "distance" in RGB space */
2960
dist = rd*rd + gd*gd + bd*bd;
2962
/* if it's an exact match, we need look no further */
2966
/* if it's the smallest distance so far, note it */
2967
if (dist < best_dist)
2974
/* return the OSGEN_COLOR_xxx ID of the best match we found */
2979
* Set the text colors.
2981
* The foreground and background colors apply to subsequent characters
2982
* displayed via os_print() (etc). If the background color is set to zero,
2983
* it indicates "transparent" drawing: subsequent text is displayed with
2984
* the "screen" color.
2986
void os_set_text_color(os_color_t fg, os_color_t bg)
2990
/* if we're in plain mode, ignore it */
2994
/* add the color sequence to the scrollback buffer */
2995
buf[0] = OSGEN_COLOR;
2996
buf[1] = osgen_xlat_color_t(fg);
2997
buf[2] = osgen_xlat_color_t(bg);
3001
/* translate the codes to an internal ossdsp color */
3002
text_color = ossgetcolor(fg, bg, osssb_cur_attrs, osssb_screen_color);
3006
* Set the screen color
3008
void os_set_screen_color(os_color_t color)
3010
/* if we're in plain mode, ignore it */
3014
/* set the new background color */
3015
osssb_screen_color = color;
3016
osssb_oss_screen_color = ossgetcolor(OSGEN_COLOR_TEXT,
3017
osgen_xlat_color_t(color), 0, 0);
3020
* recalculate the current text color, since it will be affected by the
3021
* background change if its background is transparent
3023
text_color = ossgetcolor(osssb_cur_fg, osssb_cur_bg, osssb_cur_attrs,
3024
osssb_screen_color);
3026
/* redraw the screen in the new background color */
3030
/* redraw the screen if necessary */
3031
void osssb_redraw_if_needed()
3033
/* this implementation never defers redrawing - do nothing */
3036
/* set the default cursor position */
3037
void osssb_cursor_to_default_pos()
3039
/* we don't need to do anything special here */
3044
void os_set_text_attr(int attr)
3046
/* attributes are not supported in non-RUNTIME mode */
3049
void os_set_text_color(os_color_t fg, os_color_t bg)
3051
/* colors aren't supported in non-RUNTIME mode - ignore it */
3054
void os_set_screen_color(os_color_t color)
3056
/* colors aren't supported in non-RUNTIME mode - ignore it */
3059
#endif /* RUNTIME */
3061
#endif /* STD_OS_HILITE */
3063
/* ------------------------------------------------------------------------ */
3065
* clear the screen, deleting all scrollback information
3072
/* do nothing in 'plain' mode */
3076
/* forget the scrollback buffer's contents */
3077
scrbuf_free = scrbuf;
3078
scrbuf_head = scrbuf_tail = scrbuf;
3079
scrtop = scrbot = scrlast = 0;
3081
memset(scrbuf, 0, (size_t)scrbufl);
3086
#endif /* STD_OSCLS */
3088
/* ------------------------------------------------------------------------ */
3090
* Simple implementation of os_get_sysinfo. This can be used for any
3091
* non-HTML version of the system, since all sysinfo codes currently
3092
* pertain to HTML features. Note that new sysinfo codes may be added
3093
* in the future which may be relevant to non-html versions, so the
3094
* sysinfo codes should be checked from time to time to ensure that new
3095
* codes relevant to this system version are handled correctly here.
3097
int os_get_sysinfo(int code, void *param, long *result)
3100
/* if the oss layer recognizes the code, defer to its judgment */
3101
if (oss_get_sysinfo(code, param, result))
3105
/* check the type of information they're requesting */
3108
case SYSINFO_INTERP_CLASS:
3109
/* we're a character-mode text-only interpreter */
3110
*result = SYSINFO_ICLASS_TEXT;
3118
case SYSINFO_WAV_MIDI_OVL:
3119
case SYSINFO_WAV_OVL:
3124
case SYSINFO_PREF_IMAGES:
3125
case SYSINFO_PREF_SOUNDS:
3126
case SYSINFO_PREF_MUSIC:
3127
case SYSINFO_PREF_LINKS:
3128
case SYSINFO_LINKS_HTTP:
3129
case SYSINFO_LINKS_FTP:
3130
case SYSINFO_LINKS_NEWS:
3131
case SYSINFO_LINKS_MAILTO:
3132
case SYSINFO_LINKS_TELNET:
3133
case SYSINFO_PNG_TRANS:
3134
case SYSINFO_PNG_ALPHA:
3137
case SYSINFO_MNG_TRANS:
3138
case SYSINFO_MNG_ALPHA:
3139
case SYSINFO_BANNERS:
3141
* we don't support any of these features - set the result to 0
3146
/* return true to indicate that we recognized the code */
3150
/* not recognized */
3155
/* ------------------------------------------------------------------------ */
3157
* Set the saved-game extension. Most platforms don't need to do
3158
* anything with this information, and in fact most platforms won't even
3159
* have a way of letting the game author set the saved game extension,
3160
* so this trivial implementation is suitable for most systems.
3162
* The purpose of setting a saved game extension is to support platforms
3163
* (such as Windows) where the filename suffix is used to associate
3164
* document files with applications. Each stand-alone executable
3165
* generated on such platforms must have a unique saved game extension,
3166
* so that the system can associate each game's saved position files
3167
* with that game's executable.
3169
void os_set_save_ext(const char *ext)
3171
/* ignore the setting */
3175
/* ------------------------------------------------------------------------ */
3177
* Set the game title. Most platforms have no use for this information,
3178
* so they'll just ignore it. This trivial implementation simply
3179
* ignores the title.
3181
#ifdef USE_NULL_SET_TITLE
3183
void os_set_title(const char *title)
3185
/* ignore the information */
3188
#endif /* USE_NULL_SET_TITLE */
3190
/* ------------------------------------------------------------------------ */
3192
* The "banner" window functions are not supported in this implementation.
3194
void *os_banner_create(void *parent, int where, void *other, int wintype,
3195
int align, int siz, int siz_units, unsigned long style)
3200
void os_banner_delete(void *banner_handle)
3204
void os_banner_orphan(void *banner_handle)
3208
void os_banner_disp(void *banner_handle, const char *txt, size_t len)
3212
void os_banner_set_attr(void *banner_handle, int attr)
3216
void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg)
3220
void os_banner_set_screen_color(void *banner_handle, os_color_t color)
3224
void os_banner_flush(void *banner_handle)
3228
void os_banner_set_size(void *banner_handle, int siz, int siz_units,
3233
void os_banner_size_to_contents(void *banner_handle)
3237
void os_banner_start_html(void *banner_handle)
3241
void os_banner_end_html(void *banner_handle)
3245
void os_banner_goto(void *banner_handle, int row, int col)