blob: 8a66064c6452c94bfef3afeda9c04aaaca51d892 [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 Allegretta95b0b522000-07-28 02:58:06 +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... */
155 if (fileptr == filebot)
156 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 Allegretta45dfda92000-07-25 03:20:07 +0000160 if (current_x == strlen(current->data))
161 {
Chris Allegretta45dfda92000-07-25 03:20:07 +0000162 do_delete();
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000163 SET(KEEP_CUTBUFFER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000164 marked_cut = 2;
Chris Allegretta45dfda92000-07-25 03:20:07 +0000165 return 1;
166 }
167 else
168 {
169 SET(MARK_ISSET);
170 SET(KEEP_CUTBUFFER);
171
172 mark_beginx = strlen(current->data);
173 mark_beginbuf = current;
174 cuttingtoend = 1;
175 }
Chris Allegretta627de192000-07-12 02:09:17 +0000176 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000177 if (ISSET(MARK_ISSET)) {
178 if (current->lineno == mark_beginbuf->lineno) {
179 tmp = copy_node(current);
180 newsize = abs(strlen(&current->data[mark_beginx]) -
181 strlen(&current->data[current_x]));
182
183 tmpstr = nmalloc(newsize);
184 if (current_x < mark_beginx) {
185 strncpy(tmpstr, &current->data[current_x], newsize);
186 memmove(&current->data[current_x],
187 &current->data[mark_beginx],
188 strlen(&current->data[mark_beginx] - newsize));
189 } else {
190 strncpy(tmpstr, &current->data[mark_beginx], newsize);
191 memmove(&current->data[mark_beginx],
192 &current->data[current_x],
193 strlen(&current->data[current_x] - newsize));
194 current_x = mark_beginx;
195 update_cursor();
196 }
197 tmpstr[newsize] = 0;
198 tmp->data = tmpstr;
199 add_to_cutbuffer(tmp);
200 dump_buffer(cutbuffer);
201 align(&current->data);
202 } else if (current->lineno < mark_beginbuf->lineno)
203 cut_marked_segment(current, current_x, mark_beginbuf,
204 mark_beginx);
205 else
206 cut_marked_segment(mark_beginbuf, mark_beginx, current,
207 current_x);
208
209 placewewant = xplustabs();
210 UNSET(MARK_ISSET);
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000211
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000212 marked_cut = 1;
213 set_modified();
Chris Allegretta45dfda92000-07-25 03:20:07 +0000214 if (cuttingtoend)
215 edit_refresh();
216 else
Chris Allegretta234a34d2000-07-29 04:33:38 +0000217 edit_update(current, CENTER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000218
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000219 return 1;
220#else
221 if (0) {
222#endif
223 } else if (fileptr == fileage) {
224 /* we're cutting the first line */
225 if (fileptr->next != NULL) {
226 fileptr = fileptr->next;
227 tmp = fileptr;
228 fileage = fileptr;
229 add_to_cutbuffer(fileptr->prev);
Robert Siemborski66b0fc52000-07-04 21:29:24 +0000230 totsize--; /* get the newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000231 totlines--;
232 fileptr->prev = NULL;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000233 current = fileptr;
Chris Allegretta7dc14e82000-08-05 16:03:19 +0000234 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000235 } else {
236 add_to_cutbuffer(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000237 fileage = make_new_node(NULL);
238 fileage->data = nmalloc(1);
Robert Siemborskiea19c732000-06-09 00:52:26 +0000239 fileage->data[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000240 current = fileage;
241 }
242 } else {
243 if (fileptr->prev != NULL)
244 fileptr->prev->next = fileptr->next;
245
246 if (fileptr->next != NULL) {
247 (fileptr->next)->prev = fileptr->prev;
248 current = fileptr->next;
249 totlines--;
Robert Siemborski66b0fc52000-07-04 21:29:24 +0000250 totsize--; /* get the newline */
Chris Allegrettac86f7142000-08-07 14:39:32 +0000251 } /* No longer an else here, because we never get here anymore...
252 No need to cut the magic line, as it's empty */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000253
254 add_to_cutbuffer(fileptr);
255 }
256
257 if (fileptr == edittop)
258 edittop = current;
259
260 edit_refresh();
261
262 dump_buffer(cutbuffer);
263 reset_cursor();
264
265 set_modified();
266 marked_cut = 0;
267 current_x = 0;
268 placewewant = 0;
269 update_cursor();
270 renumber(tmp);
271 SET(KEEP_CUTBUFFER);
272 return 1;
273}
274
275int do_uncut_text(void)
276{
277 filestruct *tmp = current, *fileptr = current, *newbuf, *newend;
278#ifndef NANO_SMALL
279 char *tmpstr, *tmpstr2;
280#endif
281 int i;
282
283 wrap_reset();
Chris Allegrettac86f7142000-08-07 14:39:32 +0000284 check_statblank();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000285 if (cutbuffer == NULL || fileptr == NULL)
286 return 0; /* AIEEEEEEEEEEEE */
287
288 newbuf = copy_filestruct(cutbuffer);
289 for (newend = newbuf; newend->next != NULL && newend != NULL;
290 newend = newend->next) {
291 totlines++;
292 }
293
294 /* Hook newbuf into fileptr */
295#ifndef NANO_SMALL
Chris Allegretta1013e142000-07-27 04:31:52 +0000296 if (marked_cut) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000297 /* If there's only one line in the cutbuffer */
298 if (cutbuffer->next == NULL) {
299 tmpstr =
300 nmalloc(strlen(current->data) + strlen(cutbuffer->data) +
301 1);
302 strncpy(tmpstr, current->data, current_x);
303 strcpy(&tmpstr[current_x], cutbuffer->data);
304 strcat(tmpstr, &current->data[current_x]);
305 free(current->data);
306 current->data = tmpstr;
307 current_x += strlen(cutbuffer->data);
308 totsize += strlen(cutbuffer->data);
309
310 placewewant = xplustabs();
311 update_cursor();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000312 } else { /* yuck -- no kidding! */
313 tmp = current->next;
314 /* New beginning */
315 tmpstr = nmalloc(current_x + strlen(newbuf->data) + 1);
316 strncpy(tmpstr, current->data, current_x);
317 strcpy(&tmpstr[current_x], newbuf->data);
318 totsize += strlen(newbuf->data) + strlen(newend->data) + 1;
319
320 /* New end */
321 tmpstr2 = nmalloc(strlen(newend->data) +
322 strlen(&current->data[current_x]) + 1);
323 strcpy(tmpstr2, newend->data);
324 strcat(tmpstr2, &current->data[current_x]);
325
326 free(current->data);
327 current->data = tmpstr;
328 current->next = newbuf->next;
329 newbuf->next->prev = current;
330 delete_node(newbuf);
331
332 current_x = strlen(newend->data);
333 placewewant = xplustabs();
334 free(newend->data);
335 newend->data = tmpstr2;
336
337 newend->next = tmp;
338
339 /* If tmp isn't null, we're in the middle: update the
340 * prev pointer. If it IS null, we're at the end, update
341 * the filebot pointer */
342
343 if (tmp != NULL)
344 tmp->prev = newend;
345 else
346 filebot = newend;
347
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 Allegretta939fdbd2000-07-27 13:03:31 +0000374 renumber(current->prev);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000375 dump_buffer(fileage);
376 dump_buffer(cutbuffer);
377 set_modified();
378 edit_refresh();
379 return 0;
380#else
381 if (0) {
382#endif
383 } else if (fileptr != fileage) {
384 tmp = fileptr->prev;
385 tmp->next = newbuf;
386 newbuf->prev = tmp;
387 totlines++; /* Unmarked uncuts don't split lines */
388 } else {
389 fileage = newbuf;
390 totlines++; /* Unmarked uncuts don't split lines */
391 }
392
393 /* This is so uncutting at the top of the buffer will work => */
394 if (current_y == 0)
395 edittop = newbuf;
396
397 /* Connect the end of the buffer to the filestruct */
398 newend->next = fileptr;
399 fileptr->prev = newend;
400
401 /* recalculate size *sigh* */
402 for (tmp = newbuf; tmp != fileptr; tmp = tmp->next)
403 totsize += strlen(tmp->data) + 1;
404
405 i = editbot->lineno;
406 renumber(newbuf);
Chris Allegretta95b0b522000-07-28 02:58:06 +0000407 if (i < newend->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000408 edit_update(fileptr, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000409
410 dump_buffer_reverse(fileptr);
411
412 set_modified();
413 UNSET(KEEP_CUTBUFFER);
414 edit_refresh();
415 return 1;
416}