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

« back to all changes in this revision

Viewing changes to tads/tads3/os_stdio.cpp

  • 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
/* $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