Bug Summary

File:src/usr.bin/vi/build/../ex/ex_global.c
Warning:line 305, column 5
Value stored to 'rp' 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_global.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_global.c
1/* $OpenBSD: ex_global.c,v 1.17 2016/05/27 09:18:12 martijn 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 * See the LICENSE file for redistribution information.
10 */
11
12#include "config.h"
13
14#include <sys/types.h>
15#include <sys/queue.h>
16
17#include <bitstring.h>
18#include <ctype.h>
19#include <errno(*__errno()).h>
20#include <limits.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25
26#include "../common/common.h"
27
28enum which {GLOBAL, V};
29
30static int ex_g_setup(SCR *, EXCMD *, enum which);
31
32/*
33 * ex_global -- [line [,line]] g[lobal][!] /pattern/ [commands]
34 * Exec on lines matching a pattern.
35 *
36 * PUBLIC: int ex_global(SCR *, EXCMD *);
37 */
38int
39ex_global(SCR *sp, EXCMD *cmdp)
40{
41 return (ex_g_setup(sp,
42 cmdp, FL_ISSET(cmdp->iflags, E_C_FORCE)((cmdp->iflags) & (0x00100)) ? V : GLOBAL));
43}
44
45/*
46 * ex_v -- [line [,line]] v /pattern/ [commands]
47 * Exec on lines not matching a pattern.
48 *
49 * PUBLIC: int ex_v(SCR *, EXCMD *);
50 */
51int
52ex_v(SCR *sp, EXCMD *cmdp)
53{
54 return (ex_g_setup(sp, cmdp, V));
55}
56
57/*
58 * ex_g_setup --
59 * Ex global and v commands.
60 */
61static int
62ex_g_setup(SCR *sp, EXCMD *cmdp, enum which cmd)
63{
64 CHAR_T *ptrn, *p, *t;
65 EXCMD *ecp;
66 MARK abs_mark;
67 RANGE *rp;
68 busy_t btype;
69 recno_t start, end;
70 regex_t *re;
71 regmatch_t match[1];
72 size_t len;
73 int cnt, delim, eval;
74 char *dbp;
75
76 NEEDFILE(sp, cmdp){ if ((sp)->ep == ((void *)0)) { ex_emsg((sp), (cmdp)->
cmd->name, EXM_NOFILEYET); return (1); } }
;
77
78 if (F_ISSET(sp, SC_EX_GLOBAL)(((sp)->flags) & ((0x00020000)))) {
79 msgq(sp, M_ERR,
80 "The %s command can't be used as part of a global or v command",
81 cmdp->cmd->name);
82 return (1);
83 }
84
85 /*
86 * Skip leading white space. Historic vi allowed any non-alphanumeric
87 * to serve as the global command delimiter.
88 */
89 if (cmdp->argc == 0)
90 goto usage;
91 for (p = cmdp->argv[0]->bp; isblank(*p); ++p);
92 if (*p == '\0' || isalnum(*p) ||
93 *p == '\\' || *p == '|' || *p == '\n') {
94usage: ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
95 return (1);
96 }
97 delim = *p++;
98
99 /*
100 * Get the pattern string, toss escaped characters.
101 *
102 * QUOTING NOTE:
103 * Only toss an escaped character if it escapes a delimiter.
104 */
105 for (ptrn = t = p;;) {
106 if (p[0] == '\0' || p[0] == delim) {
107 if (p[0] == delim)
108 ++p;
109 /*
110 * !!!
111 * Nul terminate the pattern string -- it's passed
112 * to regcomp which doesn't understand anything else.
113 */
114 *t = '\0';
115 break;
116 }
117 if (p[0] == '\\') {
118 if (p[1] == delim)
119 ++p;
120 else if (p[1] == '\\')
121 *t++ = *p++;
122 }
123 *t++ = *p++;
124 }
125
126 /* If the pattern string is empty, use the last one. */
127 if (*ptrn == '\0') {
128 if (sp->re == NULL((void *)0)) {
129 ex_emsg(sp, NULL((void *)0), EXM_NOPREVRE);
130 return (1);
131 }
132
133 /* Re-compile the RE if necessary. */
134 if (!F_ISSET(sp, SC_RE_SEARCH)(((sp)->flags) & ((0x00400000))) && re_compile(sp,
135 sp->re, sp->re_len, NULL((void *)0), NULL((void *)0), &sp->re_c, RE_C_SEARCH0x0002))
136 return (1);
137 } else {
138 /* Compile the RE. */
139 if (re_compile(sp, ptrn, t - ptrn,
140 &sp->re, &sp->re_len, &sp->re_c, RE_C_SEARCH0x0002))
141 return (1);
142
143 /*
144 * Set saved RE. Historic practice is that globals set
145 * direction as well as the RE.
146 */
147 sp->searchdir = FORWARD;
148 }
149 re = &sp->re_c;
150
151 /* The global commands always set the previous context mark. */
152 abs_mark.lno = sp->lno;
153 abs_mark.cno = sp->cno;
154 if (mark_set(sp, ABSMARK1'\'', &abs_mark, 1))
155 return (1);
156
157 /* Get an EXCMD structure. */
158 CALLOC_RET(sp, ecp, 1, sizeof(EXCMD)){ if (((ecp) = calloc((1), (sizeof(EXCMD)))) == ((void *)0)) {
msgq((sp), M_SYSERR, ((void *)0)); return (1); } }
;
159 TAILQ_INIT(&ecp->rq)do { (&ecp->rq)->tqh_first = ((void *)0); (&ecp
->rq)->tqh_last = &(&ecp->rq)->tqh_first;
} while (0)
;
160
161 /*
162 * Get a copy of the command string; the default command is print.
163 * Don't worry about a set of <blank>s with no command, that will
164 * default to print in the ex parser. We need to have two copies
165 * because the ex parser may step on the command string when it's
166 * parsing it.
167 */
168 if ((len = cmdp->argv[0]->len - (p - cmdp->argv[0]->bp)) == 0) {
169 p = "pp";
170 len = 1;
171 }
172
173 MALLOC_RET(sp, ecp->cp, len * 2){ if (((ecp->cp) = malloc(len * 2)) == ((void *)0)) { msgq
((sp), M_SYSERR, ((void *)0)); return (1); } }
;
174 ecp->o_cp = ecp->cp;
175 ecp->o_clen = len;
176 memcpy(ecp->cp + len, p, len);
177 ecp->range_lno = OOBLNO0;
178 FL_SET(ecp->agv_flags, cmd == GLOBAL ? AGV_GLOBAL : AGV_V)((ecp->agv_flags) |= (cmd == GLOBAL ? 0x04 : 0x08));
179 LIST_INSERT_HEAD(&sp->gp->ecq, ecp, q)do { if (((ecp)->q.le_next = (&sp->gp->ecq)->
lh_first) != ((void *)0)) (&sp->gp->ecq)->lh_first
->q.le_prev = &(ecp)->q.le_next; (&sp->gp->
ecq)->lh_first = (ecp); (ecp)->q.le_prev = &(&sp
->gp->ecq)->lh_first; } while (0)
;
180
181 /*
182 * For each line... The semantics of global matching are that we first
183 * have to decide which lines are going to get passed to the command,
184 * and then pass them to the command, ignoring other changes. There's
185 * really no way to do this in a single pass, since arbitrary line
186 * creation, deletion and movement can be done in the ex command. For
187 * example, a good vi clone test is ":g/X/mo.-3", or "g/X/.,.+1d".
188 * What we do is create linked list of lines that are tracked through
189 * each ex command. There's a callback routine which the DB interface
190 * routines call when a line is created or deleted. This doesn't help
191 * the layering much.
192 */
193 btype = BUSY_ON;
194 cnt = INTERRUPT_CHECK100;
195 for (start = cmdp->addr1.lno,
196 end = cmdp->addr2.lno; start <= end; ++start) {
197 if (cnt-- == 0) {
198 if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get
((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)->
flags) & ((0x0004)))))
) {
199 LIST_REMOVE(ecp, q)do { if ((ecp)->q.le_next != ((void *)0)) (ecp)->q.le_next
->q.le_prev = (ecp)->q.le_prev; *(ecp)->q.le_prev = (
ecp)->q.le_next; ; ; } while (0)
;
200 free(ecp->cp);
201 free(ecp);
202 break;
203 }
204 search_busy(sp, btype);
205 btype = BUSY_UPDATE;
206 cnt = INTERRUPT_CHECK100;
207 }
208 if (db_get(sp, start, DBG_FATAL0x001, &dbp, &len))
209 return (1);
210 match[0].rm_so = 0;
211 match[0].rm_eo = len;
212 switch (eval =
213 regexec(&sp->re_c, dbp, 0, match, REG_STARTEND00004)) {
214 case 0:
215 if (cmd == V)
216 continue;
217 break;
218 case REG_NOMATCH1:
219 if (cmd == GLOBAL)
220 continue;
221 break;
222 default:
223 re_error(sp, eval, &sp->re_c);
224 break;
225 }
226
227 /* If follows the last entry, extend the last entry's range. */
228 if ((rp = TAILQ_LAST(&ecp->rq, _rh)(*(((struct _rh *)((&ecp->rq)->tqh_last))->tqh_last
))
) && rp->stop == start - 1) {
229 ++rp->stop;
230 continue;
231 }
232
233 /* Allocate a new range, and append it to the list. */
234 CALLOC(sp, rp, 1, sizeof(RANGE)){ if (((rp) = calloc((1), (sizeof(RANGE)))) == ((void *)0)) msgq
((sp), M_SYSERR, ((void *)0)); }
;
235 if (rp == NULL((void *)0))
236 return (1);
237 rp->start = rp->stop = start;
238 TAILQ_INSERT_TAIL(&ecp->rq, rp, q)do { (rp)->q.tqe_next = ((void *)0); (rp)->q.tqe_prev =
(&ecp->rq)->tqh_last; *(&ecp->rq)->tqh_last
= (rp); (&ecp->rq)->tqh_last = &(rp)->q.tqe_next
; } while (0)
;
239 }
240 search_busy(sp, BUSY_OFF);
241 return (0);
242}
243
244/*
245 * ex_g_insdel --
246 * Update the ranges based on an insertion or deletion.
247 *
248 * PUBLIC: int ex_g_insdel(SCR *, lnop_t, recno_t);
249 */
250int
251ex_g_insdel(SCR *sp, lnop_t op, recno_t lno)
252{
253 EXCMD *ecp;
254 RANGE *nrp, *rp;
255
256 /* All insert/append operations are done as inserts. */
257 if (op == LINE_APPEND)
258 abort();
259
260 if (op == LINE_RESET)
261 return (0);
262
263 LIST_FOREACH(ecp, &sp->gp->ecq, q)for((ecp) = ((&sp->gp->ecq)->lh_first); (ecp)!= (
(void *)0); (ecp) = ((ecp)->q.le_next))
{
264 if (!FL_ISSET(ecp->agv_flags, AGV_AT | AGV_GLOBAL | AGV_V)((ecp->agv_flags) & (0x01 | 0x04 | 0x08)))
265 continue;
266 for (rp = TAILQ_FIRST(&ecp->rq)((&ecp->rq)->tqh_first); rp != NULL((void *)0); rp = nrp) {
267 nrp = TAILQ_NEXT(rp, q)((rp)->q.tqe_next);
268
269 /* If range less than the line, ignore it. */
270 if (rp->stop < lno)
271 continue;
272
273 /*
274 * If range greater than the line, decrement or
275 * increment the range.
276 */
277 if (rp->start > lno) {
278 if (op == LINE_DELETE) {
279 --rp->start;
280 --rp->stop;
281 } else {
282 ++rp->start;
283 ++rp->stop;
284 }
285 continue;
286 }
287
288 /*
289 * Lno is inside the range, decrement the end point
290 * for deletion, and split the range for insertion.
291 * In the latter case, since we're inserting a new
292 * element, neither range can be exhausted.
293 */
294 if (op == LINE_DELETE) {
295 if (rp->start > --rp->stop) {
296 TAILQ_REMOVE(&ecp->rq, rp, q)do { if (((rp)->q.tqe_next) != ((void *)0)) (rp)->q.tqe_next
->q.tqe_prev = (rp)->q.tqe_prev; else (&ecp->rq)
->tqh_last = (rp)->q.tqe_prev; *(rp)->q.tqe_prev = (
rp)->q.tqe_next; ; ; } while (0)
;
297 free(rp);
298 }
299 } else {
300 CALLOC_RET(sp, nrp, 1, sizeof(RANGE)){ if (((nrp) = calloc((1), (sizeof(RANGE)))) == ((void *)0)) {
msgq((sp), M_SYSERR, ((void *)0)); return (1); } }
;
301 nrp->start = lno + 1;
302 nrp->stop = rp->stop + 1;
303 rp->stop = lno - 1;
304 TAILQ_INSERT_AFTER(&ecp->rq, rp, nrp, q)do { if (((nrp)->q.tqe_next = (rp)->q.tqe_next) != ((void
*)0)) (nrp)->q.tqe_next->q.tqe_prev = &(nrp)->q
.tqe_next; else (&ecp->rq)->tqh_last = &(nrp)->
q.tqe_next; (rp)->q.tqe_next = (nrp); (nrp)->q.tqe_prev
= &(rp)->q.tqe_next; } while (0)
;
305 rp = nrp;
Value stored to 'rp' is never read
306 }
307 }
308
309 /*
310 * If the command deleted/inserted lines, the cursor moves to
311 * the line after the deleted/inserted line.
312 */
313 ecp->range_lno = lno;
314 }
315 return (0);
316}