Bug Summary

File:src/usr.bin/vi/build/../common/msg.c
Warning:line 359, column 3
Null pointer passed as 1st argument to memory copy function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name msg.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/vi/build/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/vi/build -I /usr/src/usr.bin/vi/build/../include -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/vi/build/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/vi/build/../common/msg.c
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(*__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 */
38void
39msgq(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((void *)0)) {
55 gp = NULL((void *)0);
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)(((sp)->flags) & ((0x00000002))) && !O_ISSET(sp, O_VERBOSE)((((&(((sp)))->opts[(((O_VERBOSE)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_VERBOSE
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_VERBOSE)))
].o_cur.val)
) {
65 F_SET(gp, G_BELLSCHED)(((gp)->flags) |= ((0x0002)));
66 return;
67 }
68 mt = M_ERR;
69 break;
70 case M_VINFO:
71 if (!O_ISSET(sp, O_VERBOSE)((((&(((sp)))->opts[(((O_VERBOSE)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_VERBOSE
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_VERBOSE)))
].o_cur.val)
)
72 return;
73 mt = M_INFO;
74 /* FALLTHROUGH */
75 case M_INFO:
76 if (F_ISSET(sp, SC_EX_SILENT)(((sp)->flags) & ((0x00040000))))
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) {
100retry: FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
101 nlen *= 2;
102 }
103 bp = NULL((void *)0);
104 blen = 0;
105 GET_SPACE_GOTO(sp, bp, blen, nlen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((nlen)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp))
, &((blen)), ((nlen)))) == ((void *)0)) goto alloc_err; (
(bp)) = L__bincp; } }; } else { { void *L__bincp; if (((nlen)
) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (
L__gp->tmp_bp), &(L__gp->tmp_blen), ((nlen)))) == (
(void *)0)) goto alloc_err; (L__gp->tmp_bp) = L__bincp; } }
; (bp) = L__gp->tmp_bp; (blen) = L__gp->tmp_blen; (((L__gp
)->flags) |= ((0x0100))); } }
;
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) (blen - mlen)
115 mp = bp;
116 mlen = 0;
117 if (mt == M_SYSERR) {
118 p = "Error: ";
119 len = strlen(p);
120 if (REM(blen - mlen) < 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((void *)0) && gp != NULL((void *)0) && gp->if_name != NULL((void *)0)) {
133 for (p = gp->if_name; *p != '\0'; ++p) {
134 len = snprintf(mp, REM(blen - mlen), "%s", KEY_NAME(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->cname[(unsigned
char)(*p)].name : v_key_name((sp), (*p)))
);
135 mp += len;
136 if ((mlen += len) > blen)
137 goto retry;
138 }
139 len = snprintf(mp, REM(blen - mlen), ", %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((void *)0)) {
147 len = 0;
148 goto nofmt;
149 }
150
151 /* Format the arguments into the string. */
152 va_start(ap, fmt)__builtin_va_start(ap, fmt);
153 len = vsnprintf(mp, REM(blen - mlen), fmt, ap);
154 va_end(ap)__builtin_va_end(ap);
155 if (len >= nlen)
156 goto retry;
157
158nofmt: mp += len;
159 if ((mlen += len) > blen)
160 goto retry;
161 if (mt == M_SYSERR) {
162 len = snprintf(mp, REM(blen - mlen), ": %s", strerror(errno(*__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((void *)0))
175 (void)ex_fflush(sp);
176 if (gp != NULL((void *)0))
177 gp->scr_msg(sp, mt, bp, mlen);
178 else
179 (void)fprintf(stderr(&__sF[2]), "%.*s", (int)mlen, bp);
180
181 /* Cleanup. */
182 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
183alloc_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 */
193void
194msgq_str(SCR *sp, mtype_t mtype, char *str, char *fmt)
195{
196 int nf, sv_errno;
197 char *p;
198
199 if (str == NULL((void *)0)) {
200 msgq(sp, mtype, fmt);
201 return;
202 }
203
204 sv_errno = errno(*__errno());
205 p = msg_print(sp, str, &nf);
206 errno(*__errno()) = sv_errno;
207 msgq(sp, mtype, fmt, p);
208 if (nf)
209 FREE_SPACE(sp, p, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(p); }
;
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 */
232void
233mod_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)(((sp)->flags) & ((0x00040000))))
258 return;
259
260 /* Reset changing line number. */
261 sp->rptlchange = OOBLNO0;
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)((((&((sp))->opts[((O_REPORT))])->flags) & ((0x01
))) ? ((sp))->gp->opts[((sp))->opts[((O_REPORT))].o_cur
.val].o_cur.val : ((sp))->opts[((O_REPORT))].o_cur.val)
;
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_YANKED6] < 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){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((sizeof(action) * MAXNUM + 1)) > ((blen))) { if ((L__bincp
= binc(((sp)), ((bp)), &((blen)), ((sizeof(action) * MAXNUM
+ 1)))) == ((void *)0)) goto alloc_err; ((bp)) = L__bincp; }
}; } else { { void *L__bincp; if (((sizeof(action) * MAXNUM +
1)) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp))
, (L__gp->tmp_bp), &(L__gp->tmp_blen), ((sizeof(action
) * MAXNUM + 1)))) == ((void *)0)) goto alloc_err; (L__gp->
tmp_bp) = L__bincp; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp
->tmp_blen; (((L__gp)->flags) |= ((0x0100))); } }
;
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){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
328alloc_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 */
341void
342msgq_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){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((len * 4 + 128)) > ((blen))) { if ((L__bincp = binc(((sp)
), ((bp)), &((blen)), ((len * 4 + 128)))) == ((void *)0))
goto alloc_err; ((bp)) = L__bincp; } }; } else { { void *L__bincp
; if (((len * 4 + 128)) > (L__gp->tmp_blen)) { if ((L__bincp
= binc(((sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen)
, ((len * 4 + 128)))) == ((void *)0)) goto alloc_err; (L__gp->
tmp_bp) = L__bincp; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp
->tmp_blen; (((L__gp)->flags) |= ((0x0100))); } }
;
1
'?' condition is false
2
Assuming 'L__gp' is not equal to null
3
Assuming the condition is true
4
Taking true branch
5
Null pointer value stored to 'bp'
6
Assuming the condition is false
7
Taking false branch
353 p = bp;
8
Null pointer value stored to 'p'
354 ep = bp + blen;
355
356 /* Copy in the filename. */
357 for (t = sp->frp->name; *t != '\0'; ++t) {
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
358 len = KEY_LEN(sp, *t)((unsigned char)(*t) <= 254 ? (sp)->gp->cname[(unsigned
char)(*t)].len : v_key_len((sp), (*t)))
;
11
'?' condition is true
359 memcpy(p, KEY_NAME(sp, *t)((unsigned char)(*t) <= 254 ? (sp)->gp->cname[(unsigned
char)(*t)].name : v_key_name((sp), (*t)))
, len);
12
'?' condition is true
13
Null pointer passed as 1st argument to memory copy function
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)->flags) & ((0x04000000))) && sp->argv != NULL((void *)0)) {
368 for (cnt = 0, ap = sp->argv; *ap != NULL((void *)0); ++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)(((sp)->flags) &= ~((0x04000000)));
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)(((sp->frp)->flags) & ((0x0010)))) {
387 F_CLR(sp->frp, FR_NEWFILE)(((sp->frp)->flags) &= ~((0x0010)));
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)(((sp->frp)->flags) & ((0x0008)))) {
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)(((sp->ep)->flags) & ((0x004)))) ? "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)(((sp->frp)->flags) & ((0x0100)))) {
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)((((&(((sp)))->opts[(((O_READONLY)))])->flags) &
((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_READONLY
)))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_READONLY))
)].o_cur.val)
) {
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)((flags) & ((0x01)))) {
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)((flags) & ((0x02))) && 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){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
491alloc_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 */
501const char *
502msg_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 */
537char *
538msg_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) {
554retry: if (sp == NULL((void *)0))
555 free(bp);
556 else
557 FREE_SPACE(sp, bp, blen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) (((L__gp)->flags) &= ~((0x0100))); else free(bp); }
;
558 *needfree = 0;
559 }
560 nlen += 256;
561 if (sp == NULL((void *)0)) {
562 if ((bp = malloc(nlen)) == NULL((void *)0))
563 goto alloc_err;
564 blen = 0;
565 } else
566 GET_SPACE_GOTO(sp, bp, blen, nlen){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp == ((void *)0) || (((L__gp)->flags) & ((0x0100
)))) { (bp) = ((void *)0); (blen) = 0; { void *L__bincp; if (
((nlen)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp))
, &((blen)), ((nlen)))) == ((void *)0)) goto alloc_err; (
(bp)) = L__bincp; } }; } else { { void *L__bincp; if (((nlen)
) > (L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (
L__gp->tmp_bp), &(L__gp->tmp_blen), ((nlen)))) == (
(void *)0)) goto alloc_err; (L__gp->tmp_bp) = L__bincp; } }
; (bp) = L__gp->tmp_bp; (blen) = L__gp->tmp_blen; (((L__gp
)->flags) |= ((0x0100))); } }
;
567 if (0) {
568alloc_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)((unsigned char)(*cp) <= 254 ? (sp)->gp->cname[(unsigned
char)(*cp)].name : v_key_name((sp), (*cp)))
; *t != '\0' && p < ep; *p++ = *t++);
574 if (p == ep)
575 goto retry;
576 *p = '\0';
577 return (bp);
578}