From 02517e0a0f9bce6fc7da61151e7673f00991bd28 Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Sun, 5 Sep 2004 21:40:31 +0000 Subject: [PATCH] add DB's overhaul of the file loading code to increase efficiency, remove ugly workarounds for most cases of edittop's or current's being NULL (as those cases no longer occur due to the overhaul), and remove detection of binary files (since it wasn't always accurate and will only cause problems when UTF-8 support is added); also add a few minor fixes of mine git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1928 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 36 +++ src/files.c | 609 +++++++++++++++++++++++---------------------------- src/global.c | 3 +- src/nano.c | 149 +++++++------ src/nano.h | 3 + src/proto.h | 19 +- src/rcfile.c | 4 +- src/search.c | 4 +- src/utils.c | 13 +- src/winio.c | 22 +- 10 files changed, 431 insertions(+), 431 deletions(-) diff --git a/ChangeLog b/ChangeLog index 27dd6a6c..ce624480 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,29 @@ CVS code - - Remove reference to @includedir@ in src/Makefile.am, as it's unneeded and can break cross-compilation. (DLR, found by Mike Frysinger) + - Overhaul the file opening, reading, and loading operations to + increase efficiency, avoid problems on invalid filenames + specified on the command line, and eliminate corner cases that + erroneously leave edittop or current NULL when they shouldn't + be. Also split out the code to execute a command into a + separate function, eliminate a workaround for one of the + aforementioned corner cases, handle files with a mix of DOS + and Mac format lines, and remove the code to turn on the + NO_CONVERT flag when opening a binary file, as it's not always + reliable and will cause problems with UTF-8 text files. New + functions open_file(), execute_command(), and mallocstrassn(); + changes to read_line(), load_file(), read_file(), open_file(), + get_next_filename(), do_insertfile(), do_insertfile_void(), + do_alt_speller(), and edit_refresh(). (David Benbennick) DLR: + Add a few minor fixes to make sure that current is set + properly in all cases, indicate on the statusbar when the file + has a mix of DOS and Mac format lines, move the test for DOS + line endings from read_line() to read_file() to avoid + inaccurate statusbar messages and to reduce fileformat to a + local variable in read_file(), eliminate another workaround in + edit_update(), rename open_the_file() to open_file() since the + latter has been removed, and rename load_a_file() to + load_buffer(). - files.c: do_insertfile() - Readd the NANO_SMALL #ifdef around the start_again: label to @@ -23,14 +46,23 @@ CVS code - shortcut_init() - Remove redundant NANO_SMALL #ifdef. (DLR) - nano.c: + die_save_file() + - Clarify the error message when there are too many backup files + and the current one can't be written. (DLR) do_para_begin(), do_para_end() - Maintain current_y's value when moving up or down lines so that smooth scrolling works correctly. (DLR) +- nano.h: + - Add WIDTH_OF_TAB #define, containing the default width of a + tab. (DLR) - rcfile.c: parse_rcfile() - Add missing brackets around an if statement block so that parsing the numeric argument after "tabsize" works properly again. (DLR, found by Mike Frysinger) + - Since flag values are longs, use "%ld" instead of "%d" in the + debugging messages indicating when a flag is set or unset. + (DLR) - search.c: findnextstr() - Take the no_sameline parameter after can_display_wrap and @@ -56,6 +88,10 @@ CVS code - - If there are more than MAIN_VISIBLE shortcuts available, only register clicks on the first MAIN_VISIBLE shortcuts, since bottombars() only shows that many shortcuts. (DLR) + reset_cursor() + - If this is called before any files have been opened, as it can + be by statusbar(), put the cursor at the top left corner of + the edit window before getting out. (DLR) edit_refresh() - Call edit_update() with NONE instead of CENTER when smooth scrolling is on, for consistency with the movement routines. diff --git a/src/files.c b/src/files.c index 3003f7d9..14293674 100644 --- a/src/files.c +++ b/src/files.c @@ -37,35 +37,12 @@ #include "proto.h" #include "nano.h" -/* Set a default value for PATH_MAX, so we can use it below in lines like - path = getcwd(NULL, PATH_MAX + 1); */ +/* Set a default value for PATH_MAX, so we can use it below in lines + * like "path = getcwd(NULL, PATH_MAX + 1);". */ #ifndef PATH_MAX #define PATH_MAX -1 #endif -#ifndef NANO_SMALL -static int fileformat = 0; /* 0 = *nix, 1 = DOS, 2 = Mac */ -#endif - -/* Load file into edit buffer -- takes data from file struct. */ -void load_file(int update) -{ - current = fileage; - -#ifdef ENABLE_MULTIBUFFER - /* if update is zero, add a new entry to the open_files structure; - otherwise, update the current entry (the latter is needed in the - case of the alternate spell checker) */ - add_open_file(update); -#endif - -#ifdef ENABLE_COLOR - update_color(); - if (ISSET(COLOR_SYNTAX)) - edit_refresh(); -#endif -} - /* What happens when there is no file to open? aiee! */ void new_file(void) { @@ -79,24 +56,6 @@ void new_file(void) totlines = 1; totsize = 0; -#ifdef ENABLE_MULTIBUFFER - /* if there aren't any entries in open_files, create the entry for - this new file; without this, if nano is started without a filename - on the command line, a new file will be created, but it will be - given no open_files entry */ - if (open_files == NULL) { - add_open_file(FALSE); - /* turn off view mode in this case; this is for consistency - whether multibuffers are compiled in or not */ - UNSET(VIEW_MODE); - } -#else - /* if multibuffers haven't been compiled in, turn off view mode - unconditionally; otherwise, don't turn them off (except in the - above case), so that we can view multiple files properly */ - UNSET(VIEW_MODE); -#endif - #ifdef ENABLE_COLOR update_color(); if (ISSET(COLOR_SYNTAX)) @@ -104,12 +63,17 @@ void new_file(void) #endif } -filestruct *read_line(char *buf, filestruct *prev, int *line1ins, size_t - len) +/* We make a new line of text from buf. buf is length len. If + * first_line_ins is TRUE, then we put the new line at the top of the + * file. Otherwise, we assume prev is the last line of the file, and + * put our line after prev. */ +filestruct *read_line(char *buf, filestruct *prev, bool *first_line_ins, + size_t len) { filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct)); - /* nulls to newlines; len is the string's real length here */ + /* Convert nulls to newlines. len is the string's real length + * here. */ unsunder(buf, len); assert(strlen(buf) == len); @@ -117,27 +81,25 @@ filestruct *read_line(char *buf, filestruct *prev, int *line1ins, size_t fileptr->data = mallocstrcpy(NULL, buf); #ifndef NANO_SMALL - /* If it's a DOS file (CRLF), and file conversion isn't disabled, - strip out the CR part */ + /* If it's a DOS file (CR LF), and file conversion isn't disabled, + * strip out the CR part. */ if (!ISSET(NO_CONVERT) && len > 0 && buf[len - 1] == '\r') { fileptr->data[len - 1] = '\0'; totsize--; - - if (fileformat == 0) - fileformat = 1; } #endif - if (*line1ins != 0 || fileage == NULL) { - /* Special case, insert with cursor on 1st line. */ + if (*first_line_ins || fileage == NULL) { + /* Special case: we're inserting with the cursor on the first + * line. */ fileptr->prev = NULL; fileptr->next = fileage; fileptr->lineno = 1; - if (*line1ins != 0) { - *line1ins = 0; + if (*first_line_ins) { + *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!) */ + * 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; @@ -153,70 +115,105 @@ filestruct *read_line(char *buf, filestruct *prev, int *line1ins, size_t return fileptr; } -void read_file(FILE *f, const char *filename, int quiet) +/* Load a file into the edit buffer. This takes data from the file + * struct. */ +void load_file(void) +{ + current = fileage; + +#ifdef ENABLE_MULTIBUFFER + /* Add a new entry to the open_files structure. */ + add_open_file(FALSE); + + /* Reinitialize the shortcut list. */ + shortcut_init(FALSE); +#endif +} + +void read_file(FILE *f, const char *filename) { - int num_lines = 0, len = 0; - char input = '\0'; /* current input character */ + size_t num_lines = 0; + /* The number of lines 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 = 128; + /* The size of each chunk of the file that we read. */ + char input = '\0'; + /* The current input character. */ char *buf; - long i = 0, bufx = 128; - filestruct *fileptr = current, *tmp = NULL; + /* 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 old_no_convert = ISSET(NO_CONVERT); + int fileformat = 0; + /* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */ #endif - int line1ins = 0; - int input_int; buf = charalloc(bufx); buf[0] = '\0'; if (current != NULL) { if (current == fileage) - line1ins = 1; + first_line_ins = TRUE; else fileptr = current->prev; - tmp = fileptr; } - /* For the assertion in read_line(), it must be true that if current is - * NULL then so is fileage. */ + /* For the assertion in read_line(), it must be true that if current + * is NULL, then so is fileage. */ assert(current != NULL || fileage == NULL); - /* Read the entire file into file struct. */ + /* Read the entire file into the file struct. */ while ((input_int = getc(f)) != EOF) { - input = (char)input_int; -#ifndef NANO_SMALL - /* If the file has binary chars in it, don't stupidly - assume it's a DOS or Mac formatted file if it hasn't been - detected as one already! */ - if (fileformat == 0 && !ISSET(NO_CONVERT) - && is_cntrl_char(input) && input != '\t' - && input != '\r' && input != '\n') - SET(NO_CONVERT); -#endif + input = (char)input_int; + /* If it's a *nix file (LF) or a DOS file (CR LF), and file + * conversion isn't disabled, handle it! */ if (input == '\n') { - /* read in the line properly */ - fileptr = read_line(buf, fileptr, &line1ins, len); +#ifndef NANO_SMALL + /* If there's a CR before the LF, set fileformat 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' && + (fileformat == 0 || fileformat == 2)) + fileformat++; +#endif + + /* Read in the line properly. */ + fileptr = read_line(buf, fileptr, &first_line_ins, len); - /* reset the line length, in preparation for the next line */ + /* Reset the line length in preparation for the next + * line. */ len = 0; num_lines++; buf[0] = '\0'; i = 0; #ifndef NANO_SMALL - /* If it's a Mac file (no LF just a CR), and file conversion - isn't disabled, handle it! */ + /* If it's a Mac file (CR without an LF), and file conversion + * isn't disabled, handle it! */ } else if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r') { - fileformat = 2; - /* read in the line properly */ - fileptr = read_line(buf, fileptr, &line1ins, len); + /* If we currently think the file is a *nix file, set + * fileformat to Mac. If we currently think the file is a + * DOS file, set fileformat to both DOS and Mac. */ + if (fileformat == 0 || fileformat == 1) + fileformat += 2; - /* 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 */ + /* Read in the line properly. */ + fileptr = read_line(buf, fileptr, &first_line_ins, len); + + /* 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; num_lines++; @@ -226,15 +223,14 @@ void read_file(FILE *f, const char *filename, int quiet) i = 1; #endif } else { - - /* Calculate the total length of the line; it might have - nulls in it, so we can't just use strlen(). */ + /* Calculate the total length of the line. It might have + * nulls in it, so we can't just use strlen() here. */ len++; /* Now we allocate a bigger buffer 128 characters at a time. - If we allocate a lot of space for one line, we may indeed - have to use a buffer this big later on, so we don't - decrease it at all. We do free it at the end, though. */ + * If 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 += 128; buf = charealloc(buf, bufx); @@ -246,54 +242,43 @@ void read_file(FILE *f, const char *filename, int quiet) totsize++; } - /* This conditional duplicates previous read_byte() behavior; - perhaps this could use some better handling. */ + /* This conditional duplicates previous read_byte() behavior. + * Perhaps this could use some better handling. */ if (ferror(f)) nperror(filename); fclose(f); - /* Did we not get a newline but still have stuff to do? */ - if (len > 0) { -#ifndef NANO_SMALL - /* If file conversion isn't disabled, the last character in - this file is a CR and fileformat isn't set yet, make sure - it's set to Mac format */ - if (!ISSET(NO_CONVERT) && buf[len - 1] == '\r' && fileformat == 0) - fileformat = 2; -#endif - - /* read in the LAST line properly */ - fileptr = read_line(buf, fileptr, &line1ins, len); - - num_lines++; - totsize++; - buf[0] = '\0'; - } #ifndef NANO_SMALL - else if (!ISSET(NO_CONVERT) && input == '\r') { - /* If file conversion isn't disabled and the last character in - this file is a CR, read it in properly as a (Mac format) - line */ + /* If file conversion isn't disabled and the last character in this + * file is a CR, read it in properly as a Mac format line. */ + if (len == 0 && !ISSET(NO_CONVERT) && input == '\r') { buf[0] = input; buf[1] = '\0'; len = 1; - fileptr = read_line(buf, fileptr, &line1ins, len); - num_lines++; - totsize++; - buf[0] = '\0'; } #endif - free(buf); - + /* Did we not get a newline and still have stuff to do? */ + if (len > 0) { #ifndef NANO_SMALL - /* If NO_CONVERT wasn't set before we read the file, but it is now, - unset it again. */ - if (!old_no_convert && ISSET(NO_CONVERT)) - UNSET(NO_CONVERT); + /* If file conversion isn't disabled and the last character in + * this file is a CR, set fileformat 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' && + (fileformat == 0 || fileformat == 1)) + fileformat += 2; #endif - /* Did we even GET a file if we don't already have one? */ + /* Read in the last line properly. */ + fileptr = read_line(buf, fileptr, &first_line_ins, len); + num_lines++; + totsize++; + } + free(buf); + + /* If we didn't get a file and we don't already have one, make a new + * file. */ if (totsize == 0 || fileptr == NULL) new_file(); @@ -309,93 +294,77 @@ void read_file(FILE *f, const char *filename, int quiet) filebot = fileptr; new_magicline(); totsize--; - load_file(quiet); } } #ifndef NANO_SMALL - if (fileformat == 2) - statusbar(P_("Read %d line (Converted from Mac format)", - "Read %d lines (Converted from Mac format)", - num_lines), num_lines); + if (fileformat == 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 (fileformat == 2) + 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 (fileformat == 1) - statusbar(P_("Read %d line (Converted from DOS format)", - "Read %d lines (Converted from DOS format)", - num_lines), num_lines); + 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 - statusbar(P_("Read %d line", "Read %d lines", num_lines), - num_lines); - -#ifndef NANO_SMALL - /* Set fileformat back to 0, now that we've read the file in and - possibly converted it from DOS/Mac format. */ - fileformat = 0; -#endif + statusbar(P_("Read %lu line", "Read %lu lines", + (unsigned long) num_lines),(unsigned long)num_lines); totlines += num_lines; - - return; } -/* Open the file (and decide if it exists). Return TRUE on success, - * FALSE on failure. */ -bool open_file(const char *filename, int insert, int quiet) +/* 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; - FILE *f; struct stat fileinfo; - if (filename[0] == '\0' || stat(filename, &fileinfo) == -1) { - if (insert && !quiet) { - statusbar(_("\"%s\" not found"), filename); - return FALSE; - } else { - /* We have a new file */ + assert(f != NULL); + if (filename == NULL || filename[0] == '\0' || + stat(filename, &fileinfo) == -1) { + if (newfie) { statusbar(_("New File")); - 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); - if (!insert) - new_file(); - return FALSE; + return -1; } else if ((fd = open(filename, O_RDONLY)) == -1) { - /* If we're in multibuffer mode, don't be quiet when an error - occurs while opening a file */ - if (!quiet -#ifdef ENABLE_MULTIBUFFER - || ISSET(MULTIBUFFER) -#endif - ) - statusbar("Error reading %s: %s", filename, strerror(errno)); - if (!insert) - new_file(); - return FALSE; - } else { /* File is A-OK */ - if (!quiet) - statusbar(_("Reading File")); - f = fdopen(fd, "rb"); /* Binary for our own line-end munging */ - if (f == NULL) { - nperror("fdopen"); + statusbar(_("Error reading %s: %s"), filename, strerror(errno)); + return -1; + } else { + /* File is A-OK. */ + *f = fdopen(fd, "rb"); /* Binary for our own line-end munging */ + + if (*f == NULL) { + statusbar(_("Error reading %s: %s"), filename, strerror(errno)); close(fd); - return FALSE; - } - read_file(f, filename, quiet); -#ifndef NANO_SMALL - stat(filename, &originalfilestat); -#endif + } else + statusbar(_("Reading File")); } - - return TRUE; + return 0; } /* This function will return the name of the first available extension - * of a filename (starting with the filename.save, then filename.save.1, - * etc). Memory is allocated for the return value. If no writable + * of a filename (starting with filename.save, then filename.save.1, + * etc.). Memory is allocated for the return value. If no writable * extension exists, we return "". */ char *get_next_filename(const char *name) { @@ -421,77 +390,125 @@ char *get_next_filename(const char *name) } /* We get here only if there is no possible save file. */ - buf[0] = '\0'; - + null_at(&buf, 0); return buf; } -void do_insertfile(int loading_file) +#ifndef NANO_SMALL +void execute_command(const char *command) { - int i, old_current_x = current_x; - bool opened; - /* TRUE if the file opened successfully. */ - char *realname = NULL; - static char *inspath = NULL; - - if (inspath == NULL) { - inspath = charalloc(1); - inspath[0] = '\0'; +#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 */ +} +#endif /* !NANO_SMALL */ -#ifndef DISABLE_WRAPPING - wrap_reset(); +/* 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) +{ + bool new_buffer = fileage == NULL +#ifdef ENABLE_MULTIBUFFER + || ISSET(MULTIBUFFER) #endif + ; + /* new_buffer says whether we load to 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. */ -#ifndef NANO_SMALL - start_again: +#ifndef DISABLE_OPERATINGDIR + if (check_operating_dir(name, FALSE)) { + statusbar(_("Can't insert file from outside of %s"), operating_dir); + return; + } #endif -#if !defined(DISABLE_BROWSER) || !defined(DISABLE_MOUSE) - currshortcut = insertfile_list; +#ifdef ENABLE_MULTIBUFFER + /* Update the current entry in the open_files structure. */ + add_open_file(TRUE); #endif -#ifndef DISABLE_OPERATINGDIR - if (operating_dir != NULL && strcmp(operating_dir, ".") != 0) -#ifdef ENABLE_MULTIBUFFER - if (ISSET(MULTIBUFFER)) - i = statusq(TRUE, insertfile_list, inspath, + rc = open_file(name, new_buffer, &f); + +#ifdef ENABLE_MULTIBUFFER + if (rc != -1 && ISSET(MULTIBUFFER)) { + UNSET(MODIFIED); #ifndef NANO_SMALL - NULL, + UNSET(MARK_ISSET); #endif - _("File to insert into new buffer [from %s] "), - operating_dir); - else + } #endif - i = statusq(TRUE, insertfile_list, inspath, + + if (rc != -1 && new_buffer) { + filename = mallocstrcpy(filename, name); + new_file(); + } + + if (rc == 0) { + read_file(f, filename); #ifndef NANO_SMALL - NULL, + stat(filename, &originalfilestat); #endif - _("File to insert [from %s] "), - operating_dir); + } + + /* 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) +{ + int i; + const char *msg; + char *inspath = mallocstrcpy(NULL, ""); + /* The last answer the user typed on the statusbar. Saved for if + * they do M-F or cancel the file browser. */ + + wrap_reset(); + +#if !defined(DISABLE_BROWSER) || (!defined(NANO_SMALL) && defined(ENABLE_MULTIBUFFER)) + start_again: /* Go here when the user cancels the file browser. */ +#endif + +#ifdef ENABLE_MULTIBUFFER + if (ISSET(MULTIBUFFER)) + msg = N_("File to insert into new buffer [from %s] "); else #endif -#ifdef ENABLE_MULTIBUFFER - if (ISSET(MULTIBUFFER)) - i = statusq(TRUE, insertfile_list, inspath, + msg = N_("File to insert [from %s] "); + i = statusq(TRUE, insertfile_list, inspath, #ifndef NANO_SMALL NULL, #endif - _("File to insert into new buffer [from ./] ")); - else -#endif /* ENABLE_MULTIBUFFER */ - i = statusq(TRUE, insertfile_list, inspath, -#ifndef NANO_SMALL - NULL, + _(msg), +#ifndef DISABLE_OPERATINGDIR + operating_dir != NULL && strcmp(operating_dir, ".") != 0 ? + operating_dir : #endif - _("File to insert [from ./] ")); + "./"); if (i != -1) { + int old_current_x = current_x; + inspath = mallocstrcpy(inspath, answer); -#ifdef DEBUG - fprintf(stderr, "filename is %s\n", answer); -#endif #ifndef NANO_SMALL #ifdef ENABLE_MULTIBUFFER @@ -499,11 +516,9 @@ void do_insertfile(int loading_file) /* Don't allow toggling if we're in view mode. */ if (!ISSET(VIEW_MODE)) TOGGLE(MULTIBUFFER); - loading_file = ISSET(MULTIBUFFER); goto start_again; } #endif /* ENABLE_MULTIBUFFER */ - if (i == NANO_EXTCMD_KEY) { char *ans = mallocstrcpy(NULL, answer); int ts = statusq(TRUE, extcmd_list, ans, NULL, @@ -511,137 +526,67 @@ void do_insertfile(int loading_file) free(ans); - if (ts == -1 || answer == NULL || answer[0] == '\0') { - statusbar(_("Cancelled")); - display_main_list(); - return; - } + if (ts == -1 || answer == NULL || answer[0] == '\0') + goto start_again; } #endif /* !NANO_SMALL */ #ifndef DISABLE_BROWSER if (i == NANO_TOFILES_KEY) { char *tmp = do_browse_from(answer); - if (tmp != NULL) { - free(answer); - answer = tmp; - resetstatuspos = 1; - } else + if (tmp == NULL) goto start_again; - } -#endif - -#ifndef DISABLE_OPERATINGDIR - if ( -#ifndef NANO_SMALL - i != NANO_EXTCMD_KEY && -#endif - check_operating_dir(answer, FALSE) != 0) { - statusbar(_("Can't insert file from outside of %s"), - operating_dir); - return; - } -#endif - -#ifdef ENABLE_MULTIBUFFER - if (loading_file) { - /* update the current entry in the open_files structure */ - add_open_file(TRUE); - new_file(); - UNSET(MODIFIED); -#ifndef NANO_SMALL - UNSET(MARK_ISSET); -#endif + resetstatuspos = TRUE; + free(answer); + answer = tmp; } #endif #ifndef NANO_SMALL - if (i == NANO_EXTCMD_KEY) { - realname = mallocstrcpy(realname, ""); - opened = open_pipe(answer); - } else { + if (i == NANO_EXTCMD_KEY) + execute_command(answer); + else { #endif - realname = real_dir_from_tilde(answer); - opened = open_file(realname, TRUE, loading_file); + answer = mallocstrassn(answer, real_dir_from_tilde(answer)); + load_buffer(answer); #ifndef NANO_SMALL } #endif #ifdef ENABLE_MULTIBUFFER - if (loading_file) { - /* if there was an error opening the file, free() realname, - free() fileage (which now points to the new buffer we - created to hold the file), reload the buffer we had open - before, and skip the insertion; otherwise, save realname - in filename and continue the insertion */ - if (!opened) { - free(realname); - free(fileage); - load_open_file(); - goto skip_insert; - } else - filename = mallocstrcpy(filename, realname); - } -#endif - - free(realname); - -#ifdef DEBUG - dump_buffer(fileage); -#endif + if (ISSET(MULTIBUFFER)) { + /* Update the titlebar. */ + titlebar(NULL); -#ifdef ENABLE_MULTIBUFFER - if (loading_file) - load_file(FALSE); - else + /* Reinitialize the shortcut list. */ + shortcut_init(FALSE); + } else { #endif + /* Mark the file as modified. */ set_modified(); + /* Restore the old x-coordinate position. */ + current_x = old_current_x; #ifdef ENABLE_MULTIBUFFER - /* If we've loaded another file, update the titlebar's contents */ - if (loading_file) { - clearok(topwin, FALSE); - titlebar(NULL); - - /* And re-init the shortcut list */ - shortcut_init(FALSE); - } else + } #endif - /* Restore the old x-coordinate position */ - current_x = old_current_x; /* If we've gone off the bottom, recenter; otherwise, just redraw */ edit_refresh(); - - } else { + } else statusbar(_("Cancelled")); - i = 0; - } - -#ifdef ENABLE_MULTIBUFFER - skip_insert: -#endif free(inspath); - inspath = NULL; - - display_main_list(); } void do_insertfile_void(void) { #ifdef ENABLE_MULTIBUFFER - if (ISSET(VIEW_MODE)) { - if (ISSET(MULTIBUFFER)) - do_insertfile(TRUE); - else - statusbar(_("Key illegal in non-multibuffer mode")); - } + if (ISSET(VIEW_MODE) && !ISSET(MULTIBUFFER)) + statusbar(_("Key illegal in non-multibuffer mode")); else - do_insertfile(ISSET(MULTIBUFFER)); -#else - do_insertfile(FALSE); #endif + do_insertfile(); display_main_list(); } @@ -1008,7 +953,7 @@ int close_open_file(void) display_main_list(); return 0; } -#endif /* MULTIBUFFER */ +#endif /* ENABLE_MULTIBUFFER */ #if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR) || !defined(NANO_SMALL) /* diff --git a/src/global.c b/src/global.c index c0683b3c..cea5d228 100644 --- a/src/global.c +++ b/src/global.c @@ -367,7 +367,8 @@ void shortcut_init(int unjustify) ); #ifdef ENABLE_MULTIBUFFER - if (open_files != NULL && (open_files->prev != NULL || open_files->next != NULL)) + if (open_files != NULL && (open_files->prev != NULL || + open_files->next != NULL)) /* Translators: try to keep this string under 10 characters long */ sc_init_one(&main_list, NANO_EXIT_KEY, N_("Close"), IFHELP(nano_exit_msg, NANO_NO_KEY), NANO_EXIT_FKEY, diff --git a/src/nano.c b/src/nano.c index f458a37b..eb6011f0 100644 --- a/src/nano.c +++ b/src/nano.c @@ -179,7 +179,7 @@ void die_save_file(const char *die_filename) if (!failed) fprintf(stderr, _("\nBuffer written to %s\n"), ret); else - fprintf(stderr, _("\nNo %s written (too many backup files?)\n"), ret); + fprintf(stderr, _("\nBuffer not written to %s (too many backup files?)\n"), ret); free(ret); } @@ -856,7 +856,7 @@ bool open_pipe(const char *command) if (f == NULL) nperror("fdopen"); - read_file(f, "stdin", FALSE); + read_file(f, "stdin"); /* If multibuffer mode is on, we could be here in view mode. If so, * don't set the modification flag. */ if (!ISSET(VIEW_MODE)) @@ -1406,7 +1406,7 @@ bool do_int_spell_fix(const char *word) bool reverse_search_set = ISSET(REVERSE_SEARCH); #ifndef NANO_SMALL bool case_sens_set = ISSET(CASE_SENSITIVE); - bool mark_set = ISSET(MARK_ISSET); + bool old_mark_set = ISSET(MARK_ISSET); SET(CASE_SENSITIVE); /* Make sure the marking highlight is off during spell-check. */ @@ -1475,7 +1475,7 @@ bool do_int_spell_fix(const char *word) UNSET(CASE_SENSITIVE); /* Restore marking highlight. */ - if (mark_set) + if (old_mark_set) SET(MARK_ISSET); #endif @@ -1678,16 +1678,17 @@ const char *do_alt_speller(char *tempfile_name) pid_t pid_spell; char *ptr; static int arglen = 3; - static char **spellargs = (char **)NULL; + static char **spellargs = NULL; + FILE *f; #ifndef NANO_SMALL - bool mark_set = ISSET(MARK_ISSET); + bool old_mark_set = ISSET(MARK_ISSET); int mbb_lineno_cur = 0; /* We're going to close the current file, and open the output of * the alternate spell command. The line that mark_beginbuf * points to will be freed, so we save the line number and * restore afterwards. */ - if (mark_set) { + if (old_mark_set) { mbb_lineno_cur = mark_beginbuf->lineno; UNSET(MARK_ISSET); } @@ -1738,7 +1739,7 @@ const char *do_alt_speller(char *tempfile_name) refresh(); #ifndef NANO_SMALL - if (mark_set) { + if (old_mark_set) { do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0); mark_beginbuf = current; /* In case the line got shorter, assign mark_beginx. */ @@ -1750,7 +1751,13 @@ const char *do_alt_speller(char *tempfile_name) free_filestruct(fileage); terminal_init(); global_init(TRUE); - open_file(tempfile_name, FALSE, TRUE); + + /* Do what load_buffer() would do, except for making a new + * buffer for the temp file if multibuffer support is + * available. */ + open_file(tempfile_name, FALSE, &f); + read_file(f, tempfile_name); + current = fileage; #ifndef NANO_SMALL } #endif @@ -2564,6 +2571,7 @@ void do_justify(bool full_justify) edit_refresh(); statusbar(_("Can now UnJustify!")); + /* Display the shortcut list with UnJustify. */ shortcut_init(TRUE); display_main_list(); @@ -2618,6 +2626,7 @@ void do_justify(bool full_justify) cutbuffer = cutbuffer_save; /* Note that now cutbottom is invalid, but that's okay. */ blank_statusbar(); + /* Display the shortcut list with UnCut. */ shortcut_init(FALSE); display_main_list(); @@ -2940,11 +2949,19 @@ void terminal_init(void) int main(int argc, char **argv) { int optchr; - int startline = 0; /* Line to try and start at */ + int startline = 0; + /* Line to try and start at. */ #ifndef DISABLE_WRAPJUSTIFY - bool fill_flag_used = FALSE; /* Was the fill option used? */ + bool fill_flag_used = FALSE; + /* Was the fill option used? */ #endif - int kbinput; /* Input from keyboard */ +#ifdef ENABLE_MULTIBUFFER + bool old_multibuffer; + /* The old value of the multibuffer option, restored after we + * load all files on the command line. */ +#endif + int kbinput; + /* Input from keyboard. */ bool meta_key; #ifdef HAVE_GETOPT_LONG const struct option long_options[] = { @@ -3015,8 +3032,8 @@ int main(int argc, char **argv) #endif #if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING) - /* if we don't have rcfile support, we're root, and - --disable-wrapping-as-root is used, turn wrapping off */ + /* If we don't have rcfile support, we're root, and + * --disable-wrapping-as-root is used, turn wrapping off. */ if (geteuid() == NANO_ROOT_UID) SET(NO_WRAP); #endif @@ -3190,8 +3207,8 @@ int main(int argc, char **argv) } /* We've read through the command line options. Now back up the flags - and values that are set, and read the rcfile(s). If the values - haven't changed afterward, restore the backed-up values. */ + * and values that are set, and read the rcfile(s). If the values + * haven't changed afterward, restore the backed-up values. */ #ifdef ENABLE_NANORC if (!ISSET(NO_RCFILE)) { #ifndef DISABLE_OPERATINGDIR @@ -3336,43 +3353,26 @@ int main(int argc, char **argv) #endif #if !defined(NANO_SMALL) && defined(ENABLE_NANORC) + /* If whitespace wasn't specified, set its default value. */ if (whitespace == NULL) whitespace = mallocstrcpy(NULL, " "); #endif + /* If tabsize wasn't specified, set its default value. */ if (tabsize == -1) - tabsize = 8; - - /* Clear the filename we'll be using */ - filename = charalloc(1); - filename[0] = '\0'; + tabsize = WIDTH_OF_TAB; /* If there's a +LINE flag, it is the first non-option argument. */ if (0 < optind && optind < argc && argv[optind][0] == '+') { startline = atoi(&argv[optind][1]); optind++; } - if (0 < optind && optind < argc) - filename = mallocstrcpy(filename, argv[optind]); - - /* See if there's a non-option in argv (first non-option is the - filename, if +LINE is not given) */ - if (argc > 1 && argc > optind) { - /* Look for the +line flag... */ - if (argv[optind][0] == '+') { - startline = atoi(&argv[optind][1]); - optind++; - if (argc > optind) - filename = mallocstrcpy(filename, argv[optind]); - } else - filename = mallocstrcpy(filename, argv[optind]); - } /* Back up the old terminal settings so that they can be restored. */ tcgetattr(0, &oldterm); - /* Curses initialization stuff: Start curses and set up the - * terminal state. */ + /* Curses initialization stuff: Start curses and set up the + * terminal state. */ initscr(); terminal_init(); @@ -3392,44 +3392,55 @@ int main(int argc, char **argv) mouse_init(); #endif -#ifdef DEBUG - fprintf(stderr, "Main: top and bottom win\n"); -#endif - titlebar(NULL); - display_main_list(); - #ifdef DEBUG fprintf(stderr, "Main: open file\n"); #endif - open_file(filename, FALSE, FALSE); + #ifdef ENABLE_MULTIBUFFER - /* If we're using multibuffers and more than one file is specified - on the command line, load them all and switch to the first one - afterward. */ - if (optind + 1 < argc) { - bool old_multibuffer = ISSET(MULTIBUFFER), list = FALSE; - SET(MULTIBUFFER); - for (optind++; optind < argc; optind++) { - add_open_file(TRUE); - new_file(); - filename = mallocstrcpy(filename, argv[optind]); - titlebar(NULL); - open_file(filename, FALSE, FALSE); - load_file(FALSE); - /* Display the main list with "Close" if we haven't - * already. */ - if (!list) { - shortcut_init(FALSE); - list = TRUE; - display_main_list(); - } - } - open_nextfile_void(); - if (!old_multibuffer) - UNSET(MULTIBUFFER); + old_multibuffer = ISSET(MULTIBUFFER); + SET(MULTIBUFFER); + + /* Read all the files after the first one on the command line into + * new buffers. */ + { + int i; + for (i = optind + 1; i < argc; i++) + load_buffer(argv[i]); + } +#endif + + /* Read the first file on the command line into either the current + * buffer or a new buffer, depending on whether multibuffer mode is + * enabled. */ + if (optind < argc) + load_buffer(argv[optind]); + + /* We didn't open any files if all the command line arguments were + * invalid files like directories or if there were no command line + * arguments given. In this case, we have to load a blank buffer. + * Also, we unset view mode to allow editing. */ + if (filename == NULL) { + filename = mallocstrcpy(NULL, ""); + new_file(); + UNSET(VIEW_MODE); + + /* Add this new entry to the open_files structure if we have + * multibuffer support, or to the main filestruct if we don't. */ + load_file(); } + +#ifdef ENABLE_MULTIBUFFER + if (!old_multibuffer) + UNSET(MULTIBUFFER); #endif +#ifdef DEBUG + fprintf(stderr, "Main: top and bottom win\n"); +#endif + + titlebar(NULL); + display_main_list(); + if (startline > 0) do_gotoline(startline, FALSE); diff --git a/src/nano.h b/src/nano.h index b145022f..cf96f2fc 100644 --- a/src/nano.h +++ b/src/nano.h @@ -491,6 +491,9 @@ typedef enum { * occurs. */ #define CHARS_FROM_EOL 8 +/* Default width of a tab. */ +#define WIDTH_OF_TAB 8 + /* Maximum number of search history strings saved, same value used for * replace history. */ #define MAX_SEARCH_HISTORY 100 diff --git a/src/proto.h b/src/proto.h index 5a6c5c0b..ab91b640 100644 --- a/src/proto.h +++ b/src/proto.h @@ -164,14 +164,18 @@ void do_cut_text(void); void do_uncut_text(void); /* Public functions in files.c */ -void load_file(int update); void new_file(void); -filestruct *read_line(char *buf, filestruct *prev, int *line1ins, size_t - len); -void read_file(FILE *f, const char *filename, int quiet); -bool open_file(const char *filename, int insert, int quiet); +filestruct *read_line(char *buf, filestruct *prev, bool *first_line_ins, + size_t len); +void load_file(void); +void read_file(FILE *f, const char *filename); +int open_file(const char *filename, bool newfie, FILE **f); char *get_next_filename(const char *name); -void do_insertfile(int loading_file); +#ifndef NANO_SMALL +void execute_command(const char *command); +#endif +void load_buffer(const char *name); +void do_insertfile(void); void do_insertfile_void(void); #ifdef ENABLE_MULTIBUFFER openfilestruct *make_new_opennode(openfilestruct *prevnode); @@ -411,7 +415,7 @@ int do_replace_loop(const char *needle, const filestruct *real_current, void do_replace(void); void do_gotoline(int line, bool save_pos); void do_gotoline_void(void); -#if defined (ENABLE_MULTIBUFFER) || !defined (DISABLE_SPELLER) +#if defined(ENABLE_MULTIBUFFER) || !defined(DISABLE_SPELLER) void do_gotopos(int line, int pos_x, int pos_y, size_t pos_pww); #endif void do_find_bracket(void); @@ -479,6 +483,7 @@ void nperror(const char *s); void *nmalloc(size_t howmuch); void *nrealloc(void *ptr, size_t howmuch); char *mallocstrcpy(char *dest, const char *src); +char *mallocstrassn(char *dest, char *src); void new_magicline(void); #ifndef NANO_SMALL void mark_order(const filestruct **top, size_t *top_x, const filestruct diff --git a/src/rcfile.c b/src/rcfile.c index 1f5d2adb..c07162d4 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -619,13 +619,13 @@ void parse_rcfile(FILE *rcstream) } else SET(rcopts[i].flag); #ifdef DEBUG - fprintf(stderr, "set flag %d!\n", + fprintf(stderr, "set flag %ld!\n", rcopts[i].flag); #endif } else { UNSET(rcopts[i].flag); #ifdef DEBUG - fprintf(stderr, "unset flag %d!\n", + fprintf(stderr, "unset flag %ld!\n", rcopts[i].flag); #endif } diff --git a/src/search.c b/src/search.c index a3b7d69f..4b519b25 100644 --- a/src/search.c +++ b/src/search.c @@ -616,7 +616,7 @@ int do_replace_loop(const char *needle, const filestruct *real_current, bool begin_line = FALSE, bol_or_eol = FALSE; #endif #ifndef NANO_SMALL - bool old_mark_isset = ISSET(MARK_ISSET); + bool old_mark_set = ISSET(MARK_ISSET); UNSET(MARK_ISSET); edit_refresh(); @@ -758,7 +758,7 @@ int do_replace_loop(const char *needle, const filestruct *real_current, new_magicline(); #ifndef NANO_SMALL - if (old_mark_isset) + if (old_mark_set) SET(MARK_ISSET); #endif diff --git a/src/utils.c b/src/utils.c index 4d928b56..d3d8e32c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -396,7 +396,7 @@ void *nrealloc(void *ptr, size_t howmuch) } /* Copy one malloc()ed string to another pointer. Should be used as: - * dest = mallocstrcpy(dest, src); */ + * "dest = mallocstrcpy(dest, src);". */ char *mallocstrcpy(char *dest, const char *src) { if (src == NULL) @@ -411,7 +411,16 @@ char *mallocstrcpy(char *dest, const char *src) return dest; } -/* Append a new magic-line to filebot. */ +/* Free the malloc()ed string at dest and return the malloc()ed string + * at src. Should be used as: "answer = mallocstrassn(answer, + * real_dir_from_tilde(answer));". */ +char *mallocstrassn(char *dest, char *src) +{ + free(dest); + return src; +} + +/* Append a new magicline to filebot. */ void new_magicline(void) { filebot->next = (filestruct *)nmalloc(sizeof(filestruct)); diff --git a/src/winio.c b/src/winio.c index a6ec5ad7..758a07ef 100644 --- a/src/winio.c +++ b/src/winio.c @@ -2385,13 +2385,15 @@ size_t get_page_start(size_t column) } /* Resets current_y, based on the position of current, and puts the - * cursor at (current_y, current_x). */ + * cursor in the edit window at (current_y, current_x). */ void reset_cursor(void) { - /* Yuck. This condition can be true after open_file() when opening - * the first file. */ - if (edittop == NULL) + /* If we haven't opened any files yet, put the cursor in the top + * left corner of the edit window and get out. */ + if (edittop == NULL || current == NULL) { + wmove(edit, 0, 0); return; + } current_y = current->lineno - edittop->lineno; if (current_y < editwinrows) { @@ -2884,14 +2886,6 @@ void edit_redraw(const filestruct *old_current, size_t old_pww) /* Refresh the screen without changing the position of lines. */ void edit_refresh(void) { - /* Neither of these conditions should occur, but they do. edittop - * is NULL when you open an existing file on the command line, and - * ENABLE_COLOR is defined. Yuck. */ - if (current == NULL) - return; - if (edittop == NULL) - edittop = current; - if (current->lineno < edittop->lineno || current->lineno >= edittop->lineno + editwinrows) /* Note that edit_update() changes edittop so that it's in range @@ -2932,10 +2926,6 @@ void edit_update(topmidnone location) { filestruct *foo = current; - /* We shouldn't need this check. Yuck. */ - if (current == NULL) - return; - if (location != TOP) { /* If location is CENTER, we move edittop up (editwinrows / 2) * lines. This puts current at the center of the screen. If -- 2.39.5