Bug Summary

File:src/usr.bin/vi/build/../ex/ex_script.c
Warning:line 197, column 2
Value stored to 'len' is never read

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 ex_script.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/../ex/ex_script.c
1/* $OpenBSD: ex_script.c,v 1.27 2017/04/18 01:45:35 deraadt Exp $ */
2
3/*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Brian Hirt.
11 *
12 * See the LICENSE file for redistribution information.
13 */
14
15#include "config.h"
16
17#include <sys/types.h>
18#include <sys/ioctl.h>
19#include <sys/queue.h>
20#include <sys/stat.h>
21#include <sys/time.h>
22#include <sys/wait.h>
23
24#include <bitstring.h>
25#include <errno(*__errno()).h>
26#include <fcntl.h>
27#include <stdio.h> /* XXX: OSF/1 bug: include before <grp.h> */
28#include <grp.h>
29#include <limits.h>
30#include <poll.h>
31#include <stdlib.h>
32#include <string.h>
33#include <termios.h>
34#include <unistd.h>
35#include <util.h>
36
37#include "../common/common.h"
38#include "../vi/vi.h"
39#include "script.h"
40#include "pathnames.h"
41
42static void sscr_check(SCR *);
43static int sscr_getprompt(SCR *);
44static int sscr_init(SCR *);
45static int sscr_insert(SCR *);
46static int sscr_matchprompt(SCR *, char *, size_t, size_t *);
47static int sscr_setprompt(SCR *, char *, size_t);
48
49/*
50 * ex_script -- : sc[ript][!] [file]
51 * Switch to script mode.
52 *
53 * PUBLIC: int ex_script(SCR *, EXCMD *);
54 */
55int
56ex_script(SCR *sp, EXCMD *cmdp)
57{
58 /* Vi only command. */
59 if (!F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) {
60 msgq(sp, M_ERR,
61 "The script command is only available in vi mode");
62 return (1);
63 }
64
65 /* Switch to the new file. */
66 if (cmdp->argc != 0 && ex_edit(sp, cmdp))
67 return (1);
68
69 /* Create the shell, figure out the prompt. */
70 if (sscr_init(sp))
71 return (1);
72
73 return (0);
74}
75
76/*
77 * sscr_init --
78 * Create a pty setup for a shell.
79 */
80static int
81sscr_init(SCR *sp)
82{
83 SCRIPT *sc;
84 char *sh, *sh_path;
85
86 /* We're going to need a shell. */
87 if (opts_empty(sp, O_SHELL, 0))
88 return (1);
89
90 MALLOC_RET(sp, sc, sizeof(SCRIPT)){ if (((sc) = malloc(sizeof(SCRIPT))) == ((void *)0)) { msgq(
(sp), M_SYSERR, ((void *)0)); return (1); } }
;
91 sp->script = sc;
92 sc->sh_prompt = NULL((void *)0);
93 sc->sh_prompt_len = 0;
94
95 /*
96 * There are two different processes running through this code.
97 * They are the shell and the parent.
98 */
99 sc->sh_master = sc->sh_slave = -1;
100
101 if (tcgetattr(STDIN_FILENO0, &sc->sh_term) == -1) {
102 msgq(sp, M_SYSERR, "tcgetattr");
103 goto err;
104 }
105
106 /*
107 * Turn off output postprocessing and echo.
108 */
109 sc->sh_term.c_oflag &= ~OPOST0x00000001;
110 sc->sh_term.c_cflag &= ~(ECHO0x00000008|ECHOE0x00000002|ECHONL0x00000010|ECHOK0x00000004);
111
112 if (ioctl(STDIN_FILENO0, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((104)))
, &sc->sh_win) == -1) {
113 msgq(sp, M_SYSERR, "tcgetattr");
114 goto err;
115 }
116
117 if (openpty(&sc->sh_master,
118 &sc->sh_slave, sc->sh_name, &sc->sh_term, &sc->sh_win) == -1) {
119 msgq(sp, M_SYSERR, "pty");
120 goto err;
121 }
122
123 /*
124 * __TK__ huh?
125 * Don't use vfork() here, because the signal semantics differ from
126 * implementation to implementation.
127 */
128 switch (sc->sh_pid = fork()) {
129 case -1: /* Error. */
130 msgq(sp, M_SYSERR, "fork");
131err: if (sc->sh_master != -1)
132 (void)close(sc->sh_master);
133 if (sc->sh_slave != -1)
134 (void)close(sc->sh_slave);
135 return (1);
136 case 0: /* Utility. */
137 /*
138 * XXX
139 * So that shells that do command line editing turn it off.
140 */
141 if (setenv("TERM", "emacs", 1) == -1 ||
142 setenv("TERMCAP", "emacs:", 1) == -1 ||
143 setenv("EMACS", "t", 1) == -1)
144 _exit(126);
145
146 (void)setsid();
147 /*
148 * 4.4BSD allocates a controlling terminal using the TIOCSCTTY
149 * ioctl, not by opening a terminal device file. POSIX 1003.1
150 * doesn't define a portable way to do this.
151 */
152 (void)ioctl(sc->sh_slave, TIOCSCTTY((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('t')) << 8) | ((97)))
, 0);
153 (void)close(sc->sh_master);
154 (void)dup2(sc->sh_slave, STDIN_FILENO0);
155 (void)dup2(sc->sh_slave, STDOUT_FILENO1);
156 (void)dup2(sc->sh_slave, STDERR_FILENO2);
157 (void)close(sc->sh_slave);
158
159 /* Assumes that all shells have -i. */
160 sh_path = O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01
))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur
.val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str)
;
161 if ((sh = strrchr(sh_path, '/')) == NULL((void *)0))
162 sh = sh_path;
163 else
164 ++sh;
165 execl(sh_path, sh, "-i", (char *)NULL((void *)0));
166 msgq_str(sp, M_SYSERR, sh_path, "execl: %s");
167 _exit(127);
168 default: /* Parent. */
169 break;
170 }
171
172 if (sscr_getprompt(sp))
173 return (1);
174
175 F_SET(sp, SC_SCRIPT)(((sp)->flags) |= ((0x01000000)));
176 F_SET(sp->gp, G_SCRWIN)(((sp->gp)->flags) |= ((0x0020)));
177 return (0);
178}
179
180/*
181 * sscr_getprompt --
182 * Eat lines printed by the shell until a line with no trailing
183 * carriage return comes; set the prompt from that line.
184 */
185static int
186sscr_getprompt(SCR *sp)
187{
188 CHAR_T *endp, *p, *t, buf[1024];
189 SCRIPT *sc;
190 struct pollfd pfd[1];
191 recno_t lline;
192 size_t llen, len;
193 u_int value;
194 int nr;
195
196 endp = buf;
197 len = sizeof(buf);
Value stored to 'len' is never read
198
199 /* Wait up to a second for characters to read. */
200 sc = sp->script;
201 pfd[0].fd = sc->sh_master;
202 pfd[0].events = POLLIN0x0001;
203 switch (poll(pfd, 1, 5 * 1000)) {
204 case -1: /* Error or interrupt. */
205 msgq(sp, M_SYSERR, "poll");
206 goto prompterr;
207 case 0: /* Timeout */
208 msgq(sp, M_ERR, "Error: timed out");
209 goto prompterr;
210 default: /* Characters to read. */
211 break;
212 }
213
214 /* Read the characters. */
215more: len = sizeof(buf) - (endp - buf);
216 switch (nr = read(sc->sh_master, endp, len)) {
217 case 0: /* EOF. */
218 msgq(sp, M_ERR, "Error: shell: EOF");
219 goto prompterr;
220 case -1: /* Error or interrupt. */
221 msgq(sp, M_SYSERR, "shell");
222 goto prompterr;
223 default:
224 endp += nr;
225 break;
226 }
227
228 /* If any complete lines, push them into the file. */
229 for (p = t = buf; p < endp; ++p) {
230 value = KEY_VAL(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->special_key[
(unsigned char)(*p)] : (unsigned char)(*p) > (sp)->gp->
max_special ? 0 : v_key_val((sp),(*p)))
;
231 if (value == K_CR || value == K_NL) {
232 if (db_last(sp, &lline) ||
233 db_append(sp, 0, lline, t, p - t))
234 goto prompterr;
235 t = p + 1;
236 }
237 }
238 if (p > buf) {
239 memmove(buf, t, endp - t);
240 endp = buf + (endp - t);
241 }
242 if (endp == buf)
243 goto more;
244
245 /* Wait up 1/10 of a second to make sure that we got it all. */
246 switch (poll(pfd, 1, 100)) {
247 case -1: /* Error or interrupt. */
248 msgq(sp, M_SYSERR, "poll");
249 goto prompterr;
250 case 0: /* Timeout */
251 break;
252 default: /* Characters to read. */
253 goto more;
254 }
255
256 /* Timed out, so theoretically we have a prompt. */
257 llen = endp - buf;
258 endp = buf;
259
260 /* Append the line into the file. */
261 if (db_last(sp, &lline) || db_append(sp, 0, lline, buf, llen)) {
262prompterr: sscr_end(sp);
263 return (1);
264 }
265
266 return (sscr_setprompt(sp, buf, llen));
267}
268
269/*
270 * sscr_exec --
271 * Take a line and hand it off to the shell.
272 *
273 * PUBLIC: int sscr_exec(SCR *, recno_t);
274 */
275int
276sscr_exec(SCR *sp, recno_t lno)
277{
278 SCRIPT *sc;
279 recno_t last_lno;
280 size_t blen, len, last_len, tlen;
281 int isempty, matchprompt, nw, rval;
282 char *bp, *p;
283
284 /* If there's a prompt on the last line, append the command. */
285 if (db_last(sp, &last_lno))
286 return (1);
287 if (db_get(sp, last_lno, DBG_FATAL0x001, &p, &last_len))
288 return (1);
289 if (sscr_matchprompt(sp, p, last_len, &tlen) && tlen == 0) {
290 matchprompt = 1;
291 GET_SPACE_RET(sp, bp, blen, last_len + 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 (
((last_len + 128)) > ((blen))) { if ((L__bincp = binc(((sp
)), ((bp)), &((blen)), ((last_len + 128)))) == ((void *)0
)) return (1); ((bp)) = L__bincp; } }; } else { { void *L__bincp
; if (((last_len + 128)) > (L__gp->tmp_blen)) { if ((L__bincp
= binc(((sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen)
, ((last_len + 128)))) == ((void *)0)) return (1); (L__gp->
tmp_bp) = L__bincp; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp
->tmp_blen; (((L__gp)->flags) |= ((0x0100))); } }
;
292 memmove(bp, p, last_len);
293 } else
294 matchprompt = 0;
295
296 /* Get something to execute. */
297 if (db_eget(sp, lno, &p, &len, &isempty)) {
298 if (isempty)
299 goto empty;
300 goto err1;
301 }
302
303 /* Empty lines aren't interesting. */
304 if (len == 0)
305 goto empty;
306
307 /* Delete any prompt. */
308 if (sscr_matchprompt(sp, p, len, &tlen)) {
309 if (tlen == len) {
310empty: msgq(sp, M_BERR, "No command to execute");
311 goto err1;
312 }
313 p += (len - tlen);
314 len = tlen;
315 }
316
317 /* Push the line to the shell. */
318 sc = sp->script;
319 if ((nw = write(sc->sh_master, p, len)) != len)
320 goto err2;
321 rval = 0;
322 if (write(sc->sh_master, "\n", 1) != 1) {
323err2: if (nw == 0)
324 errno(*__errno()) = EIO5;
325 msgq(sp, M_SYSERR, "shell");
326 goto err1;
327 }
328
329 if (matchprompt) {
330 ADD_SPACE_RET(sp, bp, blen, last_len + len){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp
; if (L__gp != ((void *)0) && (bp) == L__gp->tmp_bp
) { (((L__gp)->flags) &= ~((0x0100))); { void *L__bincp
; if (((last_len + len)) > (L__gp->tmp_blen)) { if ((L__bincp
= binc(((sp)), (L__gp->tmp_bp), &(L__gp->tmp_blen)
, ((last_len + len)))) == ((void *)0)) return (1); (L__gp->
tmp_bp) = L__bincp; } }; (bp) = L__gp->tmp_bp; (blen) = L__gp
->tmp_blen; (((L__gp)->flags) |= ((0x0100))); } else { void
*L__bincp; if (((last_len + len)) > ((blen))) { if ((L__bincp
= binc(((sp)), ((bp)), &((blen)), ((last_len + len)))) ==
((void *)0)) return (1); ((bp)) = L__bincp; } }; }
;
331 memmove(bp + last_len, p, len);
332 if (db_set(sp, last_lno, bp, last_len + len))
333err1: rval = 1;
334 }
335 if (matchprompt)
336 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); }
;
337 return (rval);
338}
339
340/*
341 * sscr_check_input -
342 * Check for input from command input or scripting windows.
343 *
344 * PUBLIC: int sscr_check_input(SCR *sp);
345 */
346int
347sscr_check_input(SCR *sp)
348{
349 GS *gp;
350 SCR *tsp;
351 struct pollfd *pfd;
352 int nfds, rval;
353
354 gp = sp->gp;
355 rval = 0;
356
357 /* Allocate space for pfd. */
358 nfds = 1;
359 TAILQ_FOREACH(tsp, &gp->dq, q)for((tsp) = ((&gp->dq)->tqh_first); (tsp) != ((void
*)0); (tsp) = ((tsp)->q.tqe_next))
360 if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000))))
361 nfds++;
362 pfd = calloc(nfds, sizeof(struct pollfd));
363 if (pfd == NULL((void *)0)) {
364 msgq(sp, M_SYSERR, "malloc");
365 return (1);
366 }
367
368 /* Setup events bitmasks. */
369 pfd[0].fd = STDIN_FILENO0;
370 pfd[0].events = POLLIN0x0001;
371 nfds = 1;
372 TAILQ_FOREACH(tsp, &gp->dq, q)for((tsp) = ((&gp->dq)->tqh_first); (tsp) != ((void
*)0); (tsp) = ((tsp)->q.tqe_next))
373 if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) {
374 pfd[nfds].fd = sp->script->sh_master;
375 pfd[nfds].events = POLLIN0x0001;
376 nfds++;
377 }
378
379loop:
380 /* Check for input. */
381 switch (poll(pfd, nfds, INFTIM(-1))) {
382 case -1:
383 msgq(sp, M_SYSERR, "poll");
384 rval = 1;
385 /* FALLTHROUGH */
386 case 0:
387 goto done;
388 default:
389 break;
390 }
391
392 /* Only insert from the scripting windows if no command input */
393 if (!(pfd[0].revents & POLLIN0x0001)) {
394 nfds = 1;
395 TAILQ_FOREACH(tsp, &gp->dq, q)for((tsp) = ((&gp->dq)->tqh_first); (tsp) != ((void
*)0); (tsp) = ((tsp)->q.tqe_next))
396 if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) {
397 if ((pfd[nfds].revents & POLLHUP0x0010) && sscr_end(sp))
398 goto done;
399 if ((pfd[nfds].revents & POLLIN0x0001) && sscr_insert(sp))
400 goto done;
401 nfds++;
402 }
403 goto loop;
404 }
405done:
406 free(pfd);
407 return (rval);
408}
409
410/*
411 * sscr_input --
412 * Read any waiting shell input.
413 *
414 * PUBLIC: int sscr_input(SCR *);
415 */
416int
417sscr_input(SCR *sp)
418{
419 GS *gp;
420 struct pollfd *pfd;
421 int nfds, rval;
422
423 gp = sp->gp;
424 rval = 0;
425
426 /* Allocate space for pfd. */
427 nfds = 0;
428 TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void *
)0); (sp) = ((sp)->q.tqe_next))
429 if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000))))
430 nfds++;
431 if (nfds == 0)
432 return (0);
433 pfd = calloc(nfds, sizeof(struct pollfd));
434 if (pfd == NULL((void *)0)) {
435 msgq(sp, M_SYSERR, "malloc");
436 return (1);
437 }
438
439 /* Setup events bitmasks. */
440 nfds = 0;
441 TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void *
)0); (sp) = ((sp)->q.tqe_next))
442 if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) {
443 pfd[nfds].fd = sp->script->sh_master;
444 pfd[nfds].events = POLLIN0x0001;
445 nfds++;
446 }
447
448loop:
449 /* Check for input. */
450 switch (poll(pfd, nfds, 0)) {
451 case -1:
452 msgq(sp, M_SYSERR, "poll");
453 rval = 1;
454 /* FALLTHROUGH */
455 case 0:
456 goto done;
457 default:
458 break;
459 }
460
461 /* Read the input. */
462 nfds = 0;
463 TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void *
)0); (sp) = ((sp)->q.tqe_next))
464 if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) {
465 if ((pfd[nfds].revents & POLLHUP0x0010) && sscr_end(sp))
466 goto done;
467 if ((pfd[nfds].revents & POLLIN0x0001) && sscr_insert(sp))
468 goto done;
469 nfds++;
470 }
471 goto loop;
472done:
473 free(pfd);
474 return (rval);
475}
476
477/*
478 * sscr_insert --
479 * Take a line from the shell and insert it into the file.
480 */
481static int
482sscr_insert(SCR *sp)
483{
484 CHAR_T *endp, *p, *t;
485 SCRIPT *sc;
486 struct pollfd pfd[1];
487 recno_t lno;
488 size_t blen, len, tlen;
489 u_int value;
490 int nr, rval;
491 char *bp;
492
493 /* Find out where the end of the file is. */
494 if (db_last(sp, &lno))
495 return (1);
496
497#define MINREAD1024 1024
498 GET_SPACE_RET(sp, bp, blen, MINREAD){ 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 (
((1024)) > ((blen))) { if ((L__bincp = binc(((sp)), ((bp))
, &((blen)), ((1024)))) == ((void *)0)) return (1); ((bp)
) = L__bincp; } }; } else { { void *L__bincp; if (((1024)) >
(L__gp->tmp_blen)) { if ((L__bincp = binc(((sp)), (L__gp->
tmp_bp), &(L__gp->tmp_blen), ((1024)))) == ((void *)0)
) return (1); (L__gp->tmp_bp) = L__bincp; } }; (bp) = L__gp
->tmp_bp; (blen) = L__gp->tmp_blen; (((L__gp)->flags
) |= ((0x0100))); } }
;
499 endp = bp;
500
501 /* Read the characters. */
502 rval = 1;
503 sc = sp->script;
504more: switch (nr = read(sc->sh_master, endp, MINREAD1024)) {
505 case 0: /* EOF; shell just exited. */
506 sscr_end(sp);
507 rval = 0;
508 goto ret;
509 case -1: /* Error or interrupt. */
510 msgq(sp, M_SYSERR, "shell");
511 goto ret;
512 default:
513 endp += nr;
514 break;
515 }
516
517 /* Append the lines into the file. */
518 for (p = t = bp; p < endp; ++p) {
519 value = KEY_VAL(sp, *p)((unsigned char)(*p) <= 254 ? (sp)->gp->special_key[
(unsigned char)(*p)] : (unsigned char)(*p) > (sp)->gp->
max_special ? 0 : v_key_val((sp),(*p)))
;
520 if (value == K_CR || value == K_NL) {
521 len = p - t;
522 if (db_append(sp, 1, lno++, t, len))
523 goto ret;
524 t = p + 1;
525 }
526 }
527 if (p > t) {
528 len = p - t;
529 /*
530 * If the last thing from the shell isn't another prompt, wait
531 * up to 1/10 of a second for more stuff to show up, so that
532 * we don't break the output into two separate lines. Don't
533 * want to hang indefinitely because some program is hanging,
534 * confused the shell, or whatever.
535 */
536 if (!sscr_matchprompt(sp, t, len, &tlen) || tlen != 0) {
537 pfd[0].fd = sc->sh_master;
538 pfd[0].events = POLLIN0x0001;
539 if (poll(pfd, 1, 100) > 0) {
540 memmove(bp, t, len);
541 endp = bp + len;
542 goto more;
543 }
544 }
545 if (sscr_setprompt(sp, t, len))
546 return (1);
547 if (db_append(sp, 1, lno++, t, len))
548 goto ret;
549 }
550
551 /* The cursor moves to EOF. */
552 sp->lno = lno;
553 sp->cno = len ? len - 1 : 0;
554 rval = vs_refresh(sp, 1);
555
556ret: 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); }
;
557 return (rval);
558}
559
560/*
561 * sscr_setprompt --
562 *
563 * Set the prompt to the last line we got from the shell.
564 *
565 */
566static int
567sscr_setprompt(SCR *sp, char *buf, size_t len)
568{
569 SCRIPT *sc;
570
571 sc = sp->script;
572 free(sc->sh_prompt);
573 MALLOC(sp, sc->sh_prompt, len + 1){ if (((sc->sh_prompt) = malloc(len + 1)) == ((void *)0)) msgq
((sp), M_SYSERR, ((void *)0)); }
;
574 if (sc->sh_prompt == NULL((void *)0)) {
575 sscr_end(sp);
576 return (1);
577 }
578 memmove(sc->sh_prompt, buf, len);
579 sc->sh_prompt_len = len;
580 sc->sh_prompt[len] = '\0';
581 return (0);
582}
583
584/*
585 * sscr_matchprompt --
586 * Check to see if a line matches the prompt. Nul's indicate
587 * parts that can change, in both content and size.
588 */
589static int
590sscr_matchprompt(SCR *sp, char *lp, size_t line_len, size_t *lenp)
591{
592 SCRIPT *sc;
593 size_t prompt_len;
594 char *pp;
595
596 sc = sp->script;
597 if (line_len < (prompt_len = sc->sh_prompt_len))
598 return (0);
599
600 for (pp = sc->sh_prompt;
601 prompt_len && line_len; --prompt_len, --line_len) {
602 if (*pp == '\0') {
603 for (; prompt_len && *pp == '\0'; --prompt_len, ++pp);
604 if (!prompt_len)
605 return (0);
606 for (; line_len && *lp != *pp; --line_len, ++lp);
607 if (!line_len)
608 return (0);
609 }
610 if (*pp++ != *lp++)
611 break;
612 }
613
614 if (prompt_len)
615 return (0);
616 if (lenp != NULL((void *)0))
617 *lenp = line_len;
618 return (1);
619}
620
621/*
622 * sscr_end --
623 * End the pipe to a shell.
624 *
625 * PUBLIC: int sscr_end(SCR *);
626 */
627int
628sscr_end(SCR *sp)
629{
630 SCRIPT *sc;
631
632 if ((sc = sp->script) == NULL((void *)0))
633 return (0);
634
635 /* Turn off the script flags. */
636 F_CLR(sp, SC_SCRIPT)(((sp)->flags) &= ~((0x01000000)));
637 sscr_check(sp);
638
639 /* Close down the parent's file descriptors. */
640 if (sc->sh_master != -1)
641 (void)close(sc->sh_master);
642 if (sc->sh_slave != -1)
643 (void)close(sc->sh_slave);
644
645 /* This should have killed the child. */
646 (void)proc_wait(sp, sc->sh_pid, "script-shell", 0, 0);
647
648 /* Free memory. */
649 free(sc->sh_prompt);
650 free(sc);
651 sp->script = NULL((void *)0);
652
653 return (0);
654}
655
656/*
657 * sscr_check --
658 * Set/clear the global scripting bit.
659 */
660static void
661sscr_check(SCR *sp)
662{
663 GS *gp;
664
665 gp = sp->gp;
666 TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void *
)0); (sp) = ((sp)->q.tqe_next))
667 if (F_ISSET(sp, SC_SCRIPT)(((sp)->flags) & ((0x01000000)))) {
668 F_SET(gp, G_SCRWIN)(((gp)->flags) |= ((0x0020)));
669 return;
670 }
671 F_CLR(gp, G_SCRWIN)(((gp)->flags) &= ~((0x0020)));
672}