nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

cut.c (23592B)


      1 /**************************************************************************
      2  *   cut.c  --  This file is part of GNU nano.                            *
      3  *                                                                        *
      4  *   Copyright (C) 1999-2011, 2013-2025 Free Software Foundation, Inc.    *
      5  *   Copyright (C) 2014 Mark Majeres                                      *
      6  *   Copyright (C) 2016, 2018-2020 Benno Schulenberg                      *
      7  *                                                                        *
      8  *   GNU nano is free software: you can redistribute it and/or modify     *
      9  *   it under the terms of the GNU General Public License as published    *
     10  *   by the Free Software Foundation, either version 3 of the License,    *
     11  *   or (at your option) any later version.                               *
     12  *                                                                        *
     13  *   GNU nano is distributed in the hope that it will be useful,          *
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty          *
     15  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.              *
     16  *   See the GNU General Public License for more details.                 *
     17  *                                                                        *
     18  *   You should have received a copy of the GNU General Public License    *
     19  *   along with this program.  If not, see https://gnu.org/licenses/.     *
     20  *                                                                        *
     21  **************************************************************************/
     22 
     23 #include "prototypes.h"
     24 
     25 #include <string.h>
     26 
     27 /* Delete the character at the current position, and
     28  * add or update an undo item for the given action. */
     29 void expunge(undo_type action)
     30 {
     31 	openfile->placewewant = xplustabs();
     32 
     33 	/* When in the middle of a line, delete the current character. */
     34 	if (openfile->current->data[openfile->current_x] != '\0') {
     35 		int charlen = char_length(openfile->current->data + openfile->current_x);
     36 		size_t line_len = strlen(openfile->current->data + openfile->current_x);
     37 #ifndef NANO_TINY
     38 		size_t old_amount = ISSET(SOFTWRAP) ? extra_chunks_in(openfile->current) : 0;
     39 
     40 		/* If the type of action changed or the cursor moved to a different
     41 		 * line, create a new undo item, otherwise update the existing item. */
     42 		if (action != openfile->last_action ||
     43 					openfile->current->lineno != openfile->current_undo->head_lineno)
     44 			add_undo(action, NULL);
     45 		else
     46 			update_undo(action);
     47 #endif
     48 		/* Move the remainder of the line "in", over the current character. */
     49 		memmove(&openfile->current->data[openfile->current_x],
     50 					&openfile->current->data[openfile->current_x + charlen],
     51 					line_len - charlen + 1);
     52 #ifndef NANO_TINY
     53 		/* When softwrapping, a changed number of chunks requires a refresh. */
     54 		if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount)
     55 			refresh_needed = TRUE;
     56 
     57 		/* Adjust the mark if it is after the cursor on the current line. */
     58 		if (openfile->mark == openfile->current &&
     59 								openfile->mark_x > openfile->current_x)
     60 			openfile->mark_x -= charlen;
     61 #endif
     62 	/* Otherwise, when not at end of buffer, join this line with the next. */
     63 	} else if (openfile->current != openfile->filebot) {
     64 		linestruct *joining = openfile->current->next;
     65 
     66 		/* If there is a magic line, and we're before it: don't eat it. */
     67 		if (joining == openfile->filebot && openfile->current_x != 0 &&
     68 													!ISSET(NO_NEWLINES)) {
     69 #ifndef NANO_TINY
     70 			if (action == BACK)
     71 				add_undo(BACK, NULL);
     72 #endif
     73 			return;
     74 		}
     75 
     76 #ifndef NANO_TINY
     77 		add_undo(action, NULL);
     78 
     79 		/* Adjust the mark if it is on the line that will be "eaten". */
     80 		if (openfile->mark == joining) {
     81 			openfile->mark = openfile->current;
     82 			openfile->mark_x += openfile->current_x;
     83 		}
     84 
     85 		openfile->current->has_anchor |= joining->has_anchor;
     86 #endif
     87 		/* Add the content of the next line to that of the current one. */
     88 		openfile->current->data = nrealloc(openfile->current->data,
     89 				strlen(openfile->current->data) + strlen(joining->data) + 1);
     90 		strcat(openfile->current->data, joining->data);
     91 
     92 		unlink_node(joining);
     93 
     94 		/* Two lines were joined, so do a renumbering and refresh the screen. */
     95 		renumber_from(openfile->current);
     96 		refresh_needed = TRUE;
     97 	} else
     98 		/* We're at the end-of-file: nothing to do. */
     99 		return;
    100 
    101 #ifdef ENABLE_COLOR
    102 	if (!refresh_needed)
    103 		check_the_multis(openfile->current);
    104 #endif
    105 	if (!refresh_needed)
    106 		update_line(openfile->current, openfile->current_x);
    107 
    108 	/* Adjust the file size, and remember it for a possible redo. */
    109 	openfile->totsize--;
    110 #ifndef NANO_TINY
    111 	openfile->current_undo->newsize = openfile->totsize;
    112 #endif
    113 	set_modified();
    114 }
    115 
    116 /* Delete the character under the cursor plus any succeeding zero-widths,
    117  * or, when the mark is on and --zap is active, delete the marked region. */
    118 void do_delete(void)
    119 {
    120 #ifndef NANO_TINY
    121 	if (openfile->mark && ISSET(LET_THEM_ZAP))
    122 		zap_text();
    123 	else
    124 #endif
    125 	{
    126 		expunge(DEL);
    127 #ifdef ENABLE_UTF8
    128 		while (openfile->current->data[openfile->current_x] != '\0' &&
    129 				is_zerowidth(openfile->current->data + openfile->current_x))
    130 			expunge(DEL);
    131 #endif
    132 	}
    133 }
    134 
    135 /* Backspace over one character.  That is, move the cursor left one
    136  * character, and then delete the character under the cursor.  Or,
    137  * when mark is on and --zap is active, delete the marked region. */
    138 void do_backspace(void)
    139 {
    140 #ifndef NANO_TINY
    141 	if (openfile->mark && ISSET(LET_THEM_ZAP))
    142 		zap_text();
    143 	else
    144 #endif
    145 	if (openfile->current_x > 0) {
    146 		openfile->current_x = step_left(openfile->current->data, openfile->current_x);
    147 		expunge(BACK);
    148 	} else if (openfile->current != openfile->filetop) {
    149 		do_left();
    150 		expunge(BACK);
    151 	}
    152 }
    153 
    154 /* Return FALSE when a cut command would not actually cut anything: when
    155  * on an empty line at EOF, or when the mark covers zero characters, or
    156  * (when test_cliff is TRUE) when the magic line would be cut. */
    157 bool is_cuttable(bool test_cliff)
    158 {
    159 	size_t from = (test_cliff) ? openfile->current_x : 0;
    160 
    161 	if ((openfile->current->next == NULL && openfile->current->data[from] == '\0'
    162 #ifndef NANO_TINY
    163 					&& openfile->mark == NULL) ||
    164 					(openfile->mark == openfile->current &&
    165 					openfile->mark_x == openfile->current_x) ||
    166 					(from > 0 && !ISSET(NO_NEWLINES) &&
    167 					openfile->current->data[from] == '\0' &&
    168 					openfile->current->next == openfile->filebot
    169 #endif
    170 					)) {
    171 #ifndef NANO_TINY
    172 		statusbar(_("Nothing was cut"));
    173 		openfile->mark = NULL;
    174 #endif
    175 		return FALSE;
    176 	} else
    177 		return TRUE;
    178 }
    179 
    180 #ifndef NANO_TINY
    181 /* Delete text from the cursor until the first start of a word to
    182  * the left, or to the right when forward is TRUE. */
    183 void chop_word(bool forward)
    184 {
    185 	/* Remember the current cursor position. */
    186 	linestruct *is_current = openfile->current;
    187 	size_t is_current_x = openfile->current_x;
    188 	/* Remember where the cutbuffer is, then make it seem blank. */
    189 	linestruct *is_cutbuffer = cutbuffer;
    190 
    191 	cutbuffer = NULL;
    192 
    193 	/* Move the cursor to a word start, to the left or to the right.
    194 	 * If that word is on another line and the cursor was not already
    195 	 * on the edge of the original line, then put the cursor on that
    196 	 * edge instead, so that lines will not be joined unexpectedly. */
    197 	if (!forward) {
    198 		do_prev_word();
    199 		if (openfile->current != is_current) {
    200 			if (is_current_x > 0) {
    201 				openfile->current = is_current;
    202 				openfile->current_x = 0;
    203 			} else
    204 				openfile->current_x = strlen(openfile->current->data);
    205 		}
    206 	} else {
    207 		do_next_word(ISSET(AFTER_ENDS));
    208 		if (openfile->current != is_current &&
    209 							is_current->data[is_current_x] != '\0') {
    210 			openfile->current = is_current;
    211 			openfile->current_x = strlen(is_current->data);
    212 		}
    213 	}
    214 
    215 	/* Set the mark at the start of that word. */
    216 	openfile->mark = openfile->current;
    217 	openfile->mark_x = openfile->current_x;
    218 
    219 	/* Put the cursor back where it was, so an undo will put it there too. */
    220 	openfile->current = is_current;
    221 	openfile->current_x = is_current_x;
    222 
    223 	/* Now kill the marked region and a word is gone. */
    224 	add_undo(CUT, NULL);
    225 	do_snip(TRUE, FALSE, FALSE);
    226 	update_undo(CUT);
    227 
    228 	/* Discard the cut word and restore the cutbuffer. */
    229 	free_lines(cutbuffer);
    230 	cutbuffer = is_cutbuffer;
    231 }
    232 
    233 /* Delete a word leftward. */
    234 void chop_previous_word(void)
    235 {
    236 	if (openfile->current->prev == NULL && openfile->current_x == 0)
    237 		statusbar(_("Nothing was cut"));
    238 	else
    239 		chop_word(BACKWARD);
    240 }
    241 
    242 /* Delete a word rightward. */
    243 void chop_next_word(void)
    244 {
    245 	openfile->mark = NULL;
    246 
    247 	if (is_cuttable(TRUE))
    248 		chop_word(FORWARD);
    249 }
    250 #endif /* !NANO_TINY */
    251 
    252 /* Excise the text between the given two points and add it to the cutbuffer. */
    253 void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_x)
    254 {
    255 	linestruct *taken, *last;
    256 	bool edittop_inside = (openfile->edittop->lineno >= top->lineno &&
    257 							openfile->edittop->lineno <= bot->lineno);
    258 #ifndef NANO_TINY
    259 	bool same_line = (openfile->mark == top);
    260 	bool post_marked = (openfile->mark && (openfile->mark->lineno > top->lineno ||
    261 						(same_line && openfile->mark_x > top_x)));
    262 	static bool inherited_anchor = FALSE;
    263 	bool had_anchor = top->has_anchor;
    264 
    265 	if (top == bot && top_x == bot_x)
    266 		return;
    267 
    268 	if (top != bot)
    269 		for (linestruct *line = top->next; line != bot->next; line = line->next)
    270 			had_anchor |= line->has_anchor;
    271 #endif
    272 
    273 	if (top == bot) {
    274 		taken = make_new_node(NULL);
    275 		taken->data = measured_copy(top->data + top_x, bot_x - top_x);
    276 		memmove(top->data + top_x, top->data + bot_x, strlen(top->data + bot_x) + 1);
    277 		last = taken;
    278 	} else if (top_x == 0 && bot_x == 0) {
    279 		taken = top;
    280 		last = make_new_node(NULL);
    281 		last->data = copy_of("");
    282 #ifndef NANO_TINY
    283 		last->has_anchor = bot->has_anchor;
    284 #endif
    285 		last->prev = bot->prev;
    286 		bot->prev->next = last;
    287 		last->next = NULL;
    288 
    289 		bot->prev = top->prev;
    290 		if (top->prev)
    291 			top->prev->next = bot;
    292 		else
    293 			openfile->filetop = bot;
    294 
    295 		openfile->current = bot;
    296 	} else {
    297 		taken = make_new_node(NULL);
    298 		taken->data = copy_of(top->data + top_x);
    299 		taken->next = top->next;
    300 		top->next->prev = taken;
    301 
    302 		top->next = bot->next;
    303 		if (bot->next)
    304 			bot->next->prev = top;
    305 
    306 		top->data = nrealloc(top->data, top_x + strlen(bot->data + bot_x) + 1);
    307 		strcpy(top->data + top_x, bot->data + bot_x);
    308 
    309 		last = bot;
    310 		last->data[bot_x] = '\0';
    311 		last->next = NULL;
    312 
    313 		openfile->current = top;
    314 	}
    315 
    316 	/* Subtract the size of the excised text from the buffer size. */
    317 	openfile->totsize -= number_of_characters_in(taken, last);
    318 
    319 	/* If the cutbuffer is currently empty, just move all the text directly
    320 	 * into it; otherwise, append the text to what is already there. */
    321 	if (cutbuffer == NULL) {
    322 		cutbuffer = taken;
    323 		cutbottom = last;
    324 #ifndef NANO_TINY
    325 		inherited_anchor = taken->has_anchor;
    326 #endif
    327 	} else {
    328 		cutbottom->data = nrealloc(cutbottom->data,
    329 							strlen(cutbottom->data) + strlen(taken->data) + 1);
    330 		strcat(cutbottom->data, taken->data);
    331 #ifndef NANO_TINY
    332 		cutbottom->has_anchor = taken->has_anchor && !inherited_anchor;
    333 		inherited_anchor |= taken->has_anchor;
    334 #endif
    335 		cutbottom->next = taken->next;
    336 		delete_node(taken);
    337 
    338 		if (cutbottom->next != NULL) {
    339 			cutbottom->next->prev = cutbottom;
    340 			cutbottom = last;
    341 		}
    342 	}
    343 
    344 	openfile->current_x = top_x;
    345 
    346 #ifndef NANO_TINY
    347 	openfile->current->has_anchor = had_anchor;
    348 
    349 	if (post_marked || same_line)
    350 		openfile->mark = openfile->current;
    351 	if (post_marked)
    352 		openfile->mark_x = openfile->current_x;
    353 #endif
    354 	if (openfile->filebot == bot)
    355 		openfile->filebot = openfile->current;
    356 
    357 	renumber_from(openfile->current);
    358 
    359 	/* When the beginning of the viewport was inside the excision, adjust. */
    360 	if (edittop_inside) {
    361 		adjust_viewport(STATIONARY);
    362 		refresh_needed = TRUE;
    363 	}
    364 
    365 	/* If the text doesn't end with a newline, and it should, add one. */
    366 	if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
    367 		new_magicline();
    368 }
    369 
    370 /* Meld the buffer that starts at topline into the current file buffer
    371  * at the current cursor position. */
    372 void ingraft_buffer(linestruct *topline)
    373 {
    374 	linestruct *line = openfile->current;
    375 	size_t length = strlen(line->data);
    376 	size_t extralen = strlen(topline->data);
    377 	size_t xpos = openfile->current_x;
    378 	char *tailtext = copy_of(line->data + xpos);
    379 #ifndef NANO_TINY
    380 	bool mark_follows = (openfile->mark == line && !mark_is_before_cursor());
    381 #endif
    382 	linestruct *botline = topline;
    383 
    384 	while (botline->next != NULL)
    385 		botline = botline->next;
    386 
    387 	/* Add the size of the text to be grafted to the buffer size. */
    388 	openfile->totsize += number_of_characters_in(topline, botline);
    389 
    390 	if (topline != botline)
    391 		length = xpos;
    392 
    393 	if (extralen > 0) {
    394 		/* Insert the text of topline at the current cursor position. */
    395 		line->data = nrealloc(line->data, length + extralen + 1);
    396 		memmove(line->data + xpos + extralen, line->data + xpos, length - xpos + 1);
    397 		strncpy(line->data + xpos, topline->data, extralen);
    398 	}
    399 
    400 	if (topline != botline) {
    401 		/* When inserting at end-of-buffer, update the relevant pointer. */
    402 		if (line->next == NULL)
    403 			openfile->filebot = botline;
    404 
    405 		line->data[xpos + extralen] = '\0';
    406 
    407 		/* Hook the grafted lines in after the current one. */
    408 		botline->next = openfile->current->next;
    409 		if (botline->next)
    410 			botline->next->prev = botline;
    411 		openfile->current->next = topline->next;
    412 		topline->next->prev = openfile->current;
    413 
    414 		/* Add the text after the cursor position at the end of botline. */
    415 		length = strlen(botline->data);
    416 		extralen = strlen(tailtext);
    417 		botline->data = nrealloc(botline->data, length + extralen + 1);
    418 		strcpy(botline->data + length, tailtext);
    419 
    420 		/* Put the cursor at the end of the grafted text. */
    421 		openfile->current = botline;
    422 		openfile->current_x = length;
    423 	} else
    424 		openfile->current_x += extralen;
    425 
    426 #ifndef NANO_TINY
    427 	/* When needed, update the mark's pointer and position. */
    428 	if (mark_follows && topline != botline) {
    429 		openfile->mark = botline;
    430 		openfile->mark_x += length - xpos;
    431 	} else if (mark_follows)
    432 		openfile->mark_x += extralen;
    433 #endif
    434 
    435 	delete_node(topline);
    436 	free(tailtext);
    437 
    438 	renumber_from(line);
    439 
    440 	/* If the text doesn't end with a newline, and it should, add one. */
    441 	if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0')
    442 		new_magicline();
    443 }
    444 
    445 /* Meld a copy of the given buffer into the current file buffer. */
    446 void copy_from_buffer(linestruct *somebuffer)
    447 {
    448 #ifdef ENABLE_COLOR
    449 	size_t threshold = openfile->edittop->lineno + editwinrows - 1;
    450 #endif
    451 	linestruct *the_copy = copy_buffer(somebuffer);
    452 
    453 	ingraft_buffer(the_copy);
    454 
    455 #ifdef ENABLE_COLOR
    456 	if (openfile->current->lineno > threshold || ISSET(SOFTWRAP))
    457 		recook = TRUE;
    458 	else
    459 		perturbed = TRUE;
    460 #endif
    461 }
    462 
    463 #ifndef NANO_TINY
    464 /* Move all marked text from the current buffer into the cutbuffer. */
    465 void cut_marked_region(void)
    466 {
    467 	linestruct *top, *bot;
    468 	size_t top_x, bot_x;
    469 
    470 	get_region(&top, &top_x, &bot, &bot_x);
    471 
    472 	extract_segment(top, top_x, bot, bot_x);
    473 
    474 	openfile->placewewant = xplustabs();
    475 }
    476 #endif
    477 
    478 /* Move text from the current buffer into the cutbuffer.
    479  * If until_eof is TRUE, move all text from the current cursor
    480  * position to the end of the file into the cutbuffer.  If append
    481  * is TRUE (when zapping), always append the cut to the cutbuffer. */
    482 void do_snip(bool marked, bool until_eof, bool append)
    483 {
    484 	linestruct *line = openfile->current;
    485 
    486 #ifndef NANO_TINY
    487 	keep_cutbuffer &= (openfile->last_action != COPY);
    488 #endif
    489 
    490 	/* If cuts were not continuous, or when cutting a region, clear the slate. */
    491 	if ((marked || until_eof || !keep_cutbuffer) && !append) {
    492 		free_lines(cutbuffer);
    493 		cutbuffer = NULL;
    494 	}
    495 
    496 #ifndef NANO_TINY
    497 	/* Now move the relevant piece of text into the cutbuffer. */
    498 	if (until_eof)
    499 		extract_segment(openfile->current, openfile->current_x,
    500 		                openfile->filebot, strlen(openfile->filebot->data));
    501 	else if (openfile->mark) {
    502 		cut_marked_region();
    503 		openfile->mark = NULL;
    504 	} else if (ISSET(CUT_FROM_CURSOR)) {
    505 		/* When not at the end of a line, move the rest of this line into
    506 		 * the cutbuffer.  Otherwise, when not at the end of the buffer,
    507 		 * move just the "line separator" into the cutbuffer. */
    508 		if (line->data[openfile->current_x] != '\0')
    509 			extract_segment(line, openfile->current_x, line, strlen(line->data));
    510 		else if (openfile->current != openfile->filebot) {
    511 			extract_segment(line, openfile->current_x, line->next, 0);
    512 			openfile->placewewant = xplustabs();
    513 		}
    514 	} else
    515 #endif
    516 	{
    517 		/* When not at end-of-buffer, move one full line into the cutbuffer;
    518 		 * otherwise, move all text until end-of-line into the cutbuffer. */
    519 		if (openfile->current != openfile->filebot)
    520 			extract_segment(line, 0, line->next, 0);
    521 		else
    522 			extract_segment(line, 0, line, strlen(line->data));
    523 
    524 		openfile->placewewant = 0;
    525 	}
    526 
    527 	/* After a line operation, future ones should add to the cutbuffer. */
    528 	keep_cutbuffer = !marked && !until_eof;
    529 
    530 	set_modified();
    531 	refresh_needed = TRUE;
    532 #ifdef ENABLE_COLOR
    533 	perturbed = TRUE;
    534 #endif
    535 }
    536 
    537 /* Move text from the current buffer into the cutbuffer. */
    538 void cut_text(void)
    539 {
    540 #ifndef NANO_TINY
    541 	if (!is_cuttable(ISSET(CUT_FROM_CURSOR) && openfile->mark == NULL))
    542 		return;
    543 
    544 	/* Only add a new undo item when the current item is not a CUT or when
    545 	 * the current cut is not contiguous with the previous cutting. */
    546 	if (openfile->last_action != CUT || !keep_cutbuffer) {
    547 		keep_cutbuffer = FALSE;
    548 		add_undo(CUT, NULL);
    549 	}
    550 
    551 	do_snip(openfile->mark != NULL, FALSE, FALSE);
    552 
    553 	update_undo(CUT);
    554 #else
    555 	if (is_cuttable(FALSE))
    556 		do_snip(FALSE, FALSE, FALSE);
    557 #endif
    558 	wipe_statusbar();
    559 }
    560 
    561 #ifndef NANO_TINY
    562 /* Cut from the current cursor position to the end of the file. */
    563 void cut_till_eof(void)
    564 {
    565 	ran_a_tool = TRUE;
    566 
    567 	if (openfile->current->data[openfile->current_x] == '\0' &&
    568 				(openfile->current->next == NULL ||
    569 				(!ISSET(NO_NEWLINES) && openfile->current_x > 0 &&
    570 				openfile->current->next == openfile->filebot))) {
    571 		statusbar(_("Nothing was cut"));
    572 		return;
    573 	}
    574 
    575 	add_undo(CUT_TO_EOF, NULL);
    576 	do_snip(FALSE, TRUE, FALSE);
    577 	update_undo(CUT_TO_EOF);
    578 	wipe_statusbar();
    579 }
    580 
    581 /* Erase text (current line or marked region), sending it into oblivion. */
    582 void zap_text(void)
    583 {
    584 	/* Remember the current cutbuffer so it can be restored after the zap. */
    585 	linestruct *was_cutbuffer = cutbuffer;
    586 
    587 	if (!is_cuttable(ISSET(CUT_FROM_CURSOR) && openfile->mark == NULL))
    588 		return;
    589 
    590 	/* Add a new undo item only when the current item is not a ZAP or when
    591 	 * the current zap is not contiguous with the previous zapping. */
    592 	if (openfile->last_action != ZAP || !keep_cutbuffer)
    593 		add_undo(ZAP, NULL);
    594 
    595 	/* Use the cutbuffer from the ZAP undo item, so the cut can be undone. */
    596 	cutbuffer = openfile->current_undo->cutbuffer;
    597 
    598 	do_snip(openfile->mark != NULL, FALSE, TRUE);
    599 
    600 	update_undo(ZAP);
    601 	wipe_statusbar();
    602 
    603 	cutbuffer = was_cutbuffer;
    604 }
    605 
    606 /* Make a copy of the marked region, putting it in the cutbuffer. */
    607 void copy_marked_region(void)
    608 {
    609 	linestruct *topline, *botline, *afterline;
    610 	char *was_datastart, saved_byte;
    611 	size_t top_x, bot_x;
    612 
    613 	get_region(&topline, &top_x, &botline, &bot_x);
    614 
    615 	openfile->last_action = OTHER;
    616 	keep_cutbuffer = FALSE;
    617 	openfile->mark = NULL;
    618 	refresh_needed = TRUE;
    619 
    620 	if (topline == botline && top_x == bot_x) {
    621 		statusbar(_("Copied nothing"));
    622 		return;
    623 	}
    624 
    625 	/* Make the area that was marked look like a separate buffer. */
    626 	afterline = botline->next;
    627 	botline->next = NULL;
    628 	saved_byte = botline->data[bot_x];
    629 	botline->data[bot_x] = '\0';
    630 	was_datastart = topline->data;
    631 	topline->data += top_x;
    632 
    633 	cutbuffer = copy_buffer(topline);
    634 
    635 	/* Restore the proper state of the buffer. */
    636 	topline->data = was_datastart;
    637 	botline->data[bot_x] = saved_byte;
    638 	botline->next = afterline;
    639 }
    640 #endif /* !NANO_TINY */
    641 
    642 /* Copy text from the current buffer into the cutbuffer.  The text is either
    643  * the marked region, the whole line, the text from cursor to end-of-line,
    644  * just the line break, or nothing, depending on mode and cursor position. */
    645 void copy_text(void)
    646 {
    647 	bool at_eol = (openfile->current->data[openfile->current_x] == '\0');
    648 	bool sans_newline = (ISSET(NO_NEWLINES) && openfile->current->next == NULL);
    649 	size_t from_x = (ISSET(CUT_FROM_CURSOR)) ? openfile->current_x : 0;
    650 	linestruct *was_current = openfile->current;
    651 	linestruct *addition;
    652 
    653 #ifndef NANO_TINY
    654 	if (openfile->mark || openfile->last_action != COPY)
    655 		keep_cutbuffer = FALSE;
    656 #endif
    657 
    658 	if (!keep_cutbuffer) {
    659 		free_lines(cutbuffer);
    660 		cutbuffer = NULL;
    661 	}
    662 
    663 	wipe_statusbar();
    664 
    665 #ifndef NANO_TINY
    666 	if (openfile->mark) {
    667 		copy_marked_region();
    668 		return;
    669 	}
    670 #endif
    671 
    672 	/* When at the very end of the buffer, there is nothing to do. */
    673 	if (openfile->current->next == NULL && at_eol && (ISSET(CUT_FROM_CURSOR) ||
    674 									openfile->current_x == 0 || cutbuffer)) {
    675 		statusbar(_("Copied nothing"));
    676 		return;
    677 	}
    678 
    679 	addition = make_new_node(NULL);
    680 	addition->data = copy_of(openfile->current->data + from_x);
    681 
    682 	if (ISSET(CUT_FROM_CURSOR))
    683 		sans_newline = !at_eol;
    684 
    685 	/* Create the cutbuffer OR add to it, depending on the mode, the position
    686 	 * of the cursor, and whether or not the cutbuffer is currently empty. */
    687 	if (cutbuffer == NULL && sans_newline) {
    688 		cutbuffer = addition;
    689 		cutbottom = addition;
    690 	} else if (cutbuffer == NULL) {
    691 		cutbuffer = addition;
    692 		cutbottom = make_new_node(cutbuffer);
    693 		cutbottom->data = copy_of("");
    694 		cutbuffer->next = cutbottom;
    695 	} else if (sans_newline) {
    696 		addition->prev = cutbottom->prev;
    697 		addition->prev->next = addition;
    698 		delete_node(cutbottom);
    699 		cutbottom = addition;
    700 	} else if (ISSET(CUT_FROM_CURSOR)) {
    701 		addition->prev = cutbottom;
    702 		cutbottom->next = addition;
    703 		cutbottom = addition;
    704 	} else {
    705 		addition->prev = cutbottom->prev;
    706 		addition->prev->next = addition;
    707 		addition->next = cutbottom;
    708 		cutbottom->prev = addition;
    709 	}
    710 
    711 	/* When needed and possible, move the cursor to the next line. */
    712 	if ((!ISSET(CUT_FROM_CURSOR) || at_eol) && openfile->current->next) {
    713 		openfile->current = openfile->current->next;
    714 		openfile->current_x = 0;
    715 	} else
    716 		openfile->current_x = strlen(openfile->current->data);
    717 
    718 	edit_redraw(was_current, FLOWING);
    719 
    720 #ifndef NANO_TINY
    721 	openfile->last_action = COPY;
    722 #endif
    723 	keep_cutbuffer = TRUE;
    724 }
    725 
    726 /* Copy text from the cutbuffer into the current buffer. */
    727 void paste_text(void)
    728 {
    729 #if defined(ENABLE_WRAPPING) || !defined(NANO_TINY)
    730 	/* Remember where the paste started. */
    731 	linestruct *was_current = openfile->current;
    732 #endif
    733 #ifndef NANO_TINY
    734 	bool had_anchor = was_current->has_anchor;
    735 #endif
    736 	ssize_t was_lineno = openfile->current->lineno;
    737 	size_t was_leftedge = 0;
    738 
    739 	if (cutbuffer == NULL) {
    740 		statusline(AHEM, _("Cutbuffer is empty"));
    741 		return;
    742 	}
    743 
    744 #ifndef NANO_TINY
    745 	add_undo(PASTE, NULL);
    746 
    747 	if (ISSET(SOFTWRAP))
    748 		was_leftedge = leftedge_for(xplustabs(), openfile->current);
    749 #endif
    750 
    751 	/* Add a copy of the text in the cutbuffer to the current buffer
    752 	 * at the current cursor position. */
    753 	copy_from_buffer(cutbuffer);
    754 
    755 #ifndef NANO_TINY
    756 	/* Wipe any anchors in the pasted text, so that they don't proliferate. */
    757 	for (linestruct *line = was_current; line != openfile->current->next; line = line->next)
    758 		line->has_anchor = FALSE;
    759 
    760 	was_current->has_anchor = had_anchor;
    761 
    762 	update_undo(PASTE);
    763 #endif
    764 
    765 #ifdef ENABLE_WRAPPING
    766 	/* When still on the same line and doing hard-wrapping, limit the width. */
    767 	if (openfile->current == was_current && ISSET(BREAK_LONG_LINES))
    768 		do_wrap();
    769 #endif
    770 
    771 	/* If we pasted less than a screenful, don't center the cursor. */
    772 	if (less_than_a_screenful(was_lineno, was_leftedge))
    773 		focusing = FALSE;
    774 #ifdef ENABLE_COLOR
    775 	else
    776 		precalc_multicolorinfo();
    777 #endif
    778 
    779 	/* Set the desired x position to where the pasted text ends. */
    780 	openfile->placewewant = xplustabs();
    781 
    782 	set_modified();
    783 	wipe_statusbar();
    784 	refresh_needed = TRUE;
    785 }