From: Chris Allegretta Date: Mon, 19 Jun 2000 04:22:15 +0000 (+0000) Subject: Split nano.c up more X-Git-Tag: v0.9.11~18 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=bceb1b21a64324a46e7b3d46489dc9dd97605312;p=nano.git Split nano.c up more git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@27 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- diff --git a/Makefile.am b/Makefile.am index 1e5f7d5b..1244b170 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,12 @@ bin_PROGRAMS = nano nano_SOURCES = cut.c \ + files.c \ global.c \ + move.c \ nano.c \ nano.h \ proto.h \ + search.c \ utils.c \ winio.c diff --git a/Makefile.in b/Makefile.in index 1f9429e3..e7629f29 100644 --- a/Makefile.in +++ b/Makefile.in @@ -88,7 +88,7 @@ VERSION = @VERSION@ l = @l@ bin_PROGRAMS = nano -nano_SOURCES = cut.c global.c nano.c nano.h proto.h utils.c winio.c +nano_SOURCES = cut.c files.c global.c move.c nano.c nano.h proto.h search.c utils.c winio.c man_MANS = nano.1 @@ -112,7 +112,8 @@ DEFS = @DEFS@ -I. -I$(srcdir) -I. CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -nano_OBJECTS = cut.o global.o nano.o utils.o winio.o +nano_OBJECTS = cut.o files.o global.o move.o nano.o search.o utils.o \ +winio.o nano_DEPENDENCIES = nano_LDFLAGS = CFLAGS = @CFLAGS@ @@ -398,7 +399,7 @@ distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ - cp -pr $$/$$file $(distdir)/$$file; \ + cp -pr $$d/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ diff --git a/files.c b/files.c new file mode 100644 index 00000000..03b68cbb --- /dev/null +++ b/files.c @@ -0,0 +1,470 @@ +/************************************************************************** + * files.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 +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "proto.h" +#include "nano.h" + +#ifndef NANO_SMALL +#include +#define _(string) gettext(string) +#else +#define _(string) (string) +#endif + +/* Load file into edit buffer - takes data from file struct */ +void load_file(void) +{ + current = fileage; + wmove(edit, current_y, current_x); +} + +/* What happens when there is no file to open? aiee! */ +void new_file(void) +{ + fileage = nmalloc(sizeof(filestruct)); + fileage->data = nmalloc(1); + strcpy(fileage->data, ""); + fileage->prev = NULL; + fileage->next = NULL; + fileage->lineno = 1; + filebot = fileage; + edittop = fileage; + editbot = fileage; + current = fileage; + totlines = 1; + UNSET(VIEW_MODE); +} + + +int read_byte(int fd, char *filename, char *input) +{ + static char buf[BUFSIZ]; + static int index = 0; + static int size = 0; + + if (index == size) { + index = 0; + size = read(fd, buf, BUFSIZ); + if (size == -1) { + clear(); + refresh(); + resetty(); + endwin(); + perror(filename); + } + if (!size) + return 0; + } + *input = buf[index++]; + return 1; +} + +filestruct *read_line(char *buf, filestruct * prev, int *line1ins) +{ + filestruct *fileptr; + + fileptr = nmalloc(sizeof(filestruct)); + fileptr->data = nmalloc(strlen(buf) + 2); + strcpy(fileptr->data, buf); + + if (*line1ins) { + /* Special case, insert with cursor on 1st line. */ + fileptr->prev = NULL; + fileptr->next = fileage; + fileptr->lineno = 1; + *line1ins = 0; + /* If we're inserting into the first line of the file, then + we want to make sure that our edit buffer stays on the + first line (and that fileage stays up to date!) */ + fileage = fileptr; + edittop = fileptr; + } else if (fileage == NULL) { + fileage = fileptr; + fileage->lineno = 1; + fileage->next = fileage->prev = NULL; + fileptr = filebot = fileage; + } else if (prev) { + fileptr->prev = prev; + fileptr->next = NULL; + fileptr->lineno = prev->lineno + 1; + prev->next = fileptr; + } else { + die(_("read_line: not on first line and prev is NULL")); + } + + return fileptr; +} + + +int read_file(int fd, char *filename) +{ + long size, lines = 0, linetemp = 0; + char input[2]; /* buffer */ + char *buf; + long i = 0, bufx = 128; + filestruct *fileptr = current, *tmp = NULL; + int line1ins = 0; + + buf = nmalloc(bufx); + + if (fileptr != NULL && fileptr->prev != NULL) { + fileptr = fileptr->prev; + tmp = fileptr; + } else if (fileptr != NULL && fileptr->prev == NULL) { + tmp = fileage; + current = fileage; + line1ins = 1; + } + input[1] = 0; + /* Read the entire file into file struct */ + while ((size = read_byte(fd, filename, input)) > 0) { + linetemp = 0; + if (input[0] == '\n') { + fileptr = read_line(buf, fileptr, &line1ins); + lines++; + buf[0] = 0; + i = 0; + } else { + /* Now we allocate a bigger buffer 128 characters at a time. + If we allocate a lot of space for one line, we may indeed + have to use a buffer this big later on, so we don't + decrease it at all. We do free it at the end though. */ + + if (i >= bufx - 1) { + buf = nrealloc(buf, bufx + 128); + bufx += 128; + } + buf[i] = input[0]; + buf[i + 1] = 0; + i++; + } + totsize += size; + } + + /* Did we not get a newline but still have stuff to do? */ + if (buf[0]) { + fileptr = read_line(buf, fileptr, &line1ins); + lines++; + buf[0] = 0; + } + /* Did we even GET a file? */ + if (totsize == 0) { + new_file(); + statusbar(_("Read %d lines"), lines); + return 1; + } + if (current != NULL) { + fileptr->next = current; + current->prev = fileptr; + renumber(current); + current_x = 0; + placewewant = 0; + } else if (fileptr->next == NULL) { + filebot = fileptr; + load_file(); + } + statusbar(_("Read %d lines"), lines); + totlines += lines; + + free(buf); + close(fd); + + return 1; +} + +/* Open the file (and decide if it exists) */ +int open_file(char *filename, int insert, int quiet) +{ + int fd; + struct stat fileinfo; + + if (!strcmp(filename, "") || stat(filename, &fileinfo) == -1) { + if (insert) { + if (!quiet) + statusbar(_("\"%s\" not found"), filename); + return -1; + } else { + /* We have a new file */ + statusbar(_("New File")); + new_file(); + } + } else if ((fd = open(filename, O_RDONLY)) == -1) { + if (!quiet) + statusbar("%s: %s", strerror(errno), filename); + return -1; + } else { /* File is A-OK */ + if (S_ISDIR(fileinfo.st_mode)) { + statusbar(_("File \"%s\" is a directory"), filename); + new_file(); + return -1; + } + if (!quiet) + statusbar(_("Reading File")); + read_file(fd, filename); + } + + return 1; +} + +int do_insertfile(void) +{ + int i; + + wrap_reset(); + i = statusq(writefile_list, WRITEFILE_LIST_LEN, "", + _("File to insert [from ./] ")); + if (i != -1) { + +#ifdef DEBUG + fprintf(stderr, "filename is %s", answer); +#endif + + i = open_file(answer, 1, 0); + + dump_buffer(fileage); + set_modified(); + + /* Here we want to rebuild the edit window */ + for(i = 0, editbot = edittop; + i <= editwinrows - 1 + && i <= totlines + && editbot->next != NULL; + editbot = editbot->next, i++); + + /* If we've gone off the bottom, recenter, otherwise just redraw */ + if(current->lineno > editbot->lineno) + edit_update(current); + else + edit_refresh(); + + UNSET(KEEP_CUTBUFFER); + display_main_list(); + return i; + } else { + statusbar(_("Cancelled")); + UNSET(KEEP_CUTBUFFER); + display_main_list(); + return 0; + } +} + +/* + * Write a file out. If tmp is nonzero, we set the umask to 0600, + * we don't set the global variable filename to it's name, and don't + * print out how many lines we wrote on the statusbar. + * + * Note that tmp is only set to 1 for storing temporary files internal + * to the editor, and is completely different from temp_opt. + */ +int write_file(char *name, int tmp) +{ + long size, lineswritten = 0; + char buf[PATH_MAX + 1]; + filestruct *fileptr; + int fd, mask = 0; + struct stat st; + + if (!strcmp(name, "")) { + statusbar(_("Cancelled")); + return -1; + } + titlebar(); + fileptr = fileage; + + + /* Open the file and truncate it. Trust the symlink. */ + if (ISSET(FOLLOW_SYMLINKS) && !tmp) { + if ((fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | + S_IWOTH)) == -1) { + statusbar(_("Could not open file for writing: %s"), + strerror(errno)); + return -1; + } + } + /* Don't follow symlink. Create new file. */ + else { + if (strlen(name) > (PATH_MAX - 7)) { + statusbar(_("Could not open file: Path length exceeded.")); + return -1; + } + + memset(buf, 0x00, PATH_MAX + 1); + strcat(buf, name); + strcat(buf, ".XXXXXX"); + if ((fd = mkstemp(buf)) == -1) { + statusbar(_("Could not open file for writing: %s"), + strerror(errno)); + return -1; + } + } + + + + dump_buffer(fileage); + while (fileptr != NULL && fileptr->next != NULL) { + size = write(fd, fileptr->data, strlen(fileptr->data)); + if (size == -1) { + statusbar(_("Could not open file for writing: %s"), + strerror(errno)); + return -1; + } else { +#ifdef DEBUG + fprintf(stderr, _("Wrote >%s\n"), fileptr->data); +#endif + } + write(fd, "\n", 1); + + fileptr = fileptr->next; + lineswritten++; + } + + if (fileptr != NULL) { + size = write(fd, fileptr->data, strlen(fileptr->data)); + if (size == -1) { + statusbar(_("Could not open file for writing: %s"), + strerror(errno)); + return -1; + } else if (size > 0) { + size = write(fd, "\n", 1); + if (size == -1) { + statusbar(_("Could not open file for writing: %s"), + strerror(errno)); + return -1; + } + } + } + + + if (close(fd) == -1) { + statusbar(_("Could not close %s: %s"), name, strerror(errno)); + unlink(buf); + return -1; + } + + if (!ISSET(FOLLOW_SYMLINKS) || tmp) { + if (stat(name, &st) == -1) { + /* Use default umask as file permisions if file is a new file. */ + mask = umask(0); + umask(mask); + + if (tmp) /* We don't want anyone reading our temporary file! */ + mask = 0600; + else + mask = 0666 & ~mask; + + } else { + /* Use permissions from file we are overwriting. */ + mask = st.st_mode; + if (unlink(name) == -1) { + if (errno != ENOENT) { + statusbar(_("Could not open %s for writing: %s"), + name, strerror(errno)); + unlink(buf); + return -1; + } + } + } + + if (link(buf, name) != -1) + unlink(buf); + else if (errno != EPERM) { + statusbar(_("Could not open %s for writing: %s"), + name, strerror(errno)); + unlink(buf); + return -1; + } else if (rename(buf, name) == -1) { /* Try a rename?? */ + statusbar(_("Could not open %s for writing: %s"), + name, strerror(errno)); + unlink(buf); + return -1; + } + if (chmod(name, mask) == -1) { + statusbar(_("Could not set permissions %o on %s: %s"), + mask, name, strerror(errno)); + } + + } + if (!tmp) { + strncpy(filename, name, 132); + statusbar(_("Wrote %d lines"), lineswritten); + } + UNSET(MODIFIED); + titlebar(); + return 1; +} + +int do_writeout(int exiting) +{ + int i = 0; + + strncpy(answer, filename, 132); + + if ((exiting) && (temp_opt) && (filename)) { + i = write_file(answer, 0); + display_main_list(); + return i; + } + + while (1) { + i = statusq(writefile_list, WRITEFILE_LIST_LEN, answer, + _("File Name to write")); + + if (i != -1) { + +#ifdef DEBUG + fprintf(stderr, _("filename is %s"), answer); +#endif + if (strncmp(answer, filename, 132)) { + struct stat st; + if (!stat(answer, &st)) { + i = do_yesno(0, 0, _("File exists, OVERWRITE ?")); + + if (!i || (i == -1)) + continue; + } + } + i = write_file(answer, 0); + + display_main_list(); + return i; + } else { + statusbar(_("Cancelled")); + display_main_list(); + return 0; + } + } +} + +int do_writeout_void(void) +{ + return do_writeout(0); +} + diff --git a/move.c b/move.c new file mode 100644 index 00000000..b5941086 --- /dev/null +++ b/move.c @@ -0,0 +1,195 @@ +/************************************************************************** + * move.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 +#include +#include +#include "config.h" +#include "proto.h" +#include "nano.h" + +#ifndef NANO_SMALL +#include +#define _(string) gettext(string) +#else +#define _(string) (string) +#endif + +void page_down_center(void) +{ + if (editbot->next != NULL && editbot->next != filebot) { + edit_update(editbot->next); + center_cursor(); + } else if (editbot != filebot) { + edit_update(editbot); + center_cursor(); + } else { + while (current != filebot) + current = current->next; + edit_update(current); + } + update_cursor(); + +} + +int page_down(void) +{ + wrap_reset(); + current_x = 0; + placewewant = 0; + + if (current == filebot) + return 0; + + if (editbot != filebot) { + current_y = 0; + current = editbot; + } else + while (current != filebot) { + current = current->next; + current_y++; + } + + edit_update_top(current); + update_cursor(); + UNSET(KEEP_CUTBUFFER); + check_statblank(); + return 1; +} + +int do_home(void) +{ + current_x = 0; + placewewant = 0; + update_line(current, current_x); + return 1; +} + +int do_end(void) +{ + current_x = strlen(current->data); + placewewant = xplustabs(); + update_line(current, current_x); + + return 1; +} + +/* What happens when we want to go past the bottom of the buffer */ +int do_down(void) +{ + wrap_reset(); + if (current->next != NULL) { + update_line(current->prev, 0); + + if (placewewant > 0) + current_x = actual_x(current->next, placewewant); + + if (current_x > strlen(current->next->data)) + current_x = strlen(current->next->data); + } else { + UNSET(KEEP_CUTBUFFER); + check_statblank(); + return 0; + } + + if (current_y < editwinrows - 1 && current != editbot) + current_y++; + else + page_down_center(); + + update_cursor(); + update_line(current->prev, 0); + update_line(current, current_x); + UNSET(KEEP_CUTBUFFER); + check_statblank(); + return 1; +} + +void page_up_center(void) +{ + if (edittop != fileage) { + edit_update(edittop); + center_cursor(); + } else + current_y = 0; + + update_cursor(); + +} + +int do_up(void) +{ + wrap_reset(); + if (current->prev != NULL) { + update_line(current, 0); + + if (placewewant > 0) + current_x = actual_x(current->prev, placewewant); + + if (current_x > strlen(current->prev->data)) + current_x = strlen(current->prev->data); + } + if (current_y > 0) + current_y--; + else + page_up_center(); + + update_cursor(); + update_line(current->next, 0); + update_line(current, current_x); + UNSET(KEEP_CUTBUFFER); + check_statblank(); + return 1; +} + +int do_right(void) +{ + if (current_x < strlen(current->data)) { + current_x++; + } else { + if (do_down()) + current_x = 0; + } + + placewewant = xplustabs(); + update_cursor(); + update_line(current, current_x); + UNSET(KEEP_CUTBUFFER); + check_statblank(); + return 1; +} + +int do_left(void) +{ + if (current_x > 0) + current_x--; + else if (current != fileage) { + placewewant = 0; + current_x = strlen(current->prev->data); + do_up(); + } + placewewant = xplustabs(); + + update_cursor(); + update_line(current, current_x); + UNSET(KEEP_CUTBUFFER); + check_statblank(); + return 1; +} diff --git a/nano.c b/nano.c index 1e374f13..1db5f689 100644 --- a/nano.c +++ b/nano.c @@ -63,8 +63,6 @@ char *last_replace; /* Last replacement string */ int temp_opt = 0; /* Editing temp file (pico -t option) */ int fill = 0; /* Fill - where to wrap lines, basically */ static char *alt_speller; /* Alternative spell command */ -static int editwineob = 0; /* Last Line in edit buffer - (0 - editwineob) */ struct termios oldterm; /* The user's original term settings */ static char *alt_speller; /* Alternative spell command */ static char *help_text_init = ""; @@ -117,29 +115,6 @@ void die(char *msg, ...) exit(1); /* We have a problem: exit w/ errorlevel(1) */ } -/* Thanks BG, many ppl have been asking for this... */ -void *nmalloc(size_t howmuch) -{ - void *r; - - /* Panic save? */ - - if (!(r = malloc(howmuch))) - die(_("nano: malloc: out of memory!")); - - return r; -} - -void *nrealloc(void *ptr, size_t howmuch) -{ - void *r; - - if (!(r = realloc(ptr, howmuch))) - die("nano: realloc: out of memory!"); - - return r; -} - void print_view_warning(void) { statusbar(_("Key illegal in VIEW mode")); @@ -155,7 +130,6 @@ void global_init(void) current_x = 0; current_y = 0; editwinrows = LINES - 5 + no_help(); - editwineob = editwinrows - 1; fileage = NULL; cutbuffer = NULL; current = NULL; @@ -331,243 +305,6 @@ void align(char **strp) *strp = nrealloc(*strp, strlen(*strp) + 1); } -/* Load file into edit buffer - takes data from file struct */ -void load_file(void) -{ - current = fileage; - wmove(edit, current_y, current_x); -} - -/* What happens when there is no file to open? aiee! */ -void new_file(void) -{ - fileage = nmalloc(sizeof(filestruct)); - fileage->data = nmalloc(1); - strcpy(fileage->data, ""); - fileage->prev = NULL; - fileage->next = NULL; - fileage->lineno = 1; - filebot = fileage; - edittop = fileage; - editbot = fileage; - current = fileage; - totlines = 1; - UNSET(VIEW_MODE); -} - - -int read_byte(int fd, char *filename, char *input) -{ - static char buf[BUFSIZ]; - static int index = 0; - static int size = 0; - - if (index == size) { - index = 0; - size = read(fd, buf, BUFSIZ); - if (size == -1) { - clear(); - refresh(); - resetty(); - endwin(); - perror(filename); - } - if (!size) - return 0; - } - *input = buf[index++]; - return 1; -} - -filestruct *read_line(char *buf, filestruct * prev, int *line1ins) -{ - filestruct *fileptr; - - fileptr = nmalloc(sizeof(filestruct)); - fileptr->data = nmalloc(strlen(buf) + 2); - strcpy(fileptr->data, buf); - - if (*line1ins) { - /* Special case, insert with cursor on 1st line. */ - fileptr->prev = NULL; - fileptr->next = fileage; - fileptr->lineno = 1; - *line1ins = 0; - /* If we're inserting into the first line of the file, then - we want to make sure that our edit buffer stays on the - first line (and that fileage stays up to date!) */ - fileage = fileptr; - edittop = fileptr; - } else if (fileage == NULL) { - fileage = fileptr; - fileage->lineno = 1; - fileage->next = fileage->prev = NULL; - fileptr = filebot = fileage; - } else if (prev) { - fileptr->prev = prev; - fileptr->next = NULL; - fileptr->lineno = prev->lineno + 1; - prev->next = fileptr; - } else { - die(_("read_line: not on first line and prev is NULL")); - } - - return fileptr; -} - - -int read_file(int fd, char *filename) -{ - long size, lines = 0, linetemp = 0; - char input[2]; /* buffer */ - char *buf; - long i = 0, bufx = 128; - filestruct *fileptr = current, *tmp = NULL; - int line1ins = 0; - - buf = nmalloc(bufx); - - if (fileptr != NULL && fileptr->prev != NULL) { - fileptr = fileptr->prev; - tmp = fileptr; - } else if (fileptr != NULL && fileptr->prev == NULL) { - tmp = fileage; - current = fileage; - line1ins = 1; - } - input[1] = 0; - /* Read the entire file into file struct */ - while ((size = read_byte(fd, filename, input)) > 0) { - linetemp = 0; - if (input[0] == '\n') { - fileptr = read_line(buf, fileptr, &line1ins); - lines++; - buf[0] = 0; - i = 0; - } else { - /* Now we allocate a bigger buffer 128 characters at a time. - If we allocate a lot of space for one line, we may indeed - have to use a buffer this big later on, so we don't - decrease it at all. We do free it at the end though. */ - - if (i >= bufx - 1) { - buf = nrealloc(buf, bufx + 128); - bufx += 128; - } - buf[i] = input[0]; - buf[i + 1] = 0; - i++; - } - totsize += size; - } - - /* Did we not get a newline but still have stuff to do? */ - if (buf[0]) { - fileptr = read_line(buf, fileptr, &line1ins); - lines++; - buf[0] = 0; - } - /* Did we even GET a file? */ - if (totsize == 0) { - new_file(); - statusbar(_("Read %d lines"), lines); - return 1; - } - if (current != NULL) { - fileptr->next = current; - current->prev = fileptr; - renumber(current); - current_x = 0; - placewewant = 0; - } else if (fileptr->next == NULL) { - filebot = fileptr; - load_file(); - } - statusbar(_("Read %d lines"), lines); - totlines += lines; - - free(buf); - close(fd); - - return 1; -} - -/* Open the file (and decide if it exists) */ -int open_file(char *filename, int insert, int quiet) -{ - int fd; - struct stat fileinfo; - - if (!strcmp(filename, "") || stat(filename, &fileinfo) == -1) { - if (insert) { - if (!quiet) - statusbar(_("\"%s\" not found"), filename); - return -1; - } else { - /* We have a new file */ - statusbar(_("New File")); - new_file(); - } - } else if ((fd = open(filename, O_RDONLY)) == -1) { - if (!quiet) - statusbar("%s: %s", strerror(errno), filename); - return -1; - } else { /* File is A-OK */ - if (S_ISDIR(fileinfo.st_mode)) { - statusbar(_("File \"%s\" is a directory"), filename); - new_file(); - return -1; - } - if (!quiet) - statusbar(_("Reading File")); - read_file(fd, filename); - } - - return 1; -} - -int do_insertfile(void) -{ - int i; - - wrap_reset(); - i = statusq(writefile_list, WRITEFILE_LIST_LEN, "", - _("File to insert [from ./] ")); - if (i != -1) { - -#ifdef DEBUG - fprintf(stderr, "filename is %s", answer); -#endif - - i = open_file(answer, 1, 0); - - dump_buffer(fileage); - set_modified(); - - /* Here we want to rebuild the edit window */ - for(i = 0, editbot = edittop; - i <= editwinrows - 1 - && i <= totlines - && editbot->next != NULL; - editbot = editbot->next, i++); - - /* If we've gone off the bottom, recenter, otherwise just redraw */ - if(current->lineno > editbot->lineno) - edit_update(current); - else - edit_refresh(); - - UNSET(KEEP_CUTBUFFER); - display_main_list(); - return i; - } else { - statusbar(_("Cancelled")); - UNSET(KEEP_CUTBUFFER); - display_main_list(); - return 0; - } -} - void usage(void) { #ifdef HAVE_GETOPT_LONG @@ -643,65 +380,6 @@ void version(void) printf(_(" Email: nano@asty.org Web: http://www.asty.org/nano\n")); } -void page_down_center(void) -{ - if (editbot->next != NULL && editbot->next != filebot) { - edit_update(editbot->next); - center_cursor(); - } else if (editbot != filebot) { - edit_update(editbot); - center_cursor(); - } else { - while (current != filebot) - current = current->next; - edit_update(current); - } - update_cursor(); - -} - -int page_down(void) -{ - wrap_reset(); - current_x = 0; - placewewant = 0; - - if (current == filebot) - return 0; - - if (editbot != filebot) { - current_y = 0; - current = editbot; - } else - while (current != filebot) { - current = current->next; - current_y++; - } - - edit_update_top(current); - update_cursor(); - UNSET(KEEP_CUTBUFFER); - check_statblank(); - return 1; -} - -int do_home(void) -{ - current_x = 0; - placewewant = 0; - update_line(current, current_x); - return 1; -} - -int do_end(void) -{ - current_x = strlen(current->data); - placewewant = xplustabs(); - update_line(current, current_x); - - return 1; -} - filestruct *make_new_node(filestruct * prevnode) { filestruct *newnode; @@ -754,109 +432,6 @@ void nano_small_msg(void) statusbar("Sorry, this function not available with nano-tiny option"); } -/* What happens when we want to go past the bottom of the buffer */ -int do_down(void) -{ - wrap_reset(); - if (current->next != NULL) { - update_line(current->prev, 0); - - if (placewewant > 0) - current_x = actual_x(current->next, placewewant); - - if (current_x > strlen(current->next->data)) - current_x = strlen(current->next->data); - } else { - UNSET(KEEP_CUTBUFFER); - check_statblank(); - return 0; - } - - if (current_y < editwineob && current != editbot) - current_y++; - else - page_down_center(); - - update_cursor(); - update_line(current->prev, 0); - update_line(current, current_x); - UNSET(KEEP_CUTBUFFER); - check_statblank(); - return 1; -} - -void page_up_center(void) -{ - if (edittop != fileage) { - edit_update(edittop); - center_cursor(); - } else - current_y = 0; - - update_cursor(); - -} - -int do_up(void) -{ - wrap_reset(); - if (current->prev != NULL) { - update_line(current, 0); - - if (placewewant > 0) - current_x = actual_x(current->prev, placewewant); - - if (current_x > strlen(current->prev->data)) - current_x = strlen(current->prev->data); - } - if (current_y > 0) - current_y--; - else - page_up_center(); - - update_cursor(); - update_line(current->next, 0); - update_line(current, current_x); - UNSET(KEEP_CUTBUFFER); - check_statblank(); - return 1; -} - -int do_right(void) -{ - if (current_x < strlen(current->data)) { - current_x++; - } else { - if (do_down()) - current_x = 0; - } - - placewewant = xplustabs(); - update_cursor(); - update_line(current, current_x); - UNSET(KEEP_CUTBUFFER); - check_statblank(); - return 1; -} - -int do_left(void) -{ - if (current_x > 0) - current_x--; - else if (current != fileage) { - placewewant = 0; - current_x = strlen(current->prev->data); - do_up(); - } - placewewant = xplustabs(); - - update_cursor(); - update_line(current, current_x); - UNSET(KEEP_CUTBUFFER); - check_statblank(); - return 1; -} - /* The user typed a printable character; add it to the edit buffer */ void do_char(char ch) { @@ -1315,316 +890,6 @@ void do_early_abort(void) blank_statusbar_refresh(); } -/* Set up the system variables for a search or replace. Returns -1 on - abort, 0 on success, and 1 on rerun calling program - Return -2 to run opposite program (searchg -> replace, replace -> search) - - replacing = 1 if we call from do_replace, 0 if called from do_search func. -*/ -int search_init(int replacing) -{ - int i; - char buf[135]; - - if (last_search[0]) { - sprintf(buf, " [%s]", last_search); - } else { - buf[0] = '\0'; - } - - i = statusq(replacing ? replace_list : whereis_list, - replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, "", - ISSET(CASE_SENSITIVE) ? _("Case Sensitive Search%s") : - _("Search%s"), buf); - - /* Cancel any search, or just return with no previous search */ - if ((i == -1) || (i < 0 && !last_search[0])) { - statusbar(_("Search Cancelled")); - reset_cursor(); - return -1; - } else if (i == -2) { /* Same string */ - strncpy(answer, last_search, 132); - } else if (i == 0) { /* They entered something new */ - strncpy(last_search, answer, 132); - - /* Blow away last_replace because they entered a new search - string....uh, right? =) */ - last_replace[0] = '\0'; - } else if (i == NANO_CASE_KEY) { /* They want it case sensitive */ - if (ISSET(CASE_SENSITIVE)) - UNSET(CASE_SENSITIVE); - else - SET(CASE_SENSITIVE); - - return 1; - } else if (i == NANO_OTHERSEARCH_KEY) { - return -2; /* Call the opposite search function */ - } else { /* First line key, etc. */ - do_early_abort(); - return -3; - } - - return 0; -} - -filestruct *findnextstr(int quiet, filestruct * begin, char *needle) -{ - filestruct *fileptr; - char *searchstr, *found = NULL, *tmp; - - fileptr = current; - - searchstr = ¤t->data[current_x + 1]; - /* Look for searchstr until EOF */ - while (fileptr != NULL && - (found = strstrwrapper(searchstr, needle)) == NULL) { - fileptr = fileptr->next; - - if (fileptr == begin) - return NULL; - - if (fileptr != NULL) - searchstr = fileptr->data; - } - - /* If we're not at EOF, we found an instance */ - if (fileptr != NULL) { - current = fileptr; - current_x = 0; - for (tmp = fileptr->data; tmp != found; tmp++) - current_x++; - - edit_update(current); - reset_cursor(); - } else { /* We're at EOF, go back to the top, once */ - - fileptr = fileage; - - while (fileptr != current && fileptr != begin && - (found = strstrwrapper(fileptr->data, needle)) == NULL) - fileptr = fileptr->next; - - if (fileptr == begin) { - if (!quiet) - statusbar(_("\"%s\" not found"), needle); - - return NULL; - } - if (fileptr != current) { /* We found something */ - current = fileptr; - current_x = 0; - for (tmp = fileptr->data; tmp != found; tmp++) - current_x++; - - edit_update(current); - reset_cursor(); - - if (!quiet) - statusbar(_("Search Wrapped")); - } else { /* Nada */ - - if (!quiet) - statusbar(_("\"%s\" not found"), needle); - return NULL; - } - } - - return fileptr; -} - -void search_abort(void) -{ - UNSET(KEEP_CUTBUFFER); - display_main_list(); - wrefresh(bottomwin); -} - -/* Search for a string */ -int do_search(void) -{ - int i; - filestruct *fileptr = current; - - wrap_reset(); - if ((i = search_init(0)) == -1) { - current = fileptr; - search_abort(); - return 0; - } else if (i == -3) { - search_abort(); - return 0; - } else if (i == -2) { - search_abort(); - do_replace(); - return 0; - } else if (i == 1) { - do_search(); - search_abort(); - return 1; - } - findnextstr(0, current, answer); - search_abort(); - return 1; -} - -void print_replaced(int num) -{ - if (num > 1) - statusbar(_("Replaced %d occurences"), num); - else if (num == 1) - statusbar(_("Replaced 1 occurence")); -} - -void replace_abort(void) -{ - UNSET(KEEP_CUTBUFFER); - display_main_list(); - reset_cursor(); -} - -/* Search for a string */ -int do_replace(void) -{ - int i, replaceall = 0, numreplaced = 0, beginx; - filestruct *fileptr, *begin; - char *tmp, *copy, prevanswer[132] = ""; - - if ((i = search_init(1)) == -1) { - statusbar(_("Replace Cancelled")); - replace_abort(); - return 0; - } else if (i == 1) { - do_replace(); - return 1; - } else if (i == -2) { - replace_abort(); - do_search(); - return 0; - } else if (i == -3) { - replace_abort(); - return 0; - } - strncpy(prevanswer, answer, 132); - - if (strcmp(last_replace, "")) { /* There's a previous replace str */ - i = statusq(replace_list, REPLACE_LIST_LEN, "", - _("Replace with [%s]"), last_replace); - - if (i == -1) { /* Aborted enter */ - strncpy(answer, last_replace, 132); - statusbar(_("Replace Cancelled")); - replace_abort(); - return 0; - } else if (i == 0) /* They actually entered something */ - strncpy(last_replace, answer, 132); - else if (i == NANO_CASE_KEY) { /* They asked for case sensitivity */ - if (ISSET(CASE_SENSITIVE)) - UNSET(CASE_SENSITIVE); - else - SET(CASE_SENSITIVE); - - do_replace(); - return 0; - } else { /* First page, last page, for example could get here */ - - do_early_abort(); - replace_abort(); - return 0; - } - } else { /* last_search is empty */ - - i = statusq(replace_list, REPLACE_LIST_LEN, "", _("Replace with")); - if (i == -1) { - statusbar(_("Replace Cancelled")); - reset_cursor(); - replace_abort(); - return 0; - } else if (i == 0) /* They entered something new */ - strncpy(last_replace, answer, 132); - else if (i == NANO_CASE_KEY) { /* They want it case sensitive */ - if (ISSET(CASE_SENSITIVE)) - UNSET(CASE_SENSITIVE); - else - SET(CASE_SENSITIVE); - - do_replace(); - return 1; - } else { /* First line key, etc. */ - - do_early_abort(); - replace_abort(); - return 0; - } - } - - /* save where we are */ - begin = current; - beginx = current_x; - - while (1) { - - if (replaceall) - fileptr = findnextstr(1, begin, prevanswer); - else - fileptr = findnextstr(0, begin, prevanswer); - - /* No more matches. Done! */ - if (!fileptr) - break; - - /* If we're here, we've found the search string */ - if (!replaceall) - i = do_yesno(1, 1, _("Replace this instance?")); - - if (i > 0 || replaceall) { /* Yes, replace it!!!! */ - if (i == 2) - replaceall = 1; - - /* Create buffer */ - copy = nmalloc(strlen(current->data) - strlen(last_search) + - strlen(last_replace) + 1); - - /* Head of Original Line */ - strncpy(copy, current->data, current_x); - copy[current_x] = 0; - - /* Replacement Text */ - strcat(copy, last_replace); - - /* The tail of the original line */ - /* This may expose other bugs, because it no longer - goes through each character on the string - and tests for string goodness. But because - we can assume the invariant that current->data - is less than current_x + strlen(last_search) long, - this should be safe. Or it will expose bugs ;-) */ - tmp = current->data + current_x + strlen(last_search); - strcat(copy, tmp); - - /* Cleanup */ - free(current->data); - current->data = copy; - - /* Stop bug where we replace a substring of the replacement text */ - current_x += strlen(last_replace); - - edit_refresh(); - set_modified(); - numreplaced++; - } else if (i == -1) /* Abort, else do nothing and continue loop */ - break; - } - - current = begin; - current_x = beginx; - renumber_all(); - edit_update(current); - print_replaced(numreplaced); - replace_abort(); - return 1; -} - - int page_up(void) { wrap_reset(); @@ -1759,276 +1024,18 @@ int do_delete(void) return 1; } -void goto_abort(void) -{ - UNSET(KEEP_CUTBUFFER); - display_main_list(); -} - -int do_gotoline(long defline) -{ - long line, i = 1, j = 0; - filestruct *fileptr; - - if (defline > 0) /* We already know what line we want to go to */ - line = defline; - else { /* Ask for it */ - - j = statusq(goto_list, GOTO_LIST_LEN, "", _("Enter line number")); - if (j == -1) { - statusbar(_("Aborted")); - goto_abort(); - return 0; - } else if (j != 0) { - do_early_abort(); - goto_abort(); - return 0; - } - if (!strcmp(answer, "$")) { - current = filebot; - current_x = 0; - edit_update(current); - goto_abort(); - return 1; - } - line = atoi(answer); - } - - /* Bounds check */ - if (line <= 0) { - statusbar(_("Come on, be reasonable")); - goto_abort(); - return 0; - } - if (line > totlines) { - statusbar(_("Only %d lines available, skipping to last line"), - filebot->lineno); - current = filebot; - current_x = 0; - edit_update(current); - } else { - for (fileptr = fileage; fileptr != NULL && i < line; i++) - fileptr = fileptr->next; - - current = fileptr; - current_x = 0; - edit_update(current); - } - - goto_abort(); - return 1; -} - -int do_gotoline_void(void) -{ - return do_gotoline(0); -} - void wrap_reset(void) { UNSET(SAMELINEWRAP); } -/* - * Write a file out. If tmp is nonzero, we set the umask to 0600, - * we don't set the global variable filename to it's name, and don't - * print out how many lines we wrote on the statusbar. - * - * Note that tmp is only set to 1 for storing temporary files internal - * to the editor, and is completely different from temp_opt. - */ -int write_file(char *name, int tmp) -{ - long size, lineswritten = 0; - char buf[PATH_MAX + 1]; - filestruct *fileptr; - int fd, mask = 0; - struct stat st; - - if (!strcmp(name, "")) { - statusbar(_("Cancelled")); - return -1; - } - titlebar(); - fileptr = fileage; - - - /* Open the file and truncate it. Trust the symlink. */ - if (ISSET(FOLLOW_SYMLINKS) && !tmp) { - if ((fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | - S_IWOTH)) == -1) { - statusbar(_("Could not open file for writing: %s"), - strerror(errno)); - return -1; - } - } - /* Don't follow symlink. Create new file. */ - else { - if (strlen(name) > (PATH_MAX - 7)) { - statusbar(_("Could not open file: Path length exceeded.")); - return -1; - } - - memset(buf, 0x00, PATH_MAX + 1); - strcat(buf, name); - strcat(buf, ".XXXXXX"); - if ((fd = mkstemp(buf)) == -1) { - statusbar(_("Could not open file for writing: %s"), - strerror(errno)); - return -1; - } - } - - - - dump_buffer(fileage); - while (fileptr != NULL && fileptr->next != NULL) { - size = write(fd, fileptr->data, strlen(fileptr->data)); - if (size == -1) { - statusbar(_("Could not open file for writing: %s"), - strerror(errno)); - return -1; - } else { -#ifdef DEBUG - fprintf(stderr, _("Wrote >%s\n"), fileptr->data); -#endif - } - write(fd, "\n", 1); - - fileptr = fileptr->next; - lineswritten++; - } - - if (fileptr != NULL) { - size = write(fd, fileptr->data, strlen(fileptr->data)); - if (size == -1) { - statusbar(_("Could not open file for writing: %s"), - strerror(errno)); - return -1; - } else if (size > 0) { - size = write(fd, "\n", 1); - if (size == -1) { - statusbar(_("Could not open file for writing: %s"), - strerror(errno)); - return -1; - } - } - } - - - if (close(fd) == -1) { - statusbar(_("Could not close %s: %s"), name, strerror(errno)); - unlink(buf); - return -1; - } - - if (!ISSET(FOLLOW_SYMLINKS) || tmp) { - if (stat(name, &st) == -1) { - /* Use default umask as file permisions if file is a new file. */ - mask = umask(0); - umask(mask); - - if (tmp) /* We don't want anyone reading our temporary file! */ - mask = 0600; - else - mask = 0666 & ~mask; - - } else { - /* Use permissions from file we are overwriting. */ - mask = st.st_mode; - if (unlink(name) == -1) { - if (errno != ENOENT) { - statusbar(_("Could not open %s for writing: %s"), - name, strerror(errno)); - unlink(buf); - return -1; - } - } - } - - if (link(buf, name) != -1) - unlink(buf); - else if (errno != EPERM) { - statusbar(_("Could not open %s for writing: %s"), - name, strerror(errno)); - unlink(buf); - return -1; - } else if (rename(buf, name) == -1) { /* Try a rename?? */ - statusbar(_("Could not open %s for writing: %s"), - name, strerror(errno)); - unlink(buf); - return -1; - } - if (chmod(name, mask) == -1) { - statusbar(_("Could not set permissions %o on %s: %s"), - mask, name, strerror(errno)); - } - - } - if (!tmp) { - strncpy(filename, name, 132); - statusbar(_("Wrote %d lines"), lineswritten); - } - UNSET(MODIFIED); - titlebar(); - return 1; -} - -int do_writeout(int exiting) -{ - int i = 0; - - strncpy(answer, filename, 132); - - if ((exiting) && (temp_opt) && (filename)) { - i = write_file(answer, 0); - display_main_list(); - return i; - } - - while (1) { - i = statusq(writefile_list, WRITEFILE_LIST_LEN, answer, - _("File Name to write")); - - if (i != -1) { - -#ifdef DEBUG - fprintf(stderr, _("filename is %s"), answer); -#endif - if (strncmp(answer, filename, 132)) { - struct stat st; - if (!stat(answer, &st)) { - i = do_yesno(0, 0, _("File exists, OVERWRITE ?")); - - if (!i || (i == -1)) - continue; - } - } - i = write_file(answer, 0); - - display_main_list(); - return i; - } else { - statusbar(_("Cancelled")); - display_main_list(); - return 0; - } - } -} - -int do_writeout_void(void) -{ - return do_writeout(0); -} - /* Stuff we want to do when we exit the spell program one of its many ways */ void exit_spell(char *tmpfilename, char *foo) { free(foo); - + if (remove(tmpfilename) == -1) - statusbar(_("Error deleting tempfile, ack!")); + statusbar(_("Error deleting tempfile, ack!")); } /* @@ -2258,7 +1265,6 @@ void handle_sigwinch(int s) center_x = COLS / 2; center_y = LINES / 2; editwinrows = LINES - 5 + no_help(); - editwineob = editwinrows - 1; fill = COLS - 8; free(hblank); @@ -2288,11 +1294,11 @@ void handle_sigwinch(int s) editbot = edittop; - for (i = 0; (i <= editwineob) && (editbot->next != NULL) + for (i = 0; (i <= editwinrows - 1) && (editbot->next != NULL) && (editbot->next != filebot); i++) editbot = editbot->next; - if (current_y > editwineob) { + if (current_y > editwinrows - 1) { edit_update(editbot); } erase(); @@ -2472,14 +1478,14 @@ int do_justify(void) current_x = 0; placewewant = 0; - if ((current_y < 0) || (current_y >= editwineob) || (initial_y <= 0)) { + if ((current_y < 0) || (current_y >= editwinrows - 1) || (initial_y <= 0)) { edit_update(current); center_cursor(); } else { int i = 0; editbot = edittop; - for (i = 0; (i <= editwineob) && (editbot->next != NULL) + for (i = 0; (i <= editwinrows - 1) && (editbot->next != NULL) && (editbot->next != filebot); i++) editbot = editbot->next; edit_refresh(); diff --git a/proto.h b/proto.h index 40f3c29d..6d86025c 100644 --- a/proto.h +++ b/proto.h @@ -58,6 +58,16 @@ int write_file(char *name, int tmpfile); int do_cut_text(void); int do_uncut_text(void); int no_help(void); +int renumber_all(void); +int open_file(char *filename, int insert, int quiet); +int do_writeout(int exiting); +int do_gotoline(long defline); +/* Now in move.c */ +int do_up(void); +int do_down(void); +int do_left(void); +int do_right(void); + void shortcut_init(void); void lowercase(char *src); @@ -86,6 +96,12 @@ void *nmalloc (size_t howmuch); void wrap_reset(void); void display_main_list(void); void nano_small_msg(void); +void do_early_abort(void); +void *nmalloc(size_t howmuch); +void *nrealloc(void *ptr, size_t howmuch); +void die(char *msg, ...); +void new_file(void); + int do_writeout_void(void), do_exit(void), do_gotoline_void(void); int do_insertfile(void), do_search(void), page_up(void), page_down(void); diff --git a/search.c b/search.c new file mode 100644 index 00000000..981cf06d --- /dev/null +++ b/search.c @@ -0,0 +1,408 @@ +/************************************************************************** + * search.c * + * * + * Copyright (C) 2000 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 +#include +#include +#include "config.h" +#include "proto.h" +#include "nano.h" + +#ifndef NANO_SMALL +#include +#define _(string) gettext(string) +#else +#define _(string) (string) +#endif + +/* Set up the system variables for a search or replace. Returns -1 on + abort, 0 on success, and 1 on rerun calling program + Return -2 to run opposite program (searchg -> replace, replace -> search) + + replacing = 1 if we call from do_replace, 0 if called from do_search func. +*/ +int search_init(int replacing) +{ + int i; + char buf[135]; + + if (last_search[0]) { + sprintf(buf, " [%s]", last_search); + } else { + buf[0] = '\0'; + } + + i = statusq(replacing ? replace_list : whereis_list, + replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, "", + ISSET(CASE_SENSITIVE) ? _("Case Sensitive Search%s") : + _("Search%s"), buf); + + /* Cancel any search, or just return with no previous search */ + if ((i == -1) || (i < 0 && !last_search[0])) { + statusbar(_("Search Cancelled")); + reset_cursor(); + return -1; + } else if (i == -2) { /* Same string */ + strncpy(answer, last_search, 132); + } else if (i == 0) { /* They entered something new */ + strncpy(last_search, answer, 132); + + /* Blow away last_replace because they entered a new search + string....uh, right? =) */ + last_replace[0] = '\0'; + } else if (i == NANO_CASE_KEY) { /* They want it case sensitive */ + if (ISSET(CASE_SENSITIVE)) + UNSET(CASE_SENSITIVE); + else + SET(CASE_SENSITIVE); + + return 1; + } else if (i == NANO_OTHERSEARCH_KEY) { + return -2; /* Call the opposite search function */ + } else { /* First line key, etc. */ + do_early_abort(); + return -3; + } + + return 0; +} + +filestruct *findnextstr(int quiet, filestruct * begin, char *needle) +{ + filestruct *fileptr; + char *searchstr, *found = NULL, *tmp; + + fileptr = current; + + searchstr = ¤t->data[current_x + 1]; + /* Look for searchstr until EOF */ + while (fileptr != NULL && + (found = strstrwrapper(searchstr, needle)) == NULL) { + fileptr = fileptr->next; + + if (fileptr == begin) + return NULL; + + if (fileptr != NULL) + searchstr = fileptr->data; + } + + /* If we're not at EOF, we found an instance */ + if (fileptr != NULL) { + current = fileptr; + current_x = 0; + for (tmp = fileptr->data; tmp != found; tmp++) + current_x++; + + edit_update(current); + reset_cursor(); + } else { /* We're at EOF, go back to the top, once */ + + fileptr = fileage; + + while (fileptr != current && fileptr != begin && + (found = strstrwrapper(fileptr->data, needle)) == NULL) + fileptr = fileptr->next; + + if (fileptr == begin) { + if (!quiet) + statusbar(_("\"%s\" not found"), needle); + + return NULL; + } + if (fileptr != current) { /* We found something */ + current = fileptr; + current_x = 0; + for (tmp = fileptr->data; tmp != found; tmp++) + current_x++; + + edit_update(current); + reset_cursor(); + + if (!quiet) + statusbar(_("Search Wrapped")); + } else { /* Nada */ + + if (!quiet) + statusbar(_("\"%s\" not found"), needle); + return NULL; + } + } + + return fileptr; +} + +void search_abort(void) +{ + UNSET(KEEP_CUTBUFFER); + display_main_list(); + wrefresh(bottomwin); +} + +/* Search for a string */ +int do_search(void) +{ + int i; + filestruct *fileptr = current; + + wrap_reset(); + if ((i = search_init(0)) == -1) { + current = fileptr; + search_abort(); + return 0; + } else if (i == -3) { + search_abort(); + return 0; + } else if (i == -2) { + search_abort(); + do_replace(); + return 0; + } else if (i == 1) { + do_search(); + search_abort(); + return 1; + } + findnextstr(0, current, answer); + search_abort(); + return 1; +} + +void print_replaced(int num) +{ + if (num > 1) + statusbar(_("Replaced %d occurences"), num); + else if (num == 1) + statusbar(_("Replaced 1 occurence")); +} + +void replace_abort(void) +{ + UNSET(KEEP_CUTBUFFER); + display_main_list(); + reset_cursor(); +} + +/* Search for a string */ +int do_replace(void) +{ + int i, replaceall = 0, numreplaced = 0, beginx; + filestruct *fileptr, *begin; + char *tmp, *copy, prevanswer[132] = ""; + + if ((i = search_init(1)) == -1) { + statusbar(_("Replace Cancelled")); + replace_abort(); + return 0; + } else if (i == 1) { + do_replace(); + return 1; + } else if (i == -2) { + replace_abort(); + do_search(); + return 0; + } else if (i == -3) { + replace_abort(); + return 0; + } + strncpy(prevanswer, answer, 132); + + if (strcmp(last_replace, "")) { /* There's a previous replace str */ + i = statusq(replace_list, REPLACE_LIST_LEN, "", + _("Replace with [%s]"), last_replace); + + if (i == -1) { /* Aborted enter */ + strncpy(answer, last_replace, 132); + statusbar(_("Replace Cancelled")); + replace_abort(); + return 0; + } else if (i == 0) /* They actually entered something */ + strncpy(last_replace, answer, 132); + else if (i == NANO_CASE_KEY) { /* They asked for case sensitivity */ + if (ISSET(CASE_SENSITIVE)) + UNSET(CASE_SENSITIVE); + else + SET(CASE_SENSITIVE); + + do_replace(); + return 0; + } else { /* First page, last page, for example could get here */ + + do_early_abort(); + replace_abort(); + return 0; + } + } else { /* last_search is empty */ + + i = statusq(replace_list, REPLACE_LIST_LEN, "", _("Replace with")); + if (i == -1) { + statusbar(_("Replace Cancelled")); + reset_cursor(); + replace_abort(); + return 0; + } else if (i == 0) /* They entered something new */ + strncpy(last_replace, answer, 132); + else if (i == NANO_CASE_KEY) { /* They want it case sensitive */ + if (ISSET(CASE_SENSITIVE)) + UNSET(CASE_SENSITIVE); + else + SET(CASE_SENSITIVE); + + do_replace(); + return 1; + } else { /* First line key, etc. */ + + do_early_abort(); + replace_abort(); + return 0; + } + } + + /* save where we are */ + begin = current; + beginx = current_x; + + while (1) { + + if (replaceall) + fileptr = findnextstr(1, begin, prevanswer); + else + fileptr = findnextstr(0, begin, prevanswer); + + /* No more matches. Done! */ + if (!fileptr) + break; + + /* If we're here, we've found the search string */ + if (!replaceall) + i = do_yesno(1, 1, _("Replace this instance?")); + + if (i > 0 || replaceall) { /* Yes, replace it!!!! */ + if (i == 2) + replaceall = 1; + + /* Create buffer */ + copy = nmalloc(strlen(current->data) - strlen(last_search) + + strlen(last_replace) + 1); + + /* Head of Original Line */ + strncpy(copy, current->data, current_x); + copy[current_x] = 0; + + /* Replacement Text */ + strcat(copy, last_replace); + + /* The tail of the original line */ + /* This may expose other bugs, because it no longer + goes through each character on the string + and tests for string goodness. But because + we can assume the invariant that current->data + is less than current_x + strlen(last_search) long, + this should be safe. Or it will expose bugs ;-) */ + tmp = current->data + current_x + strlen(last_search); + strcat(copy, tmp); + + /* Cleanup */ + free(current->data); + current->data = copy; + + /* Stop bug where we replace a substring of the replacement text */ + current_x += strlen(last_replace); + + edit_refresh(); + set_modified(); + numreplaced++; + } else if (i == -1) /* Abort, else do nothing and continue loop */ + break; + } + + current = begin; + current_x = beginx; + renumber_all(); + edit_update(current); + print_replaced(numreplaced); + replace_abort(); + return 1; +} + +void goto_abort(void) +{ + UNSET(KEEP_CUTBUFFER); + display_main_list(); +} + +int do_gotoline(long defline) +{ + long line, i = 1, j = 0; + filestruct *fileptr; + + if (defline > 0) /* We already know what line we want to go to */ + line = defline; + else { /* Ask for it */ + + j = statusq(goto_list, GOTO_LIST_LEN, "", _("Enter line number")); + if (j == -1) { + statusbar(_("Aborted")); + goto_abort(); + return 0; + } else if (j != 0) { + do_early_abort(); + goto_abort(); + return 0; + } + if (!strcmp(answer, "$")) { + current = filebot; + current_x = 0; + edit_update(current); + goto_abort(); + return 1; + } + line = atoi(answer); + } + + /* Bounds check */ + if (line <= 0) { + statusbar(_("Come on, be reasonable")); + goto_abort(); + return 0; + } + if (line > totlines) { + statusbar(_("Only %d lines available, skipping to last line"), + filebot->lineno); + current = filebot; + current_x = 0; + edit_update(current); + } else { + for (fileptr = fileage; fileptr != NULL && i < line; i++) + fileptr = fileptr->next; + + current = fileptr; + current_x = 0; + edit_update(current); + } + + goto_abort(); + return 1; +} + +int do_gotoline_void(void) +{ + return do_gotoline(0); +} + diff --git a/utils.c b/utils.c index fa44d80b..6649b4a2 100644 --- a/utils.c +++ b/utils.c @@ -26,6 +26,13 @@ #include "nano.h" #include "proto.h" +#ifndef NANO_SMALL +#include +#define _(string) gettext(string) +#else +#define _(string) (string) +#endif + /* Lower case a string - must be null terminated */ void lowercase(char *src) { @@ -79,3 +86,27 @@ char *strstrwrapper(char *haystack, char *needle) else return strcasestr(haystack, needle); } + +/* Thanks BG, many ppl have been asking for this... */ +void *nmalloc(size_t howmuch) +{ + void *r; + + /* Panic save? */ + + if (!(r = malloc(howmuch))) + die(_("nano: malloc: out of memory!")); + + return r; +} + +void *nrealloc(void *ptr, size_t howmuch) +{ + void *r; + + if (!(r = realloc(ptr, howmuch))) + die("nano: realloc: out of memory!"); + + return r; +} +