blob: 5e8cba7569e01ced4d6df49a475e2fbdfed9b0ec [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
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include "config.h"
26#include "proto.h"
27#include "nano.h"
28
29#ifndef NANO_SMALL
30#include <libintl.h>
31#define _(string) gettext(string)
32#else
33#define _(string) (string)
34#endif
35
36static int marked_cut; /* Is the cutbuffer from a mark */
37static filestruct *cutbottom = NULL; /* Pointer to end of cutbuffer */
38
39void add_to_cutbuffer(filestruct * inptr)
40{
41 filestruct *tmp;
42
43#ifdef DEBUG
44 fprintf(stderr, _("add_to_cutbuffer called with inptr->data = %s\n"),
45 inptr->data);
46#endif
47
Robert Siemborskiea19c732000-06-09 00:52:26 +000048 totsize -= strlen(inptr->data);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000049 tmp = cutbuffer;
50 if (cutbuffer == NULL) {
51 cutbuffer = inptr;
52 inptr->prev = NULL;
53 } else {
54 cutbottom->next = inptr;
55 inptr->prev = cutbottom;
56 }
57
58 inptr->next = NULL;
59 cutbottom = inptr;
60}
61
62#ifndef NANO_SMALL
63void cut_marked_segment(filestruct * top, int top_x, filestruct * bot,
64 int bot_x)
65{
66 filestruct *tmp, *next;
67 char *tmpstr;
68
69 /* Set up the beginning of the cutbuffer */
70 tmp = copy_node(top);
71 tmpstr = nmalloc(strlen(&top->data[top_x]) + 1);
72 strcpy(tmpstr, &top->data[top_x]);
73 free(tmp->data);
74 tmp->data = tmpstr;
75
76 /* Chop off the end of the first line */
77 tmpstr = nmalloc(top_x + 1);
78 strncpy(tmpstr, top->data, top_x);
79 free(top->data);
80 top->data = tmpstr;
81
82 do {
83 next = tmp->next;
84 add_to_cutbuffer(tmp);
85 totlines--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +000086 totsize--; /* newline (add_to_cutbuffer doesn't count newlines) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000087 tmp = next;
88 }
89 while (next != bot && next != NULL);
90
91 dump_buffer(cutbuffer);
92 if (next == NULL)
93 return;
94 /* Now, paste bot[bot_x] into top[top_x] */
95 tmpstr = nmalloc(strlen(top->data) + strlen(&bot->data[bot_x]));
96 strncpy(tmpstr, top->data, top_x);
97 strcpy(&tmpstr[top_x], &bot->data[bot_x]);
98 free(top->data);
99 top->data = tmpstr;
100
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000101 null_at(bot->data, bot_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000102 next = bot->next;
103
104 /* We explicitly don't decrement totlines here because we don't snarf
Robert Siemborskiea19c732000-06-09 00:52:26 +0000105 * up a newline when we're grabbing the last line of the mark. For
106 * the same reason we don't do an extra totsize decrement */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000107
108 add_to_cutbuffer(bot);
109 top->next = next;
110 if (next != NULL)
111 next->prev = top;
112
113 dump_buffer(cutbuffer);
114 renumber(top);
115 current = top;
116 current_x = top_x;
117
118 /* If we're hitting the end of the buffer we should clean that up. */
119 if (bot == filebot) {
120 if (next != NULL) {
121 filebot = next;
122 } else {
123 filebot = top;
124 }
125 }
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000126 if (top->lineno < edittop->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000127 edit_update(top, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000128}
129#endif
130
131int do_cut_text(void)
132{
133 filestruct *tmp, *fileptr = current;
134#ifndef NANO_SMALL
135 char *tmpstr;
Chris Allegretta45dfda92000-07-25 03:20:07 +0000136 int newsize, cuttingtoend = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000137#endif
138
Chris Allegrettac86f7142000-08-07 14:39:32 +0000139 check_statblank();
Chris Allegretta0286ba42000-08-07 14:58:26 +0000140 if (fileptr == NULL || fileptr->data == NULL)
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000141 return 0;
142
143 tmp = fileptr->next;
144
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000145 if (!ISSET(KEEP_CUTBUFFER)) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000146 free_filestruct(cutbuffer);
147 cutbuffer = NULL;
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000148
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000149#ifdef DEBUG
150 fprintf(stderr, _("Blew away cutbuffer =)\n"));
151#endif
152 }
Chris Allegretta0286ba42000-08-07 14:58:26 +0000153
154 /* Must let cutbuffer get blown away first before we do this... */
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000155 if (fileptr == filebot && !ISSET(MARK_ISSET))
Chris Allegretta0286ba42000-08-07 14:58:26 +0000156 return 0;
157
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000158#ifndef NANO_SMALL
Chris Allegrettaf4e75e12000-07-24 18:28:30 +0000159 if (ISSET(CUT_TO_END) && !ISSET(MARK_ISSET)) {
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000160 if (current_x == strlen(current->data)) {
Chris Allegretta45dfda92000-07-25 03:20:07 +0000161 do_delete();
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000162 SET(KEEP_CUTBUFFER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000163 marked_cut = 2;
Chris Allegretta45dfda92000-07-25 03:20:07 +0000164 return 1;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000165 } else {
Chris Allegretta45dfda92000-07-25 03:20:07 +0000166 SET(MARK_ISSET);
167 SET(KEEP_CUTBUFFER);
168
169 mark_beginx = strlen(current->data);
170 mark_beginbuf = current;
171 cuttingtoend = 1;
172 }
Chris Allegretta627de192000-07-12 02:09:17 +0000173 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000174 if (ISSET(MARK_ISSET)) {
175 if (current->lineno == mark_beginbuf->lineno) {
176 tmp = copy_node(current);
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000177 newsize = abs(mark_beginx - current_x) + 1;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000178
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000179 tmpstr = nmalloc(newsize + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000180 if (current_x < mark_beginx) {
181 strncpy(tmpstr, &current->data[current_x], newsize);
182 memmove(&current->data[current_x],
183 &current->data[mark_beginx],
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000184 strlen(&current->data[mark_beginx]) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000185 } else {
186 strncpy(tmpstr, &current->data[mark_beginx], newsize);
187 memmove(&current->data[mark_beginx],
188 &current->data[current_x],
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000189 strlen(&current->data[current_x]) + 1);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000190 current_x = mark_beginx;
191 update_cursor();
192 }
Chris Allegretta09f39cb2001-02-05 13:43:23 +0000193 tmpstr[newsize - 1] = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000194 tmp->data = tmpstr;
195 add_to_cutbuffer(tmp);
196 dump_buffer(cutbuffer);
197 align(&current->data);
198 } else if (current->lineno < mark_beginbuf->lineno)
199 cut_marked_segment(current, current_x, mark_beginbuf,
200 mark_beginx);
201 else
202 cut_marked_segment(mark_beginbuf, mark_beginx, current,
203 current_x);
204
205 placewewant = xplustabs();
206 UNSET(MARK_ISSET);
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000207
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000208 marked_cut = 1;
209 set_modified();
Chris Allegretta45dfda92000-07-25 03:20:07 +0000210 if (cuttingtoend)
211 edit_refresh();
212 else
Chris Allegretta234a34d2000-07-29 04:33:38 +0000213 edit_update(current, CENTER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000214
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000215 return 1;
216#else
217 if (0) {
218#endif
219 } else if (fileptr == fileage) {
220 /* we're cutting the first line */
221 if (fileptr->next != NULL) {
222 fileptr = fileptr->next;
223 tmp = fileptr;
224 fileage = fileptr;
225 add_to_cutbuffer(fileptr->prev);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000226 totsize--; /* get the newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000227 totlines--;
228 fileptr->prev = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000229 current = fileptr;
Chris Allegretta7dc14e82000-08-05 16:03:19 +0000230 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000231 } else {
232 add_to_cutbuffer(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000233 fileage = make_new_node(NULL);
234 fileage->data = nmalloc(1);
Robert Siemborskiea19c732000-06-09 00:52:26 +0000235 fileage->data[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000236 current = fileage;
237 }
238 } else {
239 if (fileptr->prev != NULL)
240 fileptr->prev->next = fileptr->next;
241
242 if (fileptr->next != NULL) {
243 (fileptr->next)->prev = fileptr->prev;
244 current = fileptr->next;
245 totlines--;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000246 totsize--; /* get the newline */
247 }
248 /* No longer an else here, because we never get here anymore...
249 No need to cut the magic line, as it's empty */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000250 add_to_cutbuffer(fileptr);
251 }
252
253 if (fileptr == edittop)
254 edittop = current;
255
256 edit_refresh();
257
258 dump_buffer(cutbuffer);
259 reset_cursor();
260
261 set_modified();
262 marked_cut = 0;
263 current_x = 0;
264 placewewant = 0;
265 update_cursor();
266 renumber(tmp);
267 SET(KEEP_CUTBUFFER);
268 return 1;
269}
270
271int do_uncut_text(void)
272{
Chris Allegretta3bc8c722000-12-10 17:03:25 +0000273 filestruct *tmp = current, *fileptr = current, *newbuf, *newend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000274#ifndef NANO_SMALL
275 char *tmpstr, *tmpstr2;
Chris Allegretta3bc8c722000-12-10 17:03:25 +0000276 filestruct *hold = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000277#endif
278 int i;
279
280 wrap_reset();
Chris Allegrettac86f7142000-08-07 14:39:32 +0000281 check_statblank();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000282 if (cutbuffer == NULL || fileptr == NULL)
283 return 0; /* AIEEEEEEEEEEEE */
284
285 newbuf = copy_filestruct(cutbuffer);
286 for (newend = newbuf; newend->next != NULL && newend != NULL;
287 newend = newend->next) {
288 totlines++;
289 }
290
291 /* Hook newbuf into fileptr */
292#ifndef NANO_SMALL
Chris Allegretta1013e142000-07-27 04:31:52 +0000293 if (marked_cut) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000294 /* If there's only one line in the cutbuffer */
295 if (cutbuffer->next == NULL) {
296 tmpstr =
297 nmalloc(strlen(current->data) + strlen(cutbuffer->data) +
298 1);
299 strncpy(tmpstr, current->data, current_x);
300 strcpy(&tmpstr[current_x], cutbuffer->data);
301 strcat(tmpstr, &current->data[current_x]);
302 free(current->data);
303 current->data = tmpstr;
304 current_x += strlen(cutbuffer->data);
305 totsize += strlen(cutbuffer->data);
306
307 placewewant = xplustabs();
308 update_cursor();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000309 } else { /* yuck -- no kidding! */
310 tmp = current->next;
311 /* New beginning */
312 tmpstr = nmalloc(current_x + strlen(newbuf->data) + 1);
313 strncpy(tmpstr, current->data, current_x);
314 strcpy(&tmpstr[current_x], newbuf->data);
315 totsize += strlen(newbuf->data) + strlen(newend->data) + 1;
316
317 /* New end */
318 tmpstr2 = nmalloc(strlen(newend->data) +
319 strlen(&current->data[current_x]) + 1);
320 strcpy(tmpstr2, newend->data);
321 strcat(tmpstr2, &current->data[current_x]);
322
323 free(current->data);
324 current->data = tmpstr;
325 current->next = newbuf->next;
326 newbuf->next->prev = current;
327 delete_node(newbuf);
328
329 current_x = strlen(newend->data);
330 placewewant = xplustabs();
331 free(newend->data);
332 newend->data = tmpstr2;
333
334 newend->next = tmp;
335
336 /* If tmp isn't null, we're in the middle: update the
337 * prev pointer. If it IS null, we're at the end, update
338 * the filebot pointer */
339
340 if (tmp != NULL)
341 tmp->prev = newend;
Chris Allegretta5146fec2000-12-10 05:44:02 +0000342 else {
343 /* Fix the editbot pointer too */
344 if (editbot == filebot)
345 editbot = newend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000346 filebot = newend;
Chris Allegrettae51c95f2000-12-10 05:54:27 +0000347 new_magicline();
Chris Allegretta5146fec2000-12-10 05:44:02 +0000348 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000349
350 /* Now why don't we update the totsize also */
351 for (tmp = current->next; tmp != newend; tmp = tmp->next)
352 totsize += strlen(tmp->data) + 1;
353
354 i = editbot->lineno;
355
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000356 current = newend;
357 if (i <= newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000358 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000359 }
360
Chris Allegretta293849e2000-07-27 05:09:22 +0000361 /* If marked cut == 2, that means that we're doing a cut to end
362 and we don't want anything else on the line, so we have to
363 screw up all the work we just did and separate the line. There
364 must be a better way to do this, but not at 1AM on a work night. */
365
366 if (marked_cut == 2 && current_x != strlen(current->data)) {
367 tmp = make_new_node(current);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000368 tmp->data = nmalloc(strlen(&current->data[current_x]) + 1);
Chris Allegretta293849e2000-07-27 05:09:22 +0000369 strcpy(tmp->data, &current->data[current_x]);
Chris Allegretta7975ed82000-07-28 00:58:35 +0000370 splice_node(current, tmp, current->next);
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000371 null_at(current->data, current_x);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000372 current = current->next;
373 current_x = 0;
374 placewewant = 0;
Chris Allegretta293849e2000-07-27 05:09:22 +0000375 }
Chris Allegretta5146fec2000-12-10 05:44:02 +0000376 /* Renumber from BEFORE where we pasted ;) */
377 renumber(hold);
378
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000379 dump_buffer(fileage);
380 dump_buffer(cutbuffer);
381 set_modified();
382 edit_refresh();
383 return 0;
384#else
385 if (0) {
386#endif
387 } else if (fileptr != fileage) {
388 tmp = fileptr->prev;
389 tmp->next = newbuf;
390 newbuf->prev = tmp;
391 totlines++; /* Unmarked uncuts don't split lines */
392 } else {
393 fileage = newbuf;
394 totlines++; /* Unmarked uncuts don't split lines */
395 }
396
397 /* This is so uncutting at the top of the buffer will work => */
398 if (current_y == 0)
399 edittop = newbuf;
400
401 /* Connect the end of the buffer to the filestruct */
402 newend->next = fileptr;
403 fileptr->prev = newend;
404
405 /* recalculate size *sigh* */
406 for (tmp = newbuf; tmp != fileptr; tmp = tmp->next)
407 totsize += strlen(tmp->data) + 1;
408
409 i = editbot->lineno;
410 renumber(newbuf);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000411 if (i < newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000412 edit_update(fileptr, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000413
414 dump_buffer_reverse(fileptr);
415
416 set_modified();
417 UNSET(KEEP_CUTBUFFER);
418 edit_refresh();
419 return 1;
420}