Commit 90573296 authored by David Lawrence Ramsey's avatar David Lawrence Ramsey
Browse files

reorder some functions for consistency

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2830 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
parent 826ab5a4
Showing with 1520 additions and 1519 deletions
+1520 -1519
......@@ -5,6 +5,7 @@ CVS code -
saved as an int instead of a ssize_t. Changes to
renumber_all(), renumber(), do_alt_speller(), and
backup_lines(). (DLR)
- Reorder some functions for consistency. (DLR)
- global.c:
shortcut_init()
- Simplify wording of nano_gotoline_msg. (Jordi)
......
......@@ -40,950 +40,950 @@
static file_format fmt = NIX_FILE;
/* The format of the current file. */
/* What happens when there is no file to open? aiee! */
void new_file(void)
#ifdef ENABLE_MULTIBUFFER
/* Create a new openfilestruct node. */
openfilestruct *make_new_opennode(void)
{
fileage = make_new_node(NULL);
fileage->data = mallocstrcpy(NULL, "");
filebot = fileage;
edittop = fileage;
current = fileage;
current_x = 0;
totlines = 1;
totsize = 0;
openfilestruct *newnode =
(openfilestruct *)nmalloc(sizeof(openfilestruct));
newnode->filename = NULL;
#ifdef ENABLE_COLOR
update_color();
if (!ISSET(NO_COLOR_SYNTAX))
edit_refresh();
#endif
return newnode;
}
/* We make a new line of text from buf. buf is length buf_len. If
* first_line_ins is TRUE, then we put the new line at the top of the
* file. Otherwise, we assume prevnode is the last line of the file,
* and put our line after prevnode. */
filestruct *read_line(char *buf, filestruct *prevnode, bool
*first_line_ins, size_t buf_len)
/* Splice a node into an existing openfilestruct. */
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
openfilestruct *end)
{
filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct));
/* Convert nulls to newlines. buf_len is the string's real length
* here. */
unsunder(buf, buf_len);
assert(strlen(buf) == buf_len);
fileptr->data = mallocstrcpy(NULL, buf);
#ifndef NANO_SMALL
/* If it's a DOS file ("\r\n"), and file conversion isn't disabled,
* strip the '\r' part from fileptr->data. */
if (!ISSET(NO_CONVERT) && buf_len > 0 && buf[buf_len - 1] == '\r')
fileptr->data[buf_len - 1] = '\0';
#endif
assert(newnode != NULL && begin != NULL);
if (*first_line_ins == TRUE || fileage == NULL) {
/* Special case: We're inserting with the cursor on the first
* line. */
fileptr->prev = NULL;
fileptr->next = fileage;
fileptr->lineno = 1;
if (*first_line_ins == TRUE) {
*first_line_ins = FALSE;
/* 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. */
edittop = fileptr;
} else
filebot = fileptr;
fileage = fileptr;
} else {
assert(prevnode != NULL);
newnode->next = end;
newnode->prev = begin;
begin->next = newnode;
if (end != NULL)
end->prev = newnode;
}
fileptr->prev = prevnode;
fileptr->next = NULL;
fileptr->lineno = prevnode->lineno + 1;
prevnode->next = fileptr;
}
/* Unlink a node from the rest of the openfilestruct, and delete it. */
void unlink_opennode(openfilestruct *fileptr)
{
assert(fileptr != NULL && fileptr->prev != NULL && fileptr->next != NULL && fileptr != fileptr->prev && fileptr != fileptr->next);
return fileptr;
fileptr->prev->next = fileptr->next;
fileptr->next->prev = fileptr->prev;
delete_opennode(fileptr);
}
/* Load a file into the edit buffer. This takes data from the file
* struct. */
void load_file(void)
/* Delete a node from the openfilestruct. */
void delete_opennode(openfilestruct *fileptr)
{
current = fileage;
#ifdef ENABLE_MULTIBUFFER
/* Add a new entry to the open_files structure. */
add_open_file(FALSE);
assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL);
/* Reinitialize the shortcut list. */
shortcut_init(FALSE);
#endif
free(fileptr->filename);
free_filestruct(fileptr->fileage);
free(fileptr);
}
void read_file(FILE *f, const char *filename)
#ifdef DEBUG
/* Deallocate all memory associated with this and later files, including
* the lines of text. */
void free_openfilestruct(openfilestruct *src)
{
size_t num_lines = 0;
/* The number of lines in the file. */
size_t num_chars;
/* The number of characters in the file. */
size_t len = 0;
/* The length of the current line of the file. */
size_t i = 0;
/* The position in the current line of the file. */
size_t bufx = MAX_BUF_SIZE;
/* The size of each chunk of the file that we read. */
char input = '\0';
/* The current input character. */
char *buf;
/* The buffer where we store chunks of the file. */
filestruct *fileptr = current;
/* The current line of the file. */
bool first_line_ins = FALSE;
/* Whether we're inserting with the cursor on the first line. */
int input_int;
/* The current value we read from the file, whether an input
* character or EOF. */
#ifndef NANO_SMALL
int format = 0;
/* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */
assert(src != NULL);
while (src != src->next) {
src = src->next;
delete_opennode(src->prev);
}
delete_opennode(src);
}
#endif
buf = charalloc(bufx);
buf[0] = '\0';
/* Add/update an entry to the open_files openfilestruct. If update is
* FALSE, a new entry is created; otherwise, the current entry is
* updated. */
void add_open_file(bool update)
{
if (update && open_files == NULL)
return;
if (current != NULL) {
if (current == fileage)
first_line_ins = TRUE;
else
fileptr = current->prev;
/* If there are no entries in open_files, make the first one. */
if (open_files == NULL) {
open_files = make_new_opennode();
splice_opennode(open_files, open_files, open_files);
/* Otherwise, if we're not updating, make a new entry for
* open_files and splice it in after the current entry. */
} else if (!update) {
splice_opennode(open_files, make_new_opennode(),
open_files->next);
open_files = open_files->next;
}
/* For the assertion in read_line(), it must be true that if current
* is NULL, then so is fileage. */
assert(current != NULL || fileage == NULL);
/* Save the current filename. */
open_files->filename = mallocstrcpy(open_files->filename, filename);
#ifndef NANO_SMALL
/* We don't know which file format we have yet, so assume it's a
* *nix file for now. */
fmt = NIX_FILE;
/* Save the current file's stat. */
open_files->originalfilestat = originalfilestat;
#endif
/* Read the entire file into the file struct. */
while ((input_int = getc(f)) != EOF) {
input = (char)input_int;
/* Save the current file buffer. */
open_files->fileage = fileage;
open_files->filebot = filebot;
/* If it's a *nix file ("\n") or a DOS file ("\r\n"), and file
* conversion isn't disabled, handle it! */
if (input == '\n') {
#ifndef NANO_SMALL
/* If there's a '\r' before the '\n', set format to DOS if
* we currently think this is a *nix file, or to both if we
* currently think it's a Mac file. */
if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r' &&
(format == 0 || format == 2))
format++;
#endif
/* Save the current top of the edit window. */
open_files->edittop = edittop;
/* Read in the line properly. */
fileptr = read_line(buf, fileptr, &first_line_ins, len);
/* Save the current line. */
open_files->current = current;
/* Reset the line length in preparation for the next
* line. */
len = 0;
/* Save the current cursor position. */
open_files->current_x = current_x;
num_lines++;
buf[0] = '\0';
i = 0;
#ifndef NANO_SMALL
/* If it's a Mac file ('\r' without '\n'), and file conversion
* isn't disabled, handle it! */
} else if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r') {
/* Save the current place we want. */
open_files->placewewant = placewewant;
/* If we currently think the file is a *nix file, set format
* to Mac. If we currently think the file is a DOS file,
* set format to both DOS and Mac. */
if (format == 0 || format == 1)
format += 2;
/* Save the current total number of lines. */
open_files->totlines = totlines;
/* Read in the line properly. */
fileptr = read_line(buf, fileptr, &first_line_ins, len);
/* Save the current total size. */
open_files->totsize = totsize;
/* Reset the line length in preparation for the next line.
* Since we've already read in the next character, reset it
* to 1 instead of 0. */
len = 1;
/* Start with no flags saved. */
open_files->flags = 0;
num_lines++;
buf[0] = input;
buf[1] = '\0';
i = 1;
#endif
} else {
/* Calculate the total length of the line. It might have
* nulls in it, so we can't just use strlen() here. */
len++;
/* Save the current modification status. */
if (ISSET(MODIFIED))
open_files->flags |= MODIFIED;
/* Now we allocate a bigger buffer MAX_BUF_SIZE 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) {
bufx += MAX_BUF_SIZE;
buf = charealloc(buf, bufx);
#ifndef NANO_SMALL
/* Save the current marking status and mark, if applicable. */
if (ISSET(MARK_ISSET)) {
open_files->flags |= MARK_ISSET;
open_files->mark_beginbuf = mark_beginbuf;
open_files->mark_beginx = mark_beginx;
}
buf[i] = input;
buf[i + 1] = '\0';
i++;
}
}
/* Save the current file format. */
open_files->fmt = fmt;
#endif
/* Perhaps this could use some better handling. */
if (ferror(f))
nperror(filename);
fclose(f);
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
}
#ifndef NANO_SMALL
/* If file conversion isn't disabled and the last character in this
* file is '\r', read it in properly as a Mac format line. */
if (len == 0 && !ISSET(NO_CONVERT) && input == '\r') {
len = 1;
/* Read the current entry in the open_files structure and set up the
* currently open file buffer using that entry's information. */
void load_open_file(void)
{
assert(open_files != NULL);
buf[0] = input;
buf[1] = '\0';
}
#endif
/* Restore the current filename. */
filename = mallocstrcpy(filename, open_files->filename);
/* Did we not get a newline and still have stuff to do? */
if (len > 0) {
#ifndef NANO_SMALL
/* If file conversion isn't disabled and the last character in
* this file is '\r', set format to Mac if we currently think
* the file is a *nix file, or to both DOS and Mac if we
* currently think the file is a DOS file. */
if (!ISSET(NO_CONVERT) && buf[len - 1] == '\r' &&
(format == 0 || format == 1))
format += 2;
/* Restore the current file's stat. */
originalfilestat = open_files->originalfilestat;
#endif
/* Read in the last line properly. */
fileptr = read_line(buf, fileptr, &first_line_ins, len);
num_lines++;
}
/* Restore the current file buffer. */
fileage = open_files->fileage;
filebot = open_files->filebot;
free(buf);
/* Restore the current top of the edit window. */
edittop = open_files->edittop;
/* If we didn't get a file and we don't already have one, make a new
* file. */
if (fileptr == NULL)
new_file();
/* Restore the current line. */
current = open_files->current;
/* Did we try to insert a file of 0 bytes? */
if (num_lines != 0) {
if (current != NULL) {
fileptr->next = current;
current->prev = fileptr;
renumber(current);
current_x = 0;
placewewant = 0;
} else if (fileptr->next == NULL) {
filebot = fileptr;
new_magicline();
totsize--;
}
}
/* Restore the current cursor position. */
current_x = open_files->current_x;
get_totals(fileage, filebot, NULL, &num_chars);
totsize += num_chars;
/* Restore the current place we want. */
placewewant = open_files->placewewant;
/* Restore the current total number of lines. */
totlines = open_files->totlines;
/* Restore the current total size. */
totsize = open_files->totsize;
/* Restore the current modification status. */
if (open_files->flags & MODIFIED)
SET(MODIFIED);
else
UNSET(MODIFIED);
#ifndef NANO_SMALL
if (format == 3)
statusbar(
P_("Read %lu line (Converted from DOS and Mac format)",
"Read %lu lines (Converted from DOS and Mac format)",
(unsigned long)num_lines), (unsigned long)num_lines);
else if (format == 2) {
fmt = MAC_FILE;
statusbar(P_("Read %lu line (Converted from Mac format)",
"Read %lu lines (Converted from Mac format)",
(unsigned long)num_lines), (unsigned long)num_lines);
} else if (format == 1) {
fmt = DOS_FILE;
statusbar(P_("Read %lu line (Converted from DOS format)",
"Read %lu lines (Converted from DOS format)",
(unsigned long)num_lines), (unsigned long)num_lines);
/* Restore the current marking status and mark, if applicable. */
if (open_files->flags & MARK_ISSET) {
mark_beginbuf = open_files->mark_beginbuf;
mark_beginx = open_files->mark_beginx;
SET(MARK_ISSET);
} else
UNSET(MARK_ISSET);
/* Restore the current file format. */
fmt = open_files->fmt;
#endif
statusbar(P_("Read %lu line", "Read %lu lines",
(unsigned long)num_lines), (unsigned long)num_lines);
totlines += num_lines;
#ifdef ENABLE_COLOR
update_color();
#endif
edit_refresh();
/* Update the titlebar. */
titlebar(NULL);
}
/* Open the file (and decide if it exists). If newfie is TRUE, display
* "New File" if the file is missing. Otherwise, say "[filename] not
* found".
*
* Return -2 if we say "New File". Otherwise, -1 if the file isn't
* opened, 0 otherwise. The file might still have an error while
* reading with a 0 return value. *f is set to the opened file. */
int open_file(const char *filename, bool newfie, FILE **f)
/* Open either the next or previous file buffer. */
void open_prevnext_file(bool next_file)
{
int fd;
struct stat fileinfo;
assert(open_files != NULL);
assert(f != NULL);
add_open_file(TRUE);
if (filename == NULL || filename[0] == '\0' ||
stat(filename, &fileinfo) == -1) {
if (newfie) {
statusbar(_("New File"));
return -2;
/* If only one file buffer is open, indicate it on the statusbar and
* get out. */
if (open_files == open_files->next) {
statusbar(_("No more open file buffers"));
return;
}
statusbar(_("\"%s\" not found"), filename);
return -1;
} else if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
S_ISBLK(fileinfo.st_mode)) {
/* Don't open character or block files. Sorry, /dev/sndstat! */
statusbar(S_ISDIR(fileinfo.st_mode) ? _("\"%s\" is a directory")
: _("File \"%s\" is a device file"), filename);
return -1;
} else if ((fd = open(filename, O_RDONLY)) == -1) {
statusbar(_("Error reading %s: %s"), filename, strerror(errno));
return -1;
} else {
/* File is A-OK. Open it in binary mode for our own end-of-line
* character munging. */
*f = fdopen(fd, "rb");
if (*f == NULL) {
statusbar(_("Error reading %s: %s"), filename,
strerror(errno));
close(fd);
} else
statusbar(_("Reading File"));
}
return 0;
/* Switch to the next or previous file, depending on the value of
* next. */
open_files = next_file ? open_files->next : open_files->prev;
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
#endif
/* Load the file we switched to. */
load_open_file();
/* And indicate the switch on the statusbar. */
statusbar(_("Switched to %s"),
((open_files->filename[0] == '\0') ? _("New Buffer") :
open_files->filename));
#ifdef DEBUG
dump_buffer(current);
#endif
}
/* This function will return the name of the first available extension
* of a filename (starting with [name][suffix], then [name][suffix].1,
* etc.). Memory is allocated for the return value. If no writable
* extension exists, we return "". */
char *get_next_filename(const char *name, const char *suffix)
/* Open the previous entry in the open_files structure. This function
* is used by the shortcut list. */
void open_prevfile_void(void)
{
unsigned long i = 0;
char *buf;
size_t namelen, suffixlen;
assert(name != NULL && suffix != NULL);
open_prevnext_file(FALSE);
}
namelen = strlen(name);
suffixlen = strlen(suffix);
/* Open the next entry in the open_files structure. This function is
* used by the shortcut list. */
void open_nextfile_void(void)
{
open_prevnext_file(TRUE);
}
buf = charalloc(namelen + suffixlen + digits(ULONG_MAX) + 2);
sprintf(buf, "%s%s", name, suffix);
/* Delete an entry from the open_files filestruct. After deletion of an
* entry, the next entry is opened. Return TRUE on success or FALSE if
* there are no more open file buffers. */
bool close_open_file(void)
{
assert(open_files != NULL);
while (TRUE) {
struct stat fs;
/* If only one file is open, get out. */
if (open_files == open_files->next)
return FALSE;
if (stat(buf, &fs) == -1)
return buf;
if (i == ULONG_MAX)
break;
/* Open the next file. */
open_nextfile_void();
i++;
sprintf(buf + namelen + suffixlen, ".%lu", i);
}
/* Close the file we had open before. */
unlink_opennode(open_files->prev);
/* We get here only if there is no possible save file. Blank out
* the filename to indicate this. */
null_at(&buf, 0);
/* Reinitialize the shortcut list. */
shortcut_init(FALSE);
display_main_list();
return buf;
return TRUE;
}
#endif /* ENABLE_MULTIBUFFER */
#ifndef NANO_SMALL
void execute_command(const char *command)
/* What happens when there is no file to open? aiee! */
void new_file(void)
{
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER)) {
/* Update the current entry in the open_files structure. */
add_open_file(TRUE);
new_file();
UNSET(MODIFIED);
UNSET(MARK_ISSET);
}
#endif /* ENABLE_MULTIBUFFER */
open_pipe(command);
#ifdef ENABLE_MULTIBUFFER
/* Add this new entry to the open_files structure. */
if (ISSET(MULTIBUFFER))
load_file();
#endif /* ENABLE_MULTIBUFFER */
fileage = make_new_node(NULL);
fileage->data = mallocstrcpy(NULL, "");
filebot = fileage;
edittop = fileage;
current = fileage;
current_x = 0;
totlines = 1;
totsize = 0;
#ifdef ENABLE_COLOR
update_color();
if (!ISSET(NO_COLOR_SYNTAX))
edit_refresh();
#endif
}
#endif /* !NANO_SMALL */
/* name is a file name to open. We make a new buffer if necessary, then
* open and read the file. */
void load_buffer(const char *name)
/* We make a new line of text from buf. buf is length buf_len. If
* first_line_ins is TRUE, then we put the new line at the top of the
* file. Otherwise, we assume prevnode is the last line of the file,
* and put our line after prevnode. */
filestruct *read_line(char *buf, filestruct *prevnode, bool
*first_line_ins, size_t buf_len)
{
bool new_buffer = (fileage == NULL
#ifdef ENABLE_MULTIBUFFER
|| ISSET(MULTIBUFFER)
#endif
);
/* new_buffer says whether we load into this buffer or a new
* one. If new_buffer is TRUE, we display "New File" if the
* file is not found, and if it is found we set filename and add
* a new open_files entry. */
FILE *f;
int rc;
/* rc == -2 means that the statusbar displayed "New File". -1
* means that the open failed. 0 means success. */
filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct));
#ifndef DISABLE_OPERATINGDIR
if (check_operating_dir(name, FALSE)) {
statusbar(_("Can't insert file from outside of %s"),
operating_dir);
return;
}
#endif
/* Convert nulls to newlines. buf_len is the string's real length
* here. */
unsunder(buf, buf_len);
#ifdef ENABLE_MULTIBUFFER
/* Update the current entry in the open_files structure. */
add_open_file(TRUE);
#endif
assert(strlen(buf) == buf_len);
rc = open_file(name, new_buffer, &f);
fileptr->data = mallocstrcpy(NULL, buf);
#ifdef ENABLE_MULTIBUFFER
if (rc != -1 && ISSET(MULTIBUFFER)) {
UNSET(MODIFIED);
#ifndef NANO_SMALL
UNSET(MARK_ISSET);
#endif
}
/* If it's a DOS file ("\r\n"), and file conversion isn't disabled,
* strip the '\r' part from fileptr->data. */
if (!ISSET(NO_CONVERT) && buf_len > 0 && buf[buf_len - 1] == '\r')
fileptr->data[buf_len - 1] = '\0';
#endif
if (rc != -1 && new_buffer) {
filename = mallocstrcpy(filename, name);
new_file();
if (*first_line_ins == TRUE || fileage == NULL) {
/* Special case: We're inserting with the cursor on the first
* line. */
fileptr->prev = NULL;
fileptr->next = fileage;
fileptr->lineno = 1;
if (*first_line_ins == TRUE) {
*first_line_ins = FALSE;
/* 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. */
edittop = fileptr;
} else
filebot = fileptr;
fileage = fileptr;
} else {
assert(prevnode != NULL);
fileptr->prev = prevnode;
fileptr->next = NULL;
fileptr->lineno = prevnode->lineno + 1;
prevnode->next = fileptr;
}
if (rc == 0) {
file_format fmt_save = fmt;
return fileptr;
}
read_file(f, filename);
/* Load a file into the edit buffer. This takes data from the file
* struct. */
void load_file(void)
{
current = fileage;
/* If we're not loading into a new buffer, preserve the file
* format. */
if (!new_buffer)
fmt = fmt_save;
#ifdef ENABLE_MULTIBUFFER
/* Add a new entry to the open_files structure. */
add_open_file(FALSE);
#ifndef NANO_SMALL
stat(filename, &originalfilestat);
/* Reinitialize the shortcut list. */
shortcut_init(FALSE);
#endif
}
/* Add this new entry to the open_files structure if we have
* multibuffer support, or to the main filestruct if we don't. */
if (rc != -1 && new_buffer)
load_file();
}
void do_insertfile(
void read_file(FILE *f, const char *filename)
{
size_t num_lines = 0;
/* The number of lines in the file. */
size_t num_chars;
/* The number of characters in the file. */
size_t len = 0;
/* The length of the current line of the file. */
size_t i = 0;
/* The position in the current line of the file. */
size_t bufx = MAX_BUF_SIZE;
/* The size of each chunk of the file that we read. */
char input = '\0';
/* The current input character. */
char *buf;
/* The buffer where we store chunks of the file. */
filestruct *fileptr = current;
/* The current line of the file. */
bool first_line_ins = FALSE;
/* Whether we're inserting with the cursor on the first line. */
int input_int;
/* The current value we read from the file, whether an input
* character or EOF. */
#ifndef NANO_SMALL
bool execute
#else
void
int format = 0;
/* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */
#endif
)
{
int i;
const char *msg;
char *ans = mallocstrcpy(NULL, "");
/* The last answer the user typed on the statusbar. */
filestruct *edittop_save = edittop;
ssize_t current_y_save = current_y;
bool at_edittop = FALSE;
/* Whether we're at the top of the edit window. */
#ifndef DISABLE_WRAPPING
wrap_reset();
#endif
buf = charalloc(bufx);
buf[0] = '\0';
while (TRUE) {
#ifndef NANO_SMALL
if (execute) {
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER))
msg = N_("Command to execute in new buffer [from %s] ");
if (current != NULL) {
if (current == fileage)
first_line_ins = TRUE;
else
#endif
msg = N_("Command to execute [from %s] ");
} else {
#endif
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER)) {
msg = N_("File to insert into new buffer [from %s] ");
} else
#endif
msg = N_("File to insert [from %s] ");
#ifndef NANO_SMALL
fileptr = current->prev;
}
#endif
i = statusq(TRUE,
/* For the assertion in read_line(), it must be true that if current
* is NULL, then so is fileage. */
assert(current != NULL || fileage == NULL);
#ifndef NANO_SMALL
execute ? extcmd_list :
/* We don't know which file format we have yet, so assume it's a
* *nix file for now. */
fmt = NIX_FILE;
#endif
insertfile_list, ans,
/* Read the entire file into the file struct. */
while ((input_int = getc(f)) != EOF) {
input = (char)input_int;
/* If it's a *nix file ("\n") or a DOS file ("\r\n"), and file
* conversion isn't disabled, handle it! */
if (input == '\n') {
#ifndef NANO_SMALL
NULL,
#endif
_(msg),
#ifndef DISABLE_OPERATINGDIR
operating_dir != NULL && strcmp(operating_dir, ".") != 0 ?
operating_dir :
/* If there's a '\r' before the '\n', set format to DOS if
* we currently think this is a *nix file, or to both if we
* currently think it's a Mac file. */
if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r' &&
(format == 0 || format == 2))
format++;
#endif
"./");
/* If we're in multibuffer mode and the filename or command is
* blank, open a new buffer instead of canceling. */
if (i == -1 || (i == -2
#ifdef ENABLE_MULTIBUFFER
&& !ISSET(MULTIBUFFER)
#endif
)) {
statusbar(_("Cancelled"));
break;
} else {
size_t pww_save = placewewant;
/* Read in the line properly. */
fileptr = read_line(buf, fileptr, &first_line_ins, len);
ans = mallocstrcpy(ans, answer);
/* Reset the line length in preparation for the next
* line. */
len = 0;
num_lines++;
buf[0] = '\0';
i = 0;
#ifndef NANO_SMALL
#ifdef ENABLE_MULTIBUFFER
if (i == TOGGLE_MULTIBUFFER_KEY) {
/* Don't allow toggling if we're in view mode. */
if (!ISSET(VIEW_MODE))
TOGGLE(MULTIBUFFER);
continue;
} else
#endif
if (i == NANO_TOOTHERINSERT_KEY) {
execute = !execute;
continue;
}
#ifndef DISABLE_BROWSER
else
#endif
#endif /* !NANO_SMALL */
/* If it's a Mac file ('\r' without '\n'), and file conversion
* isn't disabled, handle it! */
} else if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r') {
#ifndef DISABLE_BROWSER
if (i == NANO_TOFILES_KEY) {
char *tmp = do_browse_from(answer);
/* If we currently think the file is a *nix file, set format
* to Mac. If we currently think the file is a DOS file,
* set format to both DOS and Mac. */
if (format == 0 || format == 1)
format += 2;
if (tmp == NULL)
continue;
/* Read in the line properly. */
fileptr = read_line(buf, fileptr, &first_line_ins, len);
free(answer);
answer = tmp;
/* Reset the line length in preparation for the next line.
* Since we've already read in the next character, reset it
* to 1 instead of 0. */
len = 1;
/* We have a file now. Indicate this and get out of the
* statusbar prompt cleanly. */
i = 0;
statusq_abort();
}
num_lines++;
buf[0] = input;
buf[1] = '\0';
i = 1;
#endif
} else {
/* Calculate the total length of the line. It might have
* nulls in it, so we can't just use strlen() here. */
len++;
/* If we don't have a file yet, go back to the statusbar
* prompt. */
if (i != 0
#ifdef ENABLE_MULTIBUFFER
&& (i != -2 || !ISSET(MULTIBUFFER))
#endif
)
continue;
/* Now we allocate a bigger buffer MAX_BUF_SIZE 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) {
bufx += MAX_BUF_SIZE;
buf = charealloc(buf, bufx);
}
#ifdef ENABLE_MULTIBUFFER
if (!ISSET(MULTIBUFFER)) {
#endif
/* If we're not inserting into a new buffer, partition
* the filestruct so that it contains no text and hence
* looks like a new buffer, and keep track of whether
* the top of the partition is the top of the edit
* window. */
filepart = partition_filestruct(current, current_x,
current, current_x);
at_edittop = (fileage == edittop);
#ifdef ENABLE_MULTIBUFFER
buf[i] = input;
buf[i + 1] = '\0';
i++;
}
}
#endif
/* Perhaps this could use some better handling. */
if (ferror(f))
nperror(filename);
fclose(f);
#ifndef NANO_SMALL
if (execute)
execute_command(answer);
else {
#endif
answer = mallocstrassn(answer,
real_dir_from_tilde(answer));
load_buffer(answer);
#ifndef NANO_SMALL
/* If file conversion isn't disabled and the last character in this
* file is '\r', read it in properly as a Mac format line. */
if (len == 0 && !ISSET(NO_CONVERT) && input == '\r') {
len = 1;
buf[0] = input;
buf[1] = '\0';
}
#endif
#ifdef ENABLE_MULTIBUFFER
if (!ISSET(MULTIBUFFER))
/* Did we not get a newline and still have stuff to do? */
if (len > 0) {
#ifndef NANO_SMALL
/* If file conversion isn't disabled and the last character in
* this file is '\r', set format to Mac if we currently think
* the file is a *nix file, or to both DOS and Mac if we
* currently think the file is a DOS file. */
if (!ISSET(NO_CONVERT) && buf[len - 1] == '\r' &&
(format == 0 || format == 1))
format += 2;
#endif
{
filestruct *top_save = fileage;
/* If we didn't insert into a new buffer, and we were at
* the top of the edit window before, set the saved
* value of edittop to the new top of the edit window,
* and update the current y-coordinate to account for
* the number of lines inserted. */
if (at_edittop)
edittop_save = fileage;
current_y += current_y_save;
/* Read in the last line properly. */
fileptr = read_line(buf, fileptr, &first_line_ins, len);
num_lines++;
}
/* If we didn't insert into a new buffer, unpartition
* the filestruct so that it contains all the text
* again. Note that we've replaced the non-text
* originally in the partition with the text in the
* inserted file/executed command output. */
unpartition_filestruct(&filepart);
free(buf);
/* Renumber starting with the beginning line of the old
* partition. */
renumber(top_save);
/* If we didn't get a file and we don't already have one, make a new
* file. */
if (fileptr == NULL)
new_file();
/* Set edittop back to what it was before. */
edittop = edittop_save;
/* Did we try to insert a file of 0 bytes? */
if (num_lines != 0) {
if (current != NULL) {
fileptr->next = current;
current->prev = fileptr;
renumber(current);
current_x = 0;
placewewant = 0;
} else if (fileptr->next == NULL) {
filebot = fileptr;
new_magicline();
totsize--;
}
}
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER)) {
/* Update the titlebar. */
titlebar(NULL);
get_totals(fileage, filebot, NULL, &num_chars);
totsize += num_chars;
/* Reinitialize the shortcut list. */
shortcut_init(FALSE);
} else {
#ifndef NANO_SMALL
if (format == 3)
statusbar(
P_("Read %lu line (Converted from DOS and Mac format)",
"Read %lu lines (Converted from DOS and Mac format)",
(unsigned long)num_lines), (unsigned long)num_lines);
else if (format == 2) {
fmt = MAC_FILE;
statusbar(P_("Read %lu line (Converted from Mac format)",
"Read %lu lines (Converted from Mac format)",
(unsigned long)num_lines), (unsigned long)num_lines);
} else if (format == 1) {
fmt = DOS_FILE;
statusbar(P_("Read %lu line (Converted from DOS format)",
"Read %lu lines (Converted from DOS format)",
(unsigned long)num_lines), (unsigned long)num_lines);
} else
#endif
/* Mark the file as modified. */
set_modified();
statusbar(P_("Read %lu line", "Read %lu lines",
(unsigned long)num_lines), (unsigned long)num_lines);
/* Restore the old place we want. */
placewewant = pww_save;
#ifdef ENABLE_MULTIBUFFER
}
#endif
totlines += num_lines;
}
/* Refresh the screen. */
edit_refresh();
/* Open the file (and decide if it exists). If newfie is TRUE, display
* "New File" if the file is missing. Otherwise, say "[filename] not
* found".
*
* Return -2 if we say "New File". Otherwise, -1 if the file isn't
* opened, 0 otherwise. The file might still have an error while
* reading with a 0 return value. *f is set to the opened file. */
int open_file(const char *filename, bool newfie, FILE **f)
{
int fd;
struct stat fileinfo;
break;
}
assert(f != NULL);
if (filename == NULL || filename[0] == '\0' ||
stat(filename, &fileinfo) == -1) {
if (newfie) {
statusbar(_("New File"));
return -2;
}
statusbar(_("\"%s\" not found"), filename);
return -1;
} else if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
S_ISBLK(fileinfo.st_mode)) {
/* Don't open character or block files. Sorry, /dev/sndstat! */
statusbar(S_ISDIR(fileinfo.st_mode) ? _("\"%s\" is a directory")
: _("File \"%s\" is a device file"), filename);
return -1;
} else if ((fd = open(filename, O_RDONLY)) == -1) {
statusbar(_("Error reading %s: %s"), filename, strerror(errno));
return -1;
} else {
/* File is A-OK. Open it in binary mode for our own end-of-line
* character munging. */
*f = fdopen(fd, "rb");
free(ans);
if (*f == NULL) {
statusbar(_("Error reading %s: %s"), filename,
strerror(errno));
close(fd);
} else
statusbar(_("Reading File"));
}
return 0;
}
void do_insertfile_void(void)
/* This function will return the name of the first available extension
* of a filename (starting with [name][suffix], then [name][suffix].1,
* etc.). Memory is allocated for the return value. If no writable
* extension exists, we return "". */
char *get_next_filename(const char *name, const char *suffix)
{
#ifdef ENABLE_MULTIBUFFER
if (ISSET(VIEW_MODE) && !ISSET(MULTIBUFFER))
statusbar(_("Key illegal in non-multibuffer mode"));
else
#endif
do_insertfile(
#ifndef NANO_SMALL
FALSE
#endif
);
display_main_list();
}
unsigned long i = 0;
char *buf;
size_t namelen, suffixlen;
#ifdef ENABLE_MULTIBUFFER
/* Create a new openfilestruct node. */
openfilestruct *make_new_opennode(void)
{
openfilestruct *newnode =
(openfilestruct *)nmalloc(sizeof(openfilestruct));
newnode->filename = NULL;
assert(name != NULL && suffix != NULL);
return newnode;
}
namelen = strlen(name);
suffixlen = strlen(suffix);
/* Splice a node into an existing openfilestruct. */
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
openfilestruct *end)
{
assert(newnode != NULL && begin != NULL);
buf = charalloc(namelen + suffixlen + digits(ULONG_MAX) + 2);
sprintf(buf, "%s%s", name, suffix);
newnode->next = end;
newnode->prev = begin;
begin->next = newnode;
if (end != NULL)
end->prev = newnode;
}
while (TRUE) {
struct stat fs;
/* Unlink a node from the rest of the openfilestruct, and delete it. */
void unlink_opennode(openfilestruct *fileptr)
{
assert(fileptr != NULL && fileptr->prev != NULL && fileptr->next != NULL && fileptr != fileptr->prev && fileptr != fileptr->next);
if (stat(buf, &fs) == -1)
return buf;
if (i == ULONG_MAX)
break;
fileptr->prev->next = fileptr->next;
fileptr->next->prev = fileptr->prev;
delete_opennode(fileptr);
}
i++;
sprintf(buf + namelen + suffixlen, ".%lu", i);
}
/* Delete a node from the openfilestruct. */
void delete_opennode(openfilestruct *fileptr)
{
assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL);
/* We get here only if there is no possible save file. Blank out
* the filename to indicate this. */
null_at(&buf, 0);
free(fileptr->filename);
free_filestruct(fileptr->fileage);
free(fileptr);
return buf;
}
#ifdef DEBUG
/* Deallocate all memory associated with this and later files, including
* the lines of text. */
void free_openfilestruct(openfilestruct *src)
#ifndef NANO_SMALL
void execute_command(const char *command)
{
assert(src != NULL);
while (src != src->next) {
src = src->next;
delete_opennode(src->prev);
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER)) {
/* Update the current entry in the open_files structure. */
add_open_file(TRUE);
new_file();
UNSET(MODIFIED);
UNSET(MARK_ISSET);
}
delete_opennode(src);
#endif /* ENABLE_MULTIBUFFER */
open_pipe(command);
#ifdef ENABLE_MULTIBUFFER
/* Add this new entry to the open_files structure. */
if (ISSET(MULTIBUFFER))
load_file();
#endif /* ENABLE_MULTIBUFFER */
}
#endif
#endif /* !NANO_SMALL */
/* Add/update an entry to the open_files openfilestruct. If update is
* FALSE, a new entry is created; otherwise, the current entry is
* updated. */
void add_open_file(bool update)
/* name is a file name to open. We make a new buffer if necessary, then
* open and read the file. */
void load_buffer(const char *name)
{
if (update && open_files == NULL)
return;
bool new_buffer = (fileage == NULL
#ifdef ENABLE_MULTIBUFFER
|| ISSET(MULTIBUFFER)
#endif
);
/* new_buffer says whether we load into this buffer or a new
* one. If new_buffer is TRUE, we display "New File" if the
* file is not found, and if it is found we set filename and add
* a new open_files entry. */
FILE *f;
int rc;
/* rc == -2 means that the statusbar displayed "New File". -1
* means that the open failed. 0 means success. */
/* If there are no entries in open_files, make the first one. */
if (open_files == NULL) {
open_files = make_new_opennode();
splice_opennode(open_files, open_files, open_files);
/* Otherwise, if we're not updating, make a new entry for
* open_files and splice it in after the current entry. */
} else if (!update) {
splice_opennode(open_files, make_new_opennode(),
open_files->next);
open_files = open_files->next;
#ifndef DISABLE_OPERATINGDIR
if (check_operating_dir(name, FALSE)) {
statusbar(_("Can't insert file from outside of %s"),
operating_dir);
return;
}
#endif
/* Save the current filename. */
open_files->filename = mallocstrcpy(open_files->filename, filename);
#ifdef ENABLE_MULTIBUFFER
/* Update the current entry in the open_files structure. */
add_open_file(TRUE);
#endif
rc = open_file(name, new_buffer, &f);
#ifdef ENABLE_MULTIBUFFER
if (rc != -1 && ISSET(MULTIBUFFER)) {
UNSET(MODIFIED);
#ifndef NANO_SMALL
/* Save the current file's stat. */
open_files->originalfilestat = originalfilestat;
UNSET(MARK_ISSET);
#endif
}
#endif
/* Save the current file buffer. */
open_files->fileage = fileage;
open_files->filebot = filebot;
/* Save the current top of the edit window. */
open_files->edittop = edittop;
if (rc != -1 && new_buffer) {
filename = mallocstrcpy(filename, name);
new_file();
}
/* Save the current line. */
open_files->current = current;
if (rc == 0) {
file_format fmt_save = fmt;
/* Save the current cursor position. */
open_files->current_x = current_x;
read_file(f, filename);
/* Save the current place we want. */
open_files->placewewant = placewewant;
/* If we're not loading into a new buffer, preserve the file
* format. */
if (!new_buffer)
fmt = fmt_save;
/* Save the current total number of lines. */
open_files->totlines = totlines;
#ifndef NANO_SMALL
stat(filename, &originalfilestat);
#endif
}
/* Save the current total size. */
open_files->totsize = totsize;
/* Add this new entry to the open_files structure if we have
* multibuffer support, or to the main filestruct if we don't. */
if (rc != -1 && new_buffer)
load_file();
}
/* Start with no flags saved. */
open_files->flags = 0;
void do_insertfile(
#ifndef NANO_SMALL
bool execute
#else
void
#endif
)
{
int i;
const char *msg;
char *ans = mallocstrcpy(NULL, "");
/* The last answer the user typed on the statusbar. */
filestruct *edittop_save = edittop;
ssize_t current_y_save = current_y;
bool at_edittop = FALSE;
/* Whether we're at the top of the edit window. */
/* Save the current modification status. */
if (ISSET(MODIFIED))
open_files->flags |= MODIFIED;
#ifndef DISABLE_WRAPPING
wrap_reset();
#endif
while (TRUE) {
#ifndef NANO_SMALL
if (execute) {
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER))
msg = N_("Command to execute in new buffer [from %s] ");
else
#endif
msg = N_("Command to execute [from %s] ");
} else {
#endif
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER)) {
msg = N_("File to insert into new buffer [from %s] ");
} else
#endif
msg = N_("File to insert [from %s] ");
#ifndef NANO_SMALL
/* Save the current marking status and mark, if applicable. */
if (ISSET(MARK_ISSET)) {
open_files->flags |= MARK_ISSET;
open_files->mark_beginbuf = mark_beginbuf;
open_files->mark_beginx = mark_beginx;
}
/* Save the current file format. */
open_files->fmt = fmt;
#endif
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
i = statusq(TRUE,
#ifndef NANO_SMALL
execute ? extcmd_list :
#endif
}
insertfile_list, ans,
#ifndef NANO_SMALL
NULL,
#endif
_(msg),
#ifndef DISABLE_OPERATINGDIR
operating_dir != NULL && strcmp(operating_dir, ".") != 0 ?
operating_dir :
#endif
"./");
/* Read the current entry in the open_files structure and set up the
* currently open file buffer using that entry's information. */
void load_open_file(void)
{
assert(open_files != NULL);
/* If we're in multibuffer mode and the filename or command is
* blank, open a new buffer instead of canceling. */
if (i == -1 || (i == -2
#ifdef ENABLE_MULTIBUFFER
&& !ISSET(MULTIBUFFER)
#endif
)) {
statusbar(_("Cancelled"));
break;
} else {
size_t pww_save = placewewant;
/* Restore the current filename. */
filename = mallocstrcpy(filename, open_files->filename);
ans = mallocstrcpy(ans, answer);
#ifndef NANO_SMALL
/* Restore the current file's stat. */
originalfilestat = open_files->originalfilestat;
#ifdef ENABLE_MULTIBUFFER
if (i == TOGGLE_MULTIBUFFER_KEY) {
/* Don't allow toggling if we're in view mode. */
if (!ISSET(VIEW_MODE))
TOGGLE(MULTIBUFFER);
continue;
} else
#endif
if (i == NANO_TOOTHERINSERT_KEY) {
execute = !execute;
continue;
}
#ifndef DISABLE_BROWSER
else
#endif
#endif /* !NANO_SMALL */
/* Restore the current file buffer. */
fileage = open_files->fileage;
filebot = open_files->filebot;
/* Restore the current top of the edit window. */
edittop = open_files->edittop;
/* Restore the current line. */
current = open_files->current;
#ifndef DISABLE_BROWSER
if (i == NANO_TOFILES_KEY) {
char *tmp = do_browse_from(answer);
/* Restore the current cursor position. */
current_x = open_files->current_x;
if (tmp == NULL)
continue;
/* Restore the current place we want. */
placewewant = open_files->placewewant;
free(answer);
answer = tmp;
/* Restore the current total number of lines. */
totlines = open_files->totlines;
/* We have a file now. Indicate this and get out of the
* statusbar prompt cleanly. */
i = 0;
statusq_abort();
}
#endif
/* Restore the current total size. */
totsize = open_files->totsize;
/* If we don't have a file yet, go back to the statusbar
* prompt. */
if (i != 0
#ifdef ENABLE_MULTIBUFFER
&& (i != -2 || !ISSET(MULTIBUFFER))
#endif
)
continue;
/* Restore the current modification status. */
if (open_files->flags & MODIFIED)
SET(MODIFIED);
else
UNSET(MODIFIED);
#ifdef ENABLE_MULTIBUFFER
if (!ISSET(MULTIBUFFER)) {
#endif
/* If we're not inserting into a new buffer, partition
* the filestruct so that it contains no text and hence
* looks like a new buffer, and keep track of whether
* the top of the partition is the top of the edit
* window. */
filepart = partition_filestruct(current, current_x,
current, current_x);
at_edittop = (fileage == edittop);
#ifdef ENABLE_MULTIBUFFER
}
#endif
#ifndef NANO_SMALL
/* Restore the current marking status and mark, if applicable. */
if (open_files->flags & MARK_ISSET) {
mark_beginbuf = open_files->mark_beginbuf;
mark_beginx = open_files->mark_beginx;
SET(MARK_ISSET);
} else
UNSET(MARK_ISSET);
/* Restore the current file format. */
fmt = open_files->fmt;
if (execute)
execute_command(answer);
else {
#endif
answer = mallocstrassn(answer,
real_dir_from_tilde(answer));
load_buffer(answer);
#ifndef NANO_SMALL
}
#endif
#ifdef ENABLE_COLOR
update_color();
#ifdef ENABLE_MULTIBUFFER
if (!ISSET(MULTIBUFFER))
#endif
edit_refresh();
{
filestruct *top_save = fileage;
/* Update the titlebar. */
titlebar(NULL);
}
/* If we didn't insert into a new buffer, and we were at
* the top of the edit window before, set the saved
* value of edittop to the new top of the edit window,
* and update the current y-coordinate to account for
* the number of lines inserted. */
if (at_edittop)
edittop_save = fileage;
current_y += current_y_save;
/* Open either the next or previous file buffer. */
void open_prevnext_file(bool next_file)
{
assert(open_files != NULL);
/* If we didn't insert into a new buffer, unpartition
* the filestruct so that it contains all the text
* again. Note that we've replaced the non-text
* originally in the partition with the text in the
* inserted file/executed command output. */
unpartition_filestruct(&filepart);
add_open_file(TRUE);
/* Renumber starting with the beginning line of the old
* partition. */
renumber(top_save);
/* If only one file buffer is open, indicate it on the statusbar and
* get out. */
if (open_files == open_files->next) {
statusbar(_("No more open file buffers"));
return;
/* Set edittop back to what it was before. */
edittop = edittop_save;
}
/* Switch to the next or previous file, depending on the value of
* next. */
open_files = next_file ? open_files->next : open_files->prev;
#ifdef ENABLE_MULTIBUFFER
if (ISSET(MULTIBUFFER)) {
/* Update the titlebar. */
titlebar(NULL);
#ifdef DEBUG
fprintf(stderr, "filename is %s\n", open_files->filename);
/* Reinitialize the shortcut list. */
shortcut_init(FALSE);
} else {
#endif
/* Mark the file as modified. */
set_modified();
/* Load the file we switched to. */
load_open_file();
/* And indicate the switch on the statusbar. */
statusbar(_("Switched to %s"),
((open_files->filename[0] == '\0') ? _("New Buffer") :
open_files->filename));
#ifdef DEBUG
dump_buffer(current);
/* Restore the old place we want. */
placewewant = pww_save;
#ifdef ENABLE_MULTIBUFFER
}
#endif
}
/* Open the previous entry in the open_files structure. This function
* is used by the shortcut list. */
void open_prevfile_void(void)
{
open_prevnext_file(FALSE);
}
/* Refresh the screen. */
edit_refresh();
/* Open the next entry in the open_files structure. This function is
* used by the shortcut list. */
void open_nextfile_void(void)
{
open_prevnext_file(TRUE);
break;
}
}
free(ans);
}
/* Delete an entry from the open_files filestruct. After deletion of an
* entry, the next entry is opened. Return TRUE on success or FALSE if
* there are no more open file buffers. */
bool close_open_file(void)
void do_insertfile_void(void)
{
assert(open_files != NULL);
/* If only one file is open, get out. */
if (open_files == open_files->next)
return FALSE;
/* Open the next file. */
open_nextfile_void();
/* Close the file we had open before. */
unlink_opennode(open_files->prev);
#ifdef ENABLE_MULTIBUFFER
if (ISSET(VIEW_MODE) && !ISSET(MULTIBUFFER))
statusbar(_("Key illegal in non-multibuffer mode"));
else
#endif
do_insertfile(
#ifndef NANO_SMALL
FALSE
#endif
);
/* Reinitialize the shortcut list. */
shortcut_init(FALSE);
display_main_list();
return TRUE;
}
#endif /* ENABLE_MULTIBUFFER */
/* When passed "[relative path]" or "[relative path][filename]" in
* origpath, return "[full path]" or "[full path][filename]" on success,
......
......@@ -78,903 +78,903 @@ static filestruct *jusbottom = NULL;
/* Pointer to end of justify buffer. */
#endif
void print_view_warning(void)
/* Create a new filestruct node. Note that we specifically do not set
* prevnode->next equal to the new line. */
filestruct *make_new_node(filestruct *prevnode)
{
statusbar(_("Key illegal in VIEW mode"));
filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
newnode->data = NULL;
newnode->prev = prevnode;
newnode->next = NULL;
newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
return newnode;
}
/* What we do when we're all set to exit. */
void finish(void)
/* Make a copy of a filestruct node. */
filestruct *copy_node(const filestruct *src)
{
if (!ISSET(NO_HELP))
blank_bottombars();
else
blank_statusbar();
wrefresh(bottomwin);
endwin();
filestruct *dst;
/* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &oldterm);
assert(src != NULL);
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
save_history();
#endif
dst = (filestruct *)nmalloc(sizeof(filestruct));
#ifdef DEBUG
thanks_for_all_the_fish();
#endif
dst->data = mallocstrcpy(NULL, src->data);
dst->next = src->next;
dst->prev = src->prev;
dst->lineno = src->lineno;
exit(0);
return dst;
}
/* Die (gracefully?). */
void die(const char *msg, ...)
/* Splice a node into an existing filestruct. */
void splice_node(filestruct *begin, filestruct *newnode, filestruct
*end)
{
va_list ap;
endwin();
curses_ended = TRUE;
/* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &oldterm);
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
/* Save the current file buffer if it's been modified. */
if (ISSET(MODIFIED)) {
/* If we've partitioned the filestruct, unpartition it now. */
if (filepart != NULL)
unpartition_filestruct(&filepart);
assert(newnode != NULL && begin != NULL);
die_save_file(filename);
}
newnode->next = end;
newnode->prev = begin;
begin->next = newnode;
if (end != NULL)
end->prev = newnode;
}
#ifdef ENABLE_MULTIBUFFER
/* Save all of the other modified file buffers, if any. */
if (open_files != NULL) {
openfilestruct *tmp = open_files;
/* Unlink a node from the rest of the filestruct. */
void unlink_node(const filestruct *fileptr)
{
assert(fileptr != NULL);
while (tmp != open_files->next) {
open_files = open_files->next;
if (fileptr->prev != NULL)
fileptr->prev->next = fileptr->next;
if (fileptr->next != NULL)
fileptr->next->prev = fileptr->prev;
}
/* Save the current file buffer if it's been modified. */
if (open_files->flags & MODIFIED) {
/* Set fileage and filebot to match the current file
* buffer, and then write it to disk. */
fileage = open_files->fileage;
filebot = open_files->filebot;
die_save_file(open_files->filename);
}
}
}
#endif
/* Delete a node from the filestruct. */
void delete_node(filestruct *fileptr)
{
assert(fileptr != NULL && fileptr->data != NULL);
/* Get out. */
exit(1);
if (fileptr->data != NULL)
free(fileptr->data);
free(fileptr);
}
void die_save_file(const char *die_filename)
/* Duplicate a whole filestruct. */
filestruct *copy_filestruct(const filestruct *src)
{
char *retval;
bool failed = TRUE;
filestruct *head, *copy;
/* If we're using restricted mode, don't write any emergency backup
* files, since that would allow reading from or writing to files
* not specified on the command line. */
if (ISSET(RESTRICTED))
return;
assert(src != NULL);
/* If we can't save, we have REAL bad problems, but we might as well
* TRY. */
if (die_filename[0] == '\0')
die_filename = "nano";
copy = copy_node(src);
copy->prev = NULL;
head = copy;
src = src->next;
retval = get_next_filename(die_filename, ".save");
if (retval[0] != '\0')
failed = (write_file(retval, NULL, TRUE, FALSE, TRUE) == -1);
while (src != NULL) {
copy->next = copy_node(src);
copy->next->prev = copy;
copy = copy->next;
if (!failed)
fprintf(stderr, _("\nBuffer written to %s\n"), retval);
else if (retval[0] != '\0')
fprintf(stderr, _("\nBuffer not written to %s: %s\n"), retval,
strerror(errno));
else
fprintf(stderr, _("\nBuffer not written: %s\n"),
_("Too many backup files?"));
src = src->next;
}
copy->next = NULL;
free(retval);
return head;
}
/* Die with an error message that the screen was too small if, well, the
* screen is too small. */
void check_die_too_small(void)
/* Frees a filestruct. */
void free_filestruct(filestruct *src)
{
editwinrows = LINES - 5 + no_more_space() + no_help();
if (editwinrows < MIN_EDITOR_ROWS)
die(_("Window size is too small for nano...\n"));
assert(src != NULL);
while (src->next != NULL) {
src = src->next;
delete_node(src->prev);
}
delete_node(src);
}
/* Reinitialize the variables that depend on the window size. That is,
* fill and hblank. */
void resize_variables(void)
void renumber_all(void)
{
#ifndef DISABLE_WRAPJUSTIFY
fill = wrap_at;
if (fill <= 0)
fill += COLS;
if (fill < 0)
fill = 0;
#endif
filestruct *temp;
ssize_t line = 1;
hblank = charealloc(hblank, COLS + 1);
charset(hblank, ' ', COLS);
hblank[COLS] = '\0';
assert(fileage == NULL || fileage != fileage->next);
for (temp = fileage; temp != NULL; temp = temp->next)
temp->lineno = line++;
}
/* Initialize global variables -- no better way for now. If
* save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
void global_init(bool save_cutbuffer)
void renumber(filestruct *fileptr)
{
check_die_too_small();
resize_variables();
if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
renumber_all();
else {
ssize_t line = fileptr->prev->lineno;
fileage = NULL;
edittop = NULL;
current = NULL;
if (!save_cutbuffer)
cutbuffer = NULL;
current_x = 0;
placewewant = 0;
current_y = 0;
totlines = 0;
totsize = 0;
assert(fileptr != fileptr->next);
for (; fileptr != NULL; fileptr = fileptr->next)
fileptr->lineno = ++line;
}
}
void window_init(void)
/* Partition a filestruct so it begins at (top, top_x) and ends at (bot,
* bot_x). */
partition *partition_filestruct(filestruct *top, size_t top_x,
filestruct *bot, size_t bot_x)
{
check_die_too_small();
if (topwin != NULL)
delwin(topwin);
if (edit != NULL)
delwin(edit);
if (bottomwin != NULL)
delwin(bottomwin);
partition *p;
/* Set up the windows. */
topwin = newwin(2 - no_more_space(), COLS, 0, 0);
edit = newwin(editwinrows, COLS, 2 - no_more_space(), 0);
bottomwin = newwin(3 - no_help(), COLS, editwinrows +
(2 - no_more_space()), 0);
assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL);
/* Turn the keypad back on. */
keypad(edit, TRUE);
keypad(bottomwin, TRUE);
}
/* Initialize the partition. */
p = (partition *)nmalloc(sizeof(partition));
#ifndef DISABLE_MOUSE
void mouse_init(void)
{
if (ISSET(USE_MOUSE)) {
mousemask(BUTTON1_RELEASED, NULL);
mouseinterval(50);
/* If the top and bottom of the partition are different from the top
* and bottom of the filestruct, save the latter and then set them
* to top and bot. */
if (top != fileage) {
p->fileage = fileage;
fileage = top;
} else
mousemask(0, NULL);
}
#endif
p->fileage = NULL;
if (bot != filebot) {
p->filebot = filebot;
filebot = bot;
} else
p->filebot = NULL;
#ifndef DISABLE_HELP
/* This function allocates help_text, and stores the help string in it.
* help_text should be NULL initially. */
void help_init(void)
{
size_t allocsize = 0; /* Space needed for help_text. */
const char *htx[3]; /* Untranslated help message. We break
* it up into three chunks in case the
* full string is too long for the
* compiler to handle. */
char *ptr;
const shortcut *s;
#ifndef NANO_SMALL
const toggle *t;
#ifdef ENABLE_NANORC
bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
UNSET(WHITESPACE_DISPLAY);
#endif
#endif
/* First, set up the initial help text for the current function. */
if (currshortcut == whereis_list || currshortcut == replace_list
|| currshortcut == replace_list_2) {
htx[0] = N_("Search Command Help Text\n\n "
"Enter the words or characters you would like to "
"search for, and then press Enter. If there is a "
"match for the text you entered, the screen will be "
"updated to the location of the nearest match for the "
"search string.\n\n The previous search string will be "
"shown in brackets after the search prompt. Hitting "
"Enter without entering any text will perform the "
"previous search. ");
htx[1] = N_("If you have selected text with the mark and then "
"search to replace, only matches in the selected text "
"will be replaced.\n\n The following function keys are "
"available in Search mode:\n\n");
htx[2] = NULL;
} else if (currshortcut == gotoline_list) {
htx[0] = N_("Go To Line Help Text\n\n "
"Enter the line number that you wish to go to and hit "
"Enter. If there are fewer lines of text than the "
"number you entered, you will be brought to the last "
"line of the file.\n\n The following function keys are "
"available in Go To Line mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
} else if (currshortcut == insertfile_list) {
htx[0] = N_("Insert File Help Text\n\n "
"Type in the name of a file to be inserted into the "
"current file buffer at the current cursor "
"location.\n\n If you have compiled nano with multiple "
"file buffer support, and enable multiple file buffers "
"with the -F or --multibuffer command line flags, the "
"Meta-F toggle, or a nanorc file, inserting a file "
"will cause it to be loaded into a separate buffer "
"(use Meta-< and > to switch between file buffers). ");
htx[1] = N_("If you need another blank buffer, do not enter "
"any filename, or type in a nonexistent filename at "
"the prompt and press Enter.\n\n The following "
"function keys are available in Insert File mode:\n\n");
htx[2] = NULL;
} else if (currshortcut == writefile_list) {
htx[0] = N_("Write File Help Text\n\n "
"Type the name that you wish to save the current file "
"as and press Enter to save the file.\n\n If you have "
"selected text with the mark, you will be prompted to "
"save only the selected portion to a separate file. To "
"reduce the chance of overwriting the current file with "
"just a portion of it, the current filename is not the "
"default in this mode.\n\n The following function keys "
"are available in Write File mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#ifndef DISABLE_BROWSER
else if (currshortcut == browser_list) {
htx[0] = N_("File Browser Help Text\n\n "
"The file browser is used to visually browse the "
"directory structure to select a file for reading "
"or writing. You may use the arrow keys or Page Up/"
"Down to browse through the files, and S or Enter to "
"choose the selected file or enter the selected "
"directory. To move up one level, select the "
"directory called \"..\" at the top of the file "
"list.\n\n The following function keys are available "
"in the file browser:\n\n");
htx[1] = NULL;
htx[2] = NULL;
} else if (currshortcut == gotodir_list) {
htx[0] = N_("Browser Go To Directory Help Text\n\n "
"Enter the name of the directory you would like to "
"browse to.\n\n If tab completion has not been "
"disabled, you can use the Tab key to (attempt to) "
"automatically complete the directory name.\n\n The "
"following function keys are available in Browser Go "
"To Directory mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#endif
#ifndef DISABLE_SPELLER
else if (currshortcut == spell_list) {
htx[0] = N_("Spell Check Help Text\n\n "
"The spell checker checks the spelling of all text in "
"the current file. When an unknown word is "
"encountered, it is highlighted and a replacement can "
"be edited. It will then prompt to replace every "
"instance of the given misspelled word in the current "
"file, or, if you have selected text with the mark, in "
"the selected text.\n\n The following other functions "
"are available in Spell Check mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#endif
#ifndef NANO_SMALL
else if (currshortcut == extcmd_list) {
htx[0] = N_("Execute Command Help Text\n\n "
"This menu allows you to insert the output of a "
"command run by the shell into the current buffer (or "
"a new buffer in multiple file buffer mode). If you "
"need another blank buffer, do not enter any "
"command.\n\n The following keys are available in "
"Execute Command mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#endif
else {
/* Default to the main help list. */
htx[0] = N_(" nano help text\n\n "
"The nano editor is designed to emulate the "
"functionality and ease-of-use of the UW Pico text "
"editor. There are four main sections of the editor. "
"The top line shows the program version, the current "
"filename being edited, and whether or not the file "
"has been modified. Next is the main editor window "
"showing the file being edited. The status line is "
"the third line from the bottom and shows important "
"messages. The bottom two lines show the most "
"commonly used shortcuts in the editor.\n\n ");
htx[1] = N_("The notation for shortcuts is as follows: "
"Control-key sequences are notated with a caret (^) "
"symbol and can be entered either by using the Control "
"(Ctrl) key or pressing the Escape (Esc) key twice. "
"Escape-key sequences are notated with the Meta (M) "
"symbol and can be entered using either the Esc, Alt, "
"or Meta key depending on your keyboard setup. ");
htx[2] = N_("Also, pressing Esc twice and then typing a "
"three-digit decimal number from 000 to 255 will enter "
"the character with the corresponding value. The "
"following keystrokes are available in the main editor "
"window. Alternative keys are shown in "
"parentheses:\n\n");
}
htx[0] = _(htx[0]);
if (htx[1] != NULL)
htx[1] = _(htx[1]);
if (htx[2] != NULL)
htx[2] = _(htx[2]);
/* Save the line above the top of the partition, detach the top of
* the partition from it, and save the text before top_x in
* top_data. */
p->top_prev = top->prev;
top->prev = NULL;
p->top_data = mallocstrncpy(NULL, top->data, top_x + 1);
p->top_data[top_x] = '\0';
allocsize += strlen(htx[0]);
if (htx[1] != NULL)
allocsize += strlen(htx[1]);
if (htx[2] != NULL)
allocsize += strlen(htx[2]);
/* Save the line below the bottom of the partition, detach the
* bottom of the partition from it, and save the text after bot_x in
* bot_data. */
p->bot_next = bot->next;
bot->next = NULL;
p->bot_data = mallocstrcpy(NULL, bot->data + bot_x);
/* The space needed for the shortcut lists, at most COLS characters,
* plus '\n'. */
allocsize += (COLS < 24 ? (24 * mb_cur_max()) :
((COLS + 1) * mb_cur_max())) * length_of_list(currshortcut);
/* Remove all text after bot_x at the bottom of the partition. */
null_at(&bot->data, bot_x);
#ifndef NANO_SMALL
/* If we're on the main list, we also count the toggle help text.
* Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
* plus translated text, plus '\n'. */
if (currshortcut == main_list) {
size_t endis_len = strlen(_("enable/disable"));
/* Remove all text before top_x at the top of the partition. */
charmove(top->data, top->data + top_x, strlen(top->data) -
top_x + 1);
align(&top->data);
for (t = toggles; t != NULL; t = t->next)
allocsize += 8 + strlen(t->desc) + endis_len;
}
#endif
/* Return the partition. */
return p;
}
/* help_text has been freed and set to NULL unless the user resized
* while in the help screen. */
free(help_text);
/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
* (filebot, strlen(filebot)) again. */
void unpartition_filestruct(partition **p)
{
char *tmp;
/* Allocate space for the help text. */
help_text = charalloc(allocsize + 1);
assert(p != NULL && fileage != NULL && filebot != NULL);
/* Now add the text we want. */
strcpy(help_text, htx[0]);
if (htx[1] != NULL)
strcat(help_text, htx[1]);
if (htx[2] != NULL)
strcat(help_text, htx[2]);
/* Reattach the line above the top of the partition, and restore the
* text before top_x from top_data. Free top_data when we're done
* with it. */
tmp = mallocstrcpy(NULL, fileage->data);
fileage->prev = (*p)->top_prev;
if (fileage->prev != NULL)
fileage->prev->next = fileage;
fileage->data = charealloc(fileage->data, strlen((*p)->top_data) +
strlen(fileage->data) + 1);
strcpy(fileage->data, (*p)->top_data);
free((*p)->top_data);
strcat(fileage->data, tmp);
free(tmp);
ptr = help_text + strlen(help_text);
/* Reattach the line below the bottom of the partition, and restore
* the text after bot_x from bot_data. Free bot_data when we're
* done with it. */
filebot->next = (*p)->bot_next;
if (filebot->next != NULL)
filebot->next->prev = filebot;
filebot->data = charealloc(filebot->data, strlen(filebot->data) +
strlen((*p)->bot_data) + 1);
strcat(filebot->data, (*p)->bot_data);
free((*p)->bot_data);
/* Now add our shortcut info. Assume that each shortcut has, at the
* very least, an equivalent control key, an equivalent primary meta
* key sequence, or both. Also assume that the meta key values are
* not control characters. We can display a maximum of 3 shortcut
* entries. */
for (s = currshortcut; s != NULL; s = s->next) {
int entries = 0;
/* Restore the top and bottom of the filestruct, if they were
* different from the top and bottom of the partition. */
if ((*p)->fileage != NULL)
fileage = (*p)->fileage;
if ((*p)->filebot != NULL)
filebot = (*p)->filebot;
/* Control key. */
if (s->ctrlval != NANO_NO_KEY) {
entries++;
/* Yucky sentinel values that we can't handle a better
* way. */
if (s->ctrlval == NANO_CONTROL_SPACE) {
char *space_ptr = display_string(_("Space"), 0, 6,
FALSE);
/* Uninitialize the partition. */
free(*p);
*p = NULL;
}
ptr += sprintf(ptr, "^%s", space_ptr);
/* Move all the text between (top, top_x) and (bot, bot_x) in the
* current filestruct to a filestruct beginning with file_top and ending
* with file_bot. If no text is between (top, top_x) and (bot, bot_x),
* don't do anything. */
void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
filestruct *top, size_t top_x, filestruct *bot, size_t bot_x)
{
filestruct *top_save;
size_t part_totsize;
bool at_edittop;
#ifndef NANO_SMALL
bool mark_inside = FALSE;
#endif
free(space_ptr);
} else if (s->ctrlval == NANO_CONTROL_8)
ptr += sprintf(ptr, "^?");
/* Normal values. */
else
ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
*(ptr++) = '\t';
}
assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
/* Function key. */
if (s->funcval != NANO_NO_KEY) {
entries++;
/* If this is the first entry, put it in the middle. */
if (entries == 1) {
entries++;
*(ptr++) = '\t';
}
ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
*(ptr++) = '\t';
}
/* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
if (top == bot && top_x == bot_x)
return;
/* Primary meta key sequence. If it's the first entry, don't
* put parentheses around it. */
if (s->metaval != NANO_NO_KEY) {
entries++;
/* If this is the last entry, put it at the end. */
if (entries == 2 && s->miscval == NANO_NO_KEY) {
entries++;
*(ptr++) = '\t';
}
/* Yucky sentinel values that we can't handle a better
* way. */
if (s->metaval == NANO_ALT_SPACE && entries == 1) {
char *space_ptr = display_string(_("Space"), 0, 5,
FALSE);
/* Partition the filestruct so that it contains only the text from
* (top, top_x) to (bot, bot_x), keep track of whether the top of
* the partition is the top of the edit window, and keep track of
* whether the mark begins inside the partition. */
filepart = partition_filestruct(top, top_x, bot, bot_x);
at_edittop = (fileage == edittop);
#ifndef NANO_SMALL
if (ISSET(MARK_ISSET))
mark_inside = (mark_beginbuf->lineno >= fileage->lineno &&
mark_beginbuf->lineno <= filebot->lineno &&
(mark_beginbuf != fileage || mark_beginx >= top_x) &&
(mark_beginbuf != filebot || mark_beginx <= bot_x));
#endif
ptr += sprintf(ptr, "M-%s", space_ptr);
/* Get the number of characters in the text, and subtract it from
* totsize. */
get_totals(top, bot, NULL, &part_totsize);
totsize -= part_totsize;
free(space_ptr);
} else
/* Normal values. */
ptr += sprintf(ptr, (entries == 1) ? "M-%c" : "(M-%c)",
toupper(s->metaval));
*(ptr++) = '\t';
}
if (*file_top == NULL) {
/* If file_top is empty, just move all the text directly into
* it. This is equivalent to tacking the text in top onto the
* (lack of) text at the end of file_top. */
*file_top = fileage;
*file_bot = filebot;
} else {
/* Otherwise, tack the text in top onto the text at the end of
* file_bot. */
(*file_bot)->data = charealloc((*file_bot)->data,
strlen((*file_bot)->data) + strlen(fileage->data) + 1);
strcat((*file_bot)->data, fileage->data);
/* Miscellaneous meta key sequence. */
if (entries < 3 && s->miscval != NANO_NO_KEY) {
entries++;
/* If this is the last entry, put it at the end. */
if (entries == 2) {
entries++;
*(ptr++) = '\t';
/* Attach the line after top to the line after file_bot. Then,
* if there's more than one line after top, move file_bot down
* to bot. */
(*file_bot)->next = fileage->next;
if ((*file_bot)->next != NULL) {
(*file_bot)->next->prev = *file_bot;
*file_bot = filebot;
}
ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
*(ptr++) = '\t';
}
/* Make sure all the help text starts at the same place. */
while (entries < 3) {
entries++;
*(ptr++) = '\t';
/* Since the text has now been saved, remove it from the filestruct.
* If the top of the partition was the top of the edit window, set
* edittop to where the text used to start. If the mark began
* inside the partition, set the beginning of the mark to where the
* text used to start. */
fileage = (filestruct *)nmalloc(sizeof(filestruct));
fileage->data = mallocstrcpy(NULL, "");
filebot = fileage;
if (at_edittop)
edittop = fileage;
#ifndef NANO_SMALL
if (mark_inside) {
mark_beginbuf = fileage;
mark_beginx = top_x;
}
#endif
assert(s->help != NULL);
/* Restore the current line and cursor position. */
current = fileage;
current_x = top_x;
if (COLS > 24) {
char *help_ptr = display_string(s->help, 0, COLS - 24,
FALSE);
top_save = fileage;
ptr += sprintf(ptr, help_ptr);
/* Unpartition the filestruct so that it contains all the text
* again, minus the saved text. */
unpartition_filestruct(&filepart);
free(help_ptr);
}
/* Renumber starting with the beginning line of the old
* partition. */
renumber(top_save);
ptr += sprintf(ptr, "\n");
}
if (filebot->data[0] != '\0')
new_magicline();
#ifndef NANO_SMALL
/* And the toggles... */
if (currshortcut == main_list) {
for (t = toggles; t != NULL; t = t->next) {
/* Set totlines to the new number of lines in the file. */
totlines = filebot->lineno;
}
assert(t->desc != NULL);
/* Copy all the text from the filestruct beginning with file_top and
* ending with file_bot to the current filestruct at the current cursor
* position. */
void copy_from_filestruct(filestruct *file_top, filestruct *file_bot)
{
filestruct *top_save;
size_t part_totlines, part_totsize;
bool at_edittop;
ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
t->desc, _("enable/disable"));
}
}
assert(file_top != NULL && file_bot != NULL);
#ifdef ENABLE_NANORC
if (old_whitespace)
SET(WHITESPACE_DISPLAY);
#endif
#endif
/* Partition the filestruct so that it contains no text, and keep
* track of whether the top of the partition is the top of the edit
* window. */
filepart = partition_filestruct(current, current_x, current,
current_x);
at_edittop = (fileage == edittop);
/* If all went well, we didn't overwrite the allocated space for
* help_text. */
assert(strlen(help_text) <= allocsize + 1);
}
#endif
/* Put the top and bottom of the filestruct at copies of file_top
* and file_bot. */
fileage = copy_filestruct(file_top);
filebot = fileage;
while (filebot->next != NULL)
filebot = filebot->next;
/* Create a new filestruct node. Note that we specifically do not set
* prevnode->next equal to the new line. */
filestruct *make_new_node(filestruct *prevnode)
{
filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct));
/* Restore the current line and cursor position. */
current = filebot;
current_x = strlen(filebot->data);
if (fileage == filebot)
current_x += strlen(filepart->top_data);
newnode->data = NULL;
newnode->prev = prevnode;
newnode->next = NULL;
newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
/* Get the number of lines and the number of characters in the saved
* text, and add the latter to totsize. */
get_totals(fileage, filebot, &part_totlines, &part_totsize);
totsize += part_totsize;
return newnode;
}
/* If the top of the partition was the top of the edit window, set
* edittop to where the saved text now starts, and update the
* current y-coordinate to account for the number of lines it
* has, less one since the first line will be tacked onto the
* current line. */
if (at_edittop)
edittop = fileage;
current_y += part_totlines - 1;
/* Make a copy of a filestruct node. */
filestruct *copy_node(const filestruct *src)
{
filestruct *dst;
top_save = fileage;
assert(src != NULL);
/* Unpartition the filestruct so that it contains all the text
* again, minus the saved text. */
unpartition_filestruct(&filepart);
dst = (filestruct *)nmalloc(sizeof(filestruct));
/* Renumber starting with the beginning line of the old
* partition. */
renumber(top_save);
dst->data = mallocstrcpy(NULL, src->data);
dst->next = src->next;
dst->prev = src->prev;
dst->lineno = src->lineno;
if (filebot->data[0] != '\0')
new_magicline();
return dst;
/* Set totlines to the new number of lines in the file. */
totlines = filebot->lineno;
}
/* Splice a node into an existing filestruct. */
void splice_node(filestruct *begin, filestruct *newnode, filestruct
*end)
void print_view_warning(void)
{
assert(newnode != NULL && begin != NULL);
newnode->next = end;
newnode->prev = begin;
begin->next = newnode;
if (end != NULL)
end->prev = newnode;
statusbar(_("Key illegal in VIEW mode"));
}
/* Unlink a node from the rest of the filestruct. */
void unlink_node(const filestruct *fileptr)
/* What we do when we're all set to exit. */
void finish(void)
{
assert(fileptr != NULL);
if (!ISSET(NO_HELP))
blank_bottombars();
else
blank_statusbar();
if (fileptr->prev != NULL)
fileptr->prev->next = fileptr->next;
if (fileptr->next != NULL)
fileptr->next->prev = fileptr->prev;
}
wrefresh(bottomwin);
endwin();
/* Delete a node from the filestruct. */
void delete_node(filestruct *fileptr)
{
assert(fileptr != NULL && fileptr->data != NULL);
/* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &oldterm);
if (fileptr->data != NULL)
free(fileptr->data);
free(fileptr);
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
save_history();
#endif
#ifdef DEBUG
thanks_for_all_the_fish();
#endif
exit(0);
}
/* Duplicate a whole filestruct. */
filestruct *copy_filestruct(const filestruct *src)
/* Die (gracefully?). */
void die(const char *msg, ...)
{
filestruct *head, *copy;
va_list ap;
assert(src != NULL);
endwin();
curses_ended = TRUE;
copy = copy_node(src);
copy->prev = NULL;
head = copy;
src = src->next;
/* Restore the old terminal settings. */
tcsetattr(0, TCSANOW, &oldterm);
while (src != NULL) {
copy->next = copy_node(src);
copy->next->prev = copy;
copy = copy->next;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
src = src->next;
/* Save the current file buffer if it's been modified. */
if (ISSET(MODIFIED)) {
/* If we've partitioned the filestruct, unpartition it now. */
if (filepart != NULL)
unpartition_filestruct(&filepart);
die_save_file(filename);
}
copy->next = NULL;
return head;
}
#ifdef ENABLE_MULTIBUFFER
/* Save all of the other modified file buffers, if any. */
if (open_files != NULL) {
openfilestruct *tmp = open_files;
/* Frees a filestruct. */
void free_filestruct(filestruct *src)
{
assert(src != NULL);
while (tmp != open_files->next) {
open_files = open_files->next;
while (src->next != NULL) {
src = src->next;
delete_node(src->prev);
/* Save the current file buffer if it's been modified. */
if (open_files->flags & MODIFIED) {
/* Set fileage and filebot to match the current file
* buffer, and then write it to disk. */
fileage = open_files->fileage;
filebot = open_files->filebot;
die_save_file(open_files->filename);
}
delete_node(src);
}
}
#endif
/* Get out. */
exit(1);
}
/* Partition a filestruct so it begins at (top, top_x) and ends at (bot,
* bot_x). */
partition *partition_filestruct(filestruct *top, size_t top_x,
filestruct *bot, size_t bot_x)
void die_save_file(const char *die_filename)
{
partition *p;
char *retval;
bool failed = TRUE;
assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL);
/* If we're using restricted mode, don't write any emergency backup
* files, since that would allow reading from or writing to files
* not specified on the command line. */
if (ISSET(RESTRICTED))
return;
/* Initialize the partition. */
p = (partition *)nmalloc(sizeof(partition));
/* If we can't save, we have REAL bad problems, but we might as well
* TRY. */
if (die_filename[0] == '\0')
die_filename = "nano";
/* If the top and bottom of the partition are different from the top
* and bottom of the filestruct, save the latter and then set them
* to top and bot. */
if (top != fileage) {
p->fileage = fileage;
fileage = top;
} else
p->fileage = NULL;
if (bot != filebot) {
p->filebot = filebot;
filebot = bot;
} else
p->filebot = NULL;
retval = get_next_filename(die_filename, ".save");
if (retval[0] != '\0')
failed = (write_file(retval, NULL, TRUE, FALSE, TRUE) == -1);
/* Save the line above the top of the partition, detach the top of
* the partition from it, and save the text before top_x in
* top_data. */
p->top_prev = top->prev;
top->prev = NULL;
p->top_data = mallocstrncpy(NULL, top->data, top_x + 1);
p->top_data[top_x] = '\0';
if (!failed)
fprintf(stderr, _("\nBuffer written to %s\n"), retval);
else if (retval[0] != '\0')
fprintf(stderr, _("\nBuffer not written to %s: %s\n"), retval,
strerror(errno));
else
fprintf(stderr, _("\nBuffer not written: %s\n"),
_("Too many backup files?"));
/* Save the line below the bottom of the partition, detach the
* bottom of the partition from it, and save the text after bot_x in
* bot_data. */
p->bot_next = bot->next;
bot->next = NULL;
p->bot_data = mallocstrcpy(NULL, bot->data + bot_x);
free(retval);
}
/* Remove all text after bot_x at the bottom of the partition. */
null_at(&bot->data, bot_x);
/* Die with an error message that the screen was too small if, well, the
* screen is too small. */
void check_die_too_small(void)
{
editwinrows = LINES - 5 + no_more_space() + no_help();
if (editwinrows < MIN_EDITOR_ROWS)
die(_("Window size is too small for nano...\n"));
}
/* Remove all text before top_x at the top of the partition. */
charmove(top->data, top->data + top_x, strlen(top->data) -
top_x + 1);
align(&top->data);
/* Reinitialize the variables that depend on the window size. That is,
* fill and hblank. */
void resize_variables(void)
{
#ifndef DISABLE_WRAPJUSTIFY
fill = wrap_at;
if (fill <= 0)
fill += COLS;
if (fill < 0)
fill = 0;
#endif
/* Return the partition. */
return p;
hblank = charealloc(hblank, COLS + 1);
charset(hblank, ' ', COLS);
hblank[COLS] = '\0';
}
/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
* (filebot, strlen(filebot)) again. */
void unpartition_filestruct(partition **p)
/* Initialize global variables -- no better way for now. If
* save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
void global_init(bool save_cutbuffer)
{
char *tmp;
check_die_too_small();
resize_variables();
assert(p != NULL && fileage != NULL && filebot != NULL);
fileage = NULL;
edittop = NULL;
current = NULL;
if (!save_cutbuffer)
cutbuffer = NULL;
current_x = 0;
placewewant = 0;
current_y = 0;
totlines = 0;
totsize = 0;
}
/* Reattach the line above the top of the partition, and restore the
* text before top_x from top_data. Free top_data when we're done
* with it. */
tmp = mallocstrcpy(NULL, fileage->data);
fileage->prev = (*p)->top_prev;
if (fileage->prev != NULL)
fileage->prev->next = fileage;
fileage->data = charealloc(fileage->data, strlen((*p)->top_data) +
strlen(fileage->data) + 1);
strcpy(fileage->data, (*p)->top_data);
free((*p)->top_data);
strcat(fileage->data, tmp);
free(tmp);
void window_init(void)
{
check_die_too_small();
/* Reattach the line below the bottom of the partition, and restore
* the text after bot_x from bot_data. Free bot_data when we're
* done with it. */
filebot->next = (*p)->bot_next;
if (filebot->next != NULL)
filebot->next->prev = filebot;
filebot->data = charealloc(filebot->data, strlen(filebot->data) +
strlen((*p)->bot_data) + 1);
strcat(filebot->data, (*p)->bot_data);
free((*p)->bot_data);
if (topwin != NULL)
delwin(topwin);
if (edit != NULL)
delwin(edit);
if (bottomwin != NULL)
delwin(bottomwin);
/* Restore the top and bottom of the filestruct, if they were
* different from the top and bottom of the partition. */
if ((*p)->fileage != NULL)
fileage = (*p)->fileage;
if ((*p)->filebot != NULL)
filebot = (*p)->filebot;
/* Set up the windows. */
topwin = newwin(2 - no_more_space(), COLS, 0, 0);
edit = newwin(editwinrows, COLS, 2 - no_more_space(), 0);
bottomwin = newwin(3 - no_help(), COLS, editwinrows +
(2 - no_more_space()), 0);
/* Uninitialize the partition. */
free(*p);
*p = NULL;
/* Turn the keypad back on. */
keypad(edit, TRUE);
keypad(bottomwin, TRUE);
}
/* Move all the text between (top, top_x) and (bot, bot_x) in the
* current filestruct to a filestruct beginning with file_top and ending
* with file_bot. If no text is between (top, top_x) and (bot, bot_x),
* don't do anything. */
void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
filestruct *top, size_t top_x, filestruct *bot, size_t bot_x)
#ifndef DISABLE_MOUSE
void mouse_init(void)
{
filestruct *top_save;
size_t part_totsize;
bool at_edittop;
#ifndef NANO_SMALL
bool mark_inside = FALSE;
if (ISSET(USE_MOUSE)) {
mousemask(BUTTON1_RELEASED, NULL);
mouseinterval(50);
} else
mousemask(0, NULL);
}
#endif
assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
#ifndef DISABLE_HELP
/* This function allocates help_text, and stores the help string in it.
* help_text should be NULL initially. */
void help_init(void)
{
size_t allocsize = 0; /* Space needed for help_text. */
const char *htx[3]; /* Untranslated help message. We break
* it up into three chunks in case the
* full string is too long for the
* compiler to handle. */
char *ptr;
const shortcut *s;
#ifndef NANO_SMALL
const toggle *t;
#ifdef ENABLE_NANORC
bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
/* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
if (top == bot && top_x == bot_x)
return;
UNSET(WHITESPACE_DISPLAY);
#endif
#endif
/* Partition the filestruct so that it contains only the text from
* (top, top_x) to (bot, bot_x), keep track of whether the top of
* the partition is the top of the edit window, and keep track of
* whether the mark begins inside the partition. */
filepart = partition_filestruct(top, top_x, bot, bot_x);
at_edittop = (fileage == edittop);
/* First, set up the initial help text for the current function. */
if (currshortcut == whereis_list || currshortcut == replace_list
|| currshortcut == replace_list_2) {
htx[0] = N_("Search Command Help Text\n\n "
"Enter the words or characters you would like to "
"search for, and then press Enter. If there is a "
"match for the text you entered, the screen will be "
"updated to the location of the nearest match for the "
"search string.\n\n The previous search string will be "
"shown in brackets after the search prompt. Hitting "
"Enter without entering any text will perform the "
"previous search. ");
htx[1] = N_("If you have selected text with the mark and then "
"search to replace, only matches in the selected text "
"will be replaced.\n\n The following function keys are "
"available in Search mode:\n\n");
htx[2] = NULL;
} else if (currshortcut == gotoline_list) {
htx[0] = N_("Go To Line Help Text\n\n "
"Enter the line number that you wish to go to and hit "
"Enter. If there are fewer lines of text than the "
"number you entered, you will be brought to the last "
"line of the file.\n\n The following function keys are "
"available in Go To Line mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
} else if (currshortcut == insertfile_list) {
htx[0] = N_("Insert File Help Text\n\n "
"Type in the name of a file to be inserted into the "
"current file buffer at the current cursor "
"location.\n\n If you have compiled nano with multiple "
"file buffer support, and enable multiple file buffers "
"with the -F or --multibuffer command line flags, the "
"Meta-F toggle, or a nanorc file, inserting a file "
"will cause it to be loaded into a separate buffer "
"(use Meta-< and > to switch between file buffers). ");
htx[1] = N_("If you need another blank buffer, do not enter "
"any filename, or type in a nonexistent filename at "
"the prompt and press Enter.\n\n The following "
"function keys are available in Insert File mode:\n\n");
htx[2] = NULL;
} else if (currshortcut == writefile_list) {
htx[0] = N_("Write File Help Text\n\n "
"Type the name that you wish to save the current file "
"as and press Enter to save the file.\n\n If you have "
"selected text with the mark, you will be prompted to "
"save only the selected portion to a separate file. To "
"reduce the chance of overwriting the current file with "
"just a portion of it, the current filename is not the "
"default in this mode.\n\n The following function keys "
"are available in Write File mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#ifndef DISABLE_BROWSER
else if (currshortcut == browser_list) {
htx[0] = N_("File Browser Help Text\n\n "
"The file browser is used to visually browse the "
"directory structure to select a file for reading "
"or writing. You may use the arrow keys or Page Up/"
"Down to browse through the files, and S or Enter to "
"choose the selected file or enter the selected "
"directory. To move up one level, select the "
"directory called \"..\" at the top of the file "
"list.\n\n The following function keys are available "
"in the file browser:\n\n");
htx[1] = NULL;
htx[2] = NULL;
} else if (currshortcut == gotodir_list) {
htx[0] = N_("Browser Go To Directory Help Text\n\n "
"Enter the name of the directory you would like to "
"browse to.\n\n If tab completion has not been "
"disabled, you can use the Tab key to (attempt to) "
"automatically complete the directory name.\n\n The "
"following function keys are available in Browser Go "
"To Directory mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#endif
#ifndef DISABLE_SPELLER
else if (currshortcut == spell_list) {
htx[0] = N_("Spell Check Help Text\n\n "
"The spell checker checks the spelling of all text in "
"the current file. When an unknown word is "
"encountered, it is highlighted and a replacement can "
"be edited. It will then prompt to replace every "
"instance of the given misspelled word in the current "
"file, or, if you have selected text with the mark, in "
"the selected text.\n\n The following other functions "
"are available in Spell Check mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#endif
#ifndef NANO_SMALL
if (ISSET(MARK_ISSET))
mark_inside = (mark_beginbuf->lineno >= fileage->lineno &&
mark_beginbuf->lineno <= filebot->lineno &&
(mark_beginbuf != fileage || mark_beginx >= top_x) &&
(mark_beginbuf != filebot || mark_beginx <= bot_x));
else if (currshortcut == extcmd_list) {
htx[0] = N_("Execute Command Help Text\n\n "
"This menu allows you to insert the output of a "
"command run by the shell into the current buffer (or "
"a new buffer in multiple file buffer mode). If you "
"need another blank buffer, do not enter any "
"command.\n\n The following keys are available in "
"Execute Command mode:\n\n");
htx[1] = NULL;
htx[2] = NULL;
}
#endif
else {
/* Default to the main help list. */
htx[0] = N_(" nano help text\n\n "
"The nano editor is designed to emulate the "
"functionality and ease-of-use of the UW Pico text "
"editor. There are four main sections of the editor. "
"The top line shows the program version, the current "
"filename being edited, and whether or not the file "
"has been modified. Next is the main editor window "
"showing the file being edited. The status line is "
"the third line from the bottom and shows important "
"messages. The bottom two lines show the most "
"commonly used shortcuts in the editor.\n\n ");
htx[1] = N_("The notation for shortcuts is as follows: "
"Control-key sequences are notated with a caret (^) "
"symbol and can be entered either by using the Control "
"(Ctrl) key or pressing the Escape (Esc) key twice. "
"Escape-key sequences are notated with the Meta (M) "
"symbol and can be entered using either the Esc, Alt, "
"or Meta key depending on your keyboard setup. ");
htx[2] = N_("Also, pressing Esc twice and then typing a "
"three-digit decimal number from 000 to 255 will enter "
"the character with the corresponding value. The "
"following keystrokes are available in the main editor "
"window. Alternative keys are shown in "
"parentheses:\n\n");
}
/* Get the number of characters in the text, and subtract it from
* totsize. */
get_totals(top, bot, NULL, &part_totsize);
totsize -= part_totsize;
htx[0] = _(htx[0]);
if (htx[1] != NULL)
htx[1] = _(htx[1]);
if (htx[2] != NULL)
htx[2] = _(htx[2]);
if (*file_top == NULL) {
/* If file_top is empty, just move all the text directly into
* it. This is equivalent to tacking the text in top onto the
* (lack of) text at the end of file_top. */
*file_top = fileage;
*file_bot = filebot;
} else {
/* Otherwise, tack the text in top onto the text at the end of
* file_bot. */
(*file_bot)->data = charealloc((*file_bot)->data,
strlen((*file_bot)->data) + strlen(fileage->data) + 1);
strcat((*file_bot)->data, fileage->data);
allocsize += strlen(htx[0]);
if (htx[1] != NULL)
allocsize += strlen(htx[1]);
if (htx[2] != NULL)
allocsize += strlen(htx[2]);
/* Attach the line after top to the line after file_bot. Then,
* if there's more than one line after top, move file_bot down
* to bot. */
(*file_bot)->next = fileage->next;
if ((*file_bot)->next != NULL) {
(*file_bot)->next->prev = *file_bot;
*file_bot = filebot;
}
}
/* The space needed for the shortcut lists, at most COLS characters,
* plus '\n'. */
allocsize += (COLS < 24 ? (24 * mb_cur_max()) :
((COLS + 1) * mb_cur_max())) * length_of_list(currshortcut);
/* Since the text has now been saved, remove it from the filestruct.
* If the top of the partition was the top of the edit window, set
* edittop to where the text used to start. If the mark began
* inside the partition, set the beginning of the mark to where the
* text used to start. */
fileage = (filestruct *)nmalloc(sizeof(filestruct));
fileage->data = mallocstrcpy(NULL, "");
filebot = fileage;
if (at_edittop)
edittop = fileage;
#ifndef NANO_SMALL
if (mark_inside) {
mark_beginbuf = fileage;
mark_beginx = top_x;
/* If we're on the main list, we also count the toggle help text.
* Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
* plus translated text, plus '\n'. */
if (currshortcut == main_list) {
size_t endis_len = strlen(_("enable/disable"));
for (t = toggles; t != NULL; t = t->next)
allocsize += 8 + strlen(t->desc) + endis_len;
}
#endif
/* Restore the current line and cursor position. */
current = fileage;
current_x = top_x;
/* help_text has been freed and set to NULL unless the user resized
* while in the help screen. */
free(help_text);
top_save = fileage;
/* Allocate space for the help text. */
help_text = charalloc(allocsize + 1);
/* Unpartition the filestruct so that it contains all the text
* again, minus the saved text. */
unpartition_filestruct(&filepart);
/* Now add the text we want. */
strcpy(help_text, htx[0]);
if (htx[1] != NULL)
strcat(help_text, htx[1]);
if (htx[2] != NULL)
strcat(help_text, htx[2]);
/* Renumber starting with the beginning line of the old
* partition. */
renumber(top_save);
ptr = help_text + strlen(help_text);
if (filebot->data[0] != '\0')
new_magicline();
/* Now add our shortcut info. Assume that each shortcut has, at the
* very least, an equivalent control key, an equivalent primary meta
* key sequence, or both. Also assume that the meta key values are
* not control characters. We can display a maximum of 3 shortcut
* entries. */
for (s = currshortcut; s != NULL; s = s->next) {
int entries = 0;
/* Set totlines to the new number of lines in the file. */
totlines = filebot->lineno;
}
/* Control key. */
if (s->ctrlval != NANO_NO_KEY) {
entries++;
/* Yucky sentinel values that we can't handle a better
* way. */
if (s->ctrlval == NANO_CONTROL_SPACE) {
char *space_ptr = display_string(_("Space"), 0, 6,
FALSE);
/* Copy all the text from the filestruct beginning with file_top and
* ending with file_bot to the current filestruct at the current cursor
* position. */
void copy_from_filestruct(filestruct *file_top, filestruct *file_bot)
{
filestruct *top_save;
size_t part_totlines, part_totsize;
bool at_edittop;
ptr += sprintf(ptr, "^%s", space_ptr);
assert(file_top != NULL && file_bot != NULL);
free(space_ptr);
} else if (s->ctrlval == NANO_CONTROL_8)
ptr += sprintf(ptr, "^?");
/* Normal values. */
else
ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
*(ptr++) = '\t';
}
/* Partition the filestruct so that it contains no text, and keep
* track of whether the top of the partition is the top of the edit
* window. */
filepart = partition_filestruct(current, current_x, current,
current_x);
at_edittop = (fileage == edittop);
/* Function key. */
if (s->funcval != NANO_NO_KEY) {
entries++;
/* If this is the first entry, put it in the middle. */
if (entries == 1) {
entries++;
*(ptr++) = '\t';
}
ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
*(ptr++) = '\t';
}
/* Put the top and bottom of the filestruct at copies of file_top
* and file_bot. */
fileage = copy_filestruct(file_top);
filebot = fileage;
while (filebot->next != NULL)
filebot = filebot->next;
/* Primary meta key sequence. If it's the first entry, don't
* put parentheses around it. */
if (s->metaval != NANO_NO_KEY) {
entries++;
/* If this is the last entry, put it at the end. */
if (entries == 2 && s->miscval == NANO_NO_KEY) {
entries++;
*(ptr++) = '\t';
}
/* Yucky sentinel values that we can't handle a better
* way. */
if (s->metaval == NANO_ALT_SPACE && entries == 1) {
char *space_ptr = display_string(_("Space"), 0, 5,
FALSE);
/* Restore the current line and cursor position. */
current = filebot;
current_x = strlen(filebot->data);
if (fileage == filebot)
current_x += strlen(filepart->top_data);
ptr += sprintf(ptr, "M-%s", space_ptr);
/* Get the number of lines and the number of characters in the saved
* text, and add the latter to totsize. */
get_totals(fileage, filebot, &part_totlines, &part_totsize);
totsize += part_totsize;
free(space_ptr);
} else
/* Normal values. */
ptr += sprintf(ptr, (entries == 1) ? "M-%c" : "(M-%c)",
toupper(s->metaval));
*(ptr++) = '\t';
}
/* If the top of the partition was the top of the edit window, set
* edittop to where the saved text now starts, and update the
* current y-coordinate to account for the number of lines it
* has, less one since the first line will be tacked onto the
* current line. */
if (at_edittop)
edittop = fileage;
current_y += part_totlines - 1;
/* Miscellaneous meta key sequence. */
if (entries < 3 && s->miscval != NANO_NO_KEY) {
entries++;
/* If this is the last entry, put it at the end. */
if (entries == 2) {
entries++;
*(ptr++) = '\t';
}
ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
*(ptr++) = '\t';
}
top_save = fileage;
/* Make sure all the help text starts at the same place. */
while (entries < 3) {
entries++;
*(ptr++) = '\t';
}
/* Unpartition the filestruct so that it contains all the text
* again, minus the saved text. */
unpartition_filestruct(&filepart);
assert(s->help != NULL);
/* Renumber starting with the beginning line of the old
* partition. */
renumber(top_save);
if (COLS > 24) {
char *help_ptr = display_string(s->help, 0, COLS - 24,
FALSE);
if (filebot->data[0] != '\0')
new_magicline();
ptr += sprintf(ptr, help_ptr);
/* Set totlines to the new number of lines in the file. */
totlines = filebot->lineno;
}
free(help_ptr);
}
void renumber_all(void)
{
filestruct *temp;
ssize_t line = 1;
ptr += sprintf(ptr, "\n");
}
assert(fileage == NULL || fileage != fileage->next);
#ifndef NANO_SMALL
/* And the toggles... */
if (currshortcut == main_list) {
for (t = toggles; t != NULL; t = t->next) {
for (temp = fileage; temp != NULL; temp = temp->next)
temp->lineno = line++;
}
assert(t->desc != NULL);
void renumber(filestruct *fileptr)
{
if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
renumber_all();
else {
ssize_t line = fileptr->prev->lineno;
ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
t->desc, _("enable/disable"));
}
}
assert(fileptr != fileptr->next);
#ifdef ENABLE_NANORC
if (old_whitespace)
SET(WHITESPACE_DISPLAY);
#endif
#endif
for (; fileptr != NULL; fileptr = fileptr->next)
fileptr->lineno = ++line;
}
/* If all went well, we didn't overwrite the allocated space for
* help_text. */
assert(strlen(help_text) <= allocsize + 1);
}
#endif
#ifdef HAVE_GETOPT_LONG
#define print1opt(shortflag, longflag, desc) print1opt_full(shortflag, longflag, desc)
......
......@@ -246,6 +246,22 @@ void do_cut_till_end(void);
void do_uncut_text(void);
/* Public functions in files.c. */
#ifdef ENABLE_MULTIBUFFER
openfilestruct *make_new_opennode(void);
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
openfilestruct *end);
void unlink_opennode(openfilestruct *fileptr);
void delete_opennode(openfilestruct *fileptr);
#ifdef DEBUG
void free_openfilestruct(openfilestruct *src);
#endif
void add_open_file(bool update);
void load_open_file(void);
void open_prevnext_file(bool next_file);
void open_prevfile_void(void);
void open_nextfile_void(void);
bool close_open_file(void);
#endif
void new_file(void);
filestruct *read_line(char *buf, filestruct *prevnode, bool
*first_line_ins, size_t buf_len);
......@@ -265,22 +281,6 @@ void do_insertfile(
#endif
);
void do_insertfile_void(void);
#ifdef ENABLE_MULTIBUFFER
openfilestruct *make_new_opennode(void);
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
openfilestruct *end);
void unlink_opennode(openfilestruct *fileptr);
void delete_opennode(openfilestruct *fileptr);
#ifdef DEBUG
void free_openfilestruct(openfilestruct *src);
#endif
void add_open_file(bool update);
void load_open_file(void);
void open_prevnext_file(bool next_file);
void open_prevfile_void(void);
void open_nextfile_void(void);
bool close_open_file(void);
#endif
char *get_full_path(const char *origpath);
char *check_writable_directory(const char *path);
char *safe_tempfile(FILE **f);
......@@ -359,20 +359,6 @@ void do_right(bool allow_update);
void do_right_void(void);
/* Public functions in nano.c. */
void print_view_warning(void);
void finish(void);
void die(const char *msg, ...);
void die_save_file(const char *die_filename);
void check_die_too_small(void);
void resize_variables(void);
void global_init(bool save_cutbuffer);
void window_init(void);
#ifndef DISABLE_MOUSE
void mouse_init(void);
#endif
#ifndef DISABLE_HELP
void help_init(void);
#endif
filestruct *make_new_node(filestruct *prevnode);
filestruct *copy_node(const filestruct *src);
void splice_node(filestruct *begin, filestruct *newnode, filestruct
......@@ -381,14 +367,28 @@ void unlink_node(const filestruct *fileptr);
void delete_node(filestruct *fileptr);
filestruct *copy_filestruct(const filestruct *src);
void free_filestruct(filestruct *src);
void renumber_all(void);
void renumber(filestruct *fileptr);
partition *partition_filestruct(filestruct *top, size_t top_x,
filestruct *bot, size_t bot_x);
void unpartition_filestruct(partition **p);
void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
filestruct *top, size_t top_x, filestruct *bot, size_t bot_x);
void copy_from_filestruct(filestruct *file_top, filestruct *file_bot);
void renumber_all(void);
void renumber(filestruct *fileptr);
void print_view_warning(void);
void finish(void);
void die(const char *msg, ...);
void die_save_file(const char *die_filename);
void check_die_too_small(void);
void resize_variables(void);
void global_init(bool save_cutbuffer);
void window_init(void);
#ifndef DISABLE_MOUSE
void mouse_init(void);
#endif
#ifndef DISABLE_HELP
void help_init(void);
#endif
void print1opt_full(const char *shortflag
#ifdef HAVE_GETOPT_LONG
, const char *longflag
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment