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
osgen3 - Operating System dependent functions, general implementation
15
TADS 3 Version, with new "banner" interface
17
This module contains certain OS-dependent functions that are common
18
to many character-mode platforms. ("Character mode" means that the
19
display is organized as a rectangular grid of characters in a monospaced
20
font. This module isn't usable for most GUI systems, because it doesn't
21
have any support for variable-pitch fonts - GUI ports generally need to
22
provide their own custom versions of the os_xxx() functions this module
23
module provides. On GUI systems you should simply omit this entire
24
module from the build, and instead substitute a new module of your own
25
creation that defines your custom versions of the necessary os_xxx()
28
Some routines in this file are selectively enabled according to macros
29
defined in os.h, since some ports that use this file will want to provide
30
their own custom versions of these routines instead of the ones defined
31
here. The macros and associated functions are:
33
USE_STDIO - implement os_print, os_flush, os_gets with stdio functions
34
USE_DOSEXT - implement os_remext, os_defext using MSDOS-like filename
36
USE_NULLINIT - implement os_init and os_term as do-nothing routines
37
USE_NULLPAUSE - implement os_expause as a do-nothing routine
38
USE_EXPAUSE - use an os_expause that prints a 'strike any key' message
40
USE_TIMERAND - implement os_rand using localtime() as a seed
41
USE_NULLSTAT - use a do-nothing os_status function
42
USE_NULLSCORE - use a do-nothing os_score function
43
RUNTIME - enable character-mode console implementation
44
USE_STATLINE - implement os_status and os_score using character-mode
45
status line implementation
46
USE_OVWCHK - implements default saved file overwrite check
47
USE_NULLSTYPE - use a dummy os_settype routine
48
USE_NULL_SET_TITLE - use an empty os_set_title() implementation
50
If USE_STDIO is defined, we'll implicitly define USE_STDIO_INPDLG.
52
If USE_STATLINE is defined, certain subroutines must be provided for
53
your platform that handle the character-mode console:
54
ossclr - clears a portion of the screen
55
ossdsp - displays text in a given color at a given location
56
ossscr - scroll down (i.e., moves a block of screen up)
57
ossscu - scroll up (i.e., moves a block of screen down)
58
ossloc - locate cursor
60
If USE_STATLINE is defined, certain sub-options can be enabled:
61
USE_SCROLLBACK - include output buffer capture in console system
62
USE_HISTORY - include command editing and history in console system
66
01/01/98 MJRoberts - moved certain osgen.c routines to osnoui.c
67
04/24/93 JEras - add os_locate() for locating tads-related files
68
04/12/92 MJRoberts - add os_strsc (string score) function
69
03/26/92 MJRoberts - add os_setcolor function
70
09/26/91 MJRoberts - os/2 user exit support
71
09/04/91 MJRoberts - stop reading resources if we find '$eof' resource
72
08/28/91 MJRoberts - debugger bug fix
73
08/01/91 MJRoberts - make runstat work correctly
74
07/30/91 MJRoberts - add debug active/inactive visual cue
75
05/23/91 MJRoberts - add user exit reader
76
04/08/91 MJRoberts - add full-screen debugging support
77
03/10/91 MJRoberts - integrate John's qa-scripter mods
78
11/27/90 MJRoberts - use time() not localtime() in os_rand; cast time_t
79
11/15/90 MJRoberts - created (split off from os.c)
97
#if defined(TURBO) || defined(DJGPP)
105
* Flag: use "plain" mode. If this is set, we'll use plain stdio output
106
* rather than our window-oriented display.
111
# ifdef USE_SCROLLBACK
114
* Screen size variables. The underlying system-specific "oss" code must
115
* initialize these during startup and must keep them up-to-date if the
116
* screen size ever changes.
118
int G_oss_screen_width = 80;
119
int G_oss_screen_height = 24;
122
# endif /* USE_SCROLLBACK */
126
* The special character codes for controlling color.
130
* set text attributes: this is followed by one byte giving the new
136
* Set text color: this is followed by two bytes giving the foreground and
137
* background colors as OSGEN_COLOR_xxx codes.
139
* Note well that the colors encoded in this escape sequence are
140
* OSGEN_COLOR_xxx values, not os_color_t values. The latter require 32
141
* bits because they can store 24-bit RGB values plus some special
142
* parameter codes, while our internal OSGEN_COLOR_xxx values are only a
145
#define OSGEN_COLOR 2
149
* If this port is to use the default saved file overwrite check, define
150
* USE_OVWCHK. This routine tries to open the file; if successful, the
151
* file is closed and we ask the user if they're sure they want to overwrite
155
int os_chkovw(char *filename)
159
if ((fp = fopen( filename, "r" )) != 0)
164
os_printz("That file already exists. Overwrite it? (y/n) >");
165
os_gets((uchar *)buf, sizeof(buf));
166
if (buf[0] != 'y' && buf[0] != 'Y')
171
#endif /* USE_OVWCHK */
174
* non-stop mode does nothing in character-mode implementations, since the
175
* portable console layer handles MORE mode
177
void os_nonstop_mode(int flag)
181
/* ------------------------------------------------------------------------ */
183
* Ports can implement os_flush and os_gets as calls to the stdio routines
184
* of the same name, and os_print and os_printz using the fputs() to
185
* stdout, by defining USE_STDIO. These definitions can be used for any
186
* port for which the standard C run-time library is available.
192
* os_printz works just like fputs() to stdout: we write a null-terminated
193
* string to the standard output.
195
void os_printz(const char *str)
201
* os_puts works like fputs() to stdout, except that we are given a
202
* separate length, and the string might not be null-terminated
204
void os_print(const char *str, size_t len)
206
printf("%.*s", (int)len, str);
210
* os_flush forces output of anything buffered for standard output. It
211
* is generally used prior to waiting for a key (so the normal flushing
212
* may not occur, as it does when asking for a line of input).
220
* update the display - since we're using text mode, there's nothing we
223
void os_update_display(void)
228
* os_gets performs the same function as gets(). It should get a
229
* string from the keyboard, echoing it and allowing any editing
230
* appropriate to the system, and return the null-terminated string as
231
* the function's value. The closing newline should NOT be included in
234
uchar *os_gets(uchar *s, size_t bufl)
236
/* make sure everything we've displayed so far is actually displayed */
239
/* get a line of input from the standard input */
240
return((uchar *)fgets((char *)s, bufl, stdin));
244
* The default stdio implementation does not support reading a line of
247
int os_gets_timeout(unsigned char *buf, size_t bufl,
248
unsigned long timeout, int resume_editing)
250
/* tell the caller this operation is not supported */
251
return OS_EVT_NOTIMEOUT;
255
* since we don't support os_gets_timeout(), we don't need to do anything
256
* in the cancel routine
258
void os_gets_cancel(int reset)
260
/* os_gets_timeout doesn't do anything, so neither do we */
264
* Get an event - stdio version. This version does not accept a timeout
265
* value, and can only get a keystroke.
267
int os_get_event(unsigned long timeout, int use_timeout,
268
os_event_info_t *info)
270
/* if there's a timeout, return an error indicating we don't allow it */
272
return OS_EVT_NOTIMEOUT;
274
/* get a key the normal way */
275
info->key[0] = os_getc();
277
/* if it's an extended key, get the other key */
278
if (info->key[0] == 0)
280
/* get the extended key code */
281
info->key[1] = os_getc();
283
/* if it's EOF, return an EOF event rather than a key event */
284
if (info->key[1] == CMD_EOF)
288
/* return the keyboard event */
292
#endif /* USE_STDIO */
294
/******************************************************************************
295
* Ports without any special initialization/termination requirements can define
296
* USE_NULLINIT to pick up the default definitions below. These do nothing, so
297
* ports requiring special handling at startup and/or shutdown time must define
298
* their own versions of these routines.
299
******************************************************************************/
302
/* os_init returns 0 for success, 1 for failure. The arguments are &argc, the
303
* address of the count of arguments to the program, and argv, the address of
304
* an array of up to 10 pointers to those arguments. For systems which don't
305
* pass a standard command line (such as the Mac Finder), the arguments should
306
* be read here using some alternate mechanism (an alert box, for instance),
307
* and the values of argc and argv[] updated accordingly. Note that a maximum
308
* of 10 arguments are allowed to be stored in the argv[] array. The command
309
* line itself can be stored in buf, which is a buffer passed by the caller
310
* guaranteed to be bufsiz bytes long.
312
* Unix conventions are followed, so argc is 1 when no arguments are present.
313
* The final argument is a prompt string which can be used to ask the user for
314
* a command line; its use is not required, but may be desirable for producing
315
* a relevant prompt message. See the Mac implementation for a detailed
316
* example of how this mechanism is used.
318
int os_init(int *argc, char *argv[], const char *prompt,
319
char *buf, int bufsiz)
332
* os_term should perform any necessary cleaning up, then terminate the
333
* program. The int argument is a return code to be passed to the
334
* caller, generally 0 for success and other for failure.
340
#endif /* USE_NULLINIT */
342
/* ------------------------------------------------------------------------ */
344
* Ports can define USE_NULLPAUSE if no pause is required on exit.
346
* Ports needing an exit pause, and can simply print a message (with
347
* os_print) and wait for a key (with os_getc) can define USE_EXPAUSE.
351
void os_expause(void)
355
#endif /* USE_NULLPAUSE */
358
void os_expause(void)
360
os_printz("(Strike any key to exit...)");
364
#endif /* USE_EXPAUSE */
369
* USE_NULLSTAT defines a do-nothing version of os_status.
371
void os_status(int stat)
373
/* ignore the new status */
380
#endif /* USE_NULLSTAT */
384
* USE_NULLSCORE defines a do-nothing version of os_score.
386
void os_score(int cur, int turncount)
388
/* ignore the score information */
391
void os_strsc(const char *p)
395
#endif /* USE_NULLSCORE */
397
/* ------------------------------------------------------------------------ */
402
/* forward-declare the window control structure type */
403
typedef struct osgen_win_t osgen_win_t;
406
* We can be compiled with or without scrollback. The first version
407
* defines the scrollback implementation; the second just defines some
408
* dummy functions for the non-scrollback implementation.
410
# ifdef USE_SCROLLBACK
412
/* ------------------------------------------------------------------------ */
414
* Character color structure
416
typedef struct osgen_charcolor_t osgen_charcolor_t;
417
struct osgen_charcolor_t
419
/* foreground color, as an OSGEN_COLOR_xxx value */
422
/* background color, as an OSGEN_COLOR_xxx value */
427
* Window control structure. Each on-screen window is represented by one
428
* of these structures.
432
/* type of the window - this is an OS_BANNER_TYPE_xxx code */
438
/* next window in window list */
442
* Parent window. We take our display area out of the parent window's
443
* allocated space at the time we lay out this window.
447
/* head of list of children of this window */
448
osgen_win_t *first_child;
451
* The window's alignment type - this determines where the window goes
452
* relative to the main window. This is an OS_BANNER_ALIGN_xxx
453
* alignment type code.
457
/* size type (as an OS_BANNER_SIZE_xxx value) */
461
* The window's size. If size_type is OS_BANNER_SIZE_ABS, this is the
462
* size of the window in character cells. If size_type is
463
* OS_BANNER_SIZE_PCT, this is given as a percentage of the full screen
468
/* upper-left corner position of window on screen */
472
/* size of window on screen */
477
* Cursor position (location of next output). These are given in
478
* "document coordinates", which is to say that they're relative to
479
* the start of the text in the buffer.
481
* To translate to "window coordinates", simply subtract the scrolling
482
* offsets, which give the document coordinates of the first character
483
* displayed at the upper left corner of the window.
485
* To translate to absolute screen coordinates, first subtract the
486
* scrolling offsets to get window coordinates, then add the window's
487
* screen position (winx,winy).
493
* maximum row and line where we've actually written any text (this
494
* can be used for purposes like setting horizontal scrollbar limits
495
* and sizing a window horizontally to its contents)
500
/* scrolling offset of text displayed in window */
505
* current text foreground and background colors (as OSGEN_COLOR_xxx
511
/* current text attributes */
514
/* window fill color (and oss color code for same) */
520
* Ordinary text stream window. This is a subclass of the basic
521
* osgen_win_t window type, used when win_type is OS_BANNER_TYPE_TEXT.
523
* Ordinary text windows keep a circular buffer of scrollback text. We
524
* optimize space by using escape codes embedded in the saved text stream
525
* to select colors and attributes.
527
* In the circular text buffer, each line ends with a null byte. We keep
528
* an array of line-start pointers to make it fast and easy to find the
529
* first byte of a particular line. The line-start array is also
530
* circular, and is organized in ascending order of row number.
532
typedef struct osgen_txtwin_t osgen_txtwin_t;
533
struct osgen_txtwin_t
535
/* embed the base class */
538
/* text color and attributes at start of latest line */
543
/* window text buffer, and size of the buffer */
547
/* next free byte of window text buffer */
550
/* circular array of line-start pointers */
554
/* index of first line-start pointer in use */
557
/* number of lines of text stored in the buffer */
562
* Text Grid window. This is a subclass of the basic window type,
563
* osgen_win_t, used when win_type is OS_BANNER_TYPE_TEXTGRID.
565
* A text grid window keeps a simple rectangular array of text, and a
566
* corresponding array of the color of each character. The size of each
567
* array is at least as large as the window's actual area on the screen;
568
* when we resize the window, we'll reallocate the arrays at a larger size
569
* if the window has expanded beyond the stored size. We don't keep any
570
* scrollback information in a text grid; we only keep enough to cover
571
* what's actually on the screen.
573
typedef struct osgen_gridwin_t osgen_gridwin_t;
574
struct osgen_gridwin_t
576
/* embed the base class */
579
/* width and height of the text and color arrays */
587
osgen_charcolor_t *grid_color;
594
/* keep the cursor visible when adding text to the window */
595
#define OSGEN_AUTO_VSCROLL 0x0001
597
/* the window buffer is full and we're allowing nothing more to enter it */
598
#define OSGEN_FULL 0x0002
600
/* the window is in deferred-redraw mode */
601
#define OSGEN_DEFER_REDRAW 0x0004
604
* MORE mode in the banner. Note that we keep track of this only so that
605
* we can indicate it on queries for the banner style; we count on the
606
* caller to handle the actual prompting for us.
608
#define OSGEN_MOREMODE 0x0008
610
/* child banner "strut" flags */
611
#define OSGEN_VSTRUT 0x0010
612
#define OSGEN_HSTRUT 0x0020
615
* The main text area window. This window is special, because it's the
616
* root of the window tree.
618
static osfar_t osgen_txtwin_t *S_main_win = 0;
620
/* default status line window */
621
static osfar_t osgen_txtwin_t *S_status_win = 0;
623
/* default input/output window (for os_print, os_gets, etc) */
624
static osfar_t osgen_txtwin_t *S_default_win = 0;
626
/* current scrollback-mode window */
627
static osfar_t osgen_txtwin_t *S_sbmode_win = 0;
629
/* scrollback mode settings */
630
static osfar_t int S_sbmode_orig_scrolly;
631
static osfar_t int S_sbmode_orig_x;
632
static osfar_t char **S_sbmode_orig_last_line;
633
static osfar_t char *S_sbmode_orig_txtfree;
636
* flag: we're using a special cursor position; we use this to override our
637
* normal default cursor position
639
static osfar_t int S_special_cursor_pos = FALSE;
640
static osfar_t int S_special_cursor_x = 0;
641
static osfar_t int S_special_cursor_y = 0;
644
* Flag: deferred redraw required. This indicates that something happened
645
* that requires redrawing the screen, but we didn't bother actually doing
646
* the redrawing immediately in case other things that would also require
647
* redrawing were to occur shortly.
649
static osfar_t int S_deferred_redraw = FALSE;
652
* Input buffer state. This information is defined statically because
653
* os_gets_timeout() can carry the information from invocation to
654
* invocation when input editing is interrupted by a tmieout.
656
static osfar_t char S_gets_internal_buf[256]; /* internal save buffer */
657
static osfar_t char *S_gets_buf = S_gets_internal_buf; /* current save buf */
658
static osfar_t char *S_gets_buf_end = 0; /* end of input buffer */
659
static osfar_t size_t S_gets_buf_siz = sizeof(S_gets_internal_buf); /* size */
660
static osfar_t int S_gets_ofs; /* offset in buffer of insertion point */
661
static osfar_t char *S_gets_curhist; /* current history pointer */
662
static osfar_t int S_gets_x, S_gets_y; /* saved cursor position */
665
/* save buffer for line being edited before history recall began */
666
static osfar_t char S_hist_sav_internal[256];
667
static osfar_t char *S_hist_sav = S_hist_sav_internal;
668
static osfar_t size_t S_hist_sav_siz = sizeof(S_hist_sav_internal);
669
# endif /* USE_HISTORY */
672
* Flag: input is already in progress. When os_gets_timeout() returns
673
* with OS_EVT_TIMEOUT, it sets this flag to true. os_gets_cancel() sets
674
* this flag to false.
676
* When os_gets_timeout() is called again, it checks this flag to see if
677
* the input session was cancelled; if not, the routine knows that the
678
* partially-edited input line is already displayed where it left off,
679
* because the display has not been modified since the interrupted call to
680
* os_gets_timeout() returned.
682
static osfar_t int S_gets_in_progress = FALSE;
684
/* forward declarations */
685
static void osssb_add_color_code(osgen_txtwin_t *win);
686
static void osgen_gridwin_clear(osgen_gridwin_t *win, size_t ofs, size_t len);
687
static void osgen_redraw_win(osgen_win_t *win);
688
static void osgen_scrdisp(osgen_win_t *win, int x, int y, int len);
689
static void osgen_gets_redraw_cmdline(void);
694
static void osgen_delete_win(osgen_win_t *win)
698
osgen_txtwin_t *twin;
699
osgen_gridwin_t *gwin;
701
/* if we have a parent, remove ourselves from our parent's child list */
702
if (win->parent != 0)
704
/* scan our parent's child list */
705
for (prv = 0, cur = win->parent->first_child ;
706
cur != 0 && cur != win ;
707
prv = cur, cur = cur->nxt) ;
709
/* if we found it, unlink it */
712
/* set the previous item's forward pointer */
714
win->parent->first_child = win->nxt;
721
* Remove the parent reference from each child of this window. We're
722
* going to be deleted, so we can't keep references from our children
725
for (cur = win->first_child ; cur != 0 ; cur = cur->nxt)
728
/* delete the window according to its type */
729
switch(win->win_type)
731
case OS_BANNER_TYPE_TEXT:
732
/* get the text window subclass data */
733
twin = (osgen_txtwin_t *)win;
735
/* delete its scrollback buffer, if it has one */
736
if (twin->txtbuf != 0)
737
osfree(twin->txtbuf);
739
/* delete the line pointers */
740
if (twin->line_ptr != 0)
741
osfree(twin->line_ptr);
744
case OS_BANNER_TYPE_TEXTGRID:
745
/* get the grid window subclass data */
746
gwin = (osgen_gridwin_t *)win;
748
/* delete the character and color arrays */
749
if (gwin->grid_txt != 0)
750
osfree(gwin->grid_txt);
751
if (gwin->grid_color != 0)
752
osfree(gwin->grid_color);
756
/* delete the window itself */
761
* Delete a window and all of its children
763
static void osgen_delete_win_tree(osgen_win_t *win)
768
/* delete the children first */
769
for (chi = win->first_child ; chi != 0 ; chi = nxt)
771
/* remember the next one before we delete the current one */
774
/* delete this one */
775
osgen_delete_win_tree(chi);
778
/* delete this window */
779
osgen_delete_win(win);
783
* Create a window and link it into our list. We initialize the window
784
* and allocate its display buffer, but we do NOT set the window's size or
785
* position on the screen.
787
static osgen_win_t *osgen_create_win(int win_type, int where, void *other,
795
/* figure the structure size based on the window type */
798
case OS_BANNER_TYPE_TEXT:
799
struct_siz = sizeof(osgen_txtwin_t);
802
case OS_BANNER_TYPE_TEXTGRID:
803
struct_siz = sizeof(osgen_gridwin_t);
807
/* unrecognized type - return failure */
811
/* create the window object */
812
win = (osgen_win_t *)osmalloc(struct_siz);
816
/* remember the type */
817
win->win_type = win_type;
819
/* it's not in a window list yet */
822
/* initialize with default colors */
823
win->txtfg = OSGEN_COLOR_TEXT;
824
win->txtbg = OSGEN_COLOR_TRANSPARENT;
826
win->fillcolor = OSGEN_COLOR_TEXTBG;
828
/* cache the oss translation of the fill color */
829
win->oss_fillcolor = ossgetcolor(OSGEN_COLOR_TEXT, OSGEN_COLOR_TEXTBG,
832
/* start at the upper left corner */
839
* the window's position on screen will eventually be set by
840
* osgen_recalc_layout(), but initialize the position to a reasonable
841
* value for now in case anyone looks at it before then
846
/* we haven't seen any text in the window yet */
850
/* clear the flags */
853
/* remember our parent */
854
win->parent = parent;
856
/* we have no children yet */
857
win->first_child = 0;
859
/* if there's a parent, insert the window into the parent's child list */
862
/* insert into the parent's child list at the proper point */
865
case OS_BANNER_FIRST:
866
/* link it at the head of the list */
867
win->nxt = parent->first_child;
868
parent->first_child = win;
873
/* find the end of the parent's list */
874
for (cur = parent->first_child ; cur != 0 && cur->nxt != 0 ;
877
/* link it after the last element */
882
parent->first_child = win;
887
case OS_BANNER_BEFORE:
888
case OS_BANNER_AFTER:
889
/* scan the parent's child list, looking for 'other' */
890
for (prv = 0, cur = parent->first_child ;
891
cur != 0 && cur != other ;
892
prv = cur, cur = cur->nxt) ;
895
* if we didn't find 'other', link the new window at the tail
896
* of the list by default; since 'prv' will be the last item if
897
* we didn't find 'other', we can simply set the link mode to
898
* 'before' to link before the placeholder null at the end of
902
where = OS_BANNER_BEFORE;
904
/* if we're linking after 'cur', advance one position */
905
if (where == OS_BANNER_AFTER)
911
/* link before 'cur', which is right after 'prv' */
916
parent->first_child = win;
923
/* return the new window */
928
* Create a text window
930
static osgen_txtwin_t *osgen_create_txtwin(int where, void *other,
932
unsigned int buf_size,
933
unsigned int buf_lines)
937
/* create the base window */
938
win = (osgen_txtwin_t *)osgen_create_win(OS_BANNER_TYPE_TEXT,
939
where, other, parent);
941
/* if that failed, give up now */
945
/* allocate the window's buffer */
946
win->txtbufsiz = buf_size;
947
win->txtbuf = (char *)osmalloc(buf_size);
949
/* allocate the line starts */
950
win->line_ptr_cnt = buf_lines;
951
win->line_ptr = (char **)osmalloc(buf_lines * sizeof(char *));
953
/* make sure we allocated everything properly */
954
if (win->txtbuf == 0 || win->line_ptr == 0)
956
/* free anything we allocated */
957
osgen_delete_win(&win->base);
963
/* set up the buffer free pointer */
964
win->txtfree = win->txtbuf;
966
/* start out with a single line in the buffer */
969
/* set up the first line start */
971
win->line_ptr[0] = win->txtbuf;
973
/* initialize the start-of-line colors */
974
win->solfg = win->base.txtfg;
975
win->solbg = win->base.txtbg;
976
win->solattr = win->base.txtattr;
978
/* start the new first line with the current text color */
979
osssb_add_color_code(win);
981
/* return the new window */
986
* Create a text grid window
988
static osgen_gridwin_t *osgen_create_gridwin(int where, void *other,
990
int grid_wid, int grid_ht)
992
osgen_gridwin_t *win;
994
/* create the base window */
995
win = (osgen_gridwin_t *)osgen_create_win(OS_BANNER_TYPE_TEXTGRID,
996
where, other, parent);
998
/* if that failed, give up now */
1002
/* allocate the grid to the requested size */
1003
win->grid_wid = grid_wid;
1004
win->grid_ht = grid_ht;
1005
win->grid_txt = (char *)osmalloc(grid_wid * grid_ht);
1006
win->grid_color = (osgen_charcolor_t *)osmalloc(
1007
grid_wid * grid_ht * sizeof(osgen_charcolor_t));
1009
/* if we failed to allocate, delete the window and abort */
1010
if (win->grid_txt == 0 || win->grid_color == 0)
1012
/* free anything we allocated */
1013
osgen_delete_win(&win->base);
1015
/* return failure */
1019
/* clear the grid text and color arrays */
1020
osgen_gridwin_clear(win, 0, win->grid_wid * win->grid_ht);
1022
/* return the new window */
1029
static void osgen_clear_win(osgen_win_t *win)
1031
osgen_txtwin_t *twin;
1032
osgen_gridwin_t *gwin;
1034
/* check the type */
1035
switch(win->win_type)
1037
case OS_BANNER_TYPE_TEXT:
1038
/* get the text window subclass data */
1039
twin = (osgen_txtwin_t *)win;
1041
/* reset the window's scrollback buffer */
1042
twin->txtfree = twin->txtbuf;
1043
twin->line_count = 1;
1044
twin->first_line = 0;
1045
twin->line_ptr[0] = twin->txtbuf;
1047
/* start the new first line with the current text color */
1048
osssb_add_color_code(twin);
1053
case OS_BANNER_TYPE_TEXTGRID:
1054
/* get the grid window subclass data */
1055
gwin = (osgen_gridwin_t *)win;
1057
/* clear the entire grid */
1058
osgen_gridwin_clear(gwin, 0, gwin->grid_wid * gwin->grid_ht);
1064
/* put the cursor at the top left of the window */
1068
/* set the scrolling position to the top of the window */
1072
/* the content size is now zero */
1076
/* if the buffer was full, it's full no longer */
1077
win->flags &= ~OSGEN_FULL;
1080
* If this window is not auto-scrolling, don't actually clear it
1081
* visually right now, but just set a deferred-redraw on the window;
1082
* clearing a window that doesn't automatically scroll usually means
1083
* that we're updating some live status information, so we use deferred
1084
* drawing on these windows to reduce flicker during updates. If the
1085
* window automatically scrolls, then the caller presumably is
1086
* displaying more sizable data, and thus would want the user to see
1087
* the text output as it occurs.
1089
* Note that both approaches (deferred vs immediate redraw) yield the
1090
* same results in the end, because we always stop deferring redraws
1091
* when we stop to ask for input or simply pause for a time delay; the
1092
* only difference is that deferred redrawing reduces flicker by
1093
* gathering all the updates into a single operation, while immediate
1094
* update might flicker more but shows individual bits of text output
1097
if (!(win->flags & OSGEN_AUTO_VSCROLL))
1099
/* defer redrawing until we need to */
1100
win->flags |= OSGEN_DEFER_REDRAW;
1104
/* clear the window's on-screen area with its fill color */
1105
ossclr(win->winy, win->winx,
1106
win->winy + win->ht - 1, win->winx + win->wid - 1,
1107
win->oss_fillcolor);
1112
* Display text in a window, all in a single color, truncating the display
1113
* if we start before the left edge of the window or go past the right
1114
* edge of the window. The x,y coordinates are given in window
1117
static void osgen_disp_trunc(osgen_win_t *win, int y, int x, int oss_color,
1124
/* if we have deferred redrawing pending, don't bother drawing now */
1125
if (S_deferred_redraw || (win->flags & OSGEN_DEFER_REDRAW) != 0)
1128
/* get the number of characters to be displayed */
1129
chars_rem = strlen(p);
1131
/* calculate the amount of space we have to work with on the screen */
1132
wid_rem = win->wid - (x >= 0 ? x : 0);
1134
/* make sure at least some of the text overlaps the window */
1135
if (y < 0 || y >= (int)win->ht
1136
|| x + (int)chars_rem <= 0 || x >= (int)win->wid)
1140
* if we're starting to the left of the window, skip characters up to
1141
* the first character visible in the window
1146
* get the number of characters to skip - this is simply the
1147
* negative of the x position, since x position zero is the first
1153
* if we don't have enough characters to reach the left edge of
1154
* the window, we have nothing to do
1156
if (chars_rem <= (size_t)x)
1159
/* skip the desired number of characters */
1163
/* we've skipped up to column zero, so proceed from there */
1167
/* if the text entirely fits, display it and we're done */
1168
if (chars_rem < wid_rem)
1170
/* display the entire string */
1171
ossdsp(win->winy + y, win->winx + x, oss_color, p);
1178
* we have too much to display, so display as much as will fit - keep
1179
* going until we run out of space for the display (we know we'll run
1180
* out of space before we run out of text, because we know we have too
1183
while (wid_rem != 0)
1187
/* display as much as will fit, up to our buffer length */
1189
if (cur > sizeof(buf) - 1)
1190
cur = sizeof(buf) - 1;
1192
/* copy this portion to our buffer and null-terminate it */
1193
memcpy(buf, p, cur);
1197
ossdsp(win->winy + y, win->winx + x, oss_color, buf);
1199
/* advance our screen position */
1202
/* advance past the source material we just displayed */
1205
/* deduct the on-screen space we consumed from the remaining space */
1210
/* ------------------------------------------------------------------------ */
1212
* Initialize the scrollback buffer. This initializes the main text area
1215
* The oss code should call this during initialization to set up the
1216
* osgen3-layer display management; note that this routine must be called
1217
* from the oss code AFTER the screen size has been determined and stored
1218
* in the global variables G_oss_screen_width and G_oss_screen_height.
1220
void osssbini(unsigned int size)
1222
osgen_txtwin_t *win;
1224
/* allocate our main window if we're not in 'plain' mode */
1228
* Initialize the main window. The main window has no parent,
1229
* since it's the root of the window tree.
1231
S_main_win = win = osgen_create_txtwin(
1232
OS_BANNER_FIRST, 0, 0, size, size/40);
1235
/* show a message and give up */
1236
printf("There is not enough memory to run this program.\n");
1240
/* make this the default window */
1241
S_default_win = win;
1243
/* scroll to keep the cursor visible when writing to this window */
1244
win->base.flags |= OSGEN_AUTO_VSCROLL;
1246
/* initially give the window the entire screen */
1249
win->base.wid = G_oss_screen_width;
1250
win->base.ht = G_oss_screen_height;
1252
/* set the initial page size */
1253
G_os_linewidth = win->base.wid;
1254
G_os_pagelength = (win->base.ht > 2
1257
? win->base.ht - 1 : win->base.ht);
1259
/* set the initial color scheme to the default text color */
1260
os_set_text_color(OS_COLOR_P_TEXT, OS_COLOR_P_TRANSPARENT);
1261
os_set_screen_color(OS_COLOR_P_TEXTBG);
1263
/* clear the window */
1264
osgen_clear_win(&win->base);
1268
/* use the entire available display */
1269
G_os_linewidth = G_oss_screen_width;
1270
G_os_pagelength = G_oss_screen_height - 2;
1275
* Delete the scrollback buffer. The oss code should call this during
1276
* program termination to free memory allocated by the osgen3 layer.
1280
/* delete the main window and its children */
1281
if (S_main_win != 0)
1282
osgen_delete_win_tree(&S_main_win->base);
1285
/* ------------------------------------------------------------------------ */
1287
* Scrollback operations. Scrollback applies only to ordinary text
1292
* advance a pointer in a scrollback buffer
1294
static char *ossadvsp(osgen_txtwin_t *win, char *p)
1296
/* move to the next byte */
1299
/* if we've passed the end of the buffer, wrap to the beginning */
1300
if (p >= win->txtbuf + win->txtbufsiz)
1303
/* return the pointer */
1308
* decrement a scrollback buffer pointer
1310
static char *ossdecsp(osgen_txtwin_t *win, char *p)
1312
/* if we're at the start of the buffer, wrap to just past the end */
1313
if (p == win->txtbuf)
1314
p = win->txtbuf + win->txtbufsiz;
1316
/* move to the previous byte */
1319
/* return the pointer */
1324
* Get the line pointer for the given line
1326
static char **osgen_get_line_ptr(osgen_txtwin_t *win, int y)
1330
/* if the line doesn't exist, return null */
1331
if (y < 0 || (size_t)y >= win->line_count)
1334
/* add the line number to the base index to get the linear index */
1335
idx = y + win->first_line;
1337
/* wrap back to the start of the array if necessary */
1338
if (idx >= win->line_ptr_cnt)
1339
idx -= win->line_ptr_cnt;
1341
/* return the line at this index */
1342
return &win->line_ptr[idx];
1346
* Get a pointer to the text of the line in the given window at the given
1347
* document y coordinate.
1349
static char *osgen_get_line(osgen_txtwin_t *win, int y)
1353
/* get the line pointer for the given line */
1354
line_ptr = osgen_get_line_ptr(win, y);
1356
/* return the text it points to, or null if there's no such line */
1357
return (line_ptr != 0 ? *line_ptr : 0);
1361
* Add a byte to the scrollback buffer. Returns true if the byte was
1362
* successfully added, false if not.
1364
static int osssb_add_byte(osgen_txtwin_t *win, char c)
1368
/* if the window is full, indicate failure */
1369
if ((win->base.flags & OSGEN_FULL) != 0)
1373
* If there's no room, and we're not in auto-vscroll mode, simply
1374
* discard the text. A window that is not in auto-vscroll mode is
1375
* designed to always show the oldest text, so if we overflow the
1376
* buffer, then we want to start discarding the newest test.
1378
nxtfree = ossadvsp(win, win->txtfree);
1379
if (nxtfree == win->line_ptr[win->first_line]
1380
&& !(win->base.flags & OSGEN_AUTO_VSCROLL))
1383
* The buffer is full, and we're not in auto-vscroll mode -
1384
* discard the new text. Before we do, set the current last byte
1385
* to null, to terminate the current line at this point.
1387
*win->txtfree = '\0';
1389
/* set the 'full' flag */
1390
win->base.flags |= OSGEN_FULL;
1392
/* indicate failure */
1396
/* add the character to the buffer */
1399
/* advance the free pointer */
1400
win->txtfree = nxtfree;
1403
* if the free pointer has just collided with the start of the oldest
1404
* line, delete the oldest line
1406
if (win->txtfree == win->line_ptr[win->first_line])
1408
/* delete the oldest line to make room for the new data */
1410
if (win->first_line >= win->line_ptr_cnt)
1411
win->first_line = 0;
1413
/* we have one less line in the buffer */
1416
/* adjust our document cooordinates for the loss of a line */
1420
* Adjust the scrolling position for the loss of a line. If the
1421
* window is displaying the line that we just deleted (i.e., the
1422
* window's vertical scroll offset is zero), we must redraw the
1423
* window; otherwise, the change won't affect the display, so we
1424
* can merely adjust the scrolling offset.
1426
if (win->base.scrolly == 0)
1427
win->base.flags |= OSGEN_DEFER_REDRAW;
1429
win->base.scrolly--;
1432
/* we successfully added the byte */
1437
* Add a given number of bytes. The bytes will be added as a unit - if we
1438
* can't add all of the bytes, we won't add any of them.
1440
static int osssb_add_bytes(osgen_txtwin_t *win, const char *p, size_t len)
1444
/* note the original free pointer */
1445
orig_free = win->txtfree;
1448
for ( ; len != 0 ; --len)
1450
/* try adding this byte */
1451
if (!osssb_add_byte(win, *p++))
1454
* failure - forget everything we've added by resetting the
1455
* free pointer to its original value on entry
1457
win->txtfree = orig_free;
1459
/* indicate failure */
1464
/* we added all of the bytes successfully */
1469
* Add a "safety" null byte. This adds a null byte at the end of the
1470
* buffer, in case we need to inspect the current line before we add any
1473
static void osssb_add_safety_null(osgen_txtwin_t *win)
1476
if (osssb_add_byte(win, '\0'))
1479
* we added the null - decrement the free pointer so we overwrite
1480
* the null byte if we add any more text to the current line
1482
win->txtfree = ossdecsp(win, win->txtfree);
1487
* Add an appropriate color code to the scrollback buffer to yield the
1488
* current color setting.
1490
static void osssb_add_color_code(osgen_txtwin_t *win)
1494
/* if we have any attributes, add an attribute code */
1495
if (win->base.txtattr != 0)
1497
/* add the attribute code sequence */
1498
buf[0] = OSGEN_ATTR;
1499
buf[1] = (char)win->base.txtattr;
1500
osssb_add_bytes(win, buf, 2);
1503
/* if we're using the plain text color, add a color code */
1504
if (win->base.txtfg != OSGEN_COLOR_TEXT
1505
|| win->base.txtbg != OSGEN_COLOR_TRANSPARENT)
1507
/* add the explicit color code */
1508
buf[0] = OSGEN_COLOR;
1509
buf[1] = win->base.txtfg;
1510
buf[2] = win->base.txtbg;
1511
osssb_add_bytes(win, buf, 3);
1514
/* add a safety null terminator */
1515
osssb_add_safety_null(win);
1519
* Start a new line in the scrollback buffer. Returns true on success,
1520
* false if there's no space to add the newline character.
1522
static int osssb_new_line(osgen_txtwin_t *win)
1526
/* add a null byte to mark the end of the current line */
1527
if (!osssb_add_byte(win, '\0'))
1530
/* if the window is full, indicate failure */
1531
if ((win->base.flags & OSGEN_FULL) != 0)
1535
* If the line buffer is full, and this window doesn't automatically
1536
* scroll vertically, drop the new text. When we're not in
1537
* auto-vscroll mode, we drop text from the end of the buffer rather
1538
* than from the beginning.
1540
if (win->line_count + 1 > win->line_ptr_cnt
1541
&& !(win->base.flags & OSGEN_AUTO_VSCROLL))
1543
/* set the 'full' flag */
1544
win->base.flags |= OSGEN_FULL;
1546
/* indicate failure */
1550
/* move to the left column */
1553
/* add a line start */
1554
if (win->line_count >= win->line_ptr_cnt)
1556
/* forget the original first line */
1558
if (win->first_line == win->line_ptr_cnt)
1559
win->first_line = 0;
1562
* Since we took away one line and we're adding another, the total
1563
* line count and the document 'y' position aren't changing - but
1564
* the line at the document 'y' position now belongs to the new
1567
* Adjust the scrolling position for the loss of a line at the
1568
* start of the buffer. This doesn't change what we're displaying
1569
* on the screen, because we're simply reducing the amount of text
1570
* in the buffer before the top of the screen, so we must
1571
* compensate by decrementing the document coordinate of the top
1572
* line in the window. However, if the line we're taking away is
1573
* showing in the window, then we do need to redraw the contents,
1574
* because the change will be visible; set the deferred redraw
1575
* flag for the window in this case so that we eventually redraw
1578
if (win->base.scrolly == 0)
1579
win->base.flags |= OSGEN_DEFER_REDRAW;
1581
win->base.scrolly--;
1585
/* count the new line */
1588
/* note the highest output 'y' position if this is it */
1589
if (win->base.y > win->base.ymax)
1590
win->base.ymax = win->base.y;
1592
/* increase the document y position for the new line */
1596
/* get the line pointer for the new last line */
1597
line_ptr = osgen_get_line_ptr(win, win->base.y);
1600
* set the new line pointer to point to the first free byte of the
1603
*line_ptr = win->txtfree;
1605
/* add a color code to the start of the new line, if necessary */
1606
osssb_add_color_code(win);
1608
/* remember the text color at the start of this line */
1609
win->solfg = win->base.txtfg;
1610
win->solbg = win->base.txtbg;
1611
win->solattr = win->base.txtattr;
1613
/* add a safety null terminator */
1614
osssb_add_safety_null(win);
1621
* Scroll the window forward by the given number of lines
1623
static void osgen_scroll_win_fwd(osgen_txtwin_t *win, size_t lines)
1625
/* limit the scrolling to the available number of lines */
1626
if (lines > win->line_count - win->base.scrolly - win->base.ht)
1627
lines = win->line_count - win->base.scrolly - win->base.ht;
1630
* If we're scrolling more than a few lines, or more than the entire
1631
* window's height, just redraw the entire window. If it's a small
1632
* number of lines, scroll the screen one line at a time, so that we
1633
* don't have to redraw as much.
1635
if (lines > 3 || (int)lines >= win->base.ht)
1637
/* adjust the scroll position */
1638
win->base.scrolly += lines;
1640
/* redraw the entire window */
1641
osgen_redraw_win(&win->base);
1645
/* scroll one line at a time */
1646
for ( ; lines != 0 ; --lines)
1648
/* scroll the window's on-screen area one line */
1649
ossscr(win->base.winy, win->base.winx,
1650
win->base.winy + win->base.ht - 1,
1651
win->base.winx + win->base.wid - 1,
1652
win->base.oss_fillcolor);
1654
/* adjust the scroll position */
1655
win->base.scrolly++;
1657
/* redraw the bottom line */
1658
osgen_scrdisp(&win->base, 0, win->base.ht - 1, win->base.wid);
1664
* Scroll the window back by the given number of lines
1666
static void osgen_scroll_win_back(osgen_txtwin_t *win, int lines)
1668
/* limit scrolling to the available number of lines above the window */
1669
if (lines > win->base.scrolly)
1670
lines = win->base.scrolly;
1673
* If we're scrolling more than a few lines, or by the full window
1674
* height or more, just redraw the entire window. Otherwise, scroll a
1675
* line at a time to minimize redrawing.
1679
/* adjust the scroll position */
1680
win->base.scrolly -= lines;
1682
/* redraw the entire window */
1683
osgen_redraw_win(&win->base);
1687
/* scroll up by one line at a time */
1688
for ( ; lines != 0 ; --lines)
1690
/* scroll the window's on-screen area one line */
1691
ossscu(win->base.winy, win->base.winx,
1692
win->base.winy + win->base.ht - 1,
1693
win->base.winx + win->base.wid - 1,
1694
win->base.oss_fillcolor);
1696
/* adjust the scroll position */
1697
win->base.scrolly--;
1699
/* redraw the top line */
1700
osgen_scrdisp(&win->base, 0, 0, win->base.wid);
1706
* If a window is in auto-vscroll mode, bring the cursor into view in the
1709
static void osgen_auto_vscroll(osgen_txtwin_t *win)
1711
/* if the window isn't in auto-vscroll mode, ignore this */
1712
if (!(win->base.flags & OSGEN_AUTO_VSCROLL))
1716
* scroll the window forward if the cursor is outside the visible area
1719
if (win->base.y >= win->base.scrolly + (int)win->base.ht)
1720
osgen_scroll_win_fwd(win, win->base.y
1721
- (win->base.scrolly + win->base.ht) + 1);
1725
* Add text to the scrollback buffer.
1727
static void ossaddsb(osgen_txtwin_t *win, const char *p, size_t len, int draw)
1733
/* if there's no scrollback buffer, ignore it */
1734
if (win->txtbuf == 0)
1737
/* note the starting x,y position, for redrawing purposes */
1738
startx = win->base.x - win->base.scrollx;
1739
starty = win->base.y - win->base.scrolly;
1741
/* we haven't added any characters to the line yet */
1745
* Copy the text into the screen buffer, respecting the circular
1746
* nature of the screen buffer. If the given text wraps lines,
1747
* enter an explicit carriage return into the text to ensure that
1748
* users can correctly count lines.
1752
/* check what we have */
1756
/* switch to the new attributes */
1757
win->base.txtattr = (unsigned char)*(p+1);
1760
* if we're at the start of the line, this is the start-of-line
1761
* attribute - this will ensure that if we back up with '\r',
1762
* we'll re-apply this attribute change
1764
if (win->base.x == 0)
1765
win->solattr = win->base.txtattr;
1767
/* add the two-byte sequence */
1768
osssb_add_bytes(win, p, 2);
1774
/* switch to the new colors */
1775
win->base.txtfg = (unsigned char)*(p+1);
1776
win->base.txtbg = (unsigned char)*(p+2);
1779
* if we're at the start of the line, this is the new
1780
* start-of-line color
1782
if (win->base.x == 0)
1784
win->solfg = win->base.txtfg;
1785
win->solbg = win->base.txtbg;
1788
/* add and skip the three-byte color sequence */
1789
osssb_add_bytes(win, p, 3);
1795
/* add the new line */
1796
osssb_new_line(win);
1798
/* draw the part of the line we added */
1800
osgen_scrdisp(&win->base, startx, starty, line_len);
1802
/* skip this character */
1806
/* reset to the next line */
1807
startx = win->base.x - win->base.scrollx;
1811
/* bring the cursor onto the screen if auto-vscrolling */
1813
osgen_auto_vscroll(win);
1820
* We have a plain carriage return, which indicates that we
1821
* should go back to the start of the current line and
1822
* overwrite it. (This is most likely to occur for the
1826
/* set the free pointer back to the start of the current line */
1827
win->txtfree = osgen_get_line(win, win->base.y);
1829
/* switch back to the color as of the start of the line */
1830
win->base.txtfg = win->solfg;
1831
win->base.txtbg = win->solbg;
1832
win->base.txtattr = win->solattr;
1835
* since we're back at the start of the line, add a color code
1838
osssb_add_color_code(win);
1840
/* clear the window area of the line we're overwriting */
1841
if (draw && starty >= 0 && starty < (int)win->base.ht)
1842
ossclr(win->base.winy + starty, win->base.winx,
1843
win->base.winy + starty,
1844
win->base.winx + win->base.wid - 1,
1845
win->base.oss_fillcolor);
1847
/* reset to the start of the line */
1851
/* move to the left column */
1854
/* skip this character */
1862
/* for anything else, simply store the byte in the buffer */
1863
if (osssb_add_byte(win, *p))
1865
/* note the maximum output position if appropriate */
1866
if (win->base.x > win->base.xmax)
1867
win->base.xmax = win->base.x;
1869
/* adjust the output x position */
1872
/* count the ordinary character in the display length */
1876
/* skip the character */
1886
* Add a safety null terminator after each addition, in case we need
1887
* to look at the buffer before this line is finished.
1889
osssb_add_safety_null(win);
1891
/* display the added text */
1894
/* show the added text */
1895
osgen_scrdisp(&win->base, startx, starty, line_len);
1897
/* bring the cursor onto the screen if auto-vscrolling */
1898
osgen_auto_vscroll(win);
1903
* Add an input line to the scrollback buffer.
1905
void ossaddsb_input(osgen_txtwin_t *win, char *p, int add_nl)
1909
/* get the number of characters in the input to add */
1910
chars_rem = strlen(p);
1913
* add the input in chunks, wrapping whenever we reach the right edge
1916
while (chars_rem != 0)
1921
/* if we're already past the edge, add a newline */
1922
if (win->base.x >= (int)win->base.wid)
1923
osssb_new_line(win);
1925
/* figure out how much space we have */
1926
wid_rem = win->base.wid - win->base.x;
1928
/* add as much as we can, up to the width remaining */
1934
ossaddsb(win, p, cur, FALSE);
1936
/* skip this chunk */
1941
/* add a newline after the input if desired */
1943
osssb_new_line(win);
1945
osssb_add_safety_null(win);
1948
/* ------------------------------------------------------------------------ */
1950
* End scrollback mode.
1952
static void osgen_sb_mode_end()
1954
osgen_txtwin_t *win = S_sbmode_win;
1956
/* restore our original scroll position */
1957
if (win->base.scrolly > S_sbmode_orig_scrolly)
1958
osgen_scroll_win_back(win, win->base.scrolly - S_sbmode_orig_scrolly);
1959
else if (win->base.scrolly < S_sbmode_orig_scrolly)
1960
osgen_scroll_win_fwd(win, S_sbmode_orig_scrolly - win->base.scrolly);
1963
* adjust the input editing cursor position if the scrolling position
1964
* doesn't match the original position
1966
S_gets_y += S_sbmode_orig_scrolly - win->base.scrolly;
1969
* restore our full window area, adding back in the top line that we
1970
* removed to make room for the mode line
1972
win->base.winy -= 1;
1974
win->base.scrolly -= 1;
1976
/* redraw the top line, where we drew the mode line */
1977
ossclr(win->base.winy, win->base.winx,
1978
win->base.winy, win->base.winx + win->base.wid - 1,
1979
win->base.oss_fillcolor);
1980
osgen_scrdisp(&win->base, 0, 0, win->base.wid);
1983
* Delete the temporary copy of the input from the scrollback buffer.
1984
* To do this, restore the x,y position and free pointer, then delete
1985
* extra lines from the end of the buffer until the last line points
1986
* to the same text it did before we added the command input text.
1988
win->base.x = S_sbmode_orig_x;
1989
win->txtfree = S_sbmode_orig_txtfree;
1990
while (win->line_count > 1
1991
&& osgen_get_line_ptr(win, win->base.y) != S_sbmode_orig_last_line)
1993
/* this is an added line - delete the line */
1998
/* we're no longer in scrollback mode */
2003
* Draw the scrollback mode status line. This is a line we draw at the top
2004
* of the window to give a visual indication that we're in scrollback mode.
2005
* (Actually, we draw this one line above the current top of the window,
2006
* because we shrink the window vertically by one line while it's in
2007
* scrollback mode specifically to make room for the mode line.)
2009
static void osgen_draw_sb_mode_line(void)
2011
osgen_txtwin_t *win;
2014
/* get the current scrollback window */
2017
/* there's nothing to do if there's no scrollback window */
2021
/* get the color - use the reverse of the window's current color scheme */
2022
oss_color = ossgetcolor(win->base.fillcolor, win->base.txtfg, 0,
2023
OSGEN_COLOR_TRANSPARENT);
2025
/* clear the area of the mode line */
2026
ossclr(win->base.winy - 1, win->base.winx,
2027
win->base.winy - 1, win->base.winx + win->base.wid - 1, oss_color);
2029
/* momentarily bring the mode line back into the window's area */
2030
win->base.winy -= 1;
2033
/* draw the mode line text */
2034
osgen_disp_trunc(&win->base, 0, 0, oss_color, OS_SBSTAT);
2036
/* undo our temporary adjustment of the window size */
2037
win->base.winy += 1;
2042
* Process the event in scrollback mode. If we're not already in
2043
* scrollback mode, we'll enter scrollback mode; otherwise, we'll process
2044
* the event in the already running scrollback.
2046
* Returns true if we processed the event, false if we have terminated
2047
* scrollback mode and want the caller to process the event as it normally
2048
* would outside of scrollback mode.
2050
static int osgen_sb_mode(osgen_txtwin_t *win, int event_type,
2051
os_event_info_t *event_info)
2057
/* if we were doing scrollback in a different window, cancel it */
2058
if (S_sbmode_win != 0 && S_sbmode_win != win)
2059
osgen_sb_mode_end();
2061
/* note if we're just entering scrollback mode */
2062
just_started = (S_sbmode_win == 0);
2064
/* if scrollback mode isn't already in progress, set it up */
2067
/* if there's no buffer, we can't enter scrollback mode */
2068
if (win->txtbuf == 0)
2072
* If the number of lines in the scrollback buffer doesn't exceed
2073
* the number of lines displayed in the window, then don't bother
2074
* entering scrollback mode. If the window isn't at least two
2075
* lines high, don't allow it either, as we need space to draw our
2078
if (win->line_count <= win->base.ht || win->base.ht < 2)
2081
/* remember the window involved in scrollback */
2085
* Shrink the window one line at the top, to make room for the mode
2086
* line. Compensate by bumping the scrolling position forward a
2087
* line, to keep the lines that will remain visible in the rest of
2088
* the window at the same place on the screen.
2090
win->base.winy += 1;
2092
win->base.scrolly += 1;
2095
* Temporarily add the command buffer to the scrollback buffer, so
2096
* that it shows up when we're scrolling. To facilitate removing
2097
* the added text later, remember the current free pointer, last
2098
* line pointer, x document position.
2100
S_sbmode_orig_x = win->base.x;
2101
S_sbmode_orig_txtfree = win->txtfree;
2102
S_sbmode_orig_last_line = osgen_get_line_ptr(win, win->base.y);
2103
ossaddsb_input(win, S_gets_buf, FALSE);
2105
/* remember the original scrolling position */
2106
S_sbmode_orig_scrolly = win->base.scrolly;
2108
/* draw the mode line */
2109
osgen_draw_sb_mode_line();
2112
/* presume we'll handle the event */
2115
/* check the event */
2120
* If it's a regular key, exit scrollback mode immediately, and
2121
* let the caller handle the event normally. This allows the user
2122
* to resume typing even while scrollback is active; we'll simply
2123
* cancel the scrollback and resume editing with the event that
2124
* canceled the scrollback.
2126
c = event_info->key[0];
2127
if ((unsigned char)c >= 32 || c == '\n' || c == '\r' || c == 8)
2129
/* it's a regular key - terminate scrollback mode */
2130
osgen_sb_mode_end();
2132
/* let the caller handle the event */
2136
/* if it's the escape key, we're done */
2139
osgen_sb_mode_end();
2143
/* if it's not a special keystroke, we're done with it */
2147
/* it's a special keystroke - check the command ID */
2148
switch(event_info->key[1])
2151
/* if we're not just toggling in to scrollback mode, toggle out */
2153
osgen_sb_mode_end();
2158
/* it's a termination key - cancel scrollback mode */
2159
osgen_sb_mode_end();
2163
/* scroll back a line */
2164
osgen_scroll_win_back(win, 1);
2168
/* scroll forward a line */
2169
osgen_scroll_win_fwd(win, 1);
2173
/* move back by one window height */
2174
osgen_scroll_win_back(win, win->base.ht > 1
2175
? win->base.ht - 1 : 1);
2179
/* move forward by one window height */
2180
osgen_scroll_win_fwd(win, win->base.ht > 1
2181
? win->base.ht - 1 : 1);
2185
/* done with the key */
2190
* ignore any other events we receive, but consider them processed
2191
* - even though we're ignoring the event, we're deliberately
2192
* ignoring the event as our way of processing it
2197
/* return the 'processed' indication to the caller */
2202
* Display a line of text in the given ordinary text window
2204
static void osgen_scrdisp_txt(osgen_txtwin_t *win, int x, int y, int len)
2215
/* start out in ordinary text mode */
2216
fg = OSGEN_COLOR_TEXT;
2217
bg = OSGEN_COLOR_TRANSPARENT;
2219
oss_color = ossgetcolor(fg, bg, attr, win->base.fillcolor);
2221
/* get a pointer to the start of the desired line */
2222
p = osgen_get_line(win, y + win->base.scrolly);
2226
/* get the window-relative x coordinate of the start of the line */
2227
scanx = -win->base.scrollx;
2230
* Scan the line. We must scan from the start of the line, even if we
2231
* don't want to display from the start of the line, to make sure we
2232
* take into account any color and attribute settings stored in the
2235
for (bufp = buf ; *p != '\0' && len != 0 ; p = ossadvsp(win, p))
2237
/* check for special escape codes */
2241
/* skip the escape byte */
2242
p = ossadvsp(win, p);
2244
/* get the new attribute code */
2247
/* set the new colors */
2251
/* skip the escape byte */
2252
p = ossadvsp(win, p);
2254
/* get the foreground color and skip it */
2256
p = ossadvsp(win, p);
2258
/* get the background color */
2263
/* flush the buffer */
2266
/* display the contents of the buffer */
2268
osgen_disp_trunc(&win->base, y, x, oss_color, buf);
2270
/* adjust the column position for the display */
2273
/* reset the buffer */
2277
/* translate the new text color */
2278
oss_color = ossgetcolor(fg, bg, attr, win->base.fillcolor);
2282
/* if the buffer is full, flush it */
2283
if (bufp == buf + sizeof(buf) - 1)
2285
/* display the buffer */
2287
osgen_disp_trunc(&win->base, y, x, oss_color, buf);
2289
/* adjust the column position for the display */
2292
/* empty the buffer */
2297
* if we've reached the starting x coordinate, add this
2298
* character to the buffer; if we haven't, we can ignore the
2299
* character, since in that case we're just scanning for
2300
* escape codes in the line before the part we want to display
2304
/* add it to the buffer */
2307
/* count it against the length remaining to be displayed */
2311
/* adjust the x coordinate of our scan */
2319
/* display the last portion of the line if anything's left */
2322
/* null-terminate at the current point */
2326
osgen_disp_trunc(&win->base, y, x, oss_color, buf);
2331
/* ------------------------------------------------------------------------ */
2333
* Special routines for Text Grid windows
2337
* Clear the text and color arrays for a section of a grid window. Sets
2338
* each cleared character's text to a space, and sets the color to
2341
static void osgen_gridwin_clear_ptr(char *txtp, osgen_charcolor_t *colorp,
2344
/* loop through the grid from the starting offset */
2345
for ( ; len != 0 ; --len, ++txtp, ++colorp)
2347
/* set this character's text to a space */
2350
/* set this character's color to text/transparent */
2351
colorp->fg = OSGEN_COLOR_TEXT;
2352
colorp->bg = OSGEN_COLOR_TRANSPARENT;
2357
* Clear the text and color arrays for a section of a grid window. Starts
2358
* at the given character offset in the grid arrays, and clears for the
2359
* given number of character positions. Sets each cleared character's
2360
* text to a space, and sets the color to text/transparent.
2362
static void osgen_gridwin_clear(osgen_gridwin_t *win, size_t ofs, size_t len)
2364
/* clear our array in the selected areas */
2365
osgen_gridwin_clear_ptr(win->grid_txt + ofs, win->grid_color + ofs, len);
2370
* Resize a text grid window. This must be called whenever the on-screen
2371
* size of the window is changed, or we need to write outside the current
2372
* bounds of the array, so that we can expand our internal size allocation
2373
* if the window is now bigger than our internal text/color arrays.
2375
static void osgen_gridwin_resize(osgen_gridwin_t *win,
2376
size_t new_wid, size_t new_ht)
2378
/* if the window's size is now bigger than the grid, expand the grid */
2379
if (new_wid > win->grid_wid || new_ht > win->grid_ht)
2383
osgen_charcolor_t *new_color;
2385
osgen_charcolor_t *csrc, *cdst;
2389
* use the larger of the old size and the new size, so that the
2390
* window only expands (this somewhat simplifies copying the old
2393
if (win->grid_wid > new_wid)
2394
new_wid = win->grid_wid;
2395
if (win->grid_ht > new_ht)
2396
new_ht = win->grid_ht;
2398
/* allocate the new arrays */
2399
new_txt = (char *)osmalloc(new_wid * new_ht);
2400
new_color = (osgen_charcolor_t *)osmalloc(
2401
new_wid * new_ht * sizeof(new_color[0]));
2403
/* copy the old grid to the new grid */
2404
tsrc = win->grid_txt;
2405
csrc = win->grid_color;
2408
for (y = 0, ofs = 0 ; y < win->grid_ht ; ++y)
2410
/* copy the old text and color data */
2411
memcpy(tdst, tsrc, win->grid_wid);
2412
memcpy(cdst, csrc, win->grid_wid * sizeof(cdst[0]));
2414
/* clear the rest of the line if expanding the width */
2415
osgen_gridwin_clear_ptr(tdst + win->grid_wid,
2416
cdst + win->grid_wid,
2417
new_wid - win->grid_wid);
2419
/* advance the pointers */
2420
tsrc += win->grid_wid;
2421
csrc += win->grid_wid;
2426
/* clear all remaining lines */
2427
for ( ; y < new_ht ; ++y, tdst += new_wid, cdst += new_wid)
2428
osgen_gridwin_clear_ptr(tdst, cdst, new_wid);
2430
/* delete the old buffers */
2431
osfree(win->grid_txt);
2432
osfree(win->grid_color);
2434
/* set the new buffers and sizes */
2435
win->grid_txt = new_txt;
2436
win->grid_color = new_color;
2437
win->grid_wid = new_wid;
2438
win->grid_ht = new_ht;
2443
* Display a line of text in the given grid window
2445
static void osgen_scrdisp_grid(osgen_gridwin_t *win, int x, int y, int len)
2448
osgen_charcolor_t *colorp;
2456
* calculate the offset into our arrays: get the document coordinates
2457
* (by adjusting for the scrolling offset), multiply the document row
2458
* number by the row width, and add the document column number
2460
ofs = ((y - win->base.scrolly) * win->grid_wid) + (x - win->base.scrollx);
2462
/* start at the calculated offset */
2463
txtp = win->grid_txt + ofs;
2464
colorp = win->grid_color + ofs;
2466
/* start with the first character's color */
2470
/* calculate the starting oss-level color */
2471
oss_color = ossgetcolor(fg, bg, 0, win->base.fillcolor);
2474
* scan the text, flushing when we fill up the buffer or encounter a
2477
for (dst = buf ; ; --len, ++txtp, ++colorp)
2480
* if we have a color change, or we've exhausted the requested
2481
* length, or the buffer is full, display what we have in the
2485
|| dst == buf + sizeof(buf) - 1
2486
|| colorp->fg != fg || colorp->bg != bg)
2488
/* null-terminate the buffer and display it */
2490
osgen_disp_trunc(&win->base, y, x, oss_color, buf);
2492
/* count the output column change */
2495
/* reset the buffer write pointer */
2498
/* if we have a color change, calculate the new color */
2499
if (colorp->fg != fg || colorp->bg != bg)
2501
/* remember the new color */
2505
/* calculate the new oss-level color */
2506
oss_color = ossgetcolor(fg, bg, 0, win->base.fillcolor);
2510
/* if we've exhausted the request, we're done */
2514
/* add this character from the text grid to our output buffer */
2520
* Write text into a grid window
2522
static void osgen_gridwin_write(osgen_gridwin_t *win,
2523
const char *txt, size_t len)
2533
osgen_charcolor_t *cdst;
2536
* First, scan the text to check for writing beyond the end of the
2537
* current text array. If we write anything beyond the bounds of the
2538
* current array, we'll need to expand the array accordingly.
2540
xmax = x = win->base.x;
2541
ymax = y = win->base.y;
2542
for (p = txt, rem = len ; rem != 0 ; ++p, --rem)
2544
/* check what we have */
2548
/* move to the start of the next line */
2554
/* move to the start of the current line */
2560
* everything else takes up a character cell; if this is the
2561
* highest x/y position so far, note it
2568
/* move the cursor right */
2574
/* expand our text array if we're writing outside the current bounds */
2575
if (xmax >= (int)win->grid_wid || ymax >= (int)win->grid_ht)
2576
osgen_gridwin_resize(win, xmax + 1, ymax + 1);
2578
/* start at the current window coordinates */
2582
/* calculate the starting offset in the array for writing */
2583
ofs = y * win->grid_wid + x;
2584
tdst = win->grid_txt + ofs;
2585
cdst = win->grid_color + ofs;
2587
/* note the new maximum write positions */
2588
if (xmax > win->base.xmax)
2589
win->base.xmax = xmax;
2590
if (ymax > win->base.ymax)
2591
win->base.ymax = ymax;
2593
/* start at the current column */
2595
winx = x - win->base.scrollx;
2597
/* now scan the text again, writing it to the grid and displaying it */
2598
for (p = txt, rem = len ; ; ++p, --rem)
2601
* if we're at a newline or the end of the text to display,
2602
* display the section of the current line that we just built
2604
if (rem == 0 || *p == '\n' || *p == '\r')
2606
/* if we're not in deferred redraw mode, draw this section */
2607
if (!S_deferred_redraw
2608
&& !(win->base.flags & OSGEN_DEFER_REDRAW)
2610
osgen_scrdisp(&win->base, winx, y, x - startx);
2612
/* if we're out of text to display, we're done */
2616
/* apply any newline */
2619
/* move to the next line */
2623
else if (*p == '\r')
2625
/* move to the start of the current line */
2629
/* note the starting coordinates of the next chunk */
2631
winx = x - win->base.scrollx;
2633
/* calculate the new array output offset */
2634
ofs = y * win->grid_wid + x;
2635
tdst = win->grid_txt + ofs;
2636
cdst = win->grid_color + ofs;
2640
/* add this character to our array */
2642
cdst->fg = win->base.txtfg;
2643
cdst->bg = win->base.txtbg;
2645
/* ajust the output pointers */
2649
/* adjust the column counter */
2654
/* set the new output position in the window */
2660
/* ------------------------------------------------------------------------ */
2662
* Generic banner window routines
2666
* Display a window's text from the given starting position for the given
2667
* number of characters (counting only displayed characters; escape
2668
* sequences don't count). The starting position is given in
2669
* window-relative coordinates.
2671
static void osgen_scrdisp(osgen_win_t *win, int x, int y, int len)
2674
* if the text is entirely outside the window's display area, there's
2675
* nothing to display, so ignore the request
2677
if (y < 0 || (size_t)y >= win->ht
2678
|| x + len <= 0 || (size_t)x >= win->wid)
2681
/* draw according to window type */
2682
switch(win->win_type)
2684
case OS_BANNER_TYPE_TEXT:
2685
osgen_scrdisp_txt((osgen_txtwin_t *)win, x, y, len);
2688
case OS_BANNER_TYPE_TEXTGRID:
2689
osgen_scrdisp_grid((osgen_gridwin_t *)win, x, y, len);
2698
static void osgen_redraw_win(osgen_win_t *win)
2702
/* clear the window's area on the screen */
2703
ossclr(win->winy, win->winx,
2704
win->winy + win->ht - 1, win->winx + win->wid - 1,
2705
win->oss_fillcolor);
2707
/* display each line in the window */
2708
for (y = 0 ; y < win->ht ; ++y)
2709
osgen_scrdisp(win, 0, y, win->wid);
2712
/* redraw the entire screen */
2713
void os_redraw(void)
2716
* force a redraw of the entire screen by setting the global
2717
* pending-redraw flag
2719
S_deferred_redraw = TRUE;
2722
osssb_redraw_if_needed();
2726
/* redraw a window, if it needs redrawing */
2727
static void osgen_redraw_win_if_needed(int global_deferred, osgen_win_t *win)
2732
* if this window needs redrawing, or we have a global deferred redraw,
2735
if (global_deferred || (win->flags & OSGEN_DEFER_REDRAW) != 0)
2737
/* clear the window-specific deferred-redraw flag */
2738
win->flags &= ~OSGEN_DEFER_REDRAW;
2740
/* redraw the window */
2741
osgen_redraw_win(win);
2744
/* redraw this window's children if necessary */
2745
for (chi = win->first_child ; chi != 0 ; chi = chi->nxt)
2746
osgen_redraw_win_if_needed(global_deferred, chi);
2749
/* redraw the screen if necessary */
2750
void osssb_redraw_if_needed()
2752
int global_deferred = S_deferred_redraw;
2754
/* we're explicitly redrawing, so cancel any pending deferred redraw */
2755
S_deferred_redraw = FALSE;
2757
/* redraw the root window, which will redraw its children */
2758
if (S_main_win != 0)
2759
osgen_redraw_win_if_needed(global_deferred, &S_main_win->base);
2761
/* if the redraw is global, redraw other global features */
2762
if (global_deferred)
2764
/* redraw the scrollback mode line, if appropriate */
2765
osgen_draw_sb_mode_line();
2767
/* redraw any command line under construction */
2768
osgen_gets_redraw_cmdline();
2772
/* move the cursor to the default position */
2773
void osssb_cursor_to_default_pos(void)
2777
/* if we're in plain mode, ignore it */
2781
/* if we're using a special cursor position, do nothing */
2782
if (S_sbmode_win != 0)
2784
/* locate at the scrollback mode line */
2785
ossloc(S_sbmode_win->base.winy - 1, S_sbmode_win->base.winx);
2787
else if (S_special_cursor_pos)
2789
/* locate at the special cursor position */
2790
ossloc(S_special_cursor_y, S_special_cursor_x);
2795
* if we have a default window, put the cursor at the last text
2796
* position in the default window
2798
if ((win = &S_default_win->base) != 0)
2799
ossloc(win->winy + win->y - win->scrolly,
2800
win->winx + win->x - win->scrollx);
2805
* Lay out the given window
2807
static void oss_lay_out_window(osgen_win_t *win)
2812
* if we have a parent, take space from our parent window; otherwise,
2813
* assume that the caller has already laid out our main area, in which
2814
* case we just have to adjust for our children
2816
if (win->parent != 0)
2823
* our size and area will be taken from our parent's, so get the
2824
* parent window's current area
2826
x = win->parent->winx;
2827
y = win->parent->winy;
2828
wid = win->parent->wid;
2829
ht = win->parent->ht;
2831
/* get the window's size in character cells */
2832
switch(win->size_type)
2834
case OS_BANNER_SIZE_ABS:
2835
/* the size is given in character cells */
2839
case OS_BANNER_SIZE_PCT:
2841
* the size is given as a percentage of the parent's size - get
2842
* the appropriate dimension from the parent's size
2844
base_size = (win->alignment == OS_BANNER_ALIGN_LEFT
2845
|| win->alignment == OS_BANNER_ALIGN_RIGHT
2848
/* calculate the percentage of the full size */
2849
siz = (win->size * base_size) / 100;
2853
/* allocate space to the window according to its alignment */
2854
switch(win->alignment)
2856
case OS_BANNER_ALIGN_TOP:
2858
* assign the window the full width of the parent, and give it
2859
* the requested height, up to the available height
2863
win->ht = (siz <= ht ? siz : ht);
2866
/* take the window's space away from the top of the parent */
2871
case OS_BANNER_ALIGN_BOTTOM:
2872
/* give the window space at the bottom of the parent window */
2875
win->ht = (siz <= ht ? siz : ht);
2876
win->winy = y + ht - win->ht;
2878
/* deduct the window from the parent area */
2882
case OS_BANNER_ALIGN_LEFT:
2883
/* give the window space at the left of the parent area */
2884
win->wid = (siz <= wid ? siz : wid);
2889
/* deduct the window from the parent area */
2894
case OS_BANNER_ALIGN_RIGHT:
2895
/* give the window space at the right of the remaining area */
2896
win->wid = (siz <= wid ? siz : wid);
2897
win->winx = x + wid - win->wid;
2901
/* deduct the window from the parent area */
2906
/* adjust our parent's area for the removal of our area */
2907
win->parent->winx = x;
2908
win->parent->winy = y;
2909
win->parent->wid = wid;
2910
win->parent->ht = ht;
2913
/* lay out our children */
2914
for (chi = win->first_child ; chi != 0 ; chi = chi->nxt)
2915
oss_lay_out_window(chi);
2917
/* make any necessary adjustments */
2918
switch(win->win_type)
2920
case OS_BANNER_TYPE_TEXT:
2922
* If this is the current active scrollback-mode window, we must
2923
* make the same adjustment that we make on entering scrollback
2924
* mode: shrink the window one line from the top, to make room for
2925
* the scrollback-mode status line.
2927
if (win == &S_sbmode_win->base)
2929
/* it's the scrollback window - take out the mode line */
2935
case OS_BANNER_TYPE_TEXTGRID:
2936
/* make sure the window's text/color buffers are large enough */
2937
osgen_gridwin_resize((osgen_gridwin_t *)win, win->wid, win->ht);
2943
* Recalculate the window layout and redraw the screen
2945
static void osgen_recalc_layout()
2947
/* start at the root window */
2948
if (S_main_win != 0)
2952
/* start by giving the entire screen to the main window */
2953
S_main_win->base.winx = 0;
2954
S_main_win->base.winy = 0;
2955
S_main_win->base.wid = G_oss_screen_width;
2956
S_main_win->base.ht = G_oss_screen_height;
2958
/* lay out the main window and its children */
2959
oss_lay_out_window(&S_main_win->base);
2961
/* recalculate the main window's page size */
2962
G_os_linewidth = S_main_win->base.wid;
2963
ht = S_main_win->base.ht;
2964
G_os_pagelength = (ht > 2 ? ht - 2 : ht > 1 ? ht - 1 : ht);
2967
/* schedule a redraw of the entire screen */
2968
S_deferred_redraw = TRUE;
2972
* Receive notification that the screen was resized. We'll recalculate
2973
* the banner window layout.
2975
void osssb_on_resize_screen()
2977
/* recalculate the window layout */
2978
osgen_recalc_layout();
2980
/* immediately update the screen */
2981
osssb_redraw_if_needed();
2983
/* set the cursor back to the default position */
2984
osssb_cursor_to_default_pos();
2987
# else /* USE_SCROLLBACK */
2989
* for the non-scrollback version, add-to-scrollback is just a dummy
2990
* function: if we're not saving scrollback, we obviously have no need to
2991
* save any information added to the buffer
2993
static void ossaddsb(struct osgen_win_t *win, char *p, size_t len, int draw)
2999
* for the non-scrollback version, there's nothing we need to do on
3000
* resizing the screen, as we don't do anything fancy with the layout
3002
void osssb_on_resize_screen()
3007
# endif /* USE_SCROLLBACK */
3009
/* ------------------------------------------------------------------------ */
3013
/* current statusline score-area string */
3014
static osfar_t char S_scorebuf[135];
3016
/* statusline left-string reset point */
3017
static osfar_t char *S_stat_reset_free;
3018
static osfar_t int S_stat_reset_x;
3020
/* update the right portion of the statusline */
3021
static void osgen_update_stat_right()
3023
osgen_txtwin_t *win;
3028
* if there's no statusline window, or no reset point, we can't do
3029
* anything right now
3031
if ((win = S_status_win) == 0 || S_stat_reset_free == 0)
3035
* set the statusline position back to where it was when we finished
3036
* with the statusline itself
3038
win->txtfree = S_stat_reset_free;
3039
win->base.x = S_stat_reset_x;
3041
/* if there's no space, don't draw anything */
3042
if (win->base.x > (int)win->base.wid)
3045
/* figure out how much space in the window we have */
3046
wid_rem = win->base.wid - win->base.x;
3048
/* figure out how much we're adding */
3049
char_len = strlen(S_scorebuf);
3052
* if we're adding more than we have room for, add a space and then
3053
* add the buffer contents
3055
if ((int)char_len + 1 >= wid_rem)
3058
ossaddsb(win, " ", 1, TRUE);
3060
/* add the right-half string */
3061
ossaddsb(win, S_scorebuf, strlen(S_scorebuf), TRUE);
3065
/* add spaces to right-align the scorebuf text */
3066
while (wid_rem > (int)char_len + 1)
3071
/* add the remaining spaces, up to a buffer-full */
3072
cur = wid_rem - char_len - 1;
3073
if (cur > sizeof(buf) - 1)
3074
cur = sizeof(buf) - 1;
3076
/* make a buffer-full of spaces */
3077
memset(buf, ' ', cur);
3080
ossaddsb(win, buf, cur, TRUE);
3082
/* deduct the amount we displayed from the width remaining */
3086
/* add the right-half string */
3087
ossaddsb(win, S_scorebuf, strlen(S_scorebuf), TRUE);
3092
* Set the status mode. In status mode 0, text displayed via os_print and
3093
* the like will display to the main window; in mode 1, text displayed will
3094
* go to the default status line window, until we reach a newline, at which
3095
* point we'll switch to status mode 2 and text will go nowhere.
3097
void os_status(int stat)
3099
/* if we're in 'plain' mode, suppress all statusline output */
3102
/* check the requested mode */
3106
/* switching to main text mode */
3111
/* switching to statusline mode - suppress all output */
3125
/* if there's no statusline window, create one */
3126
if (S_status_win == 0)
3128
/* create the statusline window as a child of the main window */
3129
S_status_win = osgen_create_txtwin(OS_BANNER_FIRST, 0, S_main_win,
3132
/* if that succeeded, set up the window */
3133
if (S_status_win != 0)
3135
/* set up the statusline window at the top of the screen */
3136
S_status_win->base.alignment = OS_BANNER_ALIGN_TOP;
3137
S_status_win->base.size = 1;
3138
S_status_win->base.size_type = OS_BANNER_SIZE_ABS;
3140
/* use the default statusline color in this window */
3141
S_status_win->base.txtfg = OSGEN_COLOR_STATUSLINE;
3142
S_status_win->base.txtbg = OSGEN_COLOR_TRANSPARENT;
3143
S_status_win->base.fillcolor = OSGEN_COLOR_STATUSBG;
3145
/* cache the oss translations of the colors */
3146
S_status_win->base.oss_fillcolor =
3147
ossgetcolor(OSGEN_COLOR_STATUSLINE, OSGEN_COLOR_STATUSBG,
3150
/* recalculate the window layout */
3151
osgen_recalc_layout();
3155
/* if entering status mode 1, clear the statusline */
3156
if (stat == 1 && status_mode != 1 && S_status_win != 0)
3158
/* switch the default window to the status line */
3159
S_default_win = S_status_win;
3161
/* clear the statusline window */
3162
osgen_clear_win(&S_status_win->base);
3164
/* forget the score reset point */
3165
S_stat_reset_free = 0;
3168
/* if we're leaving status mode 1, finish the statusline */
3169
if (status_mode == 1 && stat != 1 && S_status_win != 0)
3172
* remember the current statusline window settings as the "reset"
3173
* point - this is where we reset the buffer contents whenever we
3174
* want to add the right-half string
3176
S_stat_reset_free = S_status_win->txtfree;
3177
S_stat_reset_x = S_status_win->base.x;
3179
/* update the right-half string */
3180
osgen_update_stat_right();
3183
/* switch to the new mode */
3186
/* check the mode */
3187
if (status_mode == 0)
3189
/* switching to the main window */
3190
S_default_win = S_main_win;
3192
else if (status_mode == 2)
3195
* entering post-status mode - ignore everything, so set the
3196
* default window to null
3207
/* Set score to a string value provided by the caller */
3208
void os_strsc(const char *p)
3212
/* copy the score, if a value was given */
3215
/* limit the copying length to our buffer size */
3216
copy_len = strlen(p);
3217
if (copy_len > sizeof(S_scorebuf) - 1)
3218
copy_len = sizeof(S_scorebuf) - 1;
3220
/* copy the text and null-terminate it */
3221
memcpy(S_scorebuf, p, copy_len);
3222
S_scorebuf[copy_len] = '\0';
3225
/* update the statusline window */
3226
osgen_update_stat_right();
3230
* Set the score. If cur == -1, the LAST score set with a non-(-1) cur is
3231
* displayed; this is used to refresh the status line without providing a
3232
* new score (for example, after exiting scrollback mode). Otherwise, the
3233
* given current score (cur) and turncount are displayed, and saved in
3234
* case cur==-1 on the next call.
3236
void os_score(int cur, int turncount)
3240
/* check for the special -1 turn count */
3241
if (turncount == -1)
3243
/* it's turn "-1" - we're simply redrawing the score */
3244
os_strsc((char *)0);
3248
/* format the score */
3249
sprintf(buf, "%d/%d", cur, turncount);
3251
/* display the score string */
3257
/* ------------------------------------------------------------------------ */
3259
* Set the terminal into 'plain' mode: disables status line,
3260
* scrollback, command editing.
3264
/* set the 'plain' mode flag */
3268
* if we're running without a stdin, turn off pagination - since the
3269
* user won't be able to respond to [more] prompts, there's no reason
3272
if (oss_eof_on_stdin())
3273
G_os_moremode = FALSE;
3277
* display text to the default window
3279
void os_printz(const char *str)
3281
/* write using the base counted-length routine */
3282
os_print(str, strlen(str));
3286
* display text to the default window
3288
void os_print(const char *str, size_t len)
3290
osgen_txtwin_t *win;
3295
/* determine what to do based on the status mode */
3299
/* we're in the post-status-line mode - suppress all output */
3303
/* we're showing the text in the default window */
3306
/* plain mode - simply write it to stdout */
3307
printf("%.*s", (int)len, str);
3311
/* normal mode - write to the default window, if there is one */
3312
win = S_default_win;
3315
/* write the text to the window buffer */
3316
ossaddsb(win, str, len, TRUE);
3319
* move the cursor to the new location, if we're not hiding
3320
* updates for the moment
3322
if (!S_deferred_redraw
3323
&& !(win->base.flags & OSGEN_DEFER_REDRAW))
3324
ossloc(win->base.winy + win->base.y - win->base.scrolly,
3325
win->base.winx + win->base.x - win->base.scrollx);
3334
* Status line contents. Ignore the status line in 'plain' mode
3335
* or if there's no statusline window.
3337
if (os_f_plain || (win = S_status_win) == 0)
3341
* Skip leading newlines at the start of the statusline output.
3342
* Only do this if we don't already have anything buffered, since
3343
* a newline after some other text indicates the end of the status
3344
* line and thus can't be ignored.
3348
if (win->base.winy == 0 || win->base.winx == 0)
3350
/* the buffer is empty, so skip leading newlines */
3351
for ( ; rem != 0 && *p == '\n' ; ++p, --rem) ;
3353
/* if that leaves nothing, we're done */
3358
* add a space before the first character, so that we always
3359
* have a space at the left edge of the status line
3361
ossaddsb(win, " ", 1, TRUE);
3364
/* scan for a newline; if we find one, it's the end of the status */
3365
for (startp = p ; rem != 0 && *p != '\n' ; ++p, --rem)
3371
/* skip the extra byte */
3377
/* skip the extra two bytes */
3383
/* everything else is one byte long */
3388
/* add this text to the statusline window */
3389
ossaddsb(win, startp, p - startp, TRUE);
3391
/* finish up if we found a newline */
3394
/* switch to status mode 2 */
3406
* we don't buffer output ourselves, so there's normally nothing to do
3407
* here; but if we're in 'plain' mode, let stdio know about the flush,
3408
* since it might be buffering output on our behalf
3414
void os_update_display(void)
3416
/* there's nothing we need to do */
3421
* For command line history, we must have some buffer space to store
3422
* past command lines. We will use a circular buffer: when we move
3423
* the pointer past the end of the buffer, it wraps back to the start
3424
* of the buffer. A "tail" indicates the oldest line in the buffer;
3425
* when we need more room for new text, we advance the tail and thereby
3426
* lose the oldest text in the buffer.
3428
static osfar_t char *histbuf = 0;
3429
static osfar_t char *histhead = 0;
3430
static osfar_t char *histtail = 0;
3433
* ossadvhp advances a history pointer, and returns the new pointer.
3434
* This function takes the circular nature of the buffer into account
3435
* by wrapping back to the start of the buffer when it hits the end.
3437
char *ossadvhp(char *p)
3439
if (++p >= histbuf + HISTBUFSIZE)
3445
* ossdechp decrements a history pointer, wrapping the pointer back
3446
* to the top of the buffer when it reaches the bottom.
3448
char *ossdechp(char *p)
3451
p = histbuf + HISTBUFSIZE;
3456
* osshstcpy copies from a history buffer into a contiguous destination
3457
* buffer, wrapping the history pointer if need be. One null-terminated
3460
void osshstcpy(char *dst, char *hst)
3462
while (*hst != '\0')
3465
hst = ossadvhp(hst);
3471
* ossprvcmd returns a pointer to the previous history command, given
3472
* a pointer to a history command. It returns a null pointer if the
3473
* given history command is the first in the buffer.
3475
char *ossprvcmd(char *hst)
3477
/* check to see if we're already at the fist command */
3478
if (hst == histtail)
3481
/* back up to the previous null byte */
3482
hst = ossdechp(hst);
3484
/* scan back to the previous line */
3487
hst = ossdechp(hst);
3488
} while (*hst && hst != histtail);
3490
/* step over the null byte to the start of the following line */
3492
hst = ossadvhp(hst);
3494
/* return the result */
3499
* ossnxtcmd returns a pointer to the next history command, given
3500
* a pointer to a history command. It returns a null pointer if the
3501
* given command is already past the last command.
3503
char *ossnxtcmd(char *hst)
3505
/* check to see if we're already past the last line */
3506
if (hst == histhead)
3509
/* scan forward to the next null byte */
3511
hst = ossadvhp(hst);
3513
/* scan past the null onto the new command */
3514
hst = ossadvhp(hst);
3516
/* return the pointer */
3519
# endif /* USE_HISTORY */
3521
/* ------------------------------------------------------------------------ */
3523
* Display an input line under construction from the given character
3524
* position. If 'delta_yscroll' is non-null, then we'll scroll the window
3525
* vertically if necessary and fill in '*delta_yscroll' with the number of
3526
* lines we scrolled by.
3528
static void ossdsp_str(osgen_win_t *win, int y, int x, int color,
3529
char *str, size_t len, int *delta_yscroll)
3531
/* presume we won't scroll */
3532
if (delta_yscroll != 0)
3535
/* keep going until we exhaust the string */
3541
/* display as much as will fit on the current line before wrapping */
3542
cur = win->winx + win->wid - x;
3546
/* null-terminate the chunk, but save the original character */
3550
/* display this chunk */
3551
ossdsp(y, x, color, (char *)str);
3553
/* restore the character where we put our null */
3556
/* move our string counters past this chunk */
3560
/* advance the x position */
3563
/* if we've reached the right edge of the window, wrap the line */
3564
if (x >= win->winx + (int)win->wid)
3566
/* wrap to the left edge of the window */
3569
/* advance to the next line */
3573
* if this puts us past the bottom of the window, and we're
3574
* allowed to scroll the window, do so
3576
if (y >= win->winy + (int)win->ht && delta_yscroll != 0)
3578
/* scroll by one line */
3579
ossscr(win->winy, win->winx,
3580
win->winy + win->ht - 1, win->winx + win->wid - 1,
3581
win->oss_fillcolor);
3583
/* adjust the scroll position of the window */
3586
/* count the scrolling */
3589
/* move back a line */
3597
* Move the cursor left by the number of characters.
3599
static void oss_gets_csrleft(osgen_txtwin_t *win, int *y, int *x, size_t len)
3601
for ( ; len != 0 ; --len)
3603
/* move left one character, wrapping at the end of the line */
3604
if (--*x < win->base.winx)
3606
/* move up a line */
3609
/* move to the end of the line */
3610
*x = win->base.winx + win->base.wid - 1;
3616
* Move the cursor right by the number of characters.
3618
static void oss_gets_csrright(osgen_txtwin_t *win, int *y, int *x, size_t len)
3620
for ( ; len != 0 ; --len)
3622
/* move right one character, wrapping at the end of the line */
3623
if (++*x >= win->base.winx + (int)win->base.wid)
3625
/* move down a line */
3628
/* move to the left column */
3629
*x = win->base.winx;
3635
* clear an area of the display formerly occupied by some input text
3637
static void oss_gets_clear(osgen_txtwin_t *win, int y, int x, size_t len)
3639
/* if we don't even reach the left edge of the window, ignore it */
3640
if (x + (int)len <= win->base.winx)
3643
/* skip anything to the left of the window */
3644
if (x < win->base.winx)
3646
/* deduct the unseen part from the length */
3647
len -= (win->base.winx - x);
3649
/* start at the left edge */
3653
/* clear one line at a time */
3658
/* calculate how much we have left to the right edge of the window */
3659
cur = win->base.winx + win->base.wid - x;
3661
/* limit the clearing to the requested length */
3665
/* clear this chunk */
3666
ossclr(y, x, y, x + cur - 1, win->base.oss_fillcolor);
3668
/* deduct this chunk from the remaining length */
3671
/* move to the start of the next line */
3675
/* if we're past the bottom of the window, stop */
3676
if (y >= win->base.winy + (int)win->base.ht)
3682
* Delete a character in the buffer, updating the display.
3684
static void oss_gets_delchar(osgen_txtwin_t *win,
3685
char *buf, char *p, char **eol, int x, int y)
3689
/* get the oss color for the current text in the window */
3690
color = ossgetcolor(win->base.txtfg, win->base.txtbg,
3691
win->base.txtattr, win->base.fillcolor);
3693
/* if the character is within the buffer, delete it */
3696
/* delete the character and close the gap */
3699
memmove(p, p + 1, *eol - p);
3701
/* null-terminate the shortened buffer */
3704
/* re-display the changed part of the string */
3705
ossdsp_str(&win->base, y, x, color, p, *eol - p, 0);
3707
/* move to the position of the former last character */
3708
oss_gets_csrright(win, &y, &x, *eol - p);
3710
/* clear the screen area where the old last character was displayed */
3711
ossclr(y, x, y, x, win->base.oss_fillcolor);
3716
* Backspace in the buffer, updating the display and adjusting the cursor
3719
static void oss_gets_backsp(osgen_txtwin_t *win,
3720
char *buf, char **p,
3721
char **eol, int *x, int *y)
3725
/* get the oss color for the current text in the window */
3726
color = ossgetcolor(win->base.txtfg, win->base.txtbg,
3727
win->base.txtattr, win->base.fillcolor);
3729
/* if we can back up, do so */
3735
/* move our insertion point back one position */
3738
/* the line is now one character shorter */
3741
/* shift all of the characters down one position */
3743
memmove(*p, *p + 1, *eol - *p);
3745
/* move the cursor back, wrapping if at the first column */
3746
if (--*x < win->base.winx)
3748
*x = win->base.winx + win->base.wid - 1;
3752
/* null-terminate the shortened buffer */
3756
* display the string from the current position, so that we update
3757
* the display for the moved characters
3761
ossdsp_str(&win->base, tmpy, tmpx, color, *p, *eol - *p, 0);
3763
/* clear the screen area where the old last character was shown */
3764
oss_gets_csrright(win, &tmpy, &tmpx, *eol - *p);
3765
ossclr(tmpy, tmpx, tmpy, tmpx, win->base.oss_fillcolor);
3770
* Redraw any command line under construction
3772
static void osgen_gets_redraw_cmdline(void)
3774
osgen_txtwin_t *win;
3779
* get the default window; if we don't have one, or there's no command
3780
* line editing in progress, there's nothing to do
3782
if ((win = S_default_win) == 0 || !S_gets_in_progress)
3785
/* set up at the current cursor position */
3789
/* move to the start of the command */
3790
oss_gets_csrleft(win, &y, &x, S_gets_ofs);
3792
/* get the color of the command text */
3793
color = ossgetcolor(win->base.txtfg, win->base.txtbg,
3794
win->base.txtattr, win->base.fillcolor);
3796
/* draw the command line */
3797
ossdsp_str(&win->base, y, x, color, S_gets_buf, strlen(S_gets_buf), 0);
3800
/* ------------------------------------------------------------------------ */
3802
* cancel interrupted input
3804
void os_gets_cancel(int reset)
3808
/* if we're doing scrollback, cancel it */
3809
if (S_sbmode_win != 0)
3810
osgen_sb_mode_end();
3812
/* do any deferred redrawing */
3813
osssb_redraw_if_needed();
3816
* if we interrupted a previous line, apply display effects as though
3817
* the user had pressed return
3819
if (S_gets_in_progress)
3821
osgen_txtwin_t *win;
3823
/* use the main window */
3826
/* move to the end of the input line */
3829
oss_gets_csrright(win, &y, &x, strlen(S_gets_buf + S_gets_ofs));
3831
/* set the cursor to the new position */
3834
/* copy the buffer to the screen save buffer, adding a newline */
3835
ossaddsb_input(win, (char *)S_gets_buf, TRUE);
3837
/* we no longer have an input in progress */
3838
S_gets_in_progress = FALSE;
3841
/* if we're resetting, clear our saved buffer */
3843
S_gets_buf[0] = '\0';
3846
/* ------------------------------------------------------------------------ */
3848
* Initialize input line editing mode. Returns true if we can
3849
* successfully set up input line editing mode, false if not.
3851
int os_gets_begin(size_t max_line_len)
3853
osgen_txtwin_t *win;
3855
/* if there's no default window, there's nothing we can do */
3856
if ((win = S_default_win) == 0)
3859
/* do any deferred redrawing */
3860
osssb_redraw_if_needed();
3862
/* if the cursor if off the screen vertically, scroll to show it */
3863
if (win->base.y >= win->base.scrolly + (int)win->base.ht)
3864
osgen_scroll_win_fwd(win, win->base.y
3865
- (win->base.scrolly + win->base.ht) + 1);
3867
/* if we're horizontally scrolled, scroll to the left edge */
3868
if (win->base.scrollx != 0)
3870
/* scroll to the left edge */
3871
win->base.scrollx = 0;
3873
/* redraw the window */
3874
osgen_redraw_win(&win->base);
3878
/* allocate the history buffer if it's not already allocated */
3881
histbuf = (char *)osmalloc(HISTBUFSIZE);
3882
histhead = histtail = histbuf;
3883
S_gets_curhist = histhead;
3885
# endif /* USE_HISTORY */
3888
* If we have saved input state from a previous interrupted call,
3889
* restore it now. Otherwise, initialize everything.
3891
if (S_gets_buf[0] != '\0' || S_gets_in_progress)
3894
* if we cancelled the previous input, we must re-display the
3895
* buffer under construction, since we have displayed something
3896
* else in between and have re-displayed the prompt
3898
if (!S_gets_in_progress)
3905
/* set up at the window's output position, in screen coords */
3906
x = win->base.winx + win->base.x - win->base.scrollx;
3907
y = win->base.winy + win->base.y - win->base.scrolly;
3909
/* get the current color in the window */
3910
color = ossgetcolor(win->base.txtfg, win->base.txtbg,
3911
win->base.txtattr, win->base.fillcolor);
3913
/* re-display the buffer */
3914
ossdsp_str(&win->base, y, x, color,
3915
S_gets_buf, strlen(S_gets_buf), &deltay);
3917
/* adjust our y position for any scrolling we just did */
3920
/* limit the initial offset to the available buffer length */
3921
if (S_gets_ofs > (int)max_line_len)
3922
S_gets_ofs = max_line_len;
3924
/* move back to the original insertion point */
3925
oss_gets_csrright(win, &y, &x, S_gets_ofs);
3927
/* note the current position as the new editing position */
3934
/* initialize our history recall pointer */
3935
S_gets_curhist = histhead;
3937
/* set up at the window's output position, in screen coords */
3938
S_gets_x = win->base.winx + win->base.x - win->base.scrollx;
3939
S_gets_y = win->base.winy + win->base.y - win->base.scrolly;
3941
/* we're at offset zero in the input line */
3946
* set the buffer end pointer to limit input to the maximum size the
3947
* caller has requested, or the maximum size of our internal buffer,
3948
* whichever is smaller
3950
if (max_line_len > S_gets_buf_siz)
3951
S_gets_buf_end = S_gets_buf + S_gets_buf_siz - 1;
3953
S_gets_buf_end = S_gets_buf + max_line_len - 1;
3955
/* override the default cursor position logic while reading */
3956
S_special_cursor_pos = TRUE;
3957
S_special_cursor_x = S_gets_x;
3958
S_special_cursor_y = S_gets_y;
3960
/* note that input is in progress */
3961
S_gets_in_progress = TRUE;
3963
/* successfully set up */
3968
/* ------------------------------------------------------------------------ */
3970
* Process an event in input line editing mode. Returns true if the user
3971
* explicitly ended input line editing by pressing Return or something
3972
* similar, false if input line editing mode remains active.
3974
int os_gets_process(int event_type, os_event_info_t *event_info)
3982
osgen_txtwin_t *win;
3985
/* use the default window */
3986
if ((win = S_default_win) == 0)
3989
/* if it's a keystroke event, convert from "raw" to a CMD_xxx code */
3990
if (event_type == OS_EVT_KEY)
3991
oss_raw_key_to_cmd(event_info);
3994
* if we're in scrollback mode, run the event through the scrollback
3995
* handler rather than handling it directly
3997
if (S_sbmode_win != 0)
3999
/* run the event through scrollback mode */
4000
if (osgen_sb_mode(win, event_type, event_info))
4003
* scrollback mode fully handled the event, so we're done;
4004
* tell the caller we didn't finish command input editing
4010
/* ignore everything except keystroke events */
4011
if (event_type != OS_EVT_KEY)
4014
/* get the key from the event */
4015
c = (unsigned char)event_info->key[0];
4017
/* set up at the current position */
4021
/* set up our buffer pointers */
4022
p = S_gets_buf + S_gets_ofs;
4024
eol = p + strlen(p);
4026
/* get the current color in the window */
4027
color = ossgetcolor(win->base.txtfg, win->base.txtbg,
4028
win->base.txtattr, win->base.fillcolor);
4031
* Check the character we got. Note that we must interpret certain
4032
* control characters explicitly, because os_get_event() returns raw
4033
* keycodes (untranslated into CMD_xxx codes) for control characters.
4038
/* backspace one character */
4039
oss_gets_backsp(win, buf, &p, &eol, &x, &y);
4043
/* Return/Enter key - we're done. Null-terminate the input. */
4046
/* move to the end of the line */
4047
oss_gets_csrright(win, &y, &x, eol - p);
4052
* Save the line in our history buffer. If we don't have enough
4053
* room, lose some old text by advancing the tail pointer far
4054
* enough. Don't save it if it's a blank line, though, or if it
4055
* duplicates the most recent previous command.
4057
if (strlen(buf) != 0)
4061
int saveflag = 1; /* assume we will be saving it */
4063
if (q = ossprvcmd(histhead))
4067
while (*p == *q && *p != '\0' && *q != '\0')
4072
if (*p == *q) /* is this a duplicate command? */
4073
saveflag = 0; /* if so, don't save it */
4078
for (q = buf, advtail = 0 ; q <= eol ; ++q)
4081
histhead = ossadvhp(histhead);
4082
if (histhead == histtail)
4084
histtail = ossadvhp(histtail);
4090
* If we have encroached on space that was already
4091
* occupied, throw away the entire command we have
4092
* partially trashed; to do so, advance the tail pointer
4093
* to the next null byte.
4098
histtail = ossadvhp(histtail);
4099
histtail = ossadvhp(histtail);
4103
# endif /* USE_HISTORY */
4105
/* add the text to the scrollback buffer */
4106
ossaddsb_input(win, buf, TRUE);
4108
/* done with the special cursor position */
4109
S_special_cursor_pos = FALSE;
4112
* immediately scroll the window if necessary, and make sure the
4113
* cursor is showing at the right location
4115
osgen_auto_vscroll(win);
4116
osssb_cursor_to_default_pos();
4118
/* input is no longer in progress */
4119
S_gets_in_progress = FALSE;
4121
/* tell the caller we're done */
4125
/* extended key code - get the second half of the code */
4126
c = (unsigned char)event_info->key[1];
4128
/* handle the command key code */
4131
# ifdef USE_SCROLLBACK
4135
/* run the event through scrollback mode */
4136
osgen_sb_mode(win, event_type, event_info);
4140
# endif /* USE_SCROLLBACK */
4143
/* move the cursor left */
4147
oss_gets_csrleft(win, &y, &x, 1);
4153
* Move back one word. This moves the cursor back a
4154
* character, then seeks back until we're on a non-space
4155
* character, then seeks back until we're on a character
4156
* preceded by a space character.
4160
/* back up one character */
4162
oss_gets_csrleft(win, &y, &x, 1);
4164
/* back up until we're on a non-space character */
4165
while (p > buf && t_isspace(*p) && !t_isspace(*(p-1)))
4168
oss_gets_csrleft(win, &y, &x, 1);
4172
* back up again until we're on a character preceded by a
4175
while (p > buf && !t_isspace(*(p-1)))
4178
oss_gets_csrleft(win, &y, &x, 1);
4184
/* move the cursor right */
4188
oss_gets_csrright(win, &y, &x, 1);
4192
case CMD_WORD_RIGHT:
4194
* Move right one word. This moves the cursor right until
4195
* we're on a space character, then moves the cursor right
4196
* again until we're on a non-space character. First, move
4197
* right until we're between words (i.e., until we're on a
4200
while (p < eol && !t_isspace(*p))
4203
oss_gets_csrright(win, &y, &x, 1);
4206
/* now move right until we're on a non-space character */
4207
while (p < eol && t_isspace(*p))
4210
oss_gets_csrright(win, &y, &x, 1);
4215
/* delete a character */
4216
oss_gets_delchar(win, buf, p, &eol, x, y);
4222
/* remove spaces preceding word */
4223
while (p >= buf && *p <= ' ')
4224
oss_gets_backsp(win, buf, &p, &eol, &x, &y);
4226
/* remove previous word (i.e., until we get a space) */
4227
while (p >= buf && *p > ' ')
4228
oss_gets_backsp(win, buf, &p, &eol, &x, &y);
4241
* Home, Kill (delete entire line), History Up, History Down -
4242
* what these all have in common is that we move to the start
4243
* of the line before doing anything else.
4246
/* if 'up', make sure we have more history to traverse */
4247
if (c == CMD_UP && !ossprvcmd(S_gets_curhist))
4250
/* if 'down', make sure there's more history to traverse */
4251
if (c == CMD_DOWN && !ossnxtcmd(S_gets_curhist))
4255
* if this is the first 'up', save the current buffer, so that
4256
* we can reinstate it if we traverse back 'down' until we're
4257
* back at the original buffer (the active buffer essentially
4258
* becomes a temporary history entry that we can recover by
4259
* history-scrolling back down to it)
4261
if (c == CMD_UP && !ossnxtcmd(S_gets_curhist))
4262
strcpy(S_hist_sav, buf);
4264
# endif /* USE_HISTORY */
4266
/* move to the start of the line */
4269
/* move the cursor */
4270
oss_gets_csrleft(win, &y, &x, p - buf);
4272
/* move the insertion pointer */
4276
/* if it was just a 'home' command, we're done */
4281
* We're at the start of the line now; fall through for
4282
* KILL, UP, and DOWN to the code which deletes to the end
4287
/* clear the remainder of the line on the display */
4288
oss_gets_clear(win, y, x, eol - p);
4290
/* truncate the buffer at the insertion point */
4297
S_gets_curhist = ossprvcmd(S_gets_curhist);
4298
osshstcpy(buf, S_gets_curhist);
4300
else if (c == CMD_DOWN)
4302
if (!ossnxtcmd(S_gets_curhist))
4303
break; /* no more */
4304
S_gets_curhist = ossnxtcmd(S_gets_curhist);
4305
if (ossnxtcmd(S_gets_curhist)) /* on a valid command */
4306
osshstcpy(buf, S_gets_curhist); /* ... so use it */
4309
/* no more history - restore original line */
4310
strcpy(buf, S_hist_sav);
4313
if ((c == CMD_UP || c == CMD_DOWN)
4314
&& strlen(buf) != 0)
4318
/* get the end pointer based on null termination */
4319
eol = buf + strlen(buf);
4321
/* display the string */
4322
ossdsp_str(&win->base, y, x, color, p, eol - p, &deltay);
4325
/* move to the end of the line */
4326
oss_gets_csrright(win, &y, &x, eol - p);
4329
# endif /* USE_HISTORY */
4335
if (++x >= win->base.winx + (int)win->base.wid)
4346
if (c >= ' ' && eol < S_gets_buf_end)
4350
/* open up the line and insert the character */
4352
memmove(p + 1, p, eol - p);
4357
/* write the updated part of the line */
4358
ossdsp_str(&win->base, y, x, color, p, eol - p, &deltay);
4361
/* move the cursor right one character */
4362
oss_gets_csrright(win, &y, &x, 1);
4364
/* advance the buffer pointer one character */
4370
/* remember the current editing position */
4371
S_special_cursor_x = S_gets_x = x;
4372
S_special_cursor_y = S_gets_y = y;
4373
S_gets_ofs = p - S_gets_buf;
4375
/* we didn't finish editing */
4379
/* ------------------------------------------------------------------------ */
4381
* Common routine to read a command from the keyboard. This
4382
* implementation provides command editing and history, as well as timeout
4385
int os_gets_timeout(unsigned char *buf, size_t bufl,
4386
unsigned long timeout, int use_timeout)
4389
osgen_txtwin_t *win;
4391
/* if we're in 'plain' mode, simply use stdio input */
4396
/* make sure the standard output is flushed */
4399
/* we don't support the timeout feature in plain mode */
4401
return OS_EVT_NOTIMEOUT;
4404
* get input from stdio, and translate the result code - if gets()
4405
* returns null, it indicates an error of some kind, so return an
4406
* end-of-file indication
4408
if (fgets((char *)buf, bufl, stdin) == 0)
4411
/* remove the trailing newline from the buffer, if present */
4412
if ((len = strlen((char *)buf)) != 0 && buf[len-1] == '\n')
4415
/* indicate that we read a line */
4419
/* begin input editing mode */
4420
os_gets_begin(bufl);
4423
* If we have a timeout, calculate the system clock time at which the
4424
* timeout expires. This is simply the current system clock time plus
4425
* the timeout interval. Since we might need to process a series of
4426
* events, we'll need to know how much time remains at each point we
4429
end_time = os_get_sys_clock_ms() + timeout;
4431
/* use the default window for input */
4432
if ((win = S_default_win) == 0)
4435
/* process keystrokes until we're done entering the command */
4439
os_event_info_t event_info;
4441
/* if we're using a timeout, check for expiration */
4446
/* note the current system clock time */
4447
cur_clock = os_get_sys_clock_ms();
4450
* if we're past the timeout expiration time already,
4451
* interrupt with timeout now
4453
if (cur_clock >= end_time)
4454
goto timeout_expired;
4456
/* note the interval remaining to the timeout expiration */
4457
timeout = end_time - cur_clock;
4460
/* move to the proper position on the screen before pausing */
4461
if (S_sbmode_win != 0)
4462
ossloc(S_sbmode_win->base.winy, S_sbmode_win->base.winx);
4464
ossloc(S_gets_y, S_gets_x);
4467
event_type = os_get_event(timeout, use_timeout, &event_info);
4469
/* handle the event according to the event type */
4472
case OS_EVT_TIMEOUT:
4474
/* done with the overridden cursor position */
4475
S_special_cursor_pos = FALSE;
4477
/* return the timeout status to the caller */
4478
return OS_EVT_TIMEOUT;
4480
case OS_EVT_NOTIMEOUT:
4482
* we can't handle events with timeouts, so we can't provide
4483
* line reading with timeouts, either
4485
S_special_cursor_pos = FALSE;
4486
return OS_EVT_NOTIMEOUT;
4489
/* end of file - end input and return the EOF to our caller */
4490
S_special_cursor_pos = FALSE;
4491
S_gets_in_progress = FALSE;
4495
/* process anything else through the input line editor */
4496
if (os_gets_process(event_type, &event_info))
4499
* Copy the result to the caller's buffer. Note that we
4500
* know the result will fit, because we always limit the
4501
* editing process to the caller's buffer size.
4503
strcpy((char *)buf, S_gets_buf);
4505
/* clear the input buffer */
4506
S_gets_buf[0] = '\0';
4508
/* input is no longer in progress */
4509
S_gets_in_progress = FALSE;
4511
/* return success */
4520
* Read a line of input. We implement this in terms of the timeout input
4521
* line reader, passing an infinite timeout to that routine.
4523
uchar *os_gets(unsigned char *buf, size_t bufl)
4527
/* cancel any previous input, clearing the buffer */
4528
os_gets_cancel(TRUE);
4530
/* get a line of input, with no timeout */
4531
evt = os_gets_timeout(buf, bufl, 0, FALSE);
4533
/* translate the event code to the appropriate return value */
4537
/* we got a line of input - return a pointer to our buffer */
4541
/* end of file - return null */
4545
/* we don't expect any other results */
4551
#else /* USE_STATLINE */
4553
#endif /* USE_STATLINE */
4555
/* ------------------------------------------------------------------------ */
4557
* Highlighting and colors
4560
#ifdef STD_OS_HILITE
4564
* Set text attributes
4566
void os_set_text_attr(int attr)
4568
osgen_txtwin_t *win;
4570
/* if there's no default output window, do nothing */
4571
if ((win = S_default_win) == 0)
4575
* if the attributes are different from the old attributes, add an
4576
* attribute-change sequence to the display buffer
4578
if (attr != win->base.txtattr)
4582
/* set up the attribute-change sequence */
4583
buf[0] = OSGEN_ATTR;
4584
buf[1] = (char)attr;
4585
ossaddsb(win, buf, 2, TRUE);
4590
* Translate a color from the os_color_t encoding to an OSGEN_xxx color.
4592
static char osgen_xlat_color_t(os_color_t color)
4597
/* the OSGEN_COLOR_xxx value */
4600
/* the RGB components for the color */
4601
unsigned char rgb[3];
4603
struct color_map_t *p;
4604
struct color_map_t *bestp;
4605
static struct color_map_t color_map[] =
4607
{ OSGEN_COLOR_BLACK, { 0x00, 0x00, 0x00 } },
4608
{ OSGEN_COLOR_WHITE, { 0xFF, 0xFF, 0xFF } },
4609
{ OSGEN_COLOR_RED, { 0xFF, 0x00, 0x00 } },
4610
{ OSGEN_COLOR_BLUE, { 0x00, 0x00, 0xFF } },
4611
{ OSGEN_COLOR_GREEN, { 0x00, 0x80, 0x00 } },
4612
{ OSGEN_COLOR_YELLOW, { 0xFF, 0xFF, 0x00 } },
4613
{ OSGEN_COLOR_CYAN, { 0x00, 0xFF, 0xFF } },
4614
{ OSGEN_COLOR_SILVER, { 0xC0, 0xC0, 0xC0 } },
4615
{ OSGEN_COLOR_GRAY, { 0x80, 0x80, 0x80 } },
4616
{ OSGEN_COLOR_MAROON, { 0x80, 0x00, 0x00 } },
4617
{ OSGEN_COLOR_PURPLE, { 0x80, 0x00, 0x80 } },
4618
{ OSGEN_COLOR_MAGENTA, { 0xFF, 0x00, 0xFF } },
4619
{ OSGEN_COLOR_LIME, { 0x00, 0xFF, 0x00 } },
4620
{ OSGEN_COLOR_OLIVE, { 0x80, 0x80, 0x00 } },
4621
{ OSGEN_COLOR_NAVY, { 0x00, 0x00, 0x80 } },
4622
{ OSGEN_COLOR_TEAL, { 0x00, 0x80, 0x80 } }
4624
unsigned char r, g, b;
4625
unsigned long best_dist;
4628
* If it's parameterized, map it by shifting the parameter code (in
4629
* the high-order 8 bits of the os_color_t) to our single-byte code,
4630
* which is defined as exactly the same code as the os_color_t values
4631
* but shifted into the low-order 8 bits.
4633
if (os_color_is_param(color))
4634
return (char)((color >> 24) & 0xFF);
4636
/* break the color into its components */
4637
r = os_color_get_r(color);
4638
g = os_color_get_g(color);
4639
b = os_color_get_b(color);
4641
/* search for the closest match among our 16 ANSI colors */
4642
for (i = 0, p = color_map, bestp = 0, best_dist = 0xFFFFFFFF ;
4643
i < sizeof(color_map)/sizeof(color_map[0]) ; ++i, ++p)
4648
/* calculate the delta for each component */
4653
/* calculate the "distance" in RGB space */
4654
dist = rd*rd + gd*gd + bd*bd;
4656
/* if it's an exact match, we need look no further */
4660
/* if it's the smallest distance so far, note it */
4661
if (dist < best_dist)
4668
/* return the OSGEN_COLOR_xxx ID of the best match we found */
4673
* Set the text colors.
4675
* The foreground and background colors apply to subsequent characters
4676
* displayed via os_print(). If the background color is set to zero, it
4677
* indicates "transparent" drawing: subsequent text is displayed with the
4680
void os_set_text_color(os_color_t fg, os_color_t bg)
4684
/* if we're in plain mode, ignore it */
4685
if (os_f_plain || S_default_win == 0)
4688
/* add the color sequence to the default window's scrollback buffer */
4689
buf[0] = OSGEN_COLOR;
4690
buf[1] = osgen_xlat_color_t(fg);
4691
buf[2] = osgen_xlat_color_t(bg);
4692
ossaddsb(S_default_win, buf, 3, TRUE);
4696
* Set the screen color
4698
void os_set_screen_color(os_color_t color)
4700
/* if we're in plain mode, ignore it */
4701
if (os_f_plain || S_default_win == 0)
4704
/* set the new background color in the default buffer */
4705
S_default_win->base.fillcolor = osgen_xlat_color_t(color);
4706
S_default_win->base.oss_fillcolor =
4707
ossgetcolor(OSGEN_COLOR_TEXT, osgen_xlat_color_t(color), 0, 0);
4709
/* redraw the window if we don't have a scheduled redraw already */
4710
if (!S_deferred_redraw
4711
&& !(S_default_win->base.flags & OSGEN_DEFER_REDRAW))
4712
osgen_redraw_win(&S_default_win->base);
4715
/* ------------------------------------------------------------------------ */
4721
* create a banner window
4723
void *os_banner_create(void *parent, int where, void *other, int wintype,
4724
int align, int siz, int siz_units, unsigned long style)
4728
/* we don't support banners in plain mode */
4732
/* if the parent is null, it means that it's a child of the main window */
4734
parent = &S_main_win->base;
4736
/* check for a supported window type */
4739
case OS_BANNER_TYPE_TEXT:
4741
* Create a text window. We don't support scrollback in the UI in
4742
* banner windows, so we only need enough for what's on the screen
4743
* for redrawing. Overallocate by a bit, though, to be safe in
4744
* case the screen grows later.
4746
win = (osgen_win_t *)osgen_create_txtwin(where, other, parent,
4747
G_oss_screen_height * G_oss_screen_width * 2,
4748
G_oss_screen_height * 2);
4751
case OS_BANNER_TYPE_TEXTGRID:
4753
* Create a text grid window. Make it ten lines high at the
4754
* current screen width; we'll automatically expand this
4755
* allocation as needed later, so this size doesn't have to be a
4756
* perfect guess; but the closer we get the better, as it's more
4757
* efficient to avoid reallocating if possible.
4759
win = (osgen_win_t *)osgen_create_gridwin(where, other, parent,
4760
G_oss_screen_width, 10);
4764
/* unsupported type - return failure */
4768
/* if that failed, return null */
4772
/* set the alignment */
4773
win->alignment = align;
4776
* Start out width a zero size in the settable dimension, and the
4777
* current main text area size in the constrained dimension.
4779
if (align == OS_BANNER_ALIGN_LEFT || align == OS_BANNER_ALIGN_RIGHT)
4781
/* the width is the settable dimension for a left/right banner */
4783
win->ht = (S_main_win != 0
4784
? S_main_win->base.ht : G_oss_screen_height);
4788
/* the height is the settable dimension for a top/bottom banner */
4789
win->wid = (S_main_win != 0
4790
? S_main_win->base.wid : G_oss_screen_width);
4794
/* set auto-vscroll mode if they want it */
4795
if ((style & OS_BANNER_STYLE_AUTO_VSCROLL) != 0)
4796
win->flags |= OSGEN_AUTO_VSCROLL;
4799
* Note the MORE mode style, if specified. MORE mode implies
4800
* auto-vscroll, so add that style as well if MORE mode is requested.
4802
if ((style & OS_BANNER_STYLE_MOREMODE) != 0)
4803
win->flags |= OSGEN_AUTO_VSCROLL | OSGEN_MOREMODE;
4805
/* note the "strut" style flags, if specified */
4806
if ((style & OS_BANNER_STYLE_VSTRUT) != 0)
4807
win->flags |= OSGEN_VSTRUT;
4808
if ((style & OS_BANNER_STYLE_HSTRUT) != 0)
4809
win->flags |= OSGEN_HSTRUT;
4811
/* remember the requested size */
4813
win->size_type = siz_units;
4816
* if the window has a non-zero size, recalculate the layout; if the
4817
* size is zero, we don't have to bother, since the layout won't affect
4818
* anything on the display
4821
osgen_recalc_layout();
4823
/* return the window */
4830
void os_banner_delete(void *banner_handle)
4832
osgen_win_t *win = (osgen_win_t *)banner_handle;
4834
/* delete the window */
4835
osgen_delete_win(win);
4837
/* recalculate the display layout */
4838
osgen_recalc_layout();
4842
* orphan a banner - treat this exactly like delete
4844
void os_banner_orphan(void *banner_handle)
4846
os_banner_delete(banner_handle);
4850
* get information on the banner
4852
int os_banner_getinfo(void *banner_handle, os_banner_info_t *info)
4854
osgen_win_t *win = (osgen_win_t *)banner_handle;
4856
/* set the alignment */
4857
info->align = win->alignment;
4861
if ((win->flags & OSGEN_AUTO_VSCROLL) != 0)
4862
info->style |= OS_BANNER_STYLE_AUTO_VSCROLL;
4863
if ((win->flags & OSGEN_MOREMODE) != 0)
4864
info->style |= OS_BANNER_STYLE_MOREMODE;
4865
if ((win->flags & OSGEN_HSTRUT) != 0)
4866
info->style |= OS_BANNER_STYLE_HSTRUT;
4867
if ((win->flags & OSGEN_VSTRUT) != 0)
4868
info->style |= OS_BANNER_STYLE_VSTRUT;
4870
/* set the character size */
4871
info->rows = win->ht;
4872
info->columns = win->wid;
4874
/* we're a character-mode platform, so we don't have a pixel size */
4875
info->pix_width = 0;
4876
info->pix_height = 0;
4879
* We are designed for fixed-pitch character-mode displays only, so we
4880
* support <TAB> alignment by virtue of our fixed pitch.
4882
info->style |= OS_BANNER_STYLE_TAB_ALIGN;
4884
/* we do not do our own line wrapping */
4885
info->os_line_wrap = FALSE;
4887
/* indicate success */
4892
* clear the contents of a banner
4894
void os_banner_clear(void *banner_handle)
4896
osgen_win_t *win = (osgen_win_t *)banner_handle;
4898
/* clear the window */
4899
osgen_clear_win(win);
4903
* display text in a banner
4905
void os_banner_disp(void *banner_handle, const char *txt, size_t len)
4907
osgen_win_t *win = (osgen_win_t *)banner_handle;
4909
/* write the text according to the window type */
4910
switch(win->win_type)
4912
case OS_BANNER_TYPE_TEXT:
4913
/* normal text window - write the text into the scrollback buffer */
4914
ossaddsb((osgen_txtwin_t *)win, txt, len, TRUE);
4917
case OS_BANNER_TYPE_TEXTGRID:
4918
/* text grid - write the text into the grid */
4919
osgen_gridwin_write((osgen_gridwin_t *)win, txt, len);
4925
* set the text attributes in a banner
4927
void os_banner_set_attr(void *banner_handle, int attr)
4929
osgen_win_t *win = (osgen_win_t *)banner_handle;
4932
/* if the attributes aren't changing, ignore it */
4933
if (attr == win->txtattr)
4936
/* set the attribute according to the window type */
4937
switch(win->win_type)
4939
case OS_BANNER_TYPE_TEXT:
4940
/* add the color sequence to the window's scrollback buffer */
4941
buf[0] = OSGEN_ATTR;
4942
buf[1] = (char)attr;
4943
ossaddsb((osgen_txtwin_t *)win, buf, 2, TRUE);
4946
case OS_BANNER_TYPE_TEXTGRID:
4947
/* text grid windows don't use attributes - ignore it */
4953
* set the text color in a banner
4955
void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg)
4957
osgen_win_t *win = (osgen_win_t *)banner_handle;
4960
/* set the color according to the window type */
4961
switch(win->win_type)
4963
case OS_BANNER_TYPE_TEXT:
4964
/* add the color sequence to the window's scrollback buffer */
4965
buf[0] = OSGEN_COLOR;
4966
buf[1] = osgen_xlat_color_t(fg);
4967
buf[2] = osgen_xlat_color_t(bg);
4968
ossaddsb((osgen_txtwin_t *)win, buf, 3, TRUE);
4971
case OS_BANNER_TYPE_TEXTGRID:
4972
/* simply set the current color in the window */
4973
win->txtfg = osgen_xlat_color_t(fg);
4974
win->txtbg = osgen_xlat_color_t(bg);
4980
* set the window color in a banner
4982
void os_banner_set_screen_color(void *banner_handle, os_color_t color)
4984
osgen_win_t *win = (osgen_win_t *)banner_handle;
4986
/* set the new background color in the window */
4987
win->fillcolor = osgen_xlat_color_t(color);
4988
win->oss_fillcolor = ossgetcolor(OSGEN_COLOR_TEXT, win->fillcolor, 0, 0);
4990
/* redraw the window if we don't have a redraw scheduled already */
4991
if (!S_deferred_redraw && !(win->flags & OSGEN_DEFER_REDRAW))
4992
osgen_redraw_win(win);
4996
* flush text in a banner
4998
void os_banner_flush(void *banner_handle)
5000
osgen_win_t *win = (osgen_win_t *)banner_handle;
5002
/* if we're deferring redrawing, redraw now */
5003
osgen_redraw_win_if_needed(FALSE, win);
5009
void os_banner_set_size(void *banner_handle, int siz, int siz_units,
5012
osgen_win_t *win = (osgen_win_t *)banner_handle;
5014
/* if the size isn't changing, do nothing */
5015
if (win->size == siz && win->size_type == siz_units)
5019
* if the size is only advisory, ignore it, since we do implement
5025
/* set the new size */
5027
win->size_type = siz_units;
5029
/* recalculate the layout */
5030
osgen_recalc_layout();
5034
* calculate the content height, for os_banner_size_to_contents()
5036
static size_t oss_get_content_height(osgen_win_t *win)
5041
/* start with our own maximum 'y' size */
5044
/* scan children for vertical strut styles, and include any we find */
5045
for (chi = win->first_child ; chi != 0 ; chi = chi->nxt)
5047
/* if this is a vertical strut, include its height as well */
5048
if ((chi->flags & OSGEN_VSTRUT) != 0)
5050
/* calculate the child height */
5051
size_t chi_y = oss_get_content_height(chi);
5054
* if the child is horizontal, add its height to the parent's;
5055
* otherwise, it shares the same height, so use the larger of
5056
* the parent's natural height or the child's natural height
5058
if (chi->alignment == OS_BANNER_ALIGN_TOP
5059
|| chi->alignment == OS_BANNER_ALIGN_BOTTOM)
5061
/* it's horizontal - add its height to the parent's */
5066
/* it's vertical - they share a common height */
5073
/* return the result */
5078
* calculate the content width, for os_banner_size_to_contents()
5080
static size_t oss_get_content_width(osgen_win_t *win)
5085
/* start with the maximum 'x' size we've seen in the window */
5088
/* scan children for horizontal strut styles, and include any we find */
5089
for (chi = win->first_child ; chi != 0 ; chi = chi->nxt)
5091
/* if this is a horizontal strut, include its height as well */
5092
if ((chi->flags & OSGEN_HSTRUT) != 0)
5094
/* calculate the child width */
5095
size_t chi_x = oss_get_content_width(chi);
5098
* if the child is vertical, add its width to the parent's;
5099
* otherwise, it shares the same width, so use the larger of
5100
* the parent's natural width or the child's natural width
5102
if (chi->alignment == OS_BANNER_ALIGN_LEFT
5103
|| chi->alignment == OS_BANNER_ALIGN_RIGHT)
5105
/* it's vertical - add its width to the parent's */
5110
/* it's horizontal - they share a common width */
5117
/* return the result */
5122
* size a banner to its contents
5124
void os_banner_size_to_contents(void *banner_handle)
5126
osgen_win_t *win = (osgen_win_t *)banner_handle;
5128
/* the sizing depends on the window's alignment */
5129
if (win->alignment == OS_BANNER_ALIGN_TOP
5130
|| win->alignment == OS_BANNER_ALIGN_BOTTOM)
5134
/* calculate the new height */
5135
newy = oss_get_content_height(win);
5138
* if this is the same as the current height, there's no need to
5141
if (win->ht == newy)
5144
/* set the new size as a fixed character-cell size */
5146
win->size_type = OS_BANNER_SIZE_ABS;
5152
/* calculate the new width */
5153
newx = oss_get_content_width(win);
5155
/* if the size isn't changing, there's no need to redraw */
5156
if (win->wid == newx)
5159
/* set the new size as a fixed character-cell size */
5161
win->size_type = OS_BANNER_SIZE_ABS;
5164
/* recalculate the window layout */
5165
osgen_recalc_layout();
5169
* get the width, in characters, of the banner window
5171
int os_banner_get_charwidth(void *banner_handle)
5173
/* return the current width from the window */
5174
return ((osgen_win_t *)banner_handle)->wid;
5178
* get the height, in characters, of the banner window
5180
int os_banner_get_charheight(void *banner_handle)
5182
/* return the current height from the window */
5183
return ((osgen_win_t *)banner_handle)->ht;
5187
* start HTML mode in a banner
5189
void os_banner_start_html(void *banner_handle)
5191
/* we don't support HTML mode, so there's nothing to do */
5195
* end HTML mode in a banner
5197
void os_banner_end_html(void *banner_handle)
5199
/* we don't support HTML mode, so there's nothing to do */
5203
* set the output position in a text grid window
5205
void os_banner_goto(void *banner_handle, int row, int col)
5207
osgen_win_t *win = (osgen_win_t *)banner_handle;
5209
/* check the window type */
5210
switch(win->win_type)
5212
case OS_BANNER_TYPE_TEXTGRID:
5213
/* it's a text grid - move the output position */
5220
* this operation is meaningless with other window types - simply
5227
/* ------------------------------------------------------------------------ */
5229
* Non-RUNTIME version
5233
void os_set_text_attr(int attr)
5235
/* attributes aren't supported in non-RUNTIME mode - ignore it */
5238
void os_set_text_color(os_color_t fg, os_color_t bg)
5240
/* colors aren't supported in non-RUNTIME mode - ignore it */
5243
void os_set_screen_color(os_color_t color)
5245
/* colors aren't supported in non-RUNTIME mode - ignore it */
5249
* Banners aren't supported in plain mode
5252
void *os_banner_create(void *parent, int where, void *other, int wintype,
5253
int align, int siz, int siz_units, unsigned long style)
5258
void os_banner_delete(void *banner_handle)
5262
void os_banner_orphan(void *banner_handle)
5266
int os_banner_getinfo(void *banner_handle, os_banner_info_t *info)
5271
void os_banner_clear(void *banner_handle)
5275
int os_banner_get_charwidth(void *banner_handle)
5280
int os_banner_get_charheight(void *banner_handle)
5285
void os_banner_disp(void *banner_handle, const char *txt, size_t len)
5289
void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg)
5293
void os_banner_set_screen_color(void *banner_handle, os_color_t color)
5297
void os_banner_flush(void *banner_handle)
5301
void os_banner_set_size(void *banner_handle, int siz, int siz_units,
5306
void os_banner_size_to_contents(void *banner_handle)
5310
void os_banner_start_html(void *banner_handle)
5314
void os_banner_end_html(void *banner_handle)
5318
void os_banner_goto(void *banner_handle, int row, int col)
5322
#endif /* RUNTIME */
5324
#endif /* STD_OS_HILITE */
5326
/* ------------------------------------------------------------------------ */
5328
* clear the screen, deleting all scrollback information
5335
/* do nothing in 'plain' mode */
5336
if (os_f_plain || S_default_win == 0)
5339
/* clear the default window */
5340
osgen_clear_win(&S_default_win->base);
5344
#endif /* STD_OSCLS */
5346
/* ------------------------------------------------------------------------ */
5348
* Simple implementation of os_get_sysinfo. This can be used for any
5349
* non-HTML version of the system, since all sysinfo codes currently
5350
* pertain to HTML features. Note that new sysinfo codes may be added
5351
* in the future which may be relevant to non-html versions, so the
5352
* sysinfo codes should be checked from time to time to ensure that new
5353
* codes relevant to this system version are handled correctly here.
5355
int os_get_sysinfo(int code, void *param, long *result)
5358
/* if the oss layer recognizes the code, defer to its judgment */
5359
if (oss_get_sysinfo(code, param, result))
5363
/* check the type of information they're requesting */
5371
case SYSINFO_WAV_MIDI_OVL:
5372
case SYSINFO_WAV_OVL:
5377
case SYSINFO_PREF_IMAGES:
5378
case SYSINFO_PREF_SOUNDS:
5379
case SYSINFO_PREF_MUSIC:
5380
case SYSINFO_PREF_LINKS:
5381
case SYSINFO_LINKS_HTTP:
5382
case SYSINFO_LINKS_FTP:
5383
case SYSINFO_LINKS_NEWS:
5384
case SYSINFO_LINKS_MAILTO:
5385
case SYSINFO_LINKS_TELNET:
5386
case SYSINFO_PNG_TRANS:
5387
case SYSINFO_PNG_ALPHA:
5390
case SYSINFO_MNG_TRANS:
5391
case SYSINFO_MNG_ALPHA:
5393
* we don't support any of these features - set the result to 0
5398
/* return true to indicate that we recognized the code */
5401
case SYSINFO_INTERP_CLASS:
5402
/* we're a text-only character-mode interpreter */
5403
*result = SYSINFO_ICLASS_TEXT;
5408
case SYSINFO_BANNERS:
5410
* we support the os_banner_xxx() interfaces, as long as we're not
5413
*result = !os_f_plain;
5416
#endif /* RUNTIME */
5419
/* not recognized */
5424
/* ------------------------------------------------------------------------ */
5426
* Set the saved-game extension. Most platforms don't need to do
5427
* anything with this information, and in fact most platforms won't even
5428
* have a way of letting the game author set the saved game extension,
5429
* so this trivial implementation is suitable for most systems.
5431
* The purpose of setting a saved game extension is to support platforms
5432
* (such as Windows) where the filename suffix is used to associate
5433
* document files with applications. Each stand-alone executable
5434
* generated on such platforms must have a unique saved game extension,
5435
* so that the system can associate each game's saved position files
5436
* with that game's executable.
5438
void os_set_save_ext(const char *ext)
5440
/* ignore the setting */
5444
/* ------------------------------------------------------------------------ */
5446
* Set the game title. Most platforms have no use for this information,
5447
* so they'll just ignore it. This trivial implementation simply
5448
* ignores the title.
5450
#ifdef USE_NULL_SET_TITLE
5452
void os_set_title(const char *title)
5454
/* ignore the information */
5457
#endif /* USE_NULL_SET_TITLE */