1/* $Id: cut.c,v 1.61 2007/01/01 05:15:32 dolorous Exp $ */
2/**************************************************************************
3 *   cut.c                                                                *
4 *                                                                        *
5 *   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Chris Allegretta    *
6 *   Copyright (C) 2005, 2006, 2007 David Lawrence Ramsey                 *
7 *   This program is free software; you can redistribute it and/or modify *
8 *   it under the terms of the GNU General Public License as published by *
9 *   the Free Software Foundation; either version 2, or (at your option)  *
10 *   any later version.                                                   *
11 *                                                                        *
12 *   This program is distributed in the hope that it will be useful, but  *
13 *   WITHOUT ANY WARRANTY; without even the implied warranty of           *
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    *
15 *   General Public License for more details.                             *
16 *                                                                        *
17 *   You should have received a copy of the GNU General Public License    *
18 *   along with this program; if not, write to the Free Software          *
19 *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA            *
20 *   02110-1301, USA.                                                     *
21 *                                                                        *
22 **************************************************************************/
23
24#include "proto.h"
25
26#include <string.h>
27#include <stdio.h>
28
29static bool keep_cutbuffer = FALSE;
30	/* Should we keep the contents of the cutbuffer? */
31static filestruct *cutbottom = NULL;
32	/* Pointer to the end of the cutbuffer. */
33
34/* Indicate that we should no longer keep the contents of the
35 * cutbuffer. */
36void cutbuffer_reset(void)
37{
38    keep_cutbuffer = FALSE;
39}
40
41/* If we aren't on the last line of the file, move all the text of the
42 * current line, plus the newline at the end, into the cutbuffer.  If we
43 * are, move all of the text of the current line into the cutbuffer.  In
44 * both cases, set the current place we want to the beginning of the
45 * current line. */
46void cut_line(void)
47{
48    if (openfile->current != openfile->filebot)
49	move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, 0,
50		openfile->current->next, 0);
51    else
52	move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, 0,
53		openfile->current, strlen(openfile->current->data));
54    openfile->placewewant = 0;
55}
56
57#ifndef NANO_TINY
58/* Move all currently marked text into the cutbuffer, and set the
59 * current place we want to where the text used to start. */
60void cut_marked(void)
61{
62    filestruct *top, *bot;
63    size_t top_x, bot_x;
64
65    mark_order((const filestruct **)&top, &top_x,
66	(const filestruct **)&bot, &bot_x, NULL);
67
68    move_to_filestruct(&cutbuffer, &cutbottom, top, top_x, bot, bot_x);
69    openfile->placewewant = xplustabs();
70}
71
72/* If we aren't at the end of the current line, move all the text from
73 * the current cursor position to the end of the current line, not
74 * counting the newline at the end, into the cutbuffer.  If we are, and
75 * we're not on the last line of the file, move the newline at the end
76 * into the cutbuffer, and set the current place we want to where the
77 * newline used to be. */
78void cut_to_eol(void)
79{
80    size_t data_len = strlen(openfile->current->data);
81
82    assert(openfile->current_x <= data_len);
83
84    if (openfile->current_x < data_len)
85	/* If we're not at the end of the line, move all the text from
86	 * the current position up to it, not counting the newline at
87	 * the end, into the cutbuffer. */
88	move_to_filestruct(&cutbuffer, &cutbottom, openfile->current,
89		openfile->current_x, openfile->current, data_len);
90    else if (openfile->current != openfile->filebot) {
91	/* If we're at the end of the line, and it isn't the last line
92	 * of the file, move all the text from the current position up
93	 * to the beginning of the next line, i.e. the newline at the
94	 * end, into the cutbuffer. */
95	move_to_filestruct(&cutbuffer, &cutbottom, openfile->current,
96		openfile->current_x, openfile->current->next, 0);
97	openfile->placewewant = xplustabs();
98    }
99}
100
101/* Move all the text from the current cursor position to the end of the
102 * file into the cutbuffer. */
103void cut_to_eof(void)
104{
105    move_to_filestruct(&cutbuffer, &cutbottom, openfile->current,
106	openfile->current_x, openfile->filebot,
107	strlen(openfile->filebot->data));
108}
109#endif /* !NANO_TINY */
110
111/* Move text from the current filestruct into the cutbuffer.  If
112 * copy_text is TRUE, copy the text back into the filestruct afterward.
113 * If cut_till_end is TRUE, move all text from the current cursor
114 * position to the end of the file into the cutbuffer. */
115void do_cut_text(
116#ifndef NANO_TINY
117	bool copy_text, bool cut_till_end
118#else
119	void
120#endif
121	)
122{
123#ifndef NANO_TINY
124    filestruct *cb_save = NULL;
125	/* The current end of the cutbuffer, before we add text to
126	 * it. */
127    size_t cb_save_len = 0;
128	/* The length of the string at the current end of the cutbuffer,
129	 * before we add text to it.  */
130    bool old_no_newlines = ISSET(NO_NEWLINES);
131#endif
132
133    assert(openfile->current != NULL && openfile->current->data != NULL);
134
135    /* If keep_cutbuffer is FALSE and the cutbuffer isn't empty, blow
136     * away the text in the cutbuffer. */
137    if (!keep_cutbuffer && cutbuffer != NULL) {
138	free_filestruct(cutbuffer);
139	cutbuffer = NULL;
140#ifdef DEBUG
141	fprintf(stderr, "Blew away cutbuffer =)\n");
142#endif
143    }
144
145#ifndef NANO_TINY
146    if (copy_text) {
147	if (cutbuffer != NULL) {
148	    /* If the cutbuffer isn't empty, save where it currently
149	     * ends.  This is where we'll add the new text. */
150	    cb_save = cutbottom;
151	    cb_save_len = strlen(cutbottom->data);
152	}
153
154	/* Set NO_NEWLINES to TRUE, so that we don't disturb the last
155	 * line of the file when moving text to the cutbuffer. */
156	SET(NO_NEWLINES);
157    }
158#endif
159
160    /* Set keep_cutbuffer to TRUE, so that the text we're going to move
161     * into the cutbuffer will be added to the text already in the
162     * cutbuffer instead of replacing it. */
163    keep_cutbuffer = TRUE;
164
165#ifndef NANO_TINY
166    if (cut_till_end) {
167	/* If cut_till_end is TRUE, move all text up to the end of the
168	 * file into the cutbuffer. */
169	cut_to_eof();
170    } else if (openfile->mark_set) {
171	/* If the mark is on, move the marked text to the cutbuffer, and
172	 * turn the mark off. */
173	cut_marked();
174	openfile->mark_set = FALSE;
175    } else if (ISSET(CUT_TO_END))
176	/* If the CUT_TO_END flag is set, move all text up to the end of
177	 * the line into the cutbuffer. */
178	cut_to_eol();
179    else
180#endif
181	/* Move the entire line into the cutbuffer. */
182	cut_line();
183
184#ifndef NANO_TINY
185    if (copy_text) {
186	/* Copy the text in the cutbuffer, starting at its saved end if
187	 * there is one, back into the filestruct.  This effectively
188	 * uncuts the text we just cut without marking the file as
189	 * modified. */
190	if (cutbuffer != NULL) {
191	    if (cb_save != NULL) {
192		cb_save->data += cb_save_len;
193		copy_from_filestruct(cb_save, cutbottom);
194		cb_save->data -= cb_save_len;
195	    } else
196		copy_from_filestruct(cutbuffer, cutbottom);
197
198	    /* Set the current place we want to where the text from the
199	     * cutbuffer ends. */
200	    openfile->placewewant = xplustabs();
201	}
202
203	/* Set NO_NEWLINES back to what it was before, since we're done
204	 * disturbing the text. */
205	if (!old_no_newlines)
206	    UNSET(NO_NEWLINES);
207    } else
208#endif
209	/* Leave the text in the cutbuffer, and mark the file as
210	 * modified. */
211	set_modified();
212
213    /* Update the screen. */
214    edit_refresh();
215
216#ifdef DEBUG
217    dump_filestruct(cutbuffer);
218#endif
219}
220
221/* Move text from the current filestruct into the cutbuffer. */
222void do_cut_text_void(void)
223{
224    do_cut_text(
225#ifndef NANO_TINY
226	FALSE, FALSE
227#endif
228	);
229}
230
231#ifndef NANO_TINY
232/* Move text from the current filestruct into the cutbuffer, and copy it
233 * back into the filestruct afterward. */
234void do_copy_text(void)
235{
236    do_cut_text(TRUE, FALSE);
237}
238
239/* Cut from the current cursor position to the end of the file. */
240void do_cut_till_end(void)
241{
242    do_cut_text(FALSE, TRUE);
243}
244#endif /* !NANO_TINY */
245
246/* Copy text from the cutbuffer into the current filestruct. */
247void do_uncut_text(void)
248{
249    assert(openfile->current != NULL && openfile->current->data != NULL);
250
251    /* If the cutbuffer is empty, get out. */
252    if (cutbuffer == NULL)
253	return;
254
255    /* Add a copy of the text in the cutbuffer to the current filestruct
256     * at the current cursor position. */
257    copy_from_filestruct(cutbuffer, cutbottom);
258
259    /* Set the current place we want to where the text from the
260     * cutbuffer ends. */
261    openfile->placewewant = xplustabs();
262
263    /* Mark the file as modified. */
264    set_modified();
265
266    /* Update the screen. */
267    edit_refresh();
268
269#ifdef DEBUG
270    dump_filestruct_reverse();
271#endif
272}
273