File: | src/usr.bin/mg/line.c |
Warning: | line 562, column 2 Value stored to 'n' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
30 | int casereplace = TRUE1; |
31 | |
32 | /* |
33 | * Preserve the case of the replaced string. |
34 | */ |
35 | int |
36 | setcasereplace(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 | */ |
50 | struct line * |
51 | lalloc(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 | |
67 | int |
68 | lrealloc(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 | */ |
87 | void |
88 | lfree(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 | */ |
130 | void |
131 | lchange(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 | */ |
158 | int |
159 | linsert(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 | */ |
254 | int |
255 | lnewline_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 | */ |
331 | int |
332 | lnewline(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 | */ |
354 | int |
355 | ldelete(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; |
431 | out: |
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 | */ |
448 | int |
449 | ldelnewline(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 | */ |
527 | int |
528 | lreplace(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 | */ |
607 | char * |
608 | linetostr(const struct line *ln) |
609 | { |
610 | int len; |
611 | char *line; |
612 | |
613 | len = llength(ln)((ln)->l_used); |
614 | if (len == INT_MAX0x7fffffff) /* (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 | } |