mirror of
git://git.sv.gnu.org/nano.git
synced 2024-11-25 06:09:38 +03:00
Split nano.c up more
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@27 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
This commit is contained in:
parent
b0b367e05d
commit
bceb1b21a6
@ -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
|
||||
|
||||
|
@ -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 \
|
||||
|
470
files.c
Normal file
470
files.c
Normal file
@ -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 <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);
|
||||
}
|
||||
|
195
move.c
Normal file
195
move.c
Normal file
@ -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 <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;
|
||||
}
|
16
proto.h
16
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);
|
||||
|
408
search.c
Normal file
408
search.c
Normal file
@ -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 <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);
|
||||
}
|
||||
|
31
utils.c
31
utils.c
@ -26,6 +26,13 @@
|
||||
#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)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user