1 |
|
|
/* $OpenBSD: msg.c,v 1.27 2016/12/18 18:28:39 krw Exp $ */ |
2 |
|
|
|
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 1991, 1993, 1994 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* Copyright (c) 1991, 1993, 1994, 1995, 1996 |
7 |
|
|
* Keith Bostic. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* See the LICENSE file for redistribution information. |
10 |
|
|
*/ |
11 |
|
|
|
12 |
|
|
#include "config.h" |
13 |
|
|
|
14 |
|
|
#include <sys/queue.h> |
15 |
|
|
#include <sys/stat.h> |
16 |
|
|
#include <sys/time.h> |
17 |
|
|
|
18 |
|
|
#include <bitstring.h> |
19 |
|
|
#include <ctype.h> |
20 |
|
|
#include <errno.h> |
21 |
|
|
#include <fcntl.h> |
22 |
|
|
#include <limits.h> |
23 |
|
|
#include <stdarg.h> |
24 |
|
|
#include <stdio.h> |
25 |
|
|
#include <stdlib.h> |
26 |
|
|
#include <string.h> |
27 |
|
|
#include <unistd.h> |
28 |
|
|
|
29 |
|
|
#include "common.h" |
30 |
|
|
#include "../vi/vi.h" |
31 |
|
|
|
32 |
|
|
/* |
33 |
|
|
* msgq -- |
34 |
|
|
* Display a message. |
35 |
|
|
* |
36 |
|
|
* PUBLIC: void msgq(SCR *, mtype_t, const char *, ...); |
37 |
|
|
*/ |
38 |
|
|
void |
39 |
|
|
msgq(SCR *sp, mtype_t mt, const char *fmt, ...) |
40 |
|
|
{ |
41 |
|
|
static int reenter; /* STATIC: Re-entrancy check. */ |
42 |
|
|
GS *gp; |
43 |
|
|
size_t blen, len, mlen, nlen; |
44 |
|
|
const char *p; |
45 |
|
|
char *bp, *mp; |
46 |
|
|
va_list ap; |
47 |
|
|
|
48 |
|
|
/* |
49 |
|
|
* !!! |
50 |
|
|
* It's possible to enter msg when there's no screen to hold the |
51 |
|
|
* message. If sp is NULL, ignore the special cases and put the |
52 |
|
|
* message out to stderr. |
53 |
|
|
*/ |
54 |
|
|
if (sp == NULL) { |
55 |
|
|
gp = NULL; |
56 |
|
|
if (mt == M_BERR) |
57 |
|
|
mt = M_ERR; |
58 |
|
|
else if (mt == M_VINFO) |
59 |
|
|
mt = M_INFO; |
60 |
|
|
} else { |
61 |
|
|
gp = sp->gp; |
62 |
|
|
switch (mt) { |
63 |
|
|
case M_BERR: |
64 |
|
|
if (F_ISSET(sp, SC_VI) && !O_ISSET(sp, O_VERBOSE)) { |
65 |
|
|
F_SET(gp, G_BELLSCHED); |
66 |
|
|
return; |
67 |
|
|
} |
68 |
|
|
mt = M_ERR; |
69 |
|
|
break; |
70 |
|
|
case M_VINFO: |
71 |
|
|
if (!O_ISSET(sp, O_VERBOSE)) |
72 |
|
|
return; |
73 |
|
|
mt = M_INFO; |
74 |
|
|
/* FALLTHROUGH */ |
75 |
|
|
case M_INFO: |
76 |
|
|
if (F_ISSET(sp, SC_EX_SILENT)) |
77 |
|
|
return; |
78 |
|
|
break; |
79 |
|
|
case M_ERR: |
80 |
|
|
case M_SYSERR: |
81 |
|
|
break; |
82 |
|
|
default: |
83 |
|
|
abort(); |
84 |
|
|
} |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
/* |
88 |
|
|
* It's possible to reenter msg when it allocates space. We're |
89 |
|
|
* probably dead anyway, but there's no reason to drop core. |
90 |
|
|
* |
91 |
|
|
* XXX |
92 |
|
|
* Yes, there's a race, but it should only be two instructions. |
93 |
|
|
*/ |
94 |
|
|
if (reenter++) |
95 |
|
|
return; |
96 |
|
|
|
97 |
|
|
/* Get space for the message. */ |
98 |
|
|
nlen = 1024; |
99 |
|
|
if (0) { |
100 |
|
|
retry: FREE_SPACE(sp, bp, blen); |
101 |
|
|
nlen *= 2; |
102 |
|
|
} |
103 |
|
|
bp = NULL; |
104 |
|
|
blen = 0; |
105 |
|
|
GET_SPACE_GOTO(sp, bp, blen, nlen); |
106 |
|
|
|
107 |
|
|
/* |
108 |
|
|
* Error prefix. |
109 |
|
|
* |
110 |
|
|
* mp: pointer to the current next character to be written |
111 |
|
|
* mlen: length of the already written characters |
112 |
|
|
* blen: total length of the buffer |
113 |
|
|
*/ |
114 |
|
|
#define REM (blen - mlen) |
115 |
|
|
mp = bp; |
116 |
|
|
mlen = 0; |
117 |
|
|
if (mt == M_SYSERR) { |
118 |
|
|
p = "Error: "; |
119 |
|
|
len = strlen(p); |
120 |
|
|
if (REM < len) |
121 |
|
|
goto retry; |
122 |
|
|
memcpy(mp, p, len); |
123 |
|
|
mp += len; |
124 |
|
|
mlen += len; |
125 |
|
|
} |
126 |
|
|
|
127 |
|
|
/* |
128 |
|
|
* If we're running an ex command that the user didn't enter, display |
129 |
|
|
* the file name and line number prefix. |
130 |
|
|
*/ |
131 |
|
|
if ((mt == M_ERR || mt == M_SYSERR) && |
132 |
|
|
sp != NULL && gp != NULL && gp->if_name != NULL) { |
133 |
|
|
for (p = gp->if_name; *p != '\0'; ++p) { |
134 |
|
|
len = snprintf(mp, REM, "%s", KEY_NAME(sp, *p)); |
135 |
|
|
mp += len; |
136 |
|
|
if ((mlen += len) > blen) |
137 |
|
|
goto retry; |
138 |
|
|
} |
139 |
|
|
len = snprintf(mp, REM, ", %d: ", gp->if_lno); |
140 |
|
|
mp += len; |
141 |
|
|
if ((mlen += len) > blen) |
142 |
|
|
goto retry; |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
/* If nothing to format, we're done. */ |
146 |
|
|
if (fmt == NULL) { |
147 |
|
|
len = 0; |
148 |
|
|
goto nofmt; |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
/* Format the arguments into the string. */ |
152 |
|
|
va_start(ap, fmt); |
153 |
|
|
len = vsnprintf(mp, REM, fmt, ap); |
154 |
|
|
va_end(ap); |
155 |
|
|
if (len >= nlen) |
156 |
|
|
goto retry; |
157 |
|
|
|
158 |
|
|
nofmt: mp += len; |
159 |
|
|
if ((mlen += len) > blen) |
160 |
|
|
goto retry; |
161 |
|
|
if (mt == M_SYSERR) { |
162 |
|
|
len = snprintf(mp, REM, ": %s", strerror(errno)); |
163 |
|
|
mp += len; |
164 |
|
|
if ((mlen += len) > blen) |
165 |
|
|
goto retry; |
166 |
|
|
mt = M_ERR; |
167 |
|
|
} |
168 |
|
|
|
169 |
|
|
/* Add trailing newline. */ |
170 |
|
|
if ((mlen += 1) > blen) |
171 |
|
|
goto retry; |
172 |
|
|
*mp = '\n'; |
173 |
|
|
|
174 |
|
|
if (sp != NULL) |
175 |
|
|
(void)ex_fflush(sp); |
176 |
|
|
if (gp != NULL) |
177 |
|
|
gp->scr_msg(sp, mt, bp, mlen); |
178 |
|
|
else |
179 |
|
|
(void)fprintf(stderr, "%.*s", (int)mlen, bp); |
180 |
|
|
|
181 |
|
|
/* Cleanup. */ |
182 |
|
|
FREE_SPACE(sp, bp, blen); |
183 |
|
|
alloc_err: |
184 |
|
|
reenter = 0; |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
/* |
188 |
|
|
* msgq_str -- |
189 |
|
|
* Display a message with an embedded string. |
190 |
|
|
* |
191 |
|
|
* PUBLIC: void msgq_str(SCR *, mtype_t, char *, char *); |
192 |
|
|
*/ |
193 |
|
|
void |
194 |
|
|
msgq_str(SCR *sp, mtype_t mtype, char *str, char *fmt) |
195 |
|
|
{ |
196 |
|
|
int nf, sv_errno; |
197 |
|
|
char *p; |
198 |
|
|
|
199 |
|
|
if (str == NULL) { |
200 |
|
|
msgq(sp, mtype, fmt); |
201 |
|
|
return; |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
sv_errno = errno; |
205 |
|
|
p = msg_print(sp, str, &nf); |
206 |
|
|
errno = sv_errno; |
207 |
|
|
msgq(sp, mtype, fmt, p); |
208 |
|
|
if (nf) |
209 |
|
|
FREE_SPACE(sp, p, 0); |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
/* |
213 |
|
|
* mod_rpt -- |
214 |
|
|
* Report on the lines that changed. |
215 |
|
|
* |
216 |
|
|
* !!! |
217 |
|
|
* Historic vi documentation (USD:15-8) claimed that "The editor will also |
218 |
|
|
* always tell you when a change you make affects text which you cannot see." |
219 |
|
|
* This wasn't true -- edit a large file and do "100d|1". We don't implement |
220 |
|
|
* this semantic since it requires tracking each line that changes during a |
221 |
|
|
* command instead of just keeping count. |
222 |
|
|
* |
223 |
|
|
* Line counts weren't right in historic vi, either. For example, given the |
224 |
|
|
* file: |
225 |
|
|
* abc |
226 |
|
|
* def |
227 |
|
|
* the command 2d}, from the 'b' would report that two lines were deleted, |
228 |
|
|
* not one. |
229 |
|
|
* |
230 |
|
|
* PUBLIC: void mod_rpt(SCR *); |
231 |
|
|
*/ |
232 |
|
|
void |
233 |
|
|
mod_rpt(SCR *sp) |
234 |
|
|
{ |
235 |
|
|
static char * const action[] = { |
236 |
|
|
"added", |
237 |
|
|
"changed", |
238 |
|
|
"deleted", |
239 |
|
|
"joined", |
240 |
|
|
"moved", |
241 |
|
|
"shifted", |
242 |
|
|
"yanked", |
243 |
|
|
}; |
244 |
|
|
static char * const lines[] = { |
245 |
|
|
"line", |
246 |
|
|
"lines", |
247 |
|
|
}; |
248 |
|
|
recno_t total; |
249 |
|
|
u_long rptval; |
250 |
|
|
int first, cnt; |
251 |
|
|
size_t blen, len, tlen; |
252 |
|
|
const char *t; |
253 |
|
|
char * const *ap; |
254 |
|
|
char *bp, *p; |
255 |
|
|
|
256 |
|
|
/* Change reports are turned off in batch mode. */ |
257 |
|
|
if (F_ISSET(sp, SC_EX_SILENT)) |
258 |
|
|
return; |
259 |
|
|
|
260 |
|
|
/* Reset changing line number. */ |
261 |
|
|
sp->rptlchange = OOBLNO; |
262 |
|
|
|
263 |
|
|
/* |
264 |
|
|
* Don't build a message if not enough changed. |
265 |
|
|
* |
266 |
|
|
* !!! |
267 |
|
|
* And now, a vi clone test. Historically, vi reported if the number |
268 |
|
|
* of changed lines was > than the value, not >=, unless it was a yank |
269 |
|
|
* command, which used >=. No lie. Furthermore, an action was never |
270 |
|
|
* reported for a single line action. This is consistent for actions |
271 |
|
|
* other than yank, but yank didn't report single line actions even if |
272 |
|
|
* the report edit option was set to 1. In addition, setting report to |
273 |
|
|
* 0 in the 4BSD historic vi was equivalent to setting it to 1, for an |
274 |
|
|
* unknown reason (this bug was fixed in System III/V at some point). |
275 |
|
|
* I got complaints, so nvi conforms to System III/V historic practice |
276 |
|
|
* except that we report a yank of 1 line if report is set to 1. |
277 |
|
|
*/ |
278 |
|
|
#define ARSIZE(a) sizeof(a) / sizeof (*a) |
279 |
|
|
#define MAXNUM 25 |
280 |
|
|
rptval = O_VAL(sp, O_REPORT); |
281 |
|
|
for (cnt = 0, total = 0; cnt < ARSIZE(action); ++cnt) |
282 |
|
|
total += sp->rptlines[cnt]; |
283 |
|
|
if (total == 0) |
284 |
|
|
return; |
285 |
|
|
if (total <= rptval && sp->rptlines[L_YANKED] < rptval) { |
286 |
|
|
for (cnt = 0; cnt < ARSIZE(action); ++cnt) |
287 |
|
|
sp->rptlines[cnt] = 0; |
288 |
|
|
return; |
289 |
|
|
} |
290 |
|
|
|
291 |
|
|
/* Build and display the message. */ |
292 |
|
|
GET_SPACE_GOTO(sp, bp, blen, sizeof(action) * MAXNUM + 1); |
293 |
|
|
for (p = bp, first = 1, tlen = 0, |
294 |
|
|
ap = action, cnt = 0; cnt < ARSIZE(action); ++ap, ++cnt) |
295 |
|
|
if (sp->rptlines[cnt] != 0) { |
296 |
|
|
if (first) |
297 |
|
|
first = 0; |
298 |
|
|
else { |
299 |
|
|
*p++ = ';'; |
300 |
|
|
*p++ = ' '; |
301 |
|
|
tlen += 2; |
302 |
|
|
} |
303 |
|
|
len = snprintf(p, MAXNUM, "%u ", sp->rptlines[cnt]); |
304 |
|
|
p += len; |
305 |
|
|
tlen += len; |
306 |
|
|
t = lines[sp->rptlines[cnt] == 1 ? 0 : 1]; |
307 |
|
|
len = strlen(t); |
308 |
|
|
memcpy(p, t, len); |
309 |
|
|
p += len; |
310 |
|
|
tlen += len; |
311 |
|
|
*p++ = ' '; |
312 |
|
|
++tlen; |
313 |
|
|
len = strlen(*ap); |
314 |
|
|
memcpy(p, *ap, len); |
315 |
|
|
p += len; |
316 |
|
|
tlen += len; |
317 |
|
|
sp->rptlines[cnt] = 0; |
318 |
|
|
} |
319 |
|
|
|
320 |
|
|
/* Add trailing newline. */ |
321 |
|
|
*p = '\n'; |
322 |
|
|
++tlen; |
323 |
|
|
|
324 |
|
|
(void)ex_fflush(sp); |
325 |
|
|
sp->gp->scr_msg(sp, M_INFO, bp, tlen); |
326 |
|
|
|
327 |
|
|
FREE_SPACE(sp, bp, blen); |
328 |
|
|
alloc_err: |
329 |
|
|
return; |
330 |
|
|
|
331 |
|
|
#undef ARSIZE |
332 |
|
|
#undef MAXNUM |
333 |
|
|
} |
334 |
|
|
|
335 |
|
|
/* |
336 |
|
|
* msgq_status -- |
337 |
|
|
* Report on the file's status. |
338 |
|
|
* |
339 |
|
|
* PUBLIC: void msgq_status(SCR *, recno_t, u_int); |
340 |
|
|
*/ |
341 |
|
|
void |
342 |
|
|
msgq_status(SCR *sp, recno_t lno, u_int flags) |
343 |
|
|
{ |
344 |
|
|
recno_t last; |
345 |
|
|
size_t blen, len; |
346 |
|
|
int cnt, needsep; |
347 |
|
|
const char *t; |
348 |
|
|
char **ap, *bp, *np, *p, *s, *ep; |
349 |
|
|
|
350 |
|
|
/* Get sufficient memory. */ |
351 |
|
|
len = strlen(sp->frp->name); |
352 |
|
|
GET_SPACE_GOTO(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128); |
353 |
|
|
p = bp; |
354 |
|
|
ep = bp + blen; |
355 |
|
|
|
356 |
|
|
/* Copy in the filename. */ |
357 |
|
|
for (t = sp->frp->name; *t != '\0'; ++t) { |
358 |
|
|
len = KEY_LEN(sp, *t); |
359 |
|
|
memcpy(p, KEY_NAME(sp, *t), len); |
360 |
|
|
p += len; |
361 |
|
|
} |
362 |
|
|
np = p; |
363 |
|
|
*p++ = ':'; |
364 |
|
|
*p++ = ' '; |
365 |
|
|
|
366 |
|
|
/* Copy in the argument count. */ |
367 |
|
|
if (F_ISSET(sp, SC_STATUS_CNT) && sp->argv != NULL) { |
368 |
|
|
for (cnt = 0, ap = sp->argv; *ap != NULL; ++ap, ++cnt); |
369 |
|
|
if (cnt > 1) { |
370 |
|
|
(void)snprintf(p, ep - p, "%d files to edit", cnt); |
371 |
|
|
p += strlen(p); |
372 |
|
|
*p++ = ':'; |
373 |
|
|
*p++ = ' '; |
374 |
|
|
} |
375 |
|
|
F_CLR(sp, SC_STATUS_CNT); |
376 |
|
|
} |
377 |
|
|
|
378 |
|
|
/* |
379 |
|
|
* See nvi/exf.c:file_init() for a description of how and when the |
380 |
|
|
* read-only bit is set. |
381 |
|
|
* |
382 |
|
|
* !!! |
383 |
|
|
* The historic display for "name changed" was "[Not edited]". |
384 |
|
|
*/ |
385 |
|
|
needsep = 0; |
386 |
|
|
if (F_ISSET(sp->frp, FR_NEWFILE)) { |
387 |
|
|
F_CLR(sp->frp, FR_NEWFILE); |
388 |
|
|
len = strlen("new file"); |
389 |
|
|
memcpy(p, "new file", len); |
390 |
|
|
p += len; |
391 |
|
|
needsep = 1; |
392 |
|
|
} else { |
393 |
|
|
if (F_ISSET(sp->frp, FR_NAMECHANGE)) { |
394 |
|
|
len = strlen("name changed"); |
395 |
|
|
memcpy(p, "name changed", len); |
396 |
|
|
p += len; |
397 |
|
|
needsep = 1; |
398 |
|
|
} |
399 |
|
|
if (needsep) { |
400 |
|
|
*p++ = ','; |
401 |
|
|
*p++ = ' '; |
402 |
|
|
} |
403 |
|
|
t = (F_ISSET(sp->ep, F_MODIFIED)) ? "modified" : "unmodified"; |
404 |
|
|
len = strlen(t); |
405 |
|
|
memcpy(p, t, len); |
406 |
|
|
p += len; |
407 |
|
|
needsep = 1; |
408 |
|
|
} |
409 |
|
|
if (F_ISSET(sp->frp, FR_UNLOCKED)) { |
410 |
|
|
if (needsep) { |
411 |
|
|
*p++ = ','; |
412 |
|
|
*p++ = ' '; |
413 |
|
|
} |
414 |
|
|
len = strlen("UNLOCKED"); |
415 |
|
|
memcpy(p, "UNLOCKED", len); |
416 |
|
|
p += len; |
417 |
|
|
needsep = 1; |
418 |
|
|
} |
419 |
|
|
if (O_ISSET(sp, O_READONLY)) { |
420 |
|
|
if (needsep) { |
421 |
|
|
*p++ = ','; |
422 |
|
|
*p++ = ' '; |
423 |
|
|
} |
424 |
|
|
len = strlen("readonly"); |
425 |
|
|
memcpy(p, "readonly", len); |
426 |
|
|
p += len; |
427 |
|
|
needsep = 1; |
428 |
|
|
} |
429 |
|
|
if (needsep) { |
430 |
|
|
*p++ = ':'; |
431 |
|
|
*p++ = ' '; |
432 |
|
|
} |
433 |
|
|
if (LF_ISSET(MSTAT_SHOWLAST)) { |
434 |
|
|
if (db_last(sp, &last)) |
435 |
|
|
return; |
436 |
|
|
if (last == 0) { |
437 |
|
|
len = strlen("emptry file"); |
438 |
|
|
memcpy(p, "empty file", len); |
439 |
|
|
p += len; |
440 |
|
|
} else { |
441 |
|
|
(void)snprintf(p, ep - p, "line %lu of %lu [%lu%%]", |
442 |
|
|
(unsigned long)lno, (unsigned long)last, |
443 |
|
|
(unsigned long)(lno * 100) / last); |
444 |
|
|
p += strlen(p); |
445 |
|
|
} |
446 |
|
|
} else { |
447 |
|
|
(void)snprintf(p, ep - p, "line %lu", (unsigned long)lno); |
448 |
|
|
p += strlen(p); |
449 |
|
|
} |
450 |
|
|
#ifdef DEBUG |
451 |
|
|
(void)snprintf(p, ep - p, " (pid %ld)", (long)getpid()); |
452 |
|
|
p += strlen(p); |
453 |
|
|
#endif |
454 |
|
|
*p++ = '\n'; |
455 |
|
|
len = p - bp; |
456 |
|
|
|
457 |
|
|
/* |
458 |
|
|
* There's a nasty problem with long path names. Tags files |
459 |
|
|
* can result in long paths and vi will request a continuation key from |
460 |
|
|
* the user as soon as it starts the screen. Unfortunately, the user |
461 |
|
|
* has already typed ahead, and chaos results. If we assume that the |
462 |
|
|
* characters in the filenames and informational messages only take a |
463 |
|
|
* single screen column each, we can trim the filename. |
464 |
|
|
* |
465 |
|
|
* XXX |
466 |
|
|
* Status lines get put up at fairly awkward times. For example, when |
467 |
|
|
* you do a filter read (e.g., :read ! echo foo) in the top screen of a |
468 |
|
|
* split screen, we have to repaint the status lines for all the screens |
469 |
|
|
* below the top screen. We don't want users having to enter continue |
470 |
|
|
* characters for those screens. Make it really hard to screw this up. |
471 |
|
|
*/ |
472 |
|
|
s = bp; |
473 |
|
|
if (LF_ISSET(MSTAT_TRUNCATE) && len > sp->cols) { |
474 |
|
|
for (; s < np && (*s != '/' || (p - s) > sp->cols - 3); ++s); |
475 |
|
|
if (s == np) { |
476 |
|
|
s = p - (sp->cols - 5); |
477 |
|
|
*--s = ' '; |
478 |
|
|
} |
479 |
|
|
*--s = '.'; |
480 |
|
|
*--s = '.'; |
481 |
|
|
*--s = '.'; |
482 |
|
|
len = p - s; |
483 |
|
|
} |
484 |
|
|
|
485 |
|
|
/* Flush any waiting ex messages. */ |
486 |
|
|
(void)ex_fflush(sp); |
487 |
|
|
|
488 |
|
|
sp->gp->scr_msg(sp, M_INFO, s, len); |
489 |
|
|
|
490 |
|
|
FREE_SPACE(sp, bp, blen); |
491 |
|
|
alloc_err: |
492 |
|
|
return; |
493 |
|
|
} |
494 |
|
|
|
495 |
|
|
/* |
496 |
|
|
* msg_cont -- |
497 |
|
|
* Return common continuation messages. |
498 |
|
|
* |
499 |
|
|
* PUBLIC: const char *msg_cmsg(SCR *, cmsg_t, size_t *); |
500 |
|
|
*/ |
501 |
|
|
const char * |
502 |
|
|
msg_cmsg(SCR *sp, cmsg_t which, size_t *lenp) |
503 |
|
|
{ |
504 |
|
|
const char *s; |
505 |
|
|
switch (which) { |
506 |
|
|
case CMSG_CONF: |
507 |
|
|
s = "confirm? [ynq]"; |
508 |
|
|
break; |
509 |
|
|
case CMSG_CONT: |
510 |
|
|
s = "Press any key to continue: "; |
511 |
|
|
break; |
512 |
|
|
case CMSG_CONT_EX: |
513 |
|
|
s = "Press any key to continue [: to enter more ex commands]: "; |
514 |
|
|
break; |
515 |
|
|
case CMSG_CONT_R: |
516 |
|
|
s = "Press Enter to continue: "; |
517 |
|
|
break; |
518 |
|
|
case CMSG_CONT_S: |
519 |
|
|
s = " cont?"; |
520 |
|
|
break; |
521 |
|
|
case CMSG_CONT_Q: |
522 |
|
|
s = "Press any key to continue [q to quit]: "; |
523 |
|
|
break; |
524 |
|
|
default: |
525 |
|
|
abort(); |
526 |
|
|
} |
527 |
|
|
*lenp = strlen(s); |
528 |
|
|
return s; |
529 |
|
|
} |
530 |
|
|
|
531 |
|
|
/* |
532 |
|
|
* msg_print -- |
533 |
|
|
* Return a printable version of a string, in allocated memory. |
534 |
|
|
* |
535 |
|
|
* PUBLIC: char *msg_print(SCR *, const char *, int *); |
536 |
|
|
*/ |
537 |
|
|
char * |
538 |
|
|
msg_print(SCR *sp, const char *s, int *needfree) |
539 |
|
|
{ |
540 |
|
|
size_t blen, nlen; |
541 |
|
|
const char *cp; |
542 |
|
|
char *bp, *ep, *p, *t; |
543 |
|
|
|
544 |
|
|
*needfree = 0; |
545 |
|
|
|
546 |
|
|
for (cp = s; *cp != '\0'; ++cp) |
547 |
|
|
if (!isprint(*cp)) |
548 |
|
|
break; |
549 |
|
|
if (*cp == '\0') |
550 |
|
|
return ((char *)s); /* SAFE: needfree set to 0. */ |
551 |
|
|
|
552 |
|
|
nlen = 0; |
553 |
|
|
if (0) { |
554 |
|
|
retry: if (sp == NULL) |
555 |
|
|
free(bp); |
556 |
|
|
else |
557 |
|
|
FREE_SPACE(sp, bp, blen); |
558 |
|
|
*needfree = 0; |
559 |
|
|
} |
560 |
|
|
nlen += 256; |
561 |
|
|
if (sp == NULL) { |
562 |
|
|
if ((bp = malloc(nlen)) == NULL) |
563 |
|
|
goto alloc_err; |
564 |
|
|
blen = 0; |
565 |
|
|
} else |
566 |
|
|
GET_SPACE_GOTO(sp, bp, blen, nlen); |
567 |
|
|
if (0) { |
568 |
|
|
alloc_err: return (""); |
569 |
|
|
} |
570 |
|
|
*needfree = 1; |
571 |
|
|
|
572 |
|
|
for (p = bp, ep = (bp + blen) - 1, cp = s; *cp != '\0' && p < ep; ++cp) |
573 |
|
|
for (t = KEY_NAME(sp, *cp); *t != '\0' && p < ep; *p++ = *t++); |
574 |
|
|
if (p == ep) |
575 |
|
|
goto retry; |
576 |
|
|
*p = '\0'; |
577 |
|
|
return (bp); |
578 |
|
|
} |