blob: f5a3232a8da8a831aba59ef4065564f079957aed [file] [log] [blame]
Chris Allegretta11b00112000-08-06 21:13:45 +00001/* $Id$ */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00002/**************************************************************************
3 * cut.c *
4 * *
5 * Copyright (C) 1999 Chris Allegretta *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 1, or (at your option) *
9 * any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
19 * *
20 **************************************************************************/
21
Chris Allegretta6efda542001-04-28 18:03:52 +000022#include "config.h"
23
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000024#include <stdlib.h>
25#include <string.h>
26#include <stdio.h>
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000027#include "proto.h"
28#include "nano.h"
29
30#ifndef NANO_SMALL
31#include <libintl.h>
32#define _(string) gettext(string)
33#else
34#define _(string) (string)
35#endif
36
37static int marked_cut; /* Is the cutbuffer from a mark */
38static filestruct *cutbottom = NULL; /* Pointer to end of cutbuffer */
39
40void add_to_cutbuffer(filestruct * inptr)
41{
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000042#ifdef DEBUG
43 fprintf(stderr, _("add_to_cutbuffer called with inptr->data = %s\n"),
44 inptr->data);
45#endif
46
Robert Siemborskiea19c732000-06-09 00:52:26 +000047 totsize -= strlen(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000048 if (cutbuffer == NULL) {
49 cutbuffer = inptr;
50 inptr->prev = NULL;
51 } else {
52 cutbottom->next = inptr;
53 inptr->prev = cutbottom;
54 }
55
56 inptr->next = NULL;
57 cutbottom = inptr;
58}
59
60#ifndef NANO_SMALL
61void cut_marked_segment(filestruct * top, int top_x, filestruct * bot,
62 int bot_x)
63{
64 filestruct *tmp, *next;
65 char *tmpstr;
66
67 /* Set up the beginning of the cutbuffer */
68 tmp = copy_node(top);
69 tmpstr = nmalloc(strlen(&top->data[top_x]) + 1);
70 strcpy(tmpstr, &top->data[top_x]);
71 free(tmp->data);
72 tmp->data = tmpstr;
73
74 /* Chop off the end of the first line */
75 tmpstr = nmalloc(top_x + 1);
76 strncpy(tmpstr, top->data, top_x);
77 free(top->data);
78 top->data = tmpstr;
79
80 do {
81 next = tmp->next;
82 add_to_cutbuffer(tmp);
83 totlines--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +000084 totsize--; /* newline (add_to_cutbuffer doesn't count newlines) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000085 tmp = next;
86 }
87 while (next != bot && next != NULL);
88
89 dump_buffer(cutbuffer);
90 if (next == NULL)
91 return;
92 /* Now, paste bot[bot_x] into top[top_x] */
93 tmpstr = nmalloc(strlen(top->data) + strlen(&bot->data[bot_x]));
94 strncpy(tmpstr, top->data, top_x);
95 strcpy(&tmpstr[top_x], &bot->data[bot_x]);
96 free(top->data);
97 top->data = tmpstr;
98
Chris Allegretta6925bbd2000-07-28 01:41:29 +000099 null_at(bot->data, bot_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000100 next = bot->next;
101
102 /* We explicitly don't decrement totlines here because we don't snarf
Robert Siemborskiea19c732000-06-09 00:52:26 +0000103 * up a newline when we're grabbing the last line of the mark. For
Chris Allegretta88520c92001-05-05 17:45:54 +0000104 * the same reason, we don't do an extra totsize decrement. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000105
106 add_to_cutbuffer(bot);
107 top->next = next;
108 if (next != NULL)
109 next->prev = top;
110
111 dump_buffer(cutbuffer);
112 renumber(top);
113 current = top;
114 current_x = top_x;
115
Chris Allegretta88520c92001-05-05 17:45:54 +0000116 /* If we're hitting the end of the buffer, we should clean that up. */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000117 if (bot == filebot) {
118 if (next != NULL) {
119 filebot = next;
120 } else {
121 filebot = top;
122 }
123 }
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000124 if (top->lineno < edittop->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000125 edit_update(top, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000126}
127#endif
128
129int do_cut_text(void)
130{
131 filestruct *tmp, *fileptr = current;
132#ifndef NANO_SMALL
133 char *tmpstr;
Chris Allegretta45dfda92000-07-25 03:20:07 +0000134 int newsize, cuttingtoend = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000135#endif
136
Chris Allegrettac86f7142000-08-07 14:39:32 +0000137 check_statblank();
Chris Allegretta0286ba42000-08-07 14:58:26 +0000138 if (fileptr == NULL || fileptr->data == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000139 return 0;
140
141 tmp = fileptr->next;
142
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000143 if (!ISSET(KEEP_CUTBUFFER)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000144 free_filestruct(cutbuffer);
145 cutbuffer = NULL;
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000146
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000147#ifdef DEBUG
148 fprintf(stderr, _("Blew away cutbuffer =)\n"));
149#endif
150 }
Chris Allegretta0286ba42000-08-07 14:58:26 +0000151
152 /* Must let cutbuffer get blown away first before we do this... */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000153 if (fileptr == filebot && !ISSET(MARK_ISSET))
Chris Allegretta0286ba42000-08-07 14:58:26 +0000154 return 0;
155
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000156#ifndef NANO_SMALL
Chris Allegrettaf4e75e12000-07-24 18:28:30 +0000157 if (ISSET(CUT_TO_END) && !ISSET(MARK_ISSET)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000158 if (current_x == strlen(current->data)) {
Chris Allegretta45dfda92000-07-25 03:20:07 +0000159 do_delete();
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000160 SET(KEEP_CUTBUFFER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000161 marked_cut = 2;
Chris Allegretta45dfda92000-07-25 03:20:07 +0000162 return 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000163 } else {
Chris Allegretta45dfda92000-07-25 03:20:07 +0000164 SET(MARK_ISSET);
165 SET(KEEP_CUTBUFFER);
166
167 mark_beginx = strlen(current->data);
168 mark_beginbuf = current;
169 cuttingtoend = 1;
170 }
Chris Allegretta627de192000-07-12 02:09:17 +0000171 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000172 if (ISSET(MARK_ISSET)) {
173 if (current->lineno == mark_beginbuf->lineno) {
174 tmp = copy_node(current);
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000175 newsize = abs(mark_beginx - current_x) + 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000176
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000177 tmpstr = nmalloc(newsize + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000178 if (current_x < mark_beginx) {
179 strncpy(tmpstr, &current->data[current_x], newsize);
180 memmove(&current->data[current_x],
181 &current->data[mark_beginx],
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000182 strlen(&current->data[mark_beginx]) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000183 } else {
184 strncpy(tmpstr, &current->data[mark_beginx], newsize);
185 memmove(&current->data[mark_beginx],
186 &current->data[current_x],
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000187 strlen(&current->data[current_x]) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000188 current_x = mark_beginx;
189 update_cursor();
190 }
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000191 tmpstr[newsize - 1] = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000192 tmp->data = tmpstr;
193 add_to_cutbuffer(tmp);
194 dump_buffer(cutbuffer);
195 align(&current->data);
196 } else if (current->lineno < mark_beginbuf->lineno)
197 cut_marked_segment(current, current_x, mark_beginbuf,
198 mark_beginx);
199 else
200 cut_marked_segment(mark_beginbuf, mark_beginx, current,
201 current_x);
202
203 placewewant = xplustabs();
204 UNSET(MARK_ISSET);
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000205
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000206 marked_cut = 1;
207 set_modified();
Chris Allegretta45dfda92000-07-25 03:20:07 +0000208 if (cuttingtoend)
209 edit_refresh();
210 else
Chris Allegretta234a34d2000-07-29 04:33:38 +0000211 edit_update(current, CENTER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000212
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000213 return 1;
214#else
215 if (0) {
216#endif
217 } else if (fileptr == fileage) {
218 /* we're cutting the first line */
219 if (fileptr->next != NULL) {
220 fileptr = fileptr->next;
221 tmp = fileptr;
222 fileage = fileptr;
223 add_to_cutbuffer(fileptr->prev);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000224 totsize--; /* get the newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000225 totlines--;
226 fileptr->prev = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000227 current = fileptr;
Chris Allegretta7dc14e82000-08-05 16:03:19 +0000228 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000229 } else {
230 add_to_cutbuffer(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000231 fileage = make_new_node(NULL);
232 fileage->data = nmalloc(1);
Robert Siemborskiea19c732000-06-09 00:52:26 +0000233 fileage->data[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000234 current = fileage;
235 }
236 } else {
237 if (fileptr->prev != NULL)
238 fileptr->prev->next = fileptr->next;
239
240 if (fileptr->next != NULL) {
241 (fileptr->next)->prev = fileptr->prev;
242 current = fileptr->next;
243 totlines--;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000244 totsize--; /* get the newline */
245 }
246 /* No longer an else here, because we never get here anymore...
247 No need to cut the magic line, as it's empty */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000248 add_to_cutbuffer(fileptr);
249 }
250
251 if (fileptr == edittop)
252 edittop = current;
253
254 edit_refresh();
255
256 dump_buffer(cutbuffer);
257 reset_cursor();
258
259 set_modified();
260 marked_cut = 0;
261 current_x = 0;
262 placewewant = 0;
263 update_cursor();
264 renumber(tmp);
265 SET(KEEP_CUTBUFFER);
266 return 1;
267}
268
269int do_uncut_text(void)
270{
Chris Allegretta3bc8c722000-12-10 17:03:25 +0000271 filestruct *tmp = current, *fileptr = current, *newbuf, *newend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000272#ifndef NANO_SMALL
273 char *tmpstr, *tmpstr2;
Chris Allegretta3bc8c722000-12-10 17:03:25 +0000274 filestruct *hold = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000275#endif
276 int i;
277
278 wrap_reset();
Chris Allegrettac86f7142000-08-07 14:39:32 +0000279 check_statblank();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000280 if (cutbuffer == NULL || fileptr == NULL)
281 return 0; /* AIEEEEEEEEEEEE */
282
283 newbuf = copy_filestruct(cutbuffer);
284 for (newend = newbuf; newend->next != NULL && newend != NULL;
285 newend = newend->next) {
286 totlines++;
287 }
288
289 /* Hook newbuf into fileptr */
290#ifndef NANO_SMALL
Chris Allegretta1013e142000-07-27 04:31:52 +0000291 if (marked_cut) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000292 /* If there's only one line in the cutbuffer */
293 if (cutbuffer->next == NULL) {
294 tmpstr =
295 nmalloc(strlen(current->data) + strlen(cutbuffer->data) +
296 1);
297 strncpy(tmpstr, current->data, current_x);
298 strcpy(&tmpstr[current_x], cutbuffer->data);
299 strcat(tmpstr, &current->data[current_x]);
300 free(current->data);
301 current->data = tmpstr;
302 current_x += strlen(cutbuffer->data);
303 totsize += strlen(cutbuffer->data);
304
305 placewewant = xplustabs();
306 update_cursor();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000307 } else { /* yuck -- no kidding! */
308 tmp = current->next;
309 /* New beginning */
310 tmpstr = nmalloc(current_x + strlen(newbuf->data) + 1);
311 strncpy(tmpstr, current->data, current_x);
312 strcpy(&tmpstr[current_x], newbuf->data);
313 totsize += strlen(newbuf->data) + strlen(newend->data) + 1;
314
315 /* New end */
316 tmpstr2 = nmalloc(strlen(newend->data) +
317 strlen(&current->data[current_x]) + 1);
318 strcpy(tmpstr2, newend->data);
319 strcat(tmpstr2, &current->data[current_x]);
320
321 free(current->data);
322 current->data = tmpstr;
323 current->next = newbuf->next;
324 newbuf->next->prev = current;
325 delete_node(newbuf);
326
327 current_x = strlen(newend->data);
328 placewewant = xplustabs();
329 free(newend->data);
330 newend->data = tmpstr2;
331
332 newend->next = tmp;
333
334 /* If tmp isn't null, we're in the middle: update the
Chris Allegretta88520c92001-05-05 17:45:54 +0000335 * prev pointer. If it IS null, we're at the end; update
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000336 * the filebot pointer */
337
338 if (tmp != NULL)
339 tmp->prev = newend;
Chris Allegretta5146fec2000-12-10 05:44:02 +0000340 else {
341 /* Fix the editbot pointer too */
342 if (editbot == filebot)
343 editbot = newend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000344 filebot = newend;
Chris Allegrettae51c95f2000-12-10 05:54:27 +0000345 new_magicline();
Chris Allegretta5146fec2000-12-10 05:44:02 +0000346 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000347
348 /* Now why don't we update the totsize also */
349 for (tmp = current->next; tmp != newend; tmp = tmp->next)
350 totsize += strlen(tmp->data) + 1;
351
352 i = editbot->lineno;
353
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000354 current = newend;
355 if (i <= newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000356 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000357 }
358
Chris Allegretta293849e2000-07-27 05:09:22 +0000359 /* If marked cut == 2, that means that we're doing a cut to end
360 and we don't want anything else on the line, so we have to
361 screw up all the work we just did and separate the line. There
362 must be a better way to do this, but not at 1AM on a work night. */
363
364 if (marked_cut == 2 && current_x != strlen(current->data)) {
365 tmp = make_new_node(current);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000366 tmp->data = nmalloc(strlen(&current->data[current_x]) + 1);
Chris Allegretta293849e2000-07-27 05:09:22 +0000367 strcpy(tmp->data, &current->data[current_x]);
Chris Allegretta7975ed82000-07-28 00:58:35 +0000368 splice_node(current, tmp, current->next);
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000369 null_at(current->data, current_x);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000370 current = current->next;
371 current_x = 0;
372 placewewant = 0;
Chris Allegretta293849e2000-07-27 05:09:22 +0000373 }
Chris Allegretta5146fec2000-12-10 05:44:02 +0000374 /* Renumber from BEFORE where we pasted ;) */
375 renumber(hold);
376
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000377 dump_buffer(fileage);
378 dump_buffer(cutbuffer);
379 set_modified();
380 edit_refresh();
381 return 0;
382#else
383 if (0) {
384#endif
385 } else if (fileptr != fileage) {
386 tmp = fileptr->prev;
387 tmp->next = newbuf;
388 newbuf->prev = tmp;
389 totlines++; /* Unmarked uncuts don't split lines */
390 } else {
391 fileage = newbuf;
392 totlines++; /* Unmarked uncuts don't split lines */
393 }
394
395 /* This is so uncutting at the top of the buffer will work => */
396 if (current_y == 0)
397 edittop = newbuf;
398
399 /* Connect the end of the buffer to the filestruct */
400 newend->next = fileptr;
401 fileptr->prev = newend;
402
403 /* recalculate size *sigh* */
404 for (tmp = newbuf; tmp != fileptr; tmp = tmp->next)
405 totsize += strlen(tmp->data) + 1;
406
407 i = editbot->lineno;
408 renumber(newbuf);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000409 if (i < newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000410 edit_update(fileptr, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000411
412 dump_buffer_reverse(fileptr);
413
414 set_modified();
415 UNSET(KEEP_CUTBUFFER);
416 edit_refresh();
417 return 1;
418}