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
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
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@
@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 \
--- /dev/null
+/**************************************************************************
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.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
+
+/* 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);
+}
+
--- /dev/null
+/**************************************************************************
+ * 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 <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
+
+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;
+}
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 = "";
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"));
current_x = 0;
current_y = 0;
editwinrows = LINES - 5 + no_help();
- editwineob = editwinrows - 1;
fileage = NULL;
cutbuffer = NULL;
current = NULL;
*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
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;
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)
{
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();
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!"));
}
/*
center_x = COLS / 2;
center_y = LINES / 2;
editwinrows = LINES - 5 + no_help();
- editwineob = editwinrows - 1;
fill = COLS - 8;
free(hblank);
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();
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();
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);
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);
--- /dev/null
+/**************************************************************************
+ * 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 <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
+
+/* 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);
+}
+
#include "nano.h"
#include "proto.h"
+#ifndef NANO_SMALL
+#include <libintl.h>
+#define _(string) gettext(string)
+#else
+#define _(string) (string)
+#endif
+
/* Lower case a string - must be null terminated */
void lowercase(char *src)
{
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;
+}
+