-
Notifications
You must be signed in to change notification settings - Fork 17
/
indlg_tx3.cpp
266 lines (231 loc) · 8.06 KB
/
indlg_tx3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#ifdef RCSID
static char RCSid[] =
"$Header$";
#endif
/*
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
indlg_tx.cpp - formatted text implementation of input_dialog
Function
Implements the input dialog using formatted text
Notes
Only one of indlg_tx.c or indlg_os.c should be included in a given
executable. For a text-only version, include indlg_tx. For a version
where os_input_dialog() provides a system dialog, use indlg_os instead.
We provide a choice of input_dialog() implementations in the portable
code (rather than only through the OS code) so that we can call
the formatted text output routines in this version. An OS-layer
implementation could not call the formatted output routines (it would
have to call os_printf directly), which would result in poor prompt
formatting any time a prompt exceeded a single line of text.
Modified
09/27/99 MJRoberts - Creation
*/
#include "os.h"
#include "t3std.h"
#include "vmglob.h"
#include "vmconsol.h"
#include "charmap.h"
/*
* formatted text-only file prompt
*/
int CVmConsole::input_dialog(VMG_ int /*icon_id*/,
const char *prompt, int standard_button_set,
const char **buttons, int button_count,
int default_index, int cancel_index,
int bypass_script)
{
/* keep going until we get a valid response */
for (;;)
{
int i;
char buf[256];
const char *p;
const char *cur;
char *resp;
int match_cnt;
int last_found;
int err;
static const struct
{
const char *buttons[3];
int button_count;
} std_btns[] =
{
{ { "&OK" }, 1 },
{ { "&OK", "&Cancel" }, 2 },
{ { "&Yes", "&No" }, 2 },
{ { "&Yes", "&No", "&Cancel" }, 3 }
};
/*
* if we have a standard button set selected, get our button
* labels
*/
switch(standard_button_set)
{
case 0:
/* use the explicit buttons provided */
break;
case OS_INDLG_OK:
i = 0;
use_std_btns:
/* use the selected standard button set */
buttons = (const char **)std_btns[i].buttons;
button_count = std_btns[i].button_count;
break;
case OS_INDLG_OKCANCEL:
i = 1;
goto use_std_btns;
case OS_INDLG_YESNO:
i = 2;
goto use_std_btns;
case OS_INDLG_YESNOCANCEL:
i = 3;
goto use_std_btns;
default:
/*
* we don't recognize other standard button sets - return an
* error
*/
return 0;
}
/*
* if there are no buttons defined, they'll never be able to
* respond, so we'd just loop forever - rather than let that
* happen, return failure
*/
if (button_count == 0)
return 0;
/* display a newline and the prompt string */
format_text(vmg_ "\n");
format_text(vmg_ prompt);
format_text(vmg_ " ");
/* display the response */
for (i = 0 ; i < button_count ; ++i)
{
/*
* display a slash to separate responses, if this isn't the
* first one
*/
if (i != 0)
format_text(vmg_ "/");
/* get the current button */
cur = buttons[i];
/*
* Look for a "&" in the response string. If we find it,
* remove the "&" and enclose the shortcut key in parens.
*/
for (p = cur ; *p != '\0' && *p != '&' ;
p = utf8_ptr::s_inc((char *)p)) ;
/* if we found the "&", put the next character in parens */
if (*p != '\0')
{
size_t pre_len;
size_t post_len;
/*
* note the length of the part up to the '&', but limit it
* to avoid overflowing the buffer
*/
pre_len = p - cur;
if (pre_len > sizeof(buf) - 5)
pre_len = sizeof(buf) - 5;
/*
* note the length of the part after the '&', limiting it
* as well
*/
post_len = strlen(p+2);
if (post_len > sizeof(buf) - 5 - pre_len)
post_len = sizeof(buf) - 5 - pre_len;
/* reformat the response string */
sprintf(buf, "%.*s(%c)%.*s",
(int)pre_len, cur, *(p + 1), (int)post_len, p + 2);
/* display it */
format_text(vmg_ buf);
}
else
{
/* no '&' - just display the response string as-is */
format_text(vmg_ cur);
}
}
/* switch to input font */
format_text(vmg_ "<font face='TADS-Input'>");
/* read the response */
format_text(vmg_ " >");
err = read_line(vmg_ buf, sizeof(buf), bypass_script);
/* close the input font tag */
format_text(vmg_ "</font>");
/* on error, return 0 */
if (err)
return 0;
/* skip any leading spaces in the reply */
for (resp = buf ; isspace(*resp) ; ++resp) ;
/* if it's one character, check it against the shortcut keys */
if (strlen(resp) == 1)
{
/* scan the responses */
for (i = 0 ; i < button_count ; ++i)
{
/* look for a '&' in this button */
for (p = buttons[i] ; *p != '&' && *p != '\0' ; ++p) ;
/* if we found the '&', check the shortcut */
if (*p == '&' && toupper(*(p+1)) == toupper(*resp))
{
/*
* this is the one - return the current index
* (bumping it by one to get a 1-based value)
*/
return i + 1;
}
}
}
/*
* Either it's not a one-character reply, or it didn't match a
* short-cut - check it against the leading substrings of the
* responses. If it matches exactly one of the responses in its
* leading substring, use that response.
*/
for (i = 0, match_cnt = 0 ; i < button_count ; ++i)
{
const char *p1;
const char *p2;
/*
* compare this response to the user's response; skip any
* '&' in the button label
*/
for (p1 = resp, p2 = buttons[i] ; *p1 != '\0' && *p2 != '\0' ;
++p1, ++p2)
{
/* if this is a '&' in the button label, skip it */
if (*p2 == '&')
++p2;
/* if these characters don't match, it's no match */
if (toupper(*p1) != toupper(*p2))
break;
}
/*
* if we reached the end of the user's response, we have a
* match in the leading substring - count it and remember
* this as the last one, but keep looking, since we need to
* make sure we don't have any other matches
*/
if (*p1 == '\0')
{
++match_cnt;
last_found = i;
}
}
/*
* if we found exactly one match, return it (adjusting to a
* 1-based index); if we found more or less than one match, it's
* not a valid response, so start over with a new prompt
*/
if (match_cnt == 1)
return last_found + 1;
}
}