blob: f3a84998361e8bb9f6db5e29d24611dfd2fb89a3 [file] [log] [blame]
Chris Allegrettaa2ea1932000-06-06 05:53:49 +00001/**************************************************************************
2 * cut.c *
3 * *
4 * Copyright (C) 1999 Chris Allegretta *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 1, or (at your option) *
8 * any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software *
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
18 * *
19 **************************************************************************/
20
21#include <stdlib.h>
22#include <string.h>
23#include <stdio.h>
24#include "config.h"
25#include "proto.h"
26#include "nano.h"
27
28#ifndef NANO_SMALL
29#include <libintl.h>
30#define _(string) gettext(string)
31#else
32#define _(string) (string)
33#endif
34
35static int marked_cut; /* Is the cutbuffer from a mark */
36static filestruct *cutbottom = NULL; /* Pointer to end of cutbuffer */
37
38void add_to_cutbuffer(filestruct * inptr)
39{
40 filestruct *tmp;
41
42#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 tmp = cutbuffer;
49 if (cutbuffer == NULL) {
50 cutbuffer = inptr;
51 inptr->prev = NULL;
52 } else {
53 cutbottom->next = inptr;
54 inptr->prev = cutbottom;
55 }
56
57 inptr->next = NULL;
58 cutbottom = inptr;
59}
60
61#ifndef NANO_SMALL
62void cut_marked_segment(filestruct * top, int top_x, filestruct * bot,
63 int bot_x)
64{
65 filestruct *tmp, *next;
66 char *tmpstr;
67
68 /* Set up the beginning of the cutbuffer */
69 tmp = copy_node(top);
70 tmpstr = nmalloc(strlen(&top->data[top_x]) + 1);
71 strcpy(tmpstr, &top->data[top_x]);
72 free(tmp->data);
73 tmp->data = tmpstr;
74
75 /* Chop off the end of the first line */
76 tmpstr = nmalloc(top_x + 1);
77 strncpy(tmpstr, top->data, top_x);
78 free(top->data);
79 top->data = tmpstr;
80
81 do {
82 next = tmp->next;
83 add_to_cutbuffer(tmp);
84 totlines--;
Chris Allegretta4da1fc62000-06-21 03:00:43 +000085 totsize--; /* newline (add_to_cutbuffer doesn't count newlines) */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +000086 tmp = next;
87 }
88 while (next != bot && next != NULL);
89
90 dump_buffer(cutbuffer);
91 if (next == NULL)
92 return;
93 /* Now, paste bot[bot_x] into top[top_x] */
94 tmpstr = nmalloc(strlen(top->data) + strlen(&bot->data[bot_x]));
95 strncpy(tmpstr, top->data, top_x);
96 strcpy(&tmpstr[top_x], &bot->data[bot_x]);
97 free(top->data);
98 top->data = tmpstr;
99
Chris Allegretta6925bbd2000-07-28 01:41:29 +0000100 null_at(bot->data, bot_x);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000101 next = bot->next;
102
103 /* We explicitly don't decrement totlines here because we don't snarf
Robert Siemborskiea19c732000-06-09 00:52:26 +0000104 * up a newline when we're grabbing the last line of the mark. For
105 * the same reason we don't do an extra totsize decrement */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000106
107 add_to_cutbuffer(bot);
108 top->next = next;
109 if (next != NULL)
110 next->prev = top;
111
112 dump_buffer(cutbuffer);
113 renumber(top);
114 current = top;
115 current_x = top_x;
116
117 /* If we're hitting the end of the buffer we should clean that up. */
118 if (bot == filebot) {
119 if (next != NULL) {
120 filebot = next;
121 } else {
122 filebot = top;
123 }
124 }
Chris Allegretta95b0b522000-07-28 02:58:06 +0000125 if (top->lineno < edittop->lineno)
Chris Allegretta234a34d2000-07-29 04:33:38 +0000126 edit_update(top, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000127}
128#endif
129
130int do_cut_text(void)
131{
132 filestruct *tmp, *fileptr = current;
133#ifndef NANO_SMALL
134 char *tmpstr;
Chris Allegretta45dfda92000-07-25 03:20:07 +0000135 int newsize, cuttingtoend = 0;
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000136#endif
137
138 if (fileptr == NULL || fileptr->data == NULL)
139 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 }
151#ifndef NANO_SMALL
Chris Allegrettaf4e75e12000-07-24 18:28:30 +0000152 if (ISSET(CUT_TO_END) && !ISSET(MARK_ISSET)) {
Chris Allegretta45dfda92000-07-25 03:20:07 +0000153 if (current_x == strlen(current->data))
154 {
Chris Allegretta45dfda92000-07-25 03:20:07 +0000155 do_delete();
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000156 SET(KEEP_CUTBUFFER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000157 marked_cut = 2;
Chris Allegretta45dfda92000-07-25 03:20:07 +0000158 return 1;
159 }
160 else
161 {
162 SET(MARK_ISSET);
163 SET(KEEP_CUTBUFFER);
164
165 mark_beginx = strlen(current->data);
166 mark_beginbuf = current;
167 cuttingtoend = 1;
168 }
Chris Allegretta627de192000-07-12 02:09:17 +0000169 }
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000170 if (ISSET(MARK_ISSET)) {
171 if (current->lineno == mark_beginbuf->lineno) {
172 tmp = copy_node(current);
173 newsize = abs(strlen(&current->data[mark_beginx]) -
174 strlen(&current->data[current_x]));
175
176 tmpstr = nmalloc(newsize);
177 if (current_x < mark_beginx) {
178 strncpy(tmpstr, &current->data[current_x], newsize);
179 memmove(&current->data[current_x],
180 &current->data[mark_beginx],
181 strlen(&current->data[mark_beginx] - newsize));
182 } else {
183 strncpy(tmpstr, &current->data[mark_beginx], newsize);
184 memmove(&current->data[mark_beginx],
185 &current->data[current_x],
186 strlen(&current->data[current_x] - newsize));
187 current_x = mark_beginx;
188 update_cursor();
189 }
190 tmpstr[newsize] = 0;
191 tmp->data = tmpstr;
192 add_to_cutbuffer(tmp);
193 dump_buffer(cutbuffer);
194 align(&current->data);
195 } else if (current->lineno < mark_beginbuf->lineno)
196 cut_marked_segment(current, current_x, mark_beginbuf,
197 mark_beginx);
198 else
199 cut_marked_segment(mark_beginbuf, mark_beginx, current,
200 current_x);
201
202 placewewant = xplustabs();
203 UNSET(MARK_ISSET);
Chris Allegretta63aa0f72000-07-27 04:09:23 +0000204
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000205 marked_cut = 1;
206 set_modified();
Chris Allegretta45dfda92000-07-25 03:20:07 +0000207 if (cuttingtoend)
208 edit_refresh();
209 else
Chris Allegretta234a34d2000-07-29 04:33:38 +0000210 edit_update(current, CENTER);
Chris Allegretta1013e142000-07-27 04:31:52 +0000211
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000212 return 1;
213#else
214 if (0) {
215#endif
216 } else if (fileptr == fileage) {
217 /* we're cutting the first line */
218 if (fileptr->next != NULL) {
219 fileptr = fileptr->next;
220 tmp = fileptr;
221 fileage = fileptr;
222 add_to_cutbuffer(fileptr->prev);
Robert Siemborski66b0fc52000-07-04 21:29:24 +0000223 totsize--; /* get the newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000224 totlines--;
225 fileptr->prev = NULL;
Chris Allegretta234a34d2000-07-29 04:33:38 +0000226 edit_update(fileage, CENTER);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000227 current = fileptr;
228 } else {
229 add_to_cutbuffer(fileptr);
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000230 fileage = make_new_node(NULL);
231 fileage->data = nmalloc(1);
Robert Siemborskiea19c732000-06-09 00:52:26 +0000232 fileage->data[0] = '\0';
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000233 current = fileage;
234 }
235 } else {
236 if (fileptr->prev != NULL)
237 fileptr->prev->next = fileptr->next;
238
239 if (fileptr->next != NULL) {
240 (fileptr->next)->prev = fileptr->prev;
241 current = fileptr->next;
242 totlines--;
Robert Siemborski66b0fc52000-07-04 21:29:24 +0000243 totsize--; /* get the newline */
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000244 } else {
245 /* we're deleteing the last line
246 and replacing it with a dummy line,
247 so totlines is the same */
248 tmp = fileptr->prev;
249 tmp->next = make_new_node(tmp);
250 tmp = tmp->next;
251 tmp->data = nmalloc(1);
252 strcpy(tmp->data, "");
253 current = tmp;
254 filebot = tmp;
255 }
256
257 add_to_cutbuffer(fileptr);
258 }
259
260 if (fileptr == edittop)
261 edittop = current;
262
263 edit_refresh();
264
265 dump_buffer(cutbuffer);
266 reset_cursor();
267
268 set_modified();
269 marked_cut = 0;
270 current_x = 0;
271 placewewant = 0;
272 update_cursor();
273 renumber(tmp);
274 SET(KEEP_CUTBUFFER);
275 return 1;
276}
277
278int do_uncut_text(void)
279{
280 filestruct *tmp = current, *fileptr = current, *newbuf, *newend;
281#ifndef NANO_SMALL
282 char *tmpstr, *tmpstr2;
283#endif
284 int i;
285
286 wrap_reset();
287 if (cutbuffer == NULL || fileptr == NULL)
288 return 0; /* AIEEEEEEEEEEEE */
289
290 newbuf = copy_filestruct(cutbuffer);
291 for (newend = newbuf; newend->next != NULL && newend != NULL;
292 newend = newend->next) {
293 totlines++;
294 }
295
296 /* Hook newbuf into fileptr */
297#ifndef NANO_SMALL
Chris Allegretta1013e142000-07-27 04:31:52 +0000298 if (marked_cut) {
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000299 /* If there's only one line in the cutbuffer */
300 if (cutbuffer->next == NULL) {
301 tmpstr =
302 nmalloc(strlen(current->data) + strlen(cutbuffer->data) +
303 1);
304 strncpy(tmpstr, current->data, current_x);
305 strcpy(&tmpstr[current_x], cutbuffer->data);
306 strcat(tmpstr, &current->data[current_x]);
307 free(current->data);
308 current->data = tmpstr;
309 current_x += strlen(cutbuffer->data);
310 totsize += strlen(cutbuffer->data);
311
312 placewewant = xplustabs();
313 update_cursor();
Chris Allegrettaa2ea1932000-06-06 05:53:49 +0000314 } else { /* yuck -- no kidding! */
315 tmp = current->next;
316 /* New beginning */
317 tmpstr = nmalloc(current_x + strlen(newbuf->data) + 1);
318 strncpy(tmpstr, current->data, current_x);
319 strcpy(&tmpstr[current_x], newbuf->data);
320 totsize += strlen(newbuf->data) + strlen(newend->data) + 1;
321
322 /* New end */
323 tmpstr2 = nmalloc(strlen(newend->data) +
324 strlen(&current->data[current_x]) + 1);
325 strcpy(tmpstr2, newend->data);
326 strcat(tmpstr2, &current->data[current_x]);
327
328 free(current->data);
329 current->data = tmpstr;
330 current->next = newbuf->next;
331 newbuf->next->prev = current;
332 delete_node(newbuf);
333
334 current_x = strlen(newend->data);
335 placewewant = xplustabs();
336 free(newend->data);
337 newend->data = tmpstr2;
338
339 newend->next = tmp;
340
341 /* If tmp isn't null, we're in the middle: update the
342 * prev pointer. If it IS null, we're at the end, update
343 * the filebot pointer */
344
345 if (tmp != NULL)
346 tmp->prev = newend;
347 else
348 filebot = newend;
349
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 Allegretta939fdbd2000-07-27 13:03:31 +0000376 renumber(current->prev);
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 Allegretta95b0b522000-07-28 02:58:06 +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}