blob: e7f6aa80de8a37c967e85d2950b6cb77f6e38c61 [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{
274 filestruct *tmp = current, *fileptr = current, *newbuf, *newend;
275#ifndef NANO_SMALL
276 char *tmpstr, *tmpstr2;
277#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;
342 else
343 filebot = newend;
344
345 /* Now why don't we update the totsize also */
346 for (tmp = current->next; tmp != newend; tmp = tmp->next)
347 totsize += strlen(tmp->data) + 1;
348
349 i = editbot->lineno;
350
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000351 current = newend;
352 if (i <= newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000353 edit_update(current, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000354 }
355
Chris Allegretta293849e2000-07-27 05:09:22 +0000356 /* If marked cut == 2, that means that we're doing a cut to end
357 and we don't want anything else on the line, so we have to
358 screw up all the work we just did and separate the line. There
359 must be a better way to do this, but not at 1AM on a work night. */
360
361 if (marked_cut == 2 && current_x != strlen(current->data)) {
362 tmp = make_new_node(current);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000363 tmp->data = nmalloc(strlen(&current->data[current_x]) + 1);
Chris Allegretta293849e2000-07-27 05:09:22 +0000364 strcpy(tmp->data, &current->data[current_x]);
Chris Allegretta7975ed82000-07-28 00:58:35 +0000365 splice_node(current, tmp, current->next);
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000366 null_at(current->data, current_x);
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000367 current = current->next;
368 current_x = 0;
369 placewewant = 0;
Chris Allegretta293849e2000-07-27 05:09:22 +0000370 }
Chris Allegretta939fdbd2000-07-27 13:03:31 +0000371 renumber(current->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000372 dump_buffer(fileage);
373 dump_buffer(cutbuffer);
374 set_modified();
375 edit_refresh();
376 return 0;
377#else
378 if (0) {
379#endif
380 } else if (fileptr != fileage) {
381 tmp = fileptr->prev;
382 tmp->next = newbuf;
383 newbuf->prev = tmp;
384 totlines++; /* Unmarked uncuts don't split lines */
385 } else {
386 fileage = newbuf;
387 totlines++; /* Unmarked uncuts don't split lines */
388 }
389
390 /* This is so uncutting at the top of the buffer will work => */
391 if (current_y == 0)
392 edittop = newbuf;
393
394 /* Connect the end of the buffer to the filestruct */
395 newend->next = fileptr;
396 fileptr->prev = newend;
397
398 /* recalculate size *sigh* */
399 for (tmp = newbuf; tmp != fileptr; tmp = tmp->next)
400 totsize += strlen(tmp->data) + 1;
401
402 i = editbot->lineno;
403 renumber(newbuf);
Chris Allegrettabd9e7c32000-10-26 01:44:42 +0000404 if (i < newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000405 edit_update(fileptr, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000406
407 dump_buffer_reverse(fileptr);
408
409 set_modified();
410 UNSET(KEEP_CUTBUFFER);
411 edit_refresh();
412 return 1;
413}