Bug Summary

File:src/usr.bin/mg/line.c
Warning:line 562, column 2
Value stored to 'n' 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 line.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/mg/obj -resource-dir /usr/local/lib/clang/13.0.0 -D REGEX -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/mg/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/mg/line.c
1/* $OpenBSD: line.c,v 1.63 2021/03/01 10:51:14 lum Exp $ */
2
3/* This file is in the public domain. */
4
5/*
6 * Text line handling.
7 *
8 * The functions in this file are a general set of line management
9 * utilities. They are the only routines that touch the text. They
10 * also touch the buffer and window structures to make sure that the
11 * necessary updating gets done.
12 *
13 * Note that this code only updates the dot and mark values in the window
14 * list. Since all the code acts on the current window, the buffer that
15 * we are editing must be displayed, which means that "b_nwnd" is non-zero,
16 * which means that the dot and mark values in the buffer headers are
17 * nonsense.
18 */
19
20#include <sys/queue.h>
21#include <ctype.h>
22#include <limits.h>
23#include <signal.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "def.h"
29
30int casereplace = TRUE1;
31
32/*
33 * Preserve the case of the replaced string.
34 */
35int
36setcasereplace(int f, int n)
37{
38 if (f & FFARG7)
39 casereplace = n > 0;
40 else
41 casereplace = !casereplace;
42 ewprintf("Case-replace is %sabled", casereplace ? "en" : "dis");
43 return (TRUE1);
44}
45
46/*
47 * Allocate a new line of size `used'. lrealloc() can be called if the line
48 * ever needs to grow beyond that.
49 */
50struct line *
51lalloc(int used)
52{
53 struct line *lp;
54
55 if ((lp = malloc(sizeof(*lp))) == NULL((void *)0))
56 return (NULL((void *)0));
57 lp->l_text = NULL((void *)0);
58 lp->l_size = 0;
59 lp->l_used = used; /* XXX */
60 if (lrealloc(lp, used) == FALSE0) {
61 free(lp);
62 return (NULL((void *)0));
63 }
64 return (lp);
65}
66
67int
68lrealloc(struct line *lp, int newsize)
69{
70 char *tmp;
71
72 if (lp->l_size < newsize) {
73 if ((tmp = realloc(lp->l_text, newsize)) == NULL((void *)0))
74 return (FALSE0);
75 lp->l_text = tmp;
76 lp->l_size = newsize;
77 }
78 return (TRUE1);
79}
80
81/*
82 * Delete line "lp". Fix all of the links that might point to it (they are
83 * moved to offset 0 of the next line. Unlink the line from whatever buffer
84 * it might be in, and release the memory. The buffers are updated too; the
85 * magic conditions described in the above comments don't hold here.
86 */
87void
88lfree(struct line *lp)
89{
90 struct buffer *bp;
91 struct mgwin *wp;
92
93 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
94 if (wp->w_linep == lp)
95 wp->w_linep = lp->l_fp;
96 if (wp->w_dotp == lp) {
97 wp->w_dotp = lp->l_fp;
98 wp->w_doto = 0;
99 }
100 if (wp->w_markp == lp) {
101 wp->w_markp = lp->l_fp;
102 wp->w_marko = 0;
103 }
104 }
105 for (bp = bheadp; bp != NULL((void *)0); bp = bp->b_bufpb_list.l_p.x_bp) {
106 if (bp->b_nwnd == 0) {
107 if (bp->b_dotp == lp) {
108 bp->b_dotp = lp->l_fp;
109 bp->b_doto = 0;
110 }
111 if (bp->b_markp == lp) {
112 bp->b_markp = lp->l_fp;
113 bp->b_marko = 0;
114 }
115 }
116 }
117 lp->l_bp->l_fp = lp->l_fp;
118 lp->l_fp->l_bp = lp->l_bp;
119 free(lp->l_text);
120 free(lp);
121}
122
123/*
124 * This routine is called when a character changes in place in the current
125 * buffer. It updates all of the required flags in the buffer and window
126 * system. The flag used is passed as an argument; if the buffer is being
127 * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
128 * mode line needs to be updated (the "*" has to be set).
129 */
130void
131lchange(int flag)
132{
133 struct mgwin *wp;
134
135 /* update mode lines if this is the first change. */
136 if ((curbp->b_flag & BFCHG0x01) == 0) {
137 flag |= WFMODE0x10;
138 curbp->b_flag |= BFCHG0x01;
139 }
140 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
141 if (wp->w_bufp == curbp) {
142 wp->w_rflag |= flag;
143 if (wp != curwp)
144 wp->w_rflag |= WFFULL0x08;
145 }
146 }
147}
148
149/*
150 * Insert "n" copies of the character "c" at the current location of dot.
151 * In the easy case all that happens is the text is stored in the line.
152 * In the hard case, the line has to be reallocated. When the window list
153 * is updated, take special care; I screwed it up once. You always update
154 * dot in the current window. You update mark and a dot in another window
155 * if it is greater than the place where you did the insert. Return TRUE
156 * if all is well, and FALSE on errors.
157 */
158int
159linsert(int n, int c)
160{
161 struct line *lp1;
162 struct mgwin *wp;
163 RSIZE i;
164 int doto;
165 int s;
166
167 if (!n)
168 return (TRUE1);
169
170 if ((s = checkdirty(curbp)) != TRUE1)
171 return (s);
172
173 if (curbp->b_flag & BFREADONLY0x10) {
174 dobeep();
175 ewprintf("Buffer is read only");
176 return (FALSE0);
177 }
178
179 lchange(WFEDIT0x04);
180
181 /* current line */
182 lp1 = curwp->w_dotp;
183
184 /* special case for the end */
185 if (lp1 == curbp->b_headp) {
186 struct line *lp2, *lp3;
187
188 /* now should only happen in empty buffer */
189 if (curwp->w_doto != 0) {
190 dobeep();
191 ewprintf("bug: linsert");
192 return (FALSE0);
193 }
194 /* allocate a new line */
195 if ((lp2 = lalloc(n)) == NULL((void *)0))
196 return (FALSE0);
197 /* previous line */
198 lp3 = lp1->l_bp;
199 /* link in */
200 lp3->l_fp = lp2;
201 lp2->l_fp = lp1;
202 lp1->l_bp = lp2;
203 lp2->l_bp = lp3;
204 for (i = 0; i < n; ++i)
205 lp2->l_text[i] = c;
206 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
207 if (wp->w_linep == lp1)
208 wp->w_linep = lp2;
209 if (wp->w_dotp == lp1)
210 wp->w_dotp = lp2;
211 if (wp->w_markp == lp1)
212 wp->w_markp = lp2;
213 }
214 undo_add_insert(lp2, 0, n);
215 curwp->w_doto = n;
216 return (TRUE1);
217 }
218 /* save for later */
219 doto = curwp->w_doto;
220
221 if ((lp1->l_used + n) > lp1->l_size) {
222 if (lrealloc(lp1, lp1->l_used + n) == FALSE0)
223 return (FALSE0);
224 }
225 lp1->l_used += n;
226 if (lp1->l_used != n)
227 memmove(&lp1->l_text[doto + n], &lp1->l_text[doto],
228 lp1->l_used - n - doto);
229
230 /* Add the characters */
231 for (i = 0; i < n; ++i)
232 lp1->l_text[doto + i] = c;
233 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
234 if (wp->w_dotp == lp1) {
235 if (wp == curwp || wp->w_doto > doto)
236 wp->w_doto += n;
237 }
238 if (wp->w_markp == lp1) {
239 if (wp->w_marko > doto)
240 wp->w_marko += n;
241 }
242 }
243 undo_add_insert(curwp->w_dotp, doto, n);
244 return (TRUE1);
245}
246
247/*
248 * Do the work of inserting a newline at the given line/offset.
249 * If mark is on the current line, we may have to move the markline
250 * to keep line numbers in sync.
251 * lnewline_at assumes the current buffer is writable. Checking for
252 * this fact should be done by the caller.
253 */
254int
255lnewline_at(struct line *lp1, int doto)
256{
257 struct line *lp2;
258 struct mgwin *wp;
259 int nlen, tcurwpdotline;
260
261 lchange(WFFULL0x08);
262
263 curwp->w_bufp->b_lines++;
264 /* Check if mark is past dot (even on current line) */
265 if (curwp->w_markline > curwp->w_dotline ||
266 (curwp->w_dotline == curwp->w_markline &&
267 curwp->w_marko >= doto))
268 curwp->w_markline++;
269
270 tcurwpdotline = curwp->w_dotline;
271
272 /* If start of line, allocate a new line instead of copying */
273 if (doto == 0) {
274 /* new first part */
275 if ((lp2 = lalloc(0)) == NULL((void *)0))
276 return (FALSE0);
277 lp2->l_bp = lp1->l_bp;
278 lp1->l_bp->l_fp = lp2;
279 lp2->l_fp = lp1;
280 lp1->l_bp = lp2;
281 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
282 if (wp->w_linep == lp1)
283 wp->w_linep = lp2;
284 if (wp->w_dotline >= tcurwpdotline &&
285 wp->w_bufp == curwp->w_bufp)
286 wp->w_dotline++;
287 }
288 undo_add_boundary(FFRAND8, 1);
289 undo_add_insert(lp2, 0, 1);
290 undo_add_boundary(FFRAND8, 1);
291 return (TRUE1);
292 }
293
294 /* length of new part */
295 nlen = llength(lp1)((lp1)->l_used) - doto;
296
297 /* new second half line */
298 if ((lp2 = lalloc(nlen)) == NULL((void *)0))
299 return (FALSE0);
300 if (nlen != 0)
301 bcopy(&lp1->l_text[doto], &lp2->l_text[0], nlen);
302 lp1->l_used = doto;
303 lp2->l_bp = lp1;
304 lp2->l_fp = lp1->l_fp;
305 lp1->l_fp = lp2;
306 lp2->l_fp->l_bp = lp2;
307 /* Windows */
308 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
309 if (wp->w_dotp == lp1 && wp->w_doto >= doto) {
310 wp->w_dotp = lp2;
311 wp->w_doto -= doto;
312 wp->w_dotline++;
313 } else if (wp->w_dotline > tcurwpdotline &&
314 wp->w_bufp == curwp->w_bufp)
315 wp->w_dotline++;
316 if (wp->w_markp == lp1 && wp->w_marko >= doto) {
317 wp->w_markp = lp2;
318 wp->w_marko -= doto;
319 }
320 }
321 undo_add_boundary(FFRAND8, 1);
322 undo_add_insert(lp1, llength(lp1)((lp1)->l_used), 1);
323 undo_add_boundary(FFRAND8, 1);
324 return (TRUE1);
325}
326
327/*
328 * Insert a newline into the buffer at the current location of dot in the
329 * current window.
330 */
331int
332lnewline(void)
333{
334 int s;
335
336 if ((s = checkdirty(curbp)) != TRUE1)
337 return (s);
338 if (curbp->b_flag & BFREADONLY0x10) {
339 dobeep();
340 ewprintf("Buffer is read only");
341 return (FALSE0);
342 }
343 return (lnewline_at(curwp->w_dotp, curwp->w_doto));
344}
345
346/*
347 * This function deletes "n" bytes, starting at dot. (actually, n+1, as the
348 * newline is included) It understands how to deal with end of lines, etc.
349 * It returns TRUE if all of the characters were deleted, and FALSE if
350 * they were not (because dot ran into the end of the buffer).
351 * The "kflag" indicates either no insertion, or direction of insertion
352 * into the kill buffer.
353 */
354int
355ldelete(RSIZE n, int kflag)
356{
357 struct line *dotp;
358 RSIZE chunk;
359 struct mgwin *wp;
360 int doto;
361 char *cp1, *cp2;
362 size_t len;
363 char *sv = NULL((void *)0);
364 int end;
365 int s;
366 int rval = FALSE0;
367
368 if ((s = checkdirty(curbp)) != TRUE1)
369 return (s);
370 if (curbp->b_flag & BFREADONLY0x10) {
371 dobeep();
372 ewprintf("Buffer is read only");
373 goto out;
374 }
375 len = n;
376 if ((sv = calloc(1, len + 1)) == NULL((void *)0))
377 goto out;
378 end = 0;
379
380 undo_add_delete(curwp->w_dotp, curwp->w_doto, n, (kflag & KREG0x04));
381
382 while (n != 0) {
383 dotp = curwp->w_dotp;
384 doto = curwp->w_doto;
385 /* Hit the end of the buffer */
386 if (dotp == curbp->b_headp)
387 goto out;
388 /* Size of the chunk */
389 chunk = dotp->l_used - doto;
390
391 if (chunk > n)
392 chunk = n;
393 /* End of line, merge */
394 if (chunk == 0) {
395 if (dotp == blastlp(curbp)((((curbp)->b_headp)->l_bp)))
396 goto out;
397 lchange(WFFULL0x08);
398 if (ldelnewline() == FALSE0)
399 goto out;
400 end = strlcat(sv, curbp->b_nlchr, len + 1);
401 --n;
402 continue;
403 }
404 lchange(WFEDIT0x04);
405 /* Scrunch text */
406 cp1 = &dotp->l_text[doto];
407 memcpy(&sv[end], cp1, chunk);
408 end += chunk;
409 sv[end] = '\0';
410 for (cp2 = cp1 + chunk; cp2 < &dotp->l_text[dotp->l_used];
411 cp2++)
412 *cp1++ = *cp2;
413 dotp->l_used -= (int)chunk;
414 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
415 if (wp->w_dotp == dotp && wp->w_doto >= doto) {
416 wp->w_doto -= chunk;
417 if (wp->w_doto < doto)
418 wp->w_doto = doto;
419 }
420 if (wp->w_markp == dotp && wp->w_marko >= doto) {
421 wp->w_marko -= chunk;
422 if (wp->w_marko < doto)
423 wp->w_marko = doto;
424 }
425 }
426 n -= chunk;
427 }
428 if (kchunk(sv, (RSIZE)len, kflag) != TRUE1)
429 goto out;
430 rval = TRUE1;
431out:
432 free(sv);
433 return (rval);
434}
435
436/*
437 * Delete a newline and join the current line with the next line. If the next
438 * line is the magic header line always return TRUE; merging the last line
439 * with the header line can be thought of as always being a successful
440 * operation. Even if nothing is done, this makes the kill buffer work
441 * "right". If the mark is past the dot (actually, markline > dotline),
442 * decrease the markline accordingly to keep line numbers in sync.
443 * Easy cases can be done by shuffling data around. Hard cases
444 * require that lines be moved about in memory. Return FALSE on error and
445 * TRUE if all looks ok. We do not update w_dotline here, as deletes are done
446 * after moves.
447 */
448int
449ldelnewline(void)
450{
451 struct line *lp1, *lp2, *lp3;
452 struct mgwin *wp;
453 int s;
454
455 if ((s = checkdirty(curbp)) != TRUE1)
456 return (s);
457 if (curbp->b_flag & BFREADONLY0x10) {
458 dobeep();
459 ewprintf("Buffer is read only");
460 return (FALSE0);
461 }
462
463 lp1 = curwp->w_dotp;
464 lp2 = lp1->l_fp;
465 /* at the end of the buffer */
466 if (lp2 == curbp->b_headp)
467 return (TRUE1);
468 /* Keep line counts in sync */
469 curwp->w_bufp->b_lines--;
470 if (curwp->w_markline > curwp->w_dotline)
471 curwp->w_markline--;
472 if (lp2->l_used <= lp1->l_size - lp1->l_used) {
473 bcopy(&lp2->l_text[0], &lp1->l_text[lp1->l_used], lp2->l_used);
474 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
475 if (wp->w_linep == lp2)
476 wp->w_linep = lp1;
477 if (wp->w_dotp == lp2) {
478 wp->w_dotp = lp1;
479 wp->w_doto += lp1->l_used;
480 }
481 if (wp->w_markp == lp2) {
482 wp->w_markp = lp1;
483 wp->w_marko += lp1->l_used;
484 }
485 }
486 lp1->l_used += lp2->l_used;
487 lp1->l_fp = lp2->l_fp;
488 lp2->l_fp->l_bp = lp1;
489 free(lp2);
490 return (TRUE1);
491 }
492 if ((lp3 = lalloc(lp1->l_used + lp2->l_used)) == NULL((void *)0))
493 return (FALSE0);
494 bcopy(&lp1->l_text[0], &lp3->l_text[0], lp1->l_used);
495 bcopy(&lp2->l_text[0], &lp3->l_text[lp1->l_used], lp2->l_used);
496 lp1->l_bp->l_fp = lp3;
497 lp3->l_fp = lp2->l_fp;
498 lp2->l_fp->l_bp = lp3;
499 lp3->l_bp = lp1->l_bp;
500 for (wp = wheadp; wp != NULL((void *)0); wp = wp->w_wndpw_list.l_p.l_wp) {
501 if (wp->w_linep == lp1 || wp->w_linep == lp2)
502 wp->w_linep = lp3;
503 if (wp->w_dotp == lp1)
504 wp->w_dotp = lp3;
505 else if (wp->w_dotp == lp2) {
506 wp->w_dotp = lp3;
507 wp->w_doto += lp1->l_used;
508 }
509 if (wp->w_markp == lp1)
510 wp->w_markp = lp3;
511 else if (wp->w_markp == lp2) {
512 wp->w_markp = lp3;
513 wp->w_marko += lp1->l_used;
514 }
515 }
516 free(lp1);
517 free(lp2);
518 return (TRUE1);
519}
520
521/*
522 * Replace plen characters before dot with argument string. Control-J
523 * characters in st are interpreted as newlines. There is a casehack
524 * disable flag (normally it likes to match case of replacement to what
525 * was there).
526 */
527int
528lreplace(RSIZE plen, char *st)
529{
530 RSIZE rlen; /* replacement length */
531 struct line *lp;
532 RSIZE n;
533 int s, doto, is_query_capitalised = 0, is_query_allcaps = 0;
534 int is_replace_alllower = 0;
535 char *repl = NULL((void *)0);
536
537 if ((s = checkdirty(curbp)) != TRUE1)
538 return (s);
539 if (curbp->b_flag & BFREADONLY0x10) {
540 dobeep();
541 ewprintf("Buffer is read only");
542 return (FALSE0);
543 }
544
545 if ((repl = strdup(st)) == NULL((void *)0)) {
546 dobeep();
547 ewprintf("out of memory");
548 return (FALSE0);
549 }
550 rlen = strlen(repl);
551
552 undo_boundary_enable(FFRAND8, 0);
553 (void)backchar(FFARG7 | FFRAND8, (int)plen);
554
555 if (casereplace != TRUE1)
556 goto done;
557
558 lp = curwp->w_dotp;
559 if (ltext(lp)((lp)->l_text) == NULL((void *)0))
560 goto done;
561 doto = curwp->w_doto;
562 n = plen;
Value stored to 'n' is never read
563
564 is_query_capitalised = isupper((unsigned char)lgetc(lp, doto)(((unsigned char) ((lp)->l_text[(doto)]))));
565
566 if (is_query_capitalised) {
567 for (n = 0, is_query_allcaps = 1; n < plen && is_query_allcaps;
568 n++) {
569 is_query_allcaps = !isalpha((unsigned char)lgetc(lp,(((unsigned char) ((lp)->l_text[(doto)])))
570 doto)(((unsigned char) ((lp)->l_text[(doto)])))) || isupper((unsigned char)lgetc(lp, doto)(((unsigned char) ((lp)->l_text[(doto)]))));
571 doto++;
572 if (doto == llength(lp)((lp)->l_used)) {
573 doto = 0;
574 lp = lforw(lp)((lp)->l_fp);
575 n++; /* \n is implicit in the buffer */
576 }
577 }
578 }
579
580 for (n = 0, is_replace_alllower = 1; n < rlen && is_replace_alllower;
581 n++)
582 is_replace_alllower = !isupper((unsigned char)repl[n]);
583
584 if (is_replace_alllower) {
585 if (is_query_allcaps) {
586 for (n = 0; n < rlen; n++)
587 repl[n] = toupper((unsigned char)repl[n]);
588 } else if (is_query_capitalised) {
589 repl[0] = toupper((unsigned char)repl[0]);
590 }
591 }
592
593 done:
594 (void)ldelete(plen, KNONE0x00);
595 region_put_data(repl, rlen);
596 lchange(WFFULL0x08);
597
598 undo_boundary_enable(FFRAND8, 1);
599
600 free(repl);
601 return (TRUE1);
602}
603
604/*
605 * Allocate and return the supplied line as a C string
606 */
607char *
608linetostr(const struct line *ln)
609{
610 int len;
611 char *line;
612
613 len = llength(ln)((ln)->l_used);
614 if (len == INT_MAX2147483647) /* (len + 1) overflow */
615 return (NULL((void *)0));
616
617 if ((line = malloc(len + 1)) == NULL((void *)0))
618 return (NULL((void *)0));
619
620 (void)memcpy(line, ltext(ln)((ln)->l_text), len);
621 line[len] = '\0';
622
623 return (line);
624}