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) { - int num_lines = 0, len = 0; - char input = '\0'; /* current input character */ - char *buf; - long i = 0, bufx = 128; - filestruct *fileptr = current, *tmp = NULL; -#ifndef NANO_SMALL - int old_no_convert = ISSET(NO_CONVERT); + 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 - int line1ins = 0; +} + +void read_file(FILE *f, const char *filename) +{ + 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; + /* 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 fileformat = 0; + /* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */ +#endif 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 - /* reset the line length, in preparation for the next line */ + /* Read in the line properly. */ + fileptr = read_line(buf, fileptr, &first_line_ins, len); + + /* 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"); - close(fd); - return FALSE; - } - read_file(f, filename, quiet); -#ifndef NANO_SMALL - stat(filename, &originalfilestat); -#endif - } + 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 */ - return TRUE; + if (*f == NULL) { + statusbar(_("Error reading %s: %s"), filename, strerror(errno)); + close(fd); + } else + statusbar(_("Reading File")); + } + 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) -{ - 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'; - } - -#ifndef DISABLE_WRAPPING - wrap_reset(); -#endif - #ifndef NANO_SMALL - start_again: -#endif +void execute_command(const char *command) +{ +#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 */ -#if !defined(DISABLE_BROWSER) || !defined(DISABLE_MOUSE) - currshortcut = insertfile_list; +/* 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 DISABLE_OPERATINGDIR - if (operating_dir != NULL && strcmp(operating_dir, ".") != 0) -#ifdef ENABLE_MULTIBUFFER - if (ISSET(MULTIBUFFER)) - i = statusq(TRUE, insertfile_list, inspath, -#ifndef NANO_SMALL - NULL, + if (check_operating_dir(name, FALSE)) { + statusbar(_("Can't insert file from outside of %s"), operating_dir); + return; + } #endif - _("File to insert into new buffer [from %s] "), - operating_dir); - else -#endif - i = statusq(TRUE, insertfile_list, inspath, -#ifndef NANO_SMALL - NULL, -#endif - _("File to insert [from %s] "), - operating_dir); +#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 + UNSET(MARK_ISSET); +#endif + } +#endif + + if (rc != -1 && new_buffer) { + filename = mallocstrcpy(filename, name); + new_file(); + } + + if (rc == 0) { + read_file(f, filename); +#ifndef NANO_SMALL + stat(filename, &originalfilestat); +#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) +{ + 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 - -#ifdef ENABLE_MULTIBUFFER - if (loading_file) - load_file(FALSE); - else -#endif - set_modified(); - -#ifdef ENABLE_MULTIBUFFER - /* If we've loaded another file, update the titlebar's contents */ - if (loading_file) { - clearok(topwin, FALSE); + if (ISSET(MULTIBUFFER)) { + /* Update the titlebar. */ titlebar(NULL); - /* And re-init the shortcut list */ + /* Reinitialize the shortcut list. */ shortcut_init(FALSE); - } else + } else { #endif - /* Restore the old x-coordinate position */ + /* Mark the file as modified. */ + set_modified(); + + /* Restore the old x-coordinate position. */ current_x = old_current_x; +#ifdef ENABLE_MULTIBUFFER + } +#endif /* 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