| /************************************************************************** |
| * cut.c * |
| * * |
| * Copyright (C) 1999 Chris Allegretta * |
| * This program is free software; you can redistribute it and/or modify * |
| * it under the terms of the GNU General Public License as published by * |
| * the Free Software Foundation; either version 1, or (at your option) * |
| * any later version. * |
| * * |
| * This program is distributed in the hope that it will be useful, * |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
| * GNU General Public License for more details. * |
| * * |
| * You should have received a copy of the GNU General Public License * |
| * along with this program; if not, write to the Free Software * |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * |
| * * |
| **************************************************************************/ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include "config.h" |
| #include "proto.h" |
| #include "nano.h" |
| |
| #ifndef NANO_SMALL |
| #include <libintl.h> |
| #define _(string) gettext(string) |
| #else |
| #define _(string) (string) |
| #endif |
| |
| static int marked_cut; /* Is the cutbuffer from a mark */ |
| static filestruct *cutbottom = NULL; /* Pointer to end of cutbuffer */ |
| |
| void add_to_cutbuffer(filestruct * inptr) |
| { |
| filestruct *tmp; |
| |
| #ifdef DEBUG |
| fprintf(stderr, _("add_to_cutbuffer called with inptr->data = %s\n"), |
| inptr->data); |
| #endif |
| |
| totsize -= strlen(inptr->data); |
| tmp = cutbuffer; |
| if (cutbuffer == NULL) { |
| cutbuffer = inptr; |
| inptr->prev = NULL; |
| } else { |
| cutbottom->next = inptr; |
| inptr->prev = cutbottom; |
| } |
| |
| inptr->next = NULL; |
| cutbottom = inptr; |
| } |
| |
| #ifndef NANO_SMALL |
| void cut_marked_segment(filestruct * top, int top_x, filestruct * bot, |
| int bot_x) |
| { |
| filestruct *tmp, *next; |
| char *tmpstr; |
| |
| /* Set up the beginning of the cutbuffer */ |
| tmp = copy_node(top); |
| tmpstr = nmalloc(strlen(&top->data[top_x]) + 1); |
| strcpy(tmpstr, &top->data[top_x]); |
| free(tmp->data); |
| tmp->data = tmpstr; |
| |
| /* Chop off the end of the first line */ |
| tmpstr = nmalloc(top_x + 1); |
| strncpy(tmpstr, top->data, top_x); |
| free(top->data); |
| top->data = tmpstr; |
| |
| do { |
| next = tmp->next; |
| add_to_cutbuffer(tmp); |
| totlines--; |
| totsize--; /* newline (add_to_cutbuffer doesn't count newlines) */ |
| tmp = next; |
| } |
| while (next != bot && next != NULL); |
| |
| dump_buffer(cutbuffer); |
| if (next == NULL) |
| return; |
| /* Now, paste bot[bot_x] into top[top_x] */ |
| tmpstr = nmalloc(strlen(top->data) + strlen(&bot->data[bot_x])); |
| strncpy(tmpstr, top->data, top_x); |
| strcpy(&tmpstr[top_x], &bot->data[bot_x]); |
| free(top->data); |
| top->data = tmpstr; |
| |
| bot->data[bot_x] = 0; |
| align(&bot->data); |
| next = bot->next; |
| |
| /* We explicitly don't decrement totlines here because we don't snarf |
| * up a newline when we're grabbing the last line of the mark. For |
| * the same reason we don't do an extra totsize decrement */ |
| |
| add_to_cutbuffer(bot); |
| top->next = next; |
| if (next != NULL) |
| next->prev = top; |
| |
| dump_buffer(cutbuffer); |
| renumber(top); |
| current = top; |
| current_x = top_x; |
| |
| /* If we're hitting the end of the buffer we should clean that up. */ |
| if (bot == filebot) { |
| if (next != NULL) { |
| filebot = next; |
| } else { |
| filebot = top; |
| } |
| } |
| if (top->lineno < edittop->lineno) |
| edit_update(top); |
| } |
| #endif |
| |
| int do_cut_text(void) |
| { |
| filestruct *tmp, *fileptr = current; |
| #ifndef NANO_SMALL |
| char *tmpstr; |
| int newsize; |
| #endif |
| |
| if (fileptr == NULL || fileptr->data == NULL) |
| return 0; |
| |
| tmp = fileptr->next; |
| |
| if (!ISSET(KEEP_CUTBUFFER) || ISSET(MARK_ISSET)) { |
| free_filestruct(cutbuffer); |
| cutbuffer = NULL; |
| #ifdef DEBUG |
| fprintf(stderr, _("Blew away cutbuffer =)\n")); |
| #endif |
| } |
| #ifndef NANO_SMALL |
| if (ISSET(MARK_ISSET)) { |
| if (current->lineno == mark_beginbuf->lineno) { |
| tmp = copy_node(current); |
| newsize = abs(strlen(¤t->data[mark_beginx]) - |
| strlen(¤t->data[current_x])); |
| |
| tmpstr = nmalloc(newsize); |
| if (current_x < mark_beginx) { |
| strncpy(tmpstr, ¤t->data[current_x], newsize); |
| memmove(¤t->data[current_x], |
| ¤t->data[mark_beginx], |
| strlen(¤t->data[mark_beginx] - newsize)); |
| } else { |
| strncpy(tmpstr, ¤t->data[mark_beginx], newsize); |
| memmove(¤t->data[mark_beginx], |
| ¤t->data[current_x], |
| strlen(¤t->data[current_x] - newsize)); |
| current_x = mark_beginx; |
| update_cursor(); |
| } |
| tmpstr[newsize] = 0; |
| tmp->data = tmpstr; |
| add_to_cutbuffer(tmp); |
| dump_buffer(cutbuffer); |
| align(¤t->data); |
| } else if (current->lineno < mark_beginbuf->lineno) |
| cut_marked_segment(current, current_x, mark_beginbuf, |
| mark_beginx); |
| else |
| cut_marked_segment(mark_beginbuf, mark_beginx, current, |
| current_x); |
| |
| placewewant = xplustabs(); |
| UNSET(MARK_ISSET); |
| marked_cut = 1; |
| set_modified(); |
| edit_update(current); |
| return 1; |
| #else |
| if (0) { |
| #endif |
| } else if (fileptr == fileage) { |
| /* we're cutting the first line */ |
| if (fileptr->next != NULL) { |
| fileptr = fileptr->next; |
| tmp = fileptr; |
| fileage = fileptr; |
| add_to_cutbuffer(fileptr->prev); |
| totsize--; /* get the newline */ |
| totlines--; |
| fileptr->prev = NULL; |
| edit_update(fileage); |
| current = fileptr; |
| } else { |
| add_to_cutbuffer(fileptr); |
| fileage = make_new_node(NULL); |
| fileage->data = nmalloc(1); |
| fileage->data[0] = '\0'; |
| current = fileage; |
| } |
| } else { |
| if (fileptr->prev != NULL) |
| fileptr->prev->next = fileptr->next; |
| |
| if (fileptr->next != NULL) { |
| (fileptr->next)->prev = fileptr->prev; |
| current = fileptr->next; |
| totlines--; |
| totsize--; /* get the newline */ |
| } else { |
| /* we're deleteing the last line |
| and replacing it with a dummy line, |
| so totlines is the same */ |
| tmp = fileptr->prev; |
| tmp->next = make_new_node(tmp); |
| tmp = tmp->next; |
| tmp->data = nmalloc(1); |
| strcpy(tmp->data, ""); |
| current = tmp; |
| filebot = tmp; |
| } |
| |
| add_to_cutbuffer(fileptr); |
| } |
| |
| if (fileptr == edittop) |
| edittop = current; |
| |
| edit_refresh(); |
| |
| dump_buffer(cutbuffer); |
| reset_cursor(); |
| |
| set_modified(); |
| marked_cut = 0; |
| current_x = 0; |
| placewewant = 0; |
| update_cursor(); |
| renumber(tmp); |
| SET(KEEP_CUTBUFFER); |
| return 1; |
| } |
| |
| int do_uncut_text(void) |
| { |
| filestruct *tmp = current, *fileptr = current, *newbuf, *newend; |
| #ifndef NANO_SMALL |
| char *tmpstr, *tmpstr2; |
| #endif |
| int i; |
| |
| wrap_reset(); |
| if (cutbuffer == NULL || fileptr == NULL) |
| return 0; /* AIEEEEEEEEEEEE */ |
| |
| newbuf = copy_filestruct(cutbuffer); |
| for (newend = newbuf; newend->next != NULL && newend != NULL; |
| newend = newend->next) { |
| totlines++; |
| } |
| |
| /* Hook newbuf into fileptr */ |
| #ifndef NANO_SMALL |
| if (marked_cut == 1) { |
| /* If there's only one line in the cutbuffer */ |
| if (cutbuffer->next == NULL) { |
| tmpstr = |
| nmalloc(strlen(current->data) + strlen(cutbuffer->data) + |
| 1); |
| strncpy(tmpstr, current->data, current_x); |
| strcpy(&tmpstr[current_x], cutbuffer->data); |
| strcat(tmpstr, ¤t->data[current_x]); |
| free(current->data); |
| current->data = tmpstr; |
| current_x += strlen(cutbuffer->data); |
| totsize += strlen(cutbuffer->data); |
| |
| placewewant = xplustabs(); |
| update_cursor(); |
| renumber(current); |
| } else { /* yuck -- no kidding! */ |
| tmp = current->next; |
| /* New beginning */ |
| tmpstr = nmalloc(current_x + strlen(newbuf->data) + 1); |
| strncpy(tmpstr, current->data, current_x); |
| strcpy(&tmpstr[current_x], newbuf->data); |
| totsize += strlen(newbuf->data) + strlen(newend->data) + 1; |
| |
| /* New end */ |
| tmpstr2 = nmalloc(strlen(newend->data) + |
| strlen(¤t->data[current_x]) + 1); |
| strcpy(tmpstr2, newend->data); |
| strcat(tmpstr2, ¤t->data[current_x]); |
| |
| free(current->data); |
| current->data = tmpstr; |
| current->next = newbuf->next; |
| newbuf->next->prev = current; |
| delete_node(newbuf); |
| |
| current_x = strlen(newend->data); |
| placewewant = xplustabs(); |
| free(newend->data); |
| newend->data = tmpstr2; |
| |
| newend->next = tmp; |
| |
| /* If tmp isn't null, we're in the middle: update the |
| * prev pointer. If it IS null, we're at the end, update |
| * the filebot pointer */ |
| |
| if (tmp != NULL) |
| tmp->prev = newend; |
| else |
| filebot = newend; |
| |
| /* Now why don't we update the totsize also */ |
| for (tmp = current->next; tmp != newend; tmp = tmp->next) |
| totsize += strlen(tmp->data) + 1; |
| |
| i = editbot->lineno; |
| |
| renumber(current); |
| |
| current = newend; |
| if (i <= newend->lineno) |
| edit_update(current); |
| } |
| |
| dump_buffer(fileage); |
| dump_buffer(cutbuffer); |
| set_modified(); |
| edit_refresh(); |
| return 0; |
| #else |
| if (0) { |
| #endif |
| } else if (fileptr != fileage) { |
| tmp = fileptr->prev; |
| tmp->next = newbuf; |
| newbuf->prev = tmp; |
| totlines++; /* Unmarked uncuts don't split lines */ |
| } else { |
| fileage = newbuf; |
| totlines++; /* Unmarked uncuts don't split lines */ |
| } |
| |
| /* This is so uncutting at the top of the buffer will work => */ |
| if (current_y == 0) |
| edittop = newbuf; |
| |
| /* Connect the end of the buffer to the filestruct */ |
| newend->next = fileptr; |
| fileptr->prev = newend; |
| |
| /* recalculate size *sigh* */ |
| for (tmp = newbuf; tmp != fileptr; tmp = tmp->next) |
| totsize += strlen(tmp->data) + 1; |
| |
| i = editbot->lineno; |
| renumber(newbuf); |
| if (i < newend->lineno) |
| edit_update(fileptr); |
| |
| dump_buffer_reverse(fileptr); |
| |
| set_modified(); |
| UNSET(KEEP_CUTBUFFER); |
| edit_refresh(); |
| return 1; |
| } |