blob: 1d9d2b765aec5f9edb76c01df77c358c048f4460 [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);
177 newsize = abs(strlen(&current->data[mark_beginx]) -
178 strlen(&current->data[current_x]));
179
180 tmpstr = nmalloc(newsize);
181 if (current_x < mark_beginx) {
182 strncpy(tmpstr, &current->data[current_x], newsize);
183 memmove(&current->data[current_x],
184 &current->data[mark_beginx],
185 strlen(&current->data[mark_beginx] - newsize));
186 } else {
187 strncpy(tmpstr, &current->data[mark_beginx], newsize);
188 memmove(&current->data[mark_beginx],
189 &current->data[current_x],
190 strlen(&current->data[current_x] - newsize));
191 current_x = mark_beginx;
192 update_cursor();
193 }
194 tmpstr[newsize] = 0;
195 tmp->data = tmpstr;
196 add_to_cutbuffer(tmp);
197 dump_buffer(cutbuffer);
198 align(&current->data);
199 } else if (current->lineno < mark_beginbuf->lineno)
200 cut_marked_segment(current, current_x, mark_beginbuf,
201 mark_beginx);
202 else
203 cut_marked_segment(mark_beginbuf, mark_beginx, current,
204 current_x);
205
206 placewewant = xplustabs();
207 UNSET(MARK_ISSET);
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000208
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000209 marked_cut = 1;
210 set_modified();
Chris Allegretta45dfda92000-07-25 03:20:07 +0000211 if (cuttingtoend)
212 edit_refresh();
213 else
Chris Allegretta234a34d2000-07-29 04:33:38 +0000214 edit_update(current, CENTER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000215
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000216 return 1;
217#else
218 if (0) {
219#endif
220 } else if (fileptr == fileage) {
221 /* we're cutting the first line */
222 if (fileptr->next != NULL) {
223 fileptr = fileptr->next;
224 tmp = fileptr;
225 fileage = fileptr;
226 add_to_cutbuffer(fileptr->prev);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000227 totsize--; /* get the newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000228 totlines--;
229 fileptr->prev = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000230 current = fileptr;
Chris Allegretta7dc14e82000-08-05 16:03:19 +0000231 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000232 } else {
233 add_to_cutbuffer(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000234 fileage = make_new_node(NULL);
235 fileage->data = nmalloc(1);
Robert Siemborskiea19c732000-06-09 00:52:26 +0000236 fileage->data[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000237 current = fileage;
238 }
239 } else {
240 if (fileptr->prev != NULL)
241 fileptr->prev->next = fileptr->next;
242
243 if (fileptr->next != NULL) {
244 (fileptr->next)->prev = fileptr->prev;
245 current = fileptr->next;
246 totlines--;
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000247 totsize--; /* get the newline */
248 }
249 /* No longer an else here, because we never get here anymore...
250 No need to cut the magic line, as it's empty */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000251 add_to_cutbuffer(fileptr);
252 }
253
254 if (fileptr == edittop)
255 edittop = current;
256
257 edit_refresh();
258
259 dump_buffer(cutbuffer);
260 reset_cursor();
261
262 set_modified();
263 marked_cut = 0;
264 current_x = 0;
265 placewewant = 0;
266 update_cursor();
267 renumber(tmp);
268 SET(KEEP_CUTBUFFER);
269 return 1;
270}
271
272int do_uncut_text(void)
273{
Chris Allegretta3bc8c722000-12-10 17:03:25 +0000274 filestruct *tmp = current, *fileptr = current, *newbuf, *newend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000275#ifndef NANO_SMALL
276 char *tmpstr, *tmpstr2;
Chris Allegretta3bc8c722000-12-10 17:03:25 +0000277 filestruct *hold = current;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000278#endif
279 int i;
280
281 wrap_reset();
Chris Allegrettac86f7142000-08-07 14:39:32 +0000282 check_statblank();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000283 if (cutbuffer == NULL || fileptr == NULL)
284 return 0; /* AIEEEEEEEEEEEE */
285
286 newbuf = copy_filestruct(cutbuffer);
287 for (newend = newbuf; newend->next != NULL && newend != NULL;
288 newend = newend->next) {
289 totlines++;
290 }
291
292 /* Hook newbuf into fileptr */
293#ifndef NANO_SMALL
Chris Allegretta1013e142000-07-27 04:31:52 +0000294 if (marked_cut) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000295 /* If there's only one line in the cutbuffer */
296 if (cutbuffer->next == NULL) {
297 tmpstr =
298 nmalloc(strlen(current->data) + strlen(cutbuffer->data) +
299 1);
300 strncpy(tmpstr, current->data, current_x);
301 strcpy(&tmpstr[current_x], cutbuffer->data);
302 strcat(tmpstr, &current->data[current_x]);
303 free(current->data);
304 current->data = tmpstr;
305 current_x += strlen(cutbuffer->data);
306 totsize += strlen(cutbuffer->data);
307
308 placewewant = xplustabs();
309 update_cursor();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000310 } else { /* yuck -- no kidding! */
311 tmp = current->next;
312 /* New beginning */
313 tmpstr = nmalloc(current_x + strlen(newbuf->data) + 1);
314 strncpy(tmpstr, current->data, current_x);
315 strcpy(&tmpstr[current_x], newbuf->data);
316 totsize += strlen(newbuf->data) + strlen(newend->data) + 1;
317
318 /* New end */
319 tmpstr2 = nmalloc(strlen(newend->data) +
320 strlen(&current->data[current_x]) + 1);
321 strcpy(tmpstr2, newend->data);
322 strcat(tmpstr2, &current->data[current_x]);
323
324 free(current->data);
325 current->data = tmpstr;
326 current->next = newbuf->next;
327 newbuf->next->prev = current;
328 delete_node(newbuf);
329
330 current_x = strlen(newend->data);
331 placewewant = xplustabs();
332 free(newend->data);
333 newend->data = tmpstr2;
334
335 newend->next = tmp;
336
337 /* If tmp isn't null, we're in the middle: update the
338 * prev pointer. If it IS null, we're at the end, update
339 * the filebot pointer */
340
341 if (tmp != NULL)
342 tmp->prev = newend;
Chris Allegretta5146fec2000-12-10 05:44:02 +0000343 else {
344 /* Fix the editbot pointer too */
345 if (editbot == filebot)
346 editbot = newend;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000347 filebot = newend;
Chris Allegrettae51c95f2000-12-10 05:54:27 +0000348 new_magicline();
Chris Allegretta5146fec2000-12-10 05:44:02 +0000349 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000350
351 /* Now why don't we update the totsize also */
352 for (tmp = current->next; tmp != newend; tmp = tmp->next)
353 totsize += strlen(tmp->data) + 1;
354
355 i = editbot->lineno;
356
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000357 current = newend;
358 if (i <= newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000359 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000360 }
361
Chris Allegretta293849e2000-07-27 05:09:22 +0000362 /* If marked cut == 2, that means that we're doing a cut to end
363 and we don't want anything else on the line, so we have to
364 screw up all the work we just did and separate the line. There
365 must be a better way to do this, but not at 1AM on a work night. */
366
367 if (marked_cut == 2 && current_x != strlen(current->data)) {
368 tmp = make_new_node(current);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000369 tmp->data = nmalloc(strlen(&current->data[current_x]) + 1);
Chris Allegretta293849e2000-07-27 05:09:22 +0000370 strcpy(tmp->data, &current->data[current_x]);
Chris Allegretta7975ed82000-07-28 00:58:35 +0000371 splice_node(current, tmp, current->next);
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000372 null_at(current->data, current_x);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000373 current = current->next;
374 current_x = 0;
375 placewewant = 0;
Chris Allegretta293849e2000-07-27 05:09:22 +0000376 }
Chris Allegretta5146fec2000-12-10 05:44:02 +0000377 /* Renumber from BEFORE where we pasted ;) */
378 renumber(hold);
379
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000380 dump_buffer(fileage);
381 dump_buffer(cutbuffer);
382 set_modified();
383 edit_refresh();
384 return 0;
385#else
386 if (0) {
387#endif
388 } else if (fileptr != fileage) {
389 tmp = fileptr->prev;
390 tmp->next = newbuf;
391 newbuf->prev = tmp;
392 totlines++; /* Unmarked uncuts don't split lines */
393 } else {
394 fileage = newbuf;
395 totlines++; /* Unmarked uncuts don't split lines */
396 }
397
398 /* This is so uncutting at the top of the buffer will work => */
399 if (current_y == 0)
400 edittop = newbuf;
401
402 /* Connect the end of the buffer to the filestruct */
403 newend->next = fileptr;
404 fileptr->prev = newend;
405
406 /* recalculate size *sigh* */
407 for (tmp = newbuf; tmp != fileptr; tmp = tmp->next)
408 totsize += strlen(tmp->data) + 1;
409
410 i = editbot->lineno;
411 renumber(newbuf);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000412 if (i < newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000413 edit_update(fileptr, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000414
415 dump_buffer_reverse(fileptr);
416
417 set_modified();
418 UNSET(KEEP_CUTBUFFER);
419 edit_refresh();
420 return 1;
421}