cfad47cfa3/t3compiler/tads3/os_stdio.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
/* $Header$ */
2
3
/* 
4
 *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
5
 *   
6
 *   Please see the accompanying license file, LICENSE.TXT, for information
7
 *   on using and copying this software.  
8
 */
9
/*
10
Name
11
  os_stdio.cpp - OS implementation for standard I/O
12
Function
13
  This is a simple stdio-based implementation of the OS display functions.
14
  This is a portable implementation (at least, it's portable to any
15
  platform where stdio can be used).
16
17
  The main purpose of this implementation is to make it easy to build
18
  command-line versions of tools that incorporate osifc-layer functions
19
  without having to drag in the full-blown OS-specific implementation.
20
  For example, test tools might find this useful.
21
Notes
22
  
23
Modified
24
  09/04/99 MJRoberts  - Creation
25
*/
26
27
#include <stdio.h>
28
#include <ctype.h>
29
#include <string.h>
30
31
#include "os.h"
32
#include "t3std.h"
33
34
/* 
35
 *   status-line display mode 
36
 */
37
static int S_status_mode = 0;
38
39
/*
40
 *   set non-stop mode 
41
 */
42
void os_nonstop_mode(int flag)
43
{
44
}
45
46
/*
47
 *   flush output 
48
 */
49
void os_flush()
50
{
51
}
52
53
/*
54
 *   update the display 
55
 */
56
void os_update_display()
57
{
58
}
59
60
/*
61
 *   get highlighting character - indicate that highlighting is to be
62
 *   ignored 
63
 */
64
/* set text attributes */
65
void os_set_text_attr(int /*attr*/)
66
{
67
    /* not supported - ignore it */
68
}
69
70
/* set text color */
71
void os_set_text_color(os_color_t /*fg*/, os_color_t /*bg*/)
72
{
73
    /* not supported - ignore it */
74
}
75
76
/* set the screen color */
77
void os_set_screen_color(os_color_t /*color*/)
78
{
79
    /* not supported - ignore it */
80
}
81
82
/*
83
 *   display text 
84
 */
85
void os_printz(const char *str)
86
{
87
    /* suppress output if we're not in plain text mode */
88
    if (S_status_mode == 0)
89
        fputs(str, stdout);
90
}
91
92
/*
93
 *   get an event 
94
 */
95
int os_get_event(unsigned long timeout, int use_timeout,
96
                 os_event_info_t *info)
97
{
98
    /* we can't handle timeouts */
99
    if (use_timeout)
100
        return OS_EVT_NOTIMEOUT;
101
102
    /* get a key */
103
    info->key[0] = os_getc_raw();
104
    if (info->key[0] == 0)
105
        info->key[1] = os_getc_raw();
106
107
    /* return the keyboard event */
108
    return OS_EVT_KEY;
109
}
110
111
/*
112
 *   clear the screen 
113
 */
114
void oscls()
115
{
116
    /* 
117
     *   print a ^L to clear the screen, if such sequences are interpreted
118
     *   by the display driver or terminal 
119
     */
120
    printf("\014\n");
121
}
122
123
/*
124
 *   read from the keyboard 
125
 */
126
unsigned char *os_gets(unsigned char *buf, size_t buflen)
127
{
128
    size_t len;
129
    
130
    /* read from stdin; return failure if fgets does */
131
    if (fgets((char *)buf, buflen, stdin) == 0)
132
        return 0;
133
134
    /* remove the trailing newline in the result, if there is one */
135
    if ((len = strlen((char *)buf)) != 0 && buf[len-1] == '\n')
136
        buf[len-1] = '\0';
137
138
    /* return the buffer pointer */
139
    return buf;
140
}
141
142
/*
143
 *   read from keyboard with timeout 
144
 */
145
int os_gets_timeout(unsigned char *buf, size_t bufl,
146
                    unsigned long timeout_in_milliseconds, int use_timeout)
147
{
148
    /* 
149
     *   if we've been asked to read with a timeout, we can't comply, so
150
     *   just return the no-timeout-available error code; if we're reading
151
     *   without a timeout, just use the ordinary input reader 
152
     */
153
    if (use_timeout)
154
    {
155
        /* timeout requested, no can do - return the no-timeout error code */
156
        return OS_EVT_NOTIMEOUT;
157
    }
158
    else
159
    {
160
        /* 
161
         *   no timeout requested, so use the ordinary reader, and translate
162
         *   its returns codes to the appropriate equivalents for this
163
         *   routine (null from os_gets -> error -> OS_EVT_EOF as our return
164
         *   code; non-null -> success -> OS_EVT_LINE) 
165
         */
166
        return (os_gets(buf, bufl) == 0 ? OS_EVT_EOF : OS_EVT_LINE);
167
    }
168
}
169
170
/*
171
 *   Cancel interrupted input.  We don't handle input with timeout in the
172
 *   first place, so interrupted input is impossible, so we need do nothing
173
 *   here. 
174
 */
175
void os_gets_cancel(int reset)
176
{
177
    /* there's nothing for us to do */
178
}
179
180
/*
181
 *   prompt for information through a dialog
182
 */
183
int os_input_dialog(int /*icon_id*/,
184
                    const char *prompt, int standard_button_set,
185
                    const char **buttons, int button_count,
186
                    int /*default_index*/, int /*cancel_index*/)
187
{
188
    /* keep going until we get a valid response */
189
    for (;;)
190
    {
191
        int i;
192
        char buf[256];
193
        const char *p;
194
        const char *cur;
195
        char *resp;
196
        int match_cnt;
197
        int last_found;
198
        static const struct
199
        {
200
            const char *buttons[3];
201
            int button_count;
202
        } std_btns[] =
203
        {
204
            { { "&OK" },                    1 },
205
            { { "&OK", "&Cancel" },         2 },
206
            { { "&Yes", "&No" },            2 },
207
            { { "&Yes", "&No", "&Cancel" }, 3 }
208
        };
209
210
        /* 
211
         *   if we have a standard button set selected, get our button
212
         *   labels 
213
         */
214
        switch(standard_button_set)
215
        {
216
        case 0:
217
            /* use the explicit buttons provided */
218
            break;
219
220
        case OS_INDLG_OK:
221
            i = 0;
222
223
        use_std_btns:
224
            /* use the selected standard button set */
225
            buttons = (const char **)std_btns[i].buttons;
226
            button_count = std_btns[i].button_count;
227
            break;
228
229
        case OS_INDLG_OKCANCEL:
230
            i = 1;
231
            goto use_std_btns;
232
233
        case OS_INDLG_YESNO:
234
            i = 2;
235
            goto use_std_btns;
236
237
        case OS_INDLG_YESNOCANCEL:
238
            i = 3;
239
            goto use_std_btns;
240
241
        default:
242
            /* 
243
             *   we don't recognize other standard button sets - return an
244
             *   error 
245
             */
246
            return 0;
247
        }
248
249
        /* 
250
         *   if there are no buttons defined, they'll never be able to
251
         *   respond, so we'd just loop forever - rather than let that
252
         *   happen, return failure 
253
         */
254
        if (button_count == 0)
255
            return 0;
256
257
        /* display a newline and the prompt string */
258
        os_printz("\n");
259
        os_printz(prompt);
260
261
        /* display the response */
262
        for (i = 0 ; i < button_count ; ++i)
263
        {
264
            /* 
265
             *   display a slash to separate responses, if this isn't the
266
             *   first one 
267
             */
268
            if (i != 0)
269
                os_printz("/");
270
271
            /* get the current button */
272
            cur = buttons[i];
273
274
            /* 
275
             *   Look for a "&" in the response string.  If we find it,
276
             *   remove the "&" and enclose the shortcut key in parens.  
277
             */
278
            for (p = cur ; *p != '&' && *p != '\0' ; ++p) ;
279
280
            /* if we found the "&", put the next character in parens */
281
            if (*p == '&')
282
            {
283
                size_t pre_len;
284
                size_t post_len;
285
286
                /* limit the prefix length to avoid overflowing the buffer */
287
                pre_len = p - cur;
288
                if (pre_len > sizeof(buf) - 5)
289
                    pre_len = sizeof(buf) - 5;
290
291
                /* limit the postfix length to avoid buffer overflow, too */
292
                post_len = strlen(p + 2);
293
                if (post_len > sizeof(buf) - 5 - pre_len)
294
                    post_len = sizeof(buf) - 5 - pre_len;
295
296
                /* reformat the response string */
297
                sprintf(buf, "%.*s(%c)%.*s",
298
                        (int)pre_len, cur, *(p + 1), (int)post_len, p + 2);
299
300
                /* show it */
301
                os_printz(buf);
302
            }
303
            else
304
            {
305
                /* no '&' - just display the response string as-is */
306
                os_printz(cur);
307
            }
308
        }
309
310
        /* read the response */
311
        os_printz(" > ");
312
        os_gets((unsigned char *)buf, sizeof(buf));
313
314
        /* skip any leading spaces in the reply */
315
        for (resp = buf ; isspace(*resp) ; ++resp) ;
316
317
        /* if it's one character, check it against the shortcut keys */
318
        if (strlen(resp) == 1)
319
        {
320
            /* scan the responses */
321
            for (i = 0 ; i < button_count ; ++i)
322
            {
323
                /* look for a '&' in this button */
324
                for (p = buttons[i] ; *p != '&' && *p != '\0' ; ++p) ;
325
326
                /* if we found the '&', check the shortcut */
327
                if (*p == '&' && toupper(*(p+1)) == toupper(*resp))
328
                {
329
                    /* 
330
                     *   this is the one - return the current index
331
                     *   (bumping it by one to get a 1-based value) 
332
                     */
333
                    return i + 1;
334
                }
335
            }
336
        }
337
338
        /* 
339
         *   Either it's not a one-character reply, or it didn't match a
340
         *   short-cut - check it against the leading substrings of the
341
         *   responses.  If it matches exactly one of the responses in its
342
         *   leading substring, use that response.  
343
         */
344
        for (i = 0, match_cnt = 0 ; i < button_count ; ++i)
345
        {
346
            const char *p1;
347
            const char *p2;
348
349
            /* 
350
             *   compare this response to the user's response; skip any
351
             *   '&' in the button label 
352
             */
353
            for (p1 = resp, p2 = buttons[i] ; *p1 != '\0' && *p2 != '\0' ;
354
                 ++p1, ++p2)
355
            {
356
                /* if this is a '&' in the button label, skip it */
357
                if (*p2 == '&')
358
                    ++p2;
359
360
                /* if these characters don't match, it's no match */
361
                if (toupper(*p1) != toupper(*p2))
362
                    break;
363
            }
364
365
            /* 
366
             *   if we reached the end of the user's response, we have a
367
             *   match in the leading substring - count it and remember
368
             *   this as the last one, but keep looking, since we need to
369
             *   make sure we don't have any other matches 
370
             */
371
            if (*p1 == '\0')
372
            {
373
                ++match_cnt;
374
                last_found = i;
375
            }
376
        }
377
378
        /* 
379
         *   if we found exactly one match, return it (adjusting to a
380
         *   1-based index); if we found more or less than one match, it's
381
         *   not a valid response, so start over with a new prompt 
382
         */
383
        if (match_cnt == 1)
384
            return last_found + 1;
385
    }
386
}
387
388
/*
389
 *   ask for a file 
390
 */
391
int os_askfile(const char *prompt, char *reply, int replen,
392
               int /*dialog_type*/, os_filetype_t /*file_type*/)
393
{
394
    /* show the prompt */
395
    os_printz(prompt);
396
    os_printz(" >");
397
398
    /* ask for the filename */
399
    os_gets((unsigned char *)reply, replen);
400
401
    /* 
402
     *   if they entered an empty line, return "cancel"; otherwise, return
403
     *   success 
404
     */
405
    return (reply[0] == '\0' ? OS_AFE_CANCEL : OS_AFE_SUCCESS);
406
}
407
408
/*
409
 *   get system information 
410
 */
411
int os_get_sysinfo(int code, void *param, long *result)
412
{
413
    switch(code)
414
    {
415
    case SYSINFO_HTML:
416
    case SYSINFO_JPEG:
417
    case SYSINFO_PNG:
418
    case SYSINFO_WAV:
419
    case SYSINFO_MIDI:
420
    case SYSINFO_WAV_MIDI_OVL:
421
    case SYSINFO_WAV_OVL:
422
    case SYSINFO_PREF_IMAGES:
423
    case SYSINFO_PREF_SOUNDS:
424
    case SYSINFO_PREF_MUSIC:
425
    case SYSINFO_PREF_LINKS:
426
    case SYSINFO_MPEG:
427
    case SYSINFO_MPEG1:
428
    case SYSINFO_MPEG2:
429
    case SYSINFO_MPEG3:
430
    case SYSINFO_LINKS_HTTP:
431
    case SYSINFO_LINKS_FTP:
432
    case SYSINFO_LINKS_NEWS:
433
    case SYSINFO_LINKS_MAILTO:
434
    case SYSINFO_LINKS_TELNET:
435
    case SYSINFO_PNG_TRANS:
436
    case SYSINFO_PNG_ALPHA:
437
    case SYSINFO_OGG:
438
    case SYSINFO_TEXT_HILITE:
439
    case SYSINFO_TEXT_COLORS:
440
    case SYSINFO_BANNERS:
441
        /* 
442
         *   we don't support any of these features - set the result to 0
443
         *   to indicate this 
444
         */
445
        *result = 0;
446
447
        /* return true to indicate that we recognized the code */
448
        return TRUE;
449
450
    case SYSINFO_INTERP_CLASS:
451
        /* indicate that we're a text-only interpreter */
452
        *result = SYSINFO_ICLASS_TEXT;
453
        return TRUE;
454
455
    default:
456
        /* we don't recognize other codes */
457
        return FALSE;
458
    }
459
}
460
461
/*
462
 *   set status mode
463
 */
464
void os_status(int mode)
465
{
466
    /* remember the new mode */
467
    S_status_mode = mode;
468
}
469
470
/*
471
 *   display a string in the right half of the status line 
472
 */
473
void os_strsc(const char *)
474
{
475
    /* ignore it - we don't have a status line in this UI */
476
}
477
478
void os_plain()
479
{
480
    /* 
481
     *   this implementation is always in plain mode, so there's nothing
482
     *   we need to do here 
483
     */
484
}
485
486
void os_expause()
487
{
488
    /* do nothing */
489
}
490
491
/* ------------------------------------------------------------------------ */
492
/*
493
 *   none of the banner functions are useful in plain stdio mode 
494
 */
495
void *os_banner_create(void *parent, int where, void *other, int wintype,
496
                       int align, int siz, int siz_units, unsigned long style)
497
{
498
    return 0;
499
}
500
501
void os_banner_delete(void *banner_handle)
502
{
503
}
504
505
void os_banner_orphan(void *banner_handle)
506
{
507
}
508
509
void os_banner_disp(void *banner_handle, const char *txt, size_t len)
510
{
511
}
512
513
void os_banner_flush(void *banner_handle)
514
{
515
}
516
517
void os_banner_set_size(void *banner_handle, int siz, int siz_units,
518
                        int is_advisory)
519
{
520
}
521
522
void os_banner_size_to_contents(void *banner_handle)
523
{
524
}
525
526
void os_banner_start_html(void *banner_handle)
527
{
528
}
529
530
void os_banner_end_html(void *banner_handle)
531
{
532
}
533
534
void os_banner_set_attr(void *banner_handle, int attr)
535
{
536
}
537
538
void os_banner_set_color(void *banner_handle, os_color_t fg, os_color_t bg)
539
{
540
}
541
542
void os_banner_set_screen_color(void *banner_handle, os_color_t color)
543
{
544
}
545
546
void os_banner_clear(void *banner_handle)
547
{
548
}
549
550
int os_banner_get_charwidth(void *banner_handle)
551
{
552
    return 0;
553
}
554
555
int os_banner_get_charheight(void *banner_handle)
556
{
557
    return 0;
558
}
559
560
int os_banner_getinfo(void *banner_handle, os_banner_info_t *info)
561
{
562
    return FALSE;
563
}
564
565
void os_banner_goto(void *banner_handle, int row, int col)
566
{
567
}
568