~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads2/osgen.c

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

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