From ad40fdba593614b6fe92373c9e84c90698d27a30 Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Fri, 6 Sep 2002 20:35:28 +0000 Subject: [PATCH] DLR: prototype overhaul, etc. git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1270 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 32 + configure.ac | 113 +-- files.c | 119 +-- global.c | 34 +- move.c | 102 +- nano.c | 2657 +++++++++++++++++++++++++------------------------- nano.h | 1 + proto.h | 327 +++++-- rcfile.c | 36 +- search.c | 80 +- utils.c | 9 +- winio.c | 313 +++--- 12 files changed, 2001 insertions(+), 1822 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2bf8b218..029a69a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,13 +11,27 @@ CVS code - need to keep the translatable strings, and (b) added a variable inspath to keep track of what the string was before toggling. I'm sure there's bugs, have at it. + - Make sure all functions have prototypes in proto.h, and swap + some functions around to put similar functions closer + together (for this, rename clear_bottombars() to + blank_bottombars()). (DLR; suggested by David Benbennick) - configure.ac: - Added pt_BR to ALL_LINGUAS (Jordi). - Changed --enable-color warning to be slightly less severe. + - Put the configure options in more or less alphabetical order, + and remove --enable-undo, since it doesn't do anything. (DLR) - files.c: open_file() - String change: "File "x" is a directory" -> ""x" is a directory". (Jordi) + do_insertfile() + - Disallow multibuffer toggling at the "Insert File" prompt if + we're in both view and multibuffer mode, so as to keep proper + integration between the two, and make sure the toggle + actually works all the time otherwise. Also, use + NANO_LOAD_KEY as an alias for TOGGLE_LOAD_KEY, so + --enable-tiny and --enable-multibuffer can be used together + again. (DLR) open_prevfile_void(), open_nextfile_void() - Return the return values of open_prevfile() and open_nextfile(), respectively, instead of (incorrectly) @@ -29,6 +43,14 @@ CVS code - - Most likely fixed the check marked with FIXME, so that tab completion works properly when we're trying to tab-complete a username and the string already contains data. (DLR) +- global.c: + shortcut_init() + - Use NANO_LOAD_KEY as an alias for TOGGLE_LOAD_KEY, so + --enable-tiny and --enable-multibuffer can be used together + again. (DLR) + thanks_for_all_the_fish() + - Make sure the reference to help_text is #ifdefed out when + --disable-help is used. (DLR) - move.c: page_up() - Fix bug where current is moved up two lines when the up arrow @@ -42,6 +64,12 @@ CVS code - off, pressing the down arrow on that last line centers the cursor without updating the edit window. (Jeff DeFouw) - nano.c: + version() + - Put the listed configure options in more or less alphabetical + order. (DLR) + open_pipe() + - If we're in view mode here (in which case we're also in + multibuffer mode), don't set the modification flag. (DLR) do_next_word(), do_prev_word() - If we're on the last/first line of the file, don't center the screen; Pico doesn't in the former case. (DLR) @@ -65,6 +93,10 @@ CVS code - do_justify() - Fix cosmetic problems caused when justifying on the magicline. (David Benbennick) + main() + - When searching through the main shortcut list looking for a + shortcut key, stop searching after finding one; this avoids a + rare segfault. (DLR) - nano.h: - Change search toggles for case sensitive searching and regexp searching to M-C and M-R, respectively. (DLR; suggested by diff --git a/configure.ac b/configure.ac index 15186eee..3edbe57c 100644 --- a/configure.ac +++ b/configure.ac @@ -29,70 +29,55 @@ if test "$debug_support" != "yes"; then AC_DEFINE(NDEBUG, 1, [Shut up the assert warnings :-)]) fi +AC_ARG_ENABLE(extra, +[ --enable-extra Enable extra (optional) functions, including easter eggs], +[if test x$enableval = xyes; then + AC_DEFINE(NANO_EXTRA, 1, [Define this to enable the extra stuff.]) extra_support=yes + AC_DEFINE(ENABLE_MULTIBUFFER, 1, [Define this to enable multiple file buffers.]) multibuffer_support=yes + fi]) + AC_ARG_ENABLE(tiny, [ --enable-tiny Disable features for the sake of size (currently disables detailed help and i18n)], [if test x$enableval = xyes; then AC_DEFINE(NANO_SMALL, 1, [Define this to make the nano executable as small as possible.]) tiny_support=yes - AC_DEFINE(DISABLE_TABCOMP, 1, [Define to disable the tab completion code Chris worked so hard on!]) - AC_DEFINE(DISABLE_SPELLER, 1, [Define this to disable the use(full|less) spelling functions.]) + AC_DEFINE(DISABLE_BROWSER, 1, [Define this to disable the built-in (crappy) file browser.]) AC_DEFINE(DISABLE_HELP, 1, [Define this to disable the ^G help menu.]) AC_DEFINE(DISABLE_JUSTIFY, 1, [Define this to disable the justify routine.]) - AC_DEFINE(DISABLE_BROWSER, 1, [Define this to disable the built-in (crappy) file browser.]) AC_DEFINE(DISABLE_MOUSE, 1, [Define this to disable the mouse functions.]) AC_DEFINE(DISABLE_OPERATINGDIR, 1, [Define this to disable setting of the operating directory (chroot of sorts).]) + AC_DEFINE(DISABLE_SPELLER, 1, [Define this to disable the use(full|less) spelling functions.]) + AC_DEFINE(DISABLE_TABCOMP, 1, [Define to disable the tab completion code Chris worked so hard on!]) fi]) -AC_ARG_ENABLE(extra, -[ --enable-extra Enable extra (optional) functions, including easter eggs], -[if test x$enableval = xyes; then - AC_DEFINE(NANO_EXTRA, 1, [Define this to enable the extra stuff.]) extra_support=yes - AC_DEFINE(ENABLE_MULTIBUFFER, 1, [Define this to enable multiple file buffers.]) multibuffer_support=yes - AC_DEFINE(ENABLE_UNDO, 1, [Define this to enable undoing... something]) undo_support=yes - fi]) - -AC_ARG_ENABLE(undo, -[ --enable-undo Enable undo support], -[if test x$enableval = xyes && test x$tiny_support != xyes; then - AC_DEFINE(ENABLE_UNDO, 1, [Define this to enable undoing... something.]) undo_support=yes +AC_ARG_ENABLE(browser, +[ --disable-browser Disable mini file browser], + [if test x$enableval != xyes; then + AC_DEFINE(DISABLE_BROWSER, 1, [Define this to disable the built-in (crappy) file browser.]) fi]) -AC_ARG_ENABLE(multibuffer, -[ --enable-multibuffer Enable multiple file buffers], -[if test x$enableval = xyes; then - AC_DEFINE(ENABLE_MULTIBUFFER, 1, [Define this to enable multiple file buffers.]) multibuffer_support=yes +AC_ARG_ENABLE(help, +[ --disable-help Disable help function (^G)], + [if test x$enableval != xyes; then + AC_DEFINE(DISABLE_HELP, 1, [Define this to disable the ^G help menu.]) fi]) -AC_ARG_ENABLE(nanorc, -[ --enable-nanorc Enable use of .nanorc file], -[if test x$enableval = xyes; then - AC_DEFINE(ENABLE_NANORC, 1, [Define this to use the .nanorc file.]) nanorc_support=yes +AC_ARG_ENABLE(justify, +[ --disable-justify Disable justify/unjustify function], + [if test x$enableval != xyes; then + AC_DEFINE(DISABLE_JUSTIFY, 1, [Define this to disable the justify routine.]) fi]) -AC_ARG_ENABLE(color, -[ --enable-color Enable color and syntax highlighting], -[if test x$enableval = xyes; then - AC_DEFINE(ENABLE_NANORC, 1, [Define this to use the .nanorc file.]) nanorc_support=yes - AC_DEFINE(ENABLE_COLOR, 1, [Define this to have syntax highlighting, requires ENABLE_NANORC too!]) color_support=yes - AC_MSG_WARN([ - -*********************************************************************** -*** WARNING: Color support is far from perfect, but functional. *** -*** Be careful with syntax in your .nanorc or nano may malfunction. *** -*********************************************************************** -]) -fi]) - -AC_ARG_ENABLE(tabcomp, -[ --disable-tabcomp Disable tab completion code for a smaller binary], +AC_ARG_ENABLE(mouse, +[ --disable-mouse Disable mouse support (and -m flag)], [if test x$enableval != xyes; then - AC_DEFINE(DISABLE_TABCOMP, 1, [Define to disable the tab completion code Chris worked so hard on!]) + AC_DEFINE(DISABLE_MOUSE, 1, [Define this to disable the mouse functions.]) fi]) -AC_ARG_ENABLE(justify, -[ --disable-justify Disable justify/unjustify function], +AC_ARG_ENABLE(operatingdir, +[ --disable-operatingdir Disable setting of operating directory (chroot of sorts)], [if test x$enableval != xyes; then - AC_DEFINE(DISABLE_JUSTIFY, 1, [Define this to disable the justify routine.]) + AC_DEFINE(DISABLE_OPERATINGDIR, 1, [Define this to disable setting of the operating directory (chroot of sorts).]) fi]) AC_ARG_ENABLE(speller, @@ -101,16 +86,10 @@ AC_ARG_ENABLE(speller, AC_DEFINE(DISABLE_SPELLER, 1, [Define this to disable the use(full|less) spelling functions.]) fi]) -AC_ARG_ENABLE(help, -[ --disable-help Disable help function (^G)], - [if test x$enableval != xyes; then - AC_DEFINE(DISABLE_HELP, 1, [Define this to disable the ^G help menu.]) - fi]) - -AC_ARG_ENABLE(browser, -[ --disable-browser Disable mini file browser], +AC_ARG_ENABLE(tabcomp, +[ --disable-tabcomp Disable tab completion code for a smaller binary], [if test x$enableval != xyes; then - AC_DEFINE(DISABLE_BROWSER, 1, [Define this to disable the built-in (crappy) file browser.]) + AC_DEFINE(DISABLE_TABCOMP, 1, [Define to disable the tab completion code Chris worked so hard on!]) fi]) AC_ARG_ENABLE(wrapping, @@ -119,16 +98,30 @@ AC_ARG_ENABLE(wrapping, AC_DEFINE(DISABLE_WRAPPING, 1, [Define this to disable any and all text wrapping.]) fi]) -AC_ARG_ENABLE(mouse, -[ --disable-mouse Disable mouse support (and -m flag)], - [if test x$enableval != xyes; then - AC_DEFINE(DISABLE_MOUSE, 1, [Define this to disable the mouse functions.]) +AC_ARG_ENABLE(color, +[ --enable-color Enable color and syntax highlighting], +[if test x$enableval = xyes; then + AC_DEFINE(ENABLE_NANORC, 1, [Define this to use the .nanorc file.]) nanorc_support=yes + AC_DEFINE(ENABLE_COLOR, 1, [Define this to have syntax highlighting, requires ENABLE_NANORC too!]) color_support=yes + AC_MSG_WARN([ + +*********************************************************************** +*** WARNING: Color support is far from perfect, but functional. *** +*** Be careful with syntax in your .nanorc or nano may malfunction. *** +*********************************************************************** +]) +fi]) + +AC_ARG_ENABLE(multibuffer, +[ --enable-multibuffer Enable multiple file buffers], +[if test x$enableval = xyes; then + AC_DEFINE(ENABLE_MULTIBUFFER, 1, [Define this to enable multiple file buffers.]) multibuffer_support=yes fi]) -AC_ARG_ENABLE(operatingdir, -[ --disable-operatingdir Disable setting of operating directory (chroot of sorts)], - [if test x$enableval != xyes; then - AC_DEFINE(DISABLE_OPERATINGDIR, 1, [Define this to disable setting of the operating directory (chroot of sorts).]) +AC_ARG_ENABLE(nanorc, +[ --enable-nanorc Enable use of .nanorc file], +[if test x$enableval = xyes; then + AC_DEFINE(ENABLE_NANORC, 1, [Define this to use the .nanorc file.]) nanorc_support=yes fi]) AC_MSG_CHECKING([whether to use slang]) diff --git a/files.c b/files.c index 46d48640..7dff3ba9 100644 --- a/files.c +++ b/files.c @@ -103,7 +103,6 @@ void new_file(void) #ifdef ENABLE_COLOR update_color(); #endif - } filestruct *read_line(char *buf, filestruct *prev, int *line1ins, int len) @@ -453,14 +452,11 @@ int do_insertfile(int loading_file) i = statusq(1, insertfile_list, inspath, _("File to insert [from ./] ")); if (i != -1) { - inspath = mallocstrcpy(inspath, answer); - #ifdef DEBUG fprintf(stderr, _("filename is %s\n"), answer); #endif - #ifndef DISABLE_TABCOMP realname = real_dir_from_tilde(answer); #else @@ -494,9 +490,12 @@ int do_insertfile(int loading_file) #endif #ifdef ENABLE_MULTIBUFFER - if (i == TOGGLE_LOAD_KEY) { - TOGGLE(MULTIBUFFER); - return do_insertfile(loading_file); + if (i == NANO_LOAD_KEY) { + /* don't allow toggling if we're in both view mode and + multibuffer mode now */ + if (!ISSET(VIEW_MODE) || !ISSET(MULTIBUFFER)) + TOGGLE(MULTIBUFFER); + return do_insertfile(ISSET(MULTIBUFFER)); } #endif #ifndef NANO_SMALL @@ -574,8 +573,6 @@ int do_insertfile(int loading_file) } #endif - - /* If we've gone off the bottom, recenter; otherwise, just redraw */ if (current->lineno > editbot->lineno) edit_update(current, CENTER); @@ -1139,8 +1136,8 @@ char *get_full_path(char *origpath) * get_full_path()). On error, if the path doesn't reference a * directory, or if the directory isn't writable, it returns NULL. */ -char *check_writable_directory(char *path) { - +char *check_writable_directory(char *path) +{ char *full_path = get_full_path(path); int writable; struct stat fileinfo; @@ -1178,8 +1175,8 @@ char *check_writable_directory(char *path) { * implementation is to go on generating random filenames regardless of * it. */ -char *safe_tempnam(const char *dirname, const char *filename_prefix) { - +char *safe_tempnam(const char *dirname, const char *filename_prefix) +{ char *buf, *tempdir = NULL, *full_tempdir = NULL; int filedesc; @@ -2221,6 +2218,12 @@ char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list) buf = mallocstrcpy(buf, tmp); matches = username_tab_completion(tmp, &num_matches); } + /* If we're in the middle of the original line, copy the string + only up to the cursor position into buf, so tab completion + will result in buf's containing only the tab-completed + path/filename. */ + else if (strlen(buf) > strlen(tmp)) + buf = mallocstrcpy(buf, tmp); /* Try to match everything in the current working directory that * matches. */ @@ -2416,51 +2419,6 @@ int diralphasort(const void *va, const void *vb) } -/* Initialize the browser code, including the list of files in *path */ -char **browser_init(char *path, int *longest, int *numents) -{ - DIR *dir; - struct dirent *next; - char **filelist = (char **) NULL; - int i = 0; - - dir = opendir(path); - if (!dir) - return NULL; - - *numents = 0; - while ((next = readdir(dir)) != NULL) { - if (!strcmp(next->d_name, ".")) - continue; - (*numents)++; - if (strlen(next->d_name) > *longest) - *longest = strlen(next->d_name); - } - rewinddir(dir); - *longest += 10; - - filelist = nmalloc(*numents * sizeof (char *)); - - while ((next = readdir(dir)) != NULL) { - if (!strcmp(next->d_name, ".")) - continue; - filelist[i] = charalloc(strlen(next->d_name) + strlen(path) + 2); - - if (!strcmp(path, "/")) - snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 1, - "%s%s", path, next->d_name); - else - snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 2, - "%s/%s", path, next->d_name); - i++; - } - - if (*longest > COLS - 1) - *longest = COLS - 1; - - return filelist; -} - /* Free our malloc()ed memory */ void free_charptrarray(char **array, int len) { @@ -2513,6 +2471,51 @@ void striponedir(char *foo) return; } +/* Initialize the browser code, including the list of files in *path */ +char **browser_init(char *path, int *longest, int *numents) +{ + DIR *dir; + struct dirent *next; + char **filelist = (char **) NULL; + int i = 0; + + dir = opendir(path); + if (!dir) + return NULL; + + *numents = 0; + while ((next = readdir(dir)) != NULL) { + if (!strcmp(next->d_name, ".")) + continue; + (*numents)++; + if (strlen(next->d_name) > *longest) + *longest = strlen(next->d_name); + } + rewinddir(dir); + *longest += 10; + + filelist = nmalloc(*numents * sizeof (char *)); + + while ((next = readdir(dir)) != NULL) { + if (!strcmp(next->d_name, ".")) + continue; + filelist[i] = charalloc(strlen(next->d_name) + strlen(path) + 2); + + if (!strcmp(path, "/")) + snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 1, + "%s%s", path, next->d_name); + else + snprintf(filelist[i], strlen(next->d_name) + strlen(path) + 2, + "%s/%s", path, next->d_name); + i++; + } + + if (*longest > COLS - 1) + *longest = COLS - 1; + + return filelist; +} + /* Our browser function. inpath is the path to start browsing from */ char *do_browser(char *inpath) { diff --git a/global.c b/global.c index 83691d5a..7a9cf725 100644 --- a/global.c +++ b/global.c @@ -217,19 +217,6 @@ void toggle_init_one(int val, const char *desc, int flag) u->next = NULL; } -#ifdef DEBUG -/* Deallocate all of the toggles. */ -void free_toggles(void) -{ - while (toggles != NULL) { - toggle *pt = toggles; /* Think "previous toggle" */ - - toggles = toggles->next; - free(pt); - } -} -#endif - void toggle_init(void) { char *toggle_const_msg, *toggle_autoindent_msg, *toggle_suspend_msg, @@ -288,6 +275,19 @@ void toggle_init(void) toggle_init_one(TOGGLE_BACKUP_KEY, toggle_backup_msg, BACKUP_FILE); toggle_init_one(TOGGLE_SMOOTH_KEY, toggle_smooth_msg, SMOOTHSCROLL); } + +#ifdef DEBUG +/* Deallocate all of the toggles. */ +void free_toggles(void) +{ + while (toggles != NULL) { + toggle *pt = toggles; /* Think "previous toggle" */ + + toggles = toggles->next; + free(pt); + } +} +#endif #endif /* !NANO_SMALL */ /* Deallocate the given shortcut. */ @@ -325,8 +325,8 @@ void shortcut_init(int unjustify) "", *nano_backup_msg = ""; #ifdef ENABLE_MULTIBUFFER - char *nano_openprev_msg = "", *nano_opennext_msg = "", - *nano_multibuffer_msg = ""; + char *nano_openprev_msg = "", *nano_opennext_msg = + "", *nano_multibuffer_msg = ""; #endif #ifdef HAVE_REGEX_H char *nano_regexp_msg = "", *nano_bracket_msg = ""; @@ -727,7 +727,7 @@ void shortcut_init(int unjustify) IFHELP(nano_execute_msg, 0), 0, 0, NOVIEW, 0); #endif #ifdef ENABLE_MULTIBUFFER - sc_init_one(&insertfile_list, TOGGLE_LOAD_KEY, _("New Buffer"), + sc_init_one(&insertfile_list, NANO_LOAD_KEY, _("New Buffer"), IFHELP(nano_multibuffer_msg, 0), 0, 0, NOVIEW, 0); #endif @@ -811,8 +811,10 @@ void thanks_for_all_the_fish(void) if (alt_speller != NULL) free(alt_speller); #endif +#ifndef DISABLE_HELP if (help_text != NULL) free(help_text); +#endif if (filename != NULL) free(filename); if (answer != NULL) diff --git a/move.c b/move.c index 27ed9ea3..d70edad6 100644 --- a/move.c +++ b/move.c @@ -35,43 +35,6 @@ #define _(string) (string) #endif -int do_page_down(void) -{ - wrap_reset(); - current_x = 0; - placewewant = 0; - - if (current == filebot) - return 0; - - /* AHEM, if we only have a screen or less of text, DON'T do an - edit_update, just move the cursor to editbot! */ - if (edittop == fileage && editbot == filebot && totlines < editwinrows) { - current = editbot; - reset_cursor(); - } else if (editbot != filebot || edittop == fileage) { - current_y = 0; - current = editbot; - - if (current->prev != NULL) - current = current->prev; - if (current->prev != NULL) - current = current->prev; - edit_update(current, TOP); - } else { - while (current != filebot) { - current = current->next; - current_y++; - } - edit_update(edittop, TOP); - } - - update_cursor(); - UNSET(KEEP_CUTBUFFER); - check_statblank(); - return 1; -} - int do_home(void) { UNSET(KEEP_CUTBUFFER); @@ -138,6 +101,43 @@ int do_page_up(void) return 1; } +int do_page_down(void) +{ + wrap_reset(); + current_x = 0; + placewewant = 0; + + if (current == filebot) + return 0; + + /* AHEM, if we only have a screen or less of text, DON'T do an + edit_update, just move the cursor to editbot! */ + if (edittop == fileage && editbot == filebot && totlines < editwinrows) { + current = editbot; + reset_cursor(); + } else if (editbot != filebot || edittop == fileage) { + current_y = 0; + current = editbot; + + if (current->prev != NULL) + current = current->prev; + if (current->prev != NULL) + current = current->prev; + edit_update(current, TOP); + } else { + while (current != filebot) { + current = current->next; + current_y++; + } + edit_update(edittop, TOP); + } + + update_cursor(); + UNSET(KEEP_CUTBUFFER); + check_statblank(); + return 1; +} + int do_up(void) { wrap_reset(); @@ -197,15 +197,13 @@ int do_down(void) { return 1; } -int do_right(void) +int do_left(void) { - assert(current_x <= strlen(current->data)); - - if (current->data[current_x] != '\0') - current_x++; - else if (current->next) { - do_down(); - current_x = 0; + if (current_x > 0) + current_x--; + else if (current != fileage) { + do_up(); + current_x = strlen(current->data); } placewewant = xplustabs(); update_line(current, current_x); @@ -214,13 +212,15 @@ int do_right(void) return 1; } -int do_left(void) +int do_right(void) { - if (current_x > 0) - current_x--; - else if (current != fileage) { - do_up(); - current_x = strlen(current->data); + assert(current_x <= strlen(current->data)); + + if (current->data[current_x] != '\0') + current_x++; + else if (current->next) { + do_down(); + current_x = 0; } placewewant = xplustabs(); update_line(current, current_x); diff --git a/nano.c b/nano.c index af63a7fd..52185080 100644 --- a/nano.c +++ b/nano.c @@ -222,6 +222,258 @@ void global_init(int save_cutbuffer) hblank[COLS] = '\0'; } +void window_init(void) +{ + if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS) + die_too_small(); + + /* Set up the main text window */ + edit = newwin(editwinrows, COLS, 2, 0); + + /* And the other windows */ + topwin = newwin(2, COLS, 0, 0); + bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0); + +#ifdef PDCURSES + /* Oops, I guess we need this again. + Moved here so the keypad still works after a Meta-X, for example */ + keypad(edit, TRUE); + keypad(bottomwin, TRUE); +#endif +} + +void mouse_init(void) +{ +#ifndef DISABLE_MOUSE +#ifdef NCURSES_MOUSE_VERSION + if (ISSET(USE_MOUSE)) { + keypad_on(edit, 1); + keypad_on(bottomwin, 1); + + mousemask(BUTTON1_RELEASED, NULL); + mouseinterval(50); + } else + mousemask(0, NULL); +#endif +#endif +} + +#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 = 1; /* space needed for help_text */ + char *ptr = NULL; +#ifndef NANO_SMALL + const toggle *t; +#endif + const shortcut *s; + + /* First set up the initial help text for the current function */ + if (currshortcut == whereis_list || currshortcut == replace_list + || currshortcut == replace_list_2) + ptr = _("Search Command Help Text\n\n " + "Enter the words or characters you would like to search " + "for, then hit 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 " + "If using Pico Mode via the -p or --pico flags, the " + "Meta-P toggle, or a nanorc file, the previous search " + "string will be shown in brackets after the Search: prompt. " + "Hitting Enter without entering any text will perform the " + "previous search. Otherwise, the previous string will be " + "placed before the cursor, and can be edited or deleted " + "before hitting enter.\n\n The following function keys are " + "available in Search mode:\n\n"); + else if (currshortcut == goto_list) + ptr = _("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"); + else if (currshortcut == insertfile_list) + ptr = _("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 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).\n\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"); + else if (currshortcut == writefile_list) + ptr = _("Write File Help Text\n\n " + "Type the name that you wish to save the current file " + "as and hit Enter to save the file.\n\n If you have " + "selected text with Ctrl-^, 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"); +#ifndef DISABLE_BROWSER + else if (currshortcut == browser_list) + ptr = _("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"); + else if (currshortcut == gotodir_list) + ptr = _("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"); +#endif + else if (currshortcut == spell_list) + ptr = _("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.\n\n The following other functions are " + "available in Spell Check mode:\n\n"); +#ifndef NANO_SMALL + else if (currshortcut == extcmd_list) + ptr = _("External 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 multibuffer mode).\n\n The following keys are " + "available in this mode:\n\n"); +#endif + else /* Default to the main help list */ + ptr = _(" 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 " + "The notation for shortcuts is as follows: Control-key " + "sequences are notated with a caret (^) symbol and are entered " + "with the Control (Ctrl) key. 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. The " + "following keystrokes are available in the main editor window. " + "Alternative keys are shown in parentheses:\n\n"); + + allocsize += strlen(ptr); + + /* The space needed for the shortcut lists, at most COLS characters, + * plus '\n'. */ + allocsize += (COLS + 1) * length_of_list(currshortcut); + +#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 at most + * COLS - 24 characters, plus '\n'.*/ + if (currshortcut == main_list) + for (t = toggles; t != NULL; t = t->next) + allocsize += COLS - 17; +#endif /* !NANO_SMALL */ + + /* help_text has been freed and set to NULL unless the user resized + * while in the help screen. */ + free(help_text); + + /* Allocate space for the help text */ + help_text = charalloc(allocsize); + + /* Now add the text we want */ + strcpy(help_text, ptr); + ptr = help_text + strlen(help_text); + + /* Now add our shortcut info */ + for (s = currshortcut; s != NULL; s = s->next) { + /* true if the character in s->altval is shown in first column */ + int meta_shortcut = 0; + + if (s->val > 0 && s->val < 32) + ptr += sprintf(ptr, "^%c", s->val + 64); +#ifndef NANO_SMALL + else if (s->val == NANO_CONTROL_SPACE) + ptr += sprintf(ptr, "^%.6s", _("Space")); + else if (s->altval == NANO_ALT_SPACE) { + meta_shortcut = 1; + ptr += sprintf(ptr, "M-%.5s", _("Space")); + } +#endif + else if (s->altval > 0) { + meta_shortcut = 1; + ptr += sprintf(ptr, "M-%c", s->altval - + (('A' <= s->altval && s->altval <= 'Z') || + 'a' <= s->altval ? 32 : 0)); + } + /* Hack */ + else if (s->val >= 'a') { + meta_shortcut = 1; + ptr += sprintf(ptr, "M-%c", s->val - 32); + } + + *(ptr++) = '\t'; + + if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64)) + ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0); + + *(ptr++) = '\t'; + + if (!meta_shortcut && s->altval > 0) + ptr += sprintf(ptr, "(M-%c)", s->altval - + (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval + ? 32 : 0)); + + *(ptr++) = '\t'; + + assert(s->help != NULL); + ptr += sprintf(ptr, "%.*s\n", COLS - 24, s->help); + } + +#ifndef NANO_SMALL + /* And the toggles... */ + if (currshortcut == main_list) + for (t = toggles; t != NULL; t = t->next) { + ptr += sprintf(ptr, "M-%c\t\t\t", t->val - 32); + assert(t->desc != NULL); + ptr += sprintf(ptr, _("%.*s enable/disable\n"), COLS - 24, t->desc); + } +#endif /* !NANO_SMALL */ + + /* If all went well, we didn't overwrite the allocated space for + help_text. */ + assert(strlen(help_text) < allocsize); +} +#endif + +/* 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)); + + newnode->data = NULL; + newnode->prev = prevnode; + newnode->next = NULL; + newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1; + + return newnode; +} + /* Make a copy of a node to a pointer (space will be malloc()ed). */ filestruct *copy_node(const filestruct *src) { @@ -238,6 +490,19 @@ filestruct *copy_node(const filestruct *src) return dst; } +/* Splice a node into an existing filestruct. */ +void splice_node(filestruct *begin, filestruct *newnode, filestruct *end) +{ + if (newnode != NULL) { + newnode->next = end; + newnode->prev = begin; + } + if (begin != NULL) + begin->next = newnode; + if (end != NULL) + end->prev = newnode; +} + /* Unlink a node from the rest of the filestruct. */ void unlink_node(const filestruct *fileptr) { @@ -329,7 +594,7 @@ void renumber(filestruct *fileptr) * strings to translate and takes out the parts that shouldn't be * translatable (the flag names). */ void print1opt(const char *shortflag, const char *longflag, - const char *desc) + const char *desc) { printf(" %s\t", shortflag); if (strlen(shortflag) < 8) @@ -430,46 +695,51 @@ void version(void) (" Email: nano@nano-editor.org Web: http://www.nano-editor.org")); printf(_("\n Compiled options:")); +#ifdef DEBUG + printf(" --enable-debug"); +#endif #ifdef NANO_EXTRA printf(" --enable-extra"); #endif -#ifdef ENABLE_MULTIBUFFER - printf(" --enable-multibuffer"); -#endif -#ifdef ENABLE_NANORC - printf(" --enable-nanorc"); -#endif -#ifdef ENABLE_COLOR - printf(" --enable-color"); -#endif - #ifdef NANO_SMALL printf(" --enable-tiny"); #else #ifdef DISABLE_BROWSER printf(" --disable-browser"); #endif -#ifdef DISABLE_TABCOMP - printf(" --disable-tabcomp"); +#ifdef DISABLE_HELP + printf(" --disable-help"); #endif #ifdef DISABLE_JUSTIFY printf(" --disable-justify"); #endif -#ifdef DISABLE_SPELLER - printf(" --disable-speller"); -#endif -#ifdef DISABLE_HELP - printf(" --disable-help"); -#endif #ifdef DISABLE_MOUSE printf(" --disable-mouse"); #endif #ifdef DISABLE_OPERATINGDIR printf(" --disable-operatingdir"); #endif -#endif /* NANO_SMALL */ -#ifdef DISABLE_WRAPPING - printf(" --disable-wrapping"); +#ifdef DISABLE_SPELLER + printf(" --disable-speller"); +#endif +#ifdef DISABLE_TABCOMP + printf(" --disable-tabcomp"); +#endif +#endif /* NANO_SMALL */ +#ifdef DISABLE_WRAPPING + printf(" --disable-wrapping"); +#endif +#ifdef ENABLE_COLOR + printf(" --enable-color"); +#endif +#ifdef ENABLE_MULTIBUFFER + printf(" --enable-multibuffer"); +#endif +#ifdef ENABLE_NANORC + printf(" --enable-nanorc"); +#endif +#ifdef ENABLE_UNDO + printf(" --enable-undo"); #endif #ifdef USE_SLANG printf(" --with-slang"); @@ -477,50 +747,11 @@ void version(void) printf("\n"); } -/* 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)); - - newnode->data = NULL; - newnode->prev = prevnode; - newnode->next = NULL; - newnode->lineno = prevnode != NULL ? prevnode->lineno + 1 : 1; - - return newnode; -} - -/* Splice a node into an existing filestruct. */ -void splice_node(filestruct *begin, filestruct *newnode, filestruct *end) -{ - if (newnode != NULL) { - newnode->next = end; - newnode->prev = begin; - } - if (begin != NULL) - begin->next = newnode; - if (end != NULL) - end->prev = newnode; -} - -int do_mark(void) +/* Stuff we do when we abort from programs and want to clean up the + * screen. This doesn't do much right now. */ +void do_early_abort(void) { -#ifdef NANO_SMALL - nano_disabled_msg(); -#else - if (!ISSET(MARK_ISSET)) { - statusbar(_("Mark Set")); - SET(MARK_ISSET); - mark_beginbuf = current; - mark_beginx = current_x; - } else { - statusbar(_("Mark UNset")); - UNSET(MARK_ISSET); - edit_refresh(); - } -#endif - return 1; + blank_statusbar_refresh(); } int no_help(void) @@ -535,448 +766,264 @@ void nano_disabled_msg(void) } #endif -/* The user typed a printable character; add it to the edit buffer. */ -void do_char(char ch) -{ - size_t current_len = strlen(current->data); -#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR) - int refresh = 0; - /* Do we have to run edit_refresh(), or can we get away with - * update_line()? */ -#endif - - /* magic-line: when a character is inserted on the current magic line, - * it means we need a new one! */ - if (filebot == current && current->data[0] == '\0') { - new_magicline(); - fix_editbot(); - } - - /* more dangerousness fun =) */ - current->data = nrealloc(current->data, current_len + 2); - assert(current_x <= current_len); - memmove(¤t->data[current_x + 1], - ¤t->data[current_x], - current_len - current_x + 1); - current->data[current_x] = ch; - totsize++; - set_modified(); - #ifndef NANO_SMALL - /* note that current_x has not yet been incremented */ - if (current == mark_beginbuf && current_x < mark_beginx) - mark_beginx++; -#endif - - do_right(); - -#ifndef DISABLE_WRAPPING - if (!ISSET(NO_WRAP) && ch != '\t') - refresh = do_wrap(current); -#endif - -#ifdef ENABLE_COLOR - refresh = 1; -#endif - -#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR) - if (refresh) - edit_refresh(); -#endif - - check_statblank(); - UNSET(KEEP_CUTBUFFER); -} +static int pid; /* This is the PID of the newly forked process + * below. It must be global since the signal + * handler needs it. */ -/* Someone hits return *gasp!* */ -int do_enter(void) +RETSIGTYPE cancel_fork(int signal) { - filestruct *newnode; - char *tmp; - - newnode = make_new_node(current); - assert(current != NULL && current->data != NULL); - tmp = ¤t->data[current_x]; - -#ifndef NANO_SMALL - /* Do auto-indenting, like the neolithic Turbo Pascal editor. */ - if (ISSET(AUTOINDENT)) { - int extra = 0; - const char *spc = current->data; - - while (*spc == ' ' || *spc == '\t') { - extra++; - spc++; - } - /* If current_x < extra, then we are breaking the line in the - * indentation. Autoindenting should add only current_x - * characters of indentation. */ - if (current_x < extra) - extra = current_x; - else - current_x = extra; - totsize += extra; - - newnode->data = charalloc(strlen(tmp) + extra + 1); - strncpy(newnode->data, current->data, extra); - strcpy(&newnode->data[extra], tmp); - } else -#endif - { - current_x = 0; - newnode->data = charalloc(strlen(tmp) + 1); - strcpy(newnode->data, tmp); - } - *tmp = '\0'; - - if (current->next == NULL) { - filebot = newnode; - editbot = newnode; - } - splice_node(current, newnode, current->next); - - totsize++; - renumber(current); - current = newnode; - align(¤t->data); - - /* The logic here is as follows: - * -> If we are at the bottom of the buffer, we want to recenter - * (read: rebuild) the screen and forcibly move the cursor. - * -> otherwise, we want simply to redraw the screen and update - * where we think the cursor is. - */ - if (current_y == editwinrows - 1) { - edit_update(current, CENTER); - reset_cursor(); - } else { - current_y++; - edit_refresh(); - update_cursor(); - } - - totlines++; - set_modified(); - - placewewant = xplustabs(); - return 1; + if (kill(pid, SIGKILL)==-1) nperror("kill"); } -#ifndef NANO_SMALL -int do_next_word(void) +int open_pipe(const char *command) { - filestruct *old = current; - - assert(current != NULL && current->data != NULL); - - /* Skip letters in this word first. */ - while (current->data[current_x] != '\0' && - isalnum((int)current->data[current_x])) - current_x++; - - for (; current != NULL; current = current->next) { - while (current->data[current_x] != '\0' && - !isalnum((int)current->data[current_x])) - current_x++; - - if (current->data[current_x] != '\0') - break; - - current_x = 0; - } - if (current == NULL) - current = filebot; + int fd[2]; + FILE *f; + struct sigaction oldaction, newaction; + /* original and temporary handlers for SIGINT */ +#ifdef _POSIX_VDISABLE + struct termios term, newterm; +#endif /* _POSIX_VDISABLE */ + int cancel_sigs = 0; + /* cancel_sigs==1 means that sigaction failed without changing the + * signal handlers. cancel_sigs==2 means the signal handler was + * changed, but the tcsetattr didn't succeed. + * I use this variable since it is important to put things back when + * we finish, even if we get errors. */ - placewewant = xplustabs(); + /* Make our pipes. */ - if (current->lineno >= editbot->lineno) { - /* If we're on the last line, don't center the screen. */ - if (current->lineno == filebot->lineno) - edit_refresh(); - else - edit_update(current, CENTER); - } - else { - /* If we've jumped lines, refresh the old line. We can't just - use current->prev here, because we may have skipped over some - blank lines, in which case the previous line is the wrong - one. */ - if (current != old) { - update_line(old, 0); - /* If the mark was set, then the lines between old and - current have to be updated too. */ - if (ISSET(MARK_ISSET)) { - while (old->next != current) { - old = old->next; - update_line(old, 0); - } - } - } - update_line(current, current_x); + if (pipe(fd) == -1) { + statusbar(_("Could not pipe")); + return 1; } - return 0; -} - -/* The same thing for backwards. */ -int do_prev_word(void) -{ - filestruct *old = current; - - assert(current != NULL); - - /* Skip letters in this word first. */ - while (current_x >= 0 && isalnum((int)current->data[current_x])) - current_x--; - for (; current != NULL; current = current->prev) { - while (current_x >= 0 && !isalnum((int)current->data[current_x])) - current_x--; + /* Fork a child. */ - if (current_x >= 0) - break; + if ((pid = fork()) == 0) { + close(fd[0]); + dup2(fd[1], fileno(stdout)); + dup2(fd[1], fileno(stderr)); + /* If execl() returns at all, there was an error. */ + + execl("/bin/sh","sh","-c",command,0); + exit(0); + } - if (current->prev != NULL) - current_x = strlen(current->prev->data); + /* Else continue as parent. */ + + close(fd[1]); + + if (pid == -1) { + close(fd[0]); + statusbar(_("Could not fork")); + return 1; } - if (current != NULL) { - while (current_x > 0 && isalnum((int)current->data[current_x - 1])) - current_x--; + /* Before we start reading the forked command's output, we set + * things up so that ^C will cancel the new process. */ + if (sigaction(SIGINT, NULL, &newaction)==-1) { + cancel_sigs = 1; + nperror("sigaction"); } else { - current = fileage; - current_x = 0; + newaction.sa_handler = cancel_fork; + if (sigaction(SIGINT, &newaction, &oldaction)==-1) { + cancel_sigs = 1; + nperror("sigaction"); + } } + /* Note that now oldaction is the previous SIGINT signal handler, + * to be restored later. */ - placewewant = xplustabs(); - - if (current->lineno <= edittop->lineno) { - /* If we're on the first line, don't center the screen. */ - if (current->lineno == fileage->lineno) - edit_refresh(); - else - edit_update(current, CENTER); + /* See if the platform supports disabling individual control + * characters. */ +#ifdef _POSIX_VDISABLE + if (!cancel_sigs && tcgetattr(0, &term) == -1) { + cancel_sigs = 2; + nperror("tcgetattr"); } - else { - /* If we've jumped lines, refresh the old line. We can't just - use current->prev here, because we may have skipped over some - blank lines, in which case the previous line is the wrong - one. */ - if (current != old) { - update_line(old, 0); - /* If the mark was set, then the lines between old and - current have to be updated too. */ - if (ISSET(MARK_ISSET)) { - while (old->prev != current) { - old = old->prev; - update_line(old, 0); - } - } + if (!cancel_sigs) { + newterm = term; + /* Grab oldterm's VINTR key :-) */ + newterm.c_cc[VINTR] = oldterm.c_cc[VINTR]; + if (tcsetattr(0, TCSANOW, &newterm) == -1) { + cancel_sigs = 2; + nperror("tcsetattr"); } - update_line(current, current_x); } +#endif /* _POSIX_VDISABLE */ + + f = fdopen(fd[0], "rb"); + if (!f) + nperror("fdopen"); + + read_file(f, "stdin", 0); + /* if multibuffer mode is on, we could be here in view mode; if so, + don't set the modification flag */ + if (!ISSET(VIEW_MODE)) + set_modified(); + + if (wait(NULL) == -1) + nperror("wait"); + +#ifdef _POSIX_VDISABLE + if (!cancel_sigs && tcsetattr(0, TCSANOW, &term) == -1) + nperror("tcsetattr"); +#endif /* _POSIX_VDISABLE */ + + if (cancel_sigs!=1 && sigaction(SIGINT, &oldaction, NULL) == -1) + nperror("sigaction"); + return 0; } -#endif /* !NANO_SMALL */ +#endif /* NANO_SMALL */ -#ifndef DISABLE_WRAPPING -/* We wrap the given line. Precondition: we assume the cursor has been - * moved forward since the last typed character. Return value: - * whether we wrapped. */ -int do_wrap(filestruct *inptr) +#ifndef DISABLE_MOUSE +#ifdef NCURSES_MOUSE_VERSION +void do_mouse(void) { - size_t len = strlen(inptr->data); /* length of the line we wrap */ - int i = 0; /* generic loop variable */ - int wrap_loc = -1; /* index of inptr->data where we wrap */ - int word_back = -1; -#ifndef NANO_SMALL - const char *indentation = NULL; - /* indentation to prepend to the new line */ - int indent_len = 0; /* strlen(indentation) */ -#endif - const char *after_break; /* text after the wrap point */ - int after_break_len; /* strlen(after_break) */ - int wrapping = 0; /* do we prepend to the next line? */ - const char *wrap_line = NULL; - /* the next line, minus indentation */ - int wrap_line_len = 0; /* strlen(wrap_line) */ - char *newline = NULL; /* the line we create */ - int new_line_len = 0; /* eventual length of newline */ + MEVENT mevent; + int currslen; + const shortcut *s = currshortcut; -/* There are three steps. First, we decide where to wrap. Then, we - * create the new wrap line. Finally, we clean up. */ + if (getmouse(&mevent) == ERR) + return; -/* Step 1, finding where to wrap. We are going to replace a white-space - * character with a new-line. In this step, we set wrap_loc as the - * location of this replacement. - * - * Where should we break the line? We need the last "legal wrap point" - * such that the last word before it ended at or before fill. If there - * is no such point, we settle for the first legal wrap point. - * - * A "legal wrap point" is a white-space character that is not the last - * typed character and is not followed by white-space. - * - * If there is no legal wrap point or we found the last character of the - * line, we should return without wrapping. - * - * Note that the initial indentation does not count as a legal wrap - * point if we are going to auto-indent! - * - * Note that the code below could be optimised, by not calling strnlenpt() - * so often. */ + /* If mouse not in edit or bottom window, return */ + if (wenclose(edit, mevent.y, mevent.x)) { -#ifndef NANO_SMALL - if (ISSET(AUTOINDENT)) - i = indent_length(inptr->data); -#endif - wrap_line = inptr->data + i; - for(; i < len; i++, wrap_line++) { - /* record where the last word ended */ - if (*wrap_line != ' ' && *wrap_line != '\t') - word_back = i; - /* if we have found a "legal wrap point" and the current word - * extends too far, then we stop */ - if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill) - break; - /* we record the latest "legal wrap point" */ - if (i != current_x - 1 && word_back != i && - wrap_line[1] != ' ' && wrap_line[1] != '\t') - wrap_loc = i; - } - if (wrap_loc < 0 || i == len) - return 0; + /* Don't let people screw with the marker when they're in a + * subfunction. */ + if (currshortcut != main_list) + return; -/* Step 2, making the new wrap line. It will consist of indentation + - * after_break + " " + wrap_line (although indentation and wrap_line are - * conditional on flags and #defines). */ + /* Subtract out size of topwin. Perhaps we need a constant + * somewhere? */ + mevent.y -= 2; - /* after_break is the text that will be moved to the next line. */ - after_break = inptr->data + wrap_loc + 1; - after_break_len = len - wrap_loc - 1; - assert(after_break_len == strlen(after_break)); + /* Selecting where the cursor is sets the mark. Selecting + * beyond the line length with the cursor at the end of the line + * sets the mark as well. */ + if ((mevent.y == current_y) && + ((mevent.x == current_x) || (current_x == strlen(current->data) + && (mevent.x > + strlen(current->data))))) { + if (ISSET(VIEW_MODE)) { + print_view_warning(); + return; + } + do_mark(); + } else if (mevent.y > current_y) { + while (mevent.y > current_y) { + if (current->next != NULL) + current = current->next; + else + break; + current_y++; + } + } else if (mevent.y < current_y) { + while (mevent.y < current_y) { + if (current->prev != NULL) + current = current->prev; + else + break; + current_y--; + } + } + current_x = actual_x(current, mevent.x); + placewewant = current_x; + update_cursor(); + edit_refresh(); + } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) { + int i, k; - /* new_line_len will later be increased by the lengths of indentation - * and wrap_line. */ - new_line_len = after_break_len; + if (currshortcut == main_list) + currslen = MAIN_VISIBLE; + else + currslen = length_of_list(currshortcut); - /* We prepend the wrapped text to the next line, if the flag is set, - * and there is a next line, and prepending would not make the line - * too long. */ - if (ISSET(SAMELINEWRAP) && inptr->next) { - wrap_line = inptr->next->data; - wrap_line_len = strlen(wrap_line); + if (currslen < 2) + k = COLS / 6; + else + k = COLS / ((currslen + (currslen %2)) / 2); - /* +1 for the space between after_break and wrap_line */ - if ((new_line_len + 1 + wrap_line_len) <= fill) { - wrapping = 1; - new_line_len += (1 + wrap_line_len); - } - } + /* Determine what shortcut list was clicked */ + mevent.y -= (editwinrows + 3); -#ifndef NANO_SMALL - if (ISSET(AUTOINDENT)) { - /* indentation comes from the next line if wrapping, else from - * this line */ - indentation = (wrapping ? wrap_line : inptr->data); - indent_len = indent_length(indentation); - if (wrapping) - /* The wrap_line text should not duplicate indentation. Note - * in this case we need not increase new_line_len. */ - wrap_line += indent_len; - else - new_line_len += indent_len; - } -#endif + if (mevent.y < 0) /* They clicked on the statusbar */ + return; + + /* Don't select stuff beyond list length */ + if (mevent.x / k >= currslen) + return; - /* Now we allocate the new line and copy into it. */ - newline = charalloc(new_line_len + 1); /* +1 for \0 */ - *newline = '\0'; + for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++) + s = s->next; -#ifndef NANO_SMALL - if (ISSET(AUTOINDENT)) { - strncpy(newline, indentation, indent_len); - newline[indent_len] = '\0'; + /* And ungetch that value */ + ungetch(s->val); + + /* And if it's an alt-key sequence, we should probably send alt + too ;-) */ + if (s->val >= 'a' && s->val <= 'z') + ungetch(27); } +} #endif - strcat(newline, after_break); - /* We end the old line at wrap_loc. Note this eats the space. */ - null_at(&inptr->data, wrap_loc); - if (wrapping) { - /* In this case, totsize does not change. We ate a space in the - * null_at() above, but we add a space between after_break and - * wrap_line below. */ - strcat(newline, " "); - strcat(newline, wrap_line); - free(inptr->next->data); - inptr->next->data = newline; - } else { - filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct)); - - /* In this case, the file size changes by -1 for the eaten - * space, +1 for the new line, and +indent_len for the new - * indentation. */ -#ifndef NANO_SMALL - totsize += indent_len; #endif - totlines++; - temp->data = newline; - temp->prev = inptr; - temp->next = inptr->next; - temp->prev->next = temp; - /* If !temp->next, then temp is the last line of the file, so we - * must set filebot */ - if (temp->next) - temp->next->prev = temp; - else - filebot = temp; - } -/* Step 3, clean up. Here we reposition the cursor and mark, and do some - * other sundry things. */ +/* The user typed a printable character; add it to the edit buffer. */ +void do_char(char ch) +{ + size_t current_len = strlen(current->data); +#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR) + int refresh = 0; + /* Do we have to run edit_refresh(), or can we get away with + * update_line()? */ +#endif - /* later wraps of this line will be prepended to the next line. */ - SET(SAMELINEWRAP); + /* magic-line: when a character is inserted on the current magic line, + * it means we need a new one! */ + if (filebot == current && current->data[0] == '\0') { + new_magicline(); + fix_editbot(); + } - /* Each line knows its line number. We recalculate these if we - * inserted a new line. */ - if (!wrapping) - renumber(inptr); + /* more dangerousness fun =) */ + current->data = nrealloc(current->data, current_len + 2); + assert(current_x <= current_len); + memmove(¤t->data[current_x + 1], + ¤t->data[current_x], + current_len - current_x + 1); + current->data[current_x] = ch; + totsize++; + set_modified(); - /* If the cursor was after the break point, we must move it. */ - if (current_x > wrap_loc) { - current = current->next; - current_x -= #ifndef NANO_SMALL - -indent_len + + /* note that current_x has not yet been incremented */ + if (current == mark_beginbuf && current_x < mark_beginx) + mark_beginx++; #endif - wrap_loc + 1; - wrap_reset(); - placewewant = xplustabs(); - } -#ifndef NANO_SMALL - /* If the mark was on this line after the wrap point, we move it down. - * If it was on the next line and we wrapped, we must move it - * right. */ - if (mark_beginbuf == inptr && mark_beginx > wrap_loc) { - mark_beginbuf = inptr->next; - mark_beginx -= wrap_loc - indent_len + 1; - } else if (wrapping && mark_beginbuf == inptr->next) - mark_beginx += after_break_len; -#endif /* !NANO_SMALL */ + do_right(); - /* Place the cursor. */ - reset_cursor(); +#ifndef DISABLE_WRAPPING + if (!ISSET(NO_WRAP) && ch != '\t') + refresh = do_wrap(current); +#endif - return 1; -} -#endif /* !DISABLE_WRAPPING */ +#ifdef ENABLE_COLOR + refresh = 1; +#endif -/* Stuff we do when we abort from programs and want to clean up the - * screen. This doesn't do much right now. */ -void do_early_abort(void) -{ - blank_statusbar_refresh(); +#if !defined(DISABLE_WRAPPING) || defined(ENABLE_COLOR) + if (refresh) + edit_refresh(); +#endif + + check_statblank(); + UNSET(KEEP_CUTBUFFER); } int do_backspace(void) @@ -1116,841 +1163,774 @@ int do_delete(void) return 1; } -void wrap_reset(void) +int do_tab(void) { - UNSET(SAMELINEWRAP); + do_char('\t'); + return 1; } -#ifndef DISABLE_SPELLER -int do_int_spell_fix(const char *word) +/* Someone hits return *gasp!* */ +int do_enter(void) { - char *save_search; - char *save_replace; - filestruct *begin; - int i = 0, j = 0, beginx, beginx_top, reverse_search_set; -#ifndef NANO_SMALL - int mark_set; -#endif - - /* save where we are */ - begin = current; - beginx = current_x + 1; + filestruct *newnode; + char *tmp; - /* Make sure Spell Check goes forward only */ - reverse_search_set = ISSET(REVERSE_SEARCH); - UNSET(REVERSE_SEARCH); + newnode = make_new_node(current); + assert(current != NULL && current->data != NULL); + tmp = ¤t->data[current_x]; #ifndef NANO_SMALL - /* Make sure the marking highlight is off during Spell Check */ - mark_set = ISSET(MARK_ISSET); - UNSET(MARK_ISSET); -#endif - - /* save the current search/replace strings */ - search_init_globals(); - save_search = last_search; - save_replace = last_replace; - - /* set search/replace strings to mis-spelt word */ - last_search = mallocstrcpy(NULL, word); - last_replace = mallocstrcpy(NULL, word); - - /* start from the top of file */ - current = fileage; - current_x = beginx_top = -1; - - search_last_line = FALSE; - - edit_update(fileage, TOP); - - while (1) { - /* make sure word is still mis-spelt (i.e. when multi-errors) */ - if (findnextstr(TRUE, FALSE, fileage, beginx_top, word) != NULL) { - - /* find whole words only */ - if (!is_whole_word(current_x, current->data, word)) - continue; - - do_replace_highlight(TRUE, word); - - /* allow replace word to be corrected */ - i = statusq(0, spell_list, last_replace, _("Edit a replacement")); - - do_replace_highlight(FALSE, word); - - /* start from the start of this line again */ - current = fileage; - current_x = beginx_top; - - search_last_line = FALSE; + /* Do auto-indenting, like the neolithic Turbo Pascal editor. */ + if (ISSET(AUTOINDENT)) { + int extra = 0; + const char *spc = current->data; - if (strcmp(word, answer)) { - j = i; - do_replace_loop(word, fileage, &beginx_top, TRUE, &j); - } + while (*spc == ' ' || *spc == '\t') { + extra++; + spc++; } - break; - } - - /* restore the search/replace strings */ - free(last_search); last_search=save_search; - free(last_replace); last_replace=save_replace; + /* If current_x < extra, then we are breaking the line in the + * indentation. Autoindenting should add only current_x + * characters of indentation. */ + if (current_x < extra) + extra = current_x; + else + current_x = extra; + totsize += extra; - /* restore where we were */ - current = begin; - current_x = beginx - 1; + newnode->data = charalloc(strlen(tmp) + extra + 1); + strncpy(newnode->data, current->data, extra); + strcpy(&newnode->data[extra], tmp); + } else +#endif + { + current_x = 0; + newnode->data = charalloc(strlen(tmp) + 1); + strcpy(newnode->data, tmp); + } + *tmp = '\0'; - /* restore Search/Replace direction */ - if (reverse_search_set) - SET(REVERSE_SEARCH); + if (current->next == NULL) { + filebot = newnode; + editbot = newnode; + } + splice_node(current, newnode, current->next); -#ifndef NANO_SMALL - /* restore marking highlight */ - if (mark_set) - SET(MARK_ISSET); -#endif + totsize++; + renumber(current); + current = newnode; + align(¤t->data); - edit_update(current, CENTER); + /* The logic here is as follows: + * -> If we are at the bottom of the buffer, we want to recenter + * (read: rebuild) the screen and forcibly move the cursor. + * -> otherwise, we want simply to redraw the screen and update + * where we think the cursor is. + */ + if (current_y == editwinrows - 1) { + edit_update(current, CENTER); + reset_cursor(); + } else { + current_y++; + edit_refresh(); + update_cursor(); + } - if (i == -1) - return FALSE; + totlines++; + set_modified(); - return TRUE; + placewewant = xplustabs(); + return 1; } -/* Integrated spell checking using 'spell' program. */ -int do_int_speller(char *tempfile_name) +#ifndef NANO_SMALL +int do_next_word(void) { - char *read_buff, *read_buff_ptr, *read_buff_word; - size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread; - int in_fd[2], tempfile_fd, spell_status; - pid_t pid_spell; - - /* Create a pipe to spell program */ - - if (pipe(in_fd) == -1) - return FALSE; - - /* A new process to run spell in */ - - if ((pid_spell = fork()) == 0) { + filestruct *old = current; - /* Child continues, (i.e. future spell process) */ + assert(current != NULL && current->data != NULL); - close(in_fd[0]); + /* Skip letters in this word first. */ + while (current->data[current_x] != '\0' && + isalnum((int)current->data[current_x])) + current_x++; - /* replace the standard in with the tempfile */ + for (; current != NULL; current = current->next) { + while (current->data[current_x] != '\0' && + !isalnum((int)current->data[current_x])) + current_x++; - if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) { - close(in_fd[1]); - exit(1); - } + if (current->data[current_x] != '\0') + break; - if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) { - close(tempfile_fd); - close(in_fd[1]); - exit(1); - } - close(tempfile_fd); + current_x = 0; + } + if (current == NULL) + current = filebot; - /* send spell's standard out to the pipe */ + placewewant = xplustabs(); - if (dup2(in_fd[1], STDOUT_FILENO) != STDOUT_FILENO) { - close(in_fd[1]); - exit(1); + if (current->lineno >= editbot->lineno) { + /* If we're on the last line, don't center the screen. */ + if (current->lineno == filebot->lineno) + edit_refresh(); + else + edit_update(current, CENTER); + } + else { + /* If we've jumped lines, refresh the old line. We can't just + use current->prev here, because we may have skipped over some + blank lines, in which case the previous line is the wrong + one. */ + if (current != old) { + update_line(old, 0); + /* If the mark was set, then the lines between old and + current have to be updated too. */ + if (ISSET(MARK_ISSET)) { + while (old->next != current) { + old = old->next; + update_line(old, 0); + } + } } - close(in_fd[1]); - - /* Start spell program, we are using the PATH here!?!? */ - execlp("spell", "spell", NULL); - - /* Should not be reached, if spell is found!!! */ - - exit(1); + update_line(current, current_x); } + return 0; +} - /* Parent continues here */ +/* The same thing for backwards. */ +int do_prev_word(void) +{ + filestruct *old = current; - close(in_fd[1]); + assert(current != NULL); - /* Child process was not forked successfully */ + /* Skip letters in this word first. */ + while (current_x >= 0 && isalnum((int)current->data[current_x])) + current_x--; - if (pid_spell < 0) { - close(in_fd[0]); - return FALSE; - } + for (; current != NULL; current = current->prev) { + while (current_x >= 0 && !isalnum((int)current->data[current_x])) + current_x--; - /* Get system pipe buffer size */ + if (current_x >= 0) + break; - if ((pipe_buff_size = fpathconf(in_fd[0], _PC_PIPE_BUF)) < 1) { - close(in_fd[0]); - return FALSE; + if (current->prev != NULL) + current_x = strlen(current->prev->data); } - /* Read-in the returned spelling errors */ - - read_buff_read = 0; - read_buff_size = pipe_buff_size + 1; - read_buff = read_buff_ptr = charalloc(read_buff_size); - - while ((bytesread = read(in_fd[0], read_buff_ptr, pipe_buff_size)) > 0) { - read_buff_read += bytesread; - read_buff_size += pipe_buff_size; - read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size); - read_buff_ptr += read_buff_read; + if (current != NULL) { + while (current_x > 0 && isalnum((int)current->data[current_x - 1])) + current_x--; + } else { + current = fileage; + current_x = 0; } - *read_buff_ptr = (char) NULL; - close(in_fd[0]); - - /* Process the spelling errors */ - - read_buff_word = read_buff_ptr = read_buff; - - while (*read_buff_ptr) { + placewewant = xplustabs(); - if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) { - *read_buff_ptr = (char) NULL; - if (read_buff_word != read_buff_ptr) { - if (!do_int_spell_fix(read_buff_word)) { - read_buff_word = read_buff_ptr; - break; + if (current->lineno <= edittop->lineno) { + /* If we're on the first line, don't center the screen. */ + if (current->lineno == fileage->lineno) + edit_refresh(); + else + edit_update(current, CENTER); + } + else { + /* If we've jumped lines, refresh the old line. We can't just + use current->prev here, because we may have skipped over some + blank lines, in which case the previous line is the wrong + one. */ + if (current != old) { + update_line(old, 0); + /* If the mark was set, then the lines between old and + current have to be updated too. */ + if (ISSET(MARK_ISSET)) { + while (old->prev != current) { + old = old->prev; + update_line(old, 0); } } - read_buff_word = read_buff_ptr + 1; } - read_buff_ptr++; + update_line(current, current_x); } + return 0; +} +#endif /* !NANO_SMALL */ - /* special case where last word doesn't end with \n or \r */ - if (read_buff_word != read_buff_ptr) - do_int_spell_fix(read_buff_word); - - free(read_buff); - replace_abort(); - - /* Process end of spell process */ - - wait(&spell_status); - if (WIFEXITED(spell_status)) { - if (WEXITSTATUS(spell_status) != 0) - return FALSE; - } else - return FALSE; +int do_mark(void) +{ +#ifdef NANO_SMALL + nano_disabled_msg(); +#else + if (!ISSET(MARK_ISSET)) { + statusbar(_("Mark Set")); + SET(MARK_ISSET); + mark_beginbuf = current; + mark_beginx = current_x; + } else { + statusbar(_("Mark UNset")); + UNSET(MARK_ISSET); + edit_refresh(); + } +#endif + return 1; +} - return TRUE; +void wrap_reset(void) +{ + UNSET(SAMELINEWRAP); } -/* External spell checking. */ -int do_alt_speller(char *file_name) +#ifndef DISABLE_WRAPPING +/* We wrap the given line. Precondition: we assume the cursor has been + * moved forward since the last typed character. Return value: + * whether we wrapped. */ +int do_wrap(filestruct *inptr) { - int alt_spell_status, lineno_cur = current->lineno; - int x_cur = current_x, y_cur = current_y, pww_cur = placewewant; - pid_t pid_spell; - char *ptr; - static int arglen = 3; - static char **spellargs = (char **)NULL; + size_t len = strlen(inptr->data); /* length of the line we wrap */ + int i = 0; /* generic loop variable */ + int wrap_loc = -1; /* index of inptr->data where we wrap */ + int word_back = -1; #ifndef NANO_SMALL - int 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) { - mbb_lineno_cur = mark_beginbuf->lineno; - UNSET(MARK_ISSET); - } + const char *indentation = NULL; + /* indentation to prepend to the new line */ + int indent_len = 0; /* strlen(indentation) */ #endif + const char *after_break; /* text after the wrap point */ + int after_break_len; /* strlen(after_break) */ + int wrapping = 0; /* do we prepend to the next line? */ + const char *wrap_line = NULL; + /* the next line, minus indentation */ + int wrap_line_len = 0; /* strlen(wrap_line) */ + char *newline = NULL; /* the line we create */ + int new_line_len = 0; /* eventual length of newline */ - endwin(); +/* There are three steps. First, we decide where to wrap. Then, we + * create the new wrap line. Finally, we clean up. */ - /* Set up an argument list to pass the execvp function */ - if (spellargs == NULL) { - spellargs = nmalloc(arglen * sizeof(char *)); +/* Step 1, finding where to wrap. We are going to replace a white-space + * character with a new-line. In this step, we set wrap_loc as the + * location of this replacement. + * + * Where should we break the line? We need the last "legal wrap point" + * such that the last word before it ended at or before fill. If there + * is no such point, we settle for the first legal wrap point. + * + * A "legal wrap point" is a white-space character that is not the last + * typed character and is not followed by white-space. + * + * If there is no legal wrap point or we found the last character of the + * line, we should return without wrapping. + * + * Note that the initial indentation does not count as a legal wrap + * point if we are going to auto-indent! + * + * Note that the code below could be optimised, by not calling strnlenpt() + * so often. */ - spellargs[0] = strtok(alt_speller, " "); - while ((ptr = strtok(NULL, " ")) != NULL) { - arglen++; - spellargs = nrealloc(spellargs, arglen * sizeof(char *)); - spellargs[arglen - 3] = ptr; - } - spellargs[arglen - 1] = NULL; +#ifndef NANO_SMALL + if (ISSET(AUTOINDENT)) + i = indent_length(inptr->data); +#endif + wrap_line = inptr->data + i; + for(; i < len; i++, wrap_line++) { + /* record where the last word ended */ + if (*wrap_line != ' ' && *wrap_line != '\t') + word_back = i; + /* if we have found a "legal wrap point" and the current word + * extends too far, then we stop */ + if (wrap_loc != -1 && strnlenpt(inptr->data, word_back + 1) > fill) + break; + /* we record the latest "legal wrap point" */ + if (i != current_x - 1 && word_back != i && + wrap_line[1] != ' ' && wrap_line[1] != '\t') + wrap_loc = i; } - spellargs[arglen - 2] = file_name; - - /* Start a new process for the alternate speller */ - if ((pid_spell = fork()) == 0) { - /* Start alternate spell program; we are using the PATH here!?!? */ - execvp(spellargs[0], spellargs); + if (wrap_loc < 0 || i == len) + return 0; - /* Should not be reached, if alternate speller is found!!! */ - exit(1); - } +/* Step 2, making the new wrap line. It will consist of indentation + + * after_break + " " + wrap_line (although indentation and wrap_line are + * conditional on flags and #defines). */ - /* Could not fork?? */ - if (pid_spell < 0) - return FALSE; + /* after_break is the text that will be moved to the next line. */ + after_break = inptr->data + wrap_loc + 1; + after_break_len = len - wrap_loc - 1; + assert(after_break_len == strlen(after_break)); - /* Wait for alternate speller to complete */ + /* new_line_len will later be increased by the lengths of indentation + * and wrap_line. */ + new_line_len = after_break_len; - wait(&alt_spell_status); - if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) - return FALSE; + /* We prepend the wrapped text to the next line, if the flag is set, + * and there is a next line, and prepending would not make the line + * too long. */ + if (ISSET(SAMELINEWRAP) && inptr->next) { + wrap_line = inptr->next->data; + wrap_line_len = strlen(wrap_line); - refresh(); - free_filestruct(fileage); - global_init(1); - open_file(file_name, 0, 1); + /* +1 for the space between after_break and wrap_line */ + if ((new_line_len + 1 + wrap_line_len) <= fill) { + wrapping = 1; + new_line_len += (1 + wrap_line_len); + } + } #ifndef NANO_SMALL - if (mark_set) { - do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0); - mark_beginbuf = current; - mark_beginx = current_x; - /* In case the line got shorter, assign mark_beginx. */ - SET(MARK_ISSET); + if (ISSET(AUTOINDENT)) { + /* indentation comes from the next line if wrapping, else from + * this line */ + indentation = (wrapping ? wrap_line : inptr->data); + indent_len = indent_length(indentation); + if (wrapping) + /* The wrap_line text should not duplicate indentation. Note + * in this case we need not increase new_line_len. */ + wrap_line += indent_len; + else + new_line_len += indent_len; } #endif - /* go back to the old position, mark the file as modified, and make - sure that the titlebar is refreshed */ - do_gotopos(lineno_cur, x_cur, y_cur, pww_cur); - set_modified(); - clearok(topwin, FALSE); - titlebar(NULL); - - return TRUE; -} -#endif - -int do_spell(void) -{ -#ifdef DISABLE_SPELLER - nano_disabled_msg(); - return (TRUE); -#else - char *temp; - int spell_res; - - if ((temp = safe_tempnam(0, "nano.")) == NULL) { - statusbar(_("Could not create a temporary filename: %s"), - strerror(errno)); - return 0; - } + /* Now we allocate the new line and copy into it. */ + newline = charalloc(new_line_len + 1); /* +1 for \0 */ + *newline = '\0'; - if (write_file(temp, 1, 0, 0) == -1) { - statusbar(_("Spell checking failed: unable to write temp file!")); - free(temp); - return 0; +#ifndef NANO_SMALL + if (ISSET(AUTOINDENT)) { + strncpy(newline, indentation, indent_len); + newline[indent_len] = '\0'; } - -#ifdef ENABLE_MULTIBUFFER - /* update the current open_files entry before spell-checking, in case - any problems occur */ - add_open_file(1); #endif + strcat(newline, after_break); + /* We end the old line at wrap_loc. Note this eats the space. */ + null_at(&inptr->data, wrap_loc); + if (wrapping) { + /* In this case, totsize does not change. We ate a space in the + * null_at() above, but we add a space between after_break and + * wrap_line below. */ + strcat(newline, " "); + strcat(newline, wrap_line); + free(inptr->next->data); + inptr->next->data = newline; + } else { + filestruct *temp = (filestruct *)nmalloc(sizeof(filestruct)); - if (alt_speller) - spell_res = do_alt_speller(temp); - else - spell_res = do_int_speller(temp); + /* In this case, the file size changes by -1 for the eaten + * space, +1 for the new line, and +indent_len for the new + * indentation. */ +#ifndef NANO_SMALL + totsize += indent_len; +#endif + totlines++; + temp->data = newline; + temp->prev = inptr; + temp->next = inptr->next; + temp->prev->next = temp; + /* If !temp->next, then temp is the last line of the file, so we + * must set filebot */ + if (temp->next) + temp->next->prev = temp; + else + filebot = temp; + } - remove(temp); +/* Step 3, clean up. Here we reposition the cursor and mark, and do some + * other sundry things. */ - if (spell_res) - statusbar(_("Finished checking spelling")); - else - statusbar(_("Spell checking failed")); + /* later wraps of this line will be prepended to the next line. */ + SET(SAMELINEWRAP); - free(temp); - return spell_res; + /* Each line knows its line number. We recalculate these if we + * inserted a new line. */ + if (!wrapping) + renumber(inptr); + /* If the cursor was after the break point, we must move it. */ + if (current_x > wrap_loc) { + current = current->next; + current_x -= +#ifndef NANO_SMALL + -indent_len + #endif -} + wrap_loc + 1; + wrap_reset(); + placewewant = xplustabs(); + } #ifndef NANO_SMALL -static int pid; /* This is the PID of the newly forked process - * below. It must be global since the signal - * handler needs it. */ + /* If the mark was on this line after the wrap point, we move it down. + * If it was on the next line and we wrapped, we must move it + * right. */ + if (mark_beginbuf == inptr && mark_beginx > wrap_loc) { + mark_beginbuf = inptr->next; + mark_beginx -= wrap_loc - indent_len + 1; + } else if (wrapping && mark_beginbuf == inptr->next) + mark_beginx += after_break_len; +#endif /* !NANO_SMALL */ -RETSIGTYPE cancel_fork(int signal) -{ - if (kill(pid, SIGKILL)==-1) nperror("kill"); + /* Place the cursor. */ + reset_cursor(); + + return 1; } +#endif /* !DISABLE_WRAPPING */ -int open_pipe(const char *command) +#ifndef DISABLE_SPELLER +int do_int_spell_fix(const char *word) { - int fd[2]; - FILE *f; - struct sigaction oldaction, newaction; - /* original and temporary handlers for SIGINT */ -#ifdef _POSIX_VDISABLE - struct termios term, newterm; -#endif /* _POSIX_VDISABLE */ - int cancel_sigs = 0; - /* cancel_sigs==1 means that sigaction failed without changing the - * signal handlers. cancel_sigs==2 means the signal handler was - * changed, but the tcsetattr didn't succeed. - * I use this variable since it is important to put things back when - * we finish, even if we get errors. */ - - /* Make our pipes. */ + char *save_search; + char *save_replace; + filestruct *begin; + int i = 0, j = 0, beginx, beginx_top, reverse_search_set; +#ifndef NANO_SMALL + int mark_set; +#endif - if (pipe(fd) == -1) { - statusbar(_("Could not pipe")); - return 1; - } + /* save where we are */ + begin = current; + beginx = current_x + 1; - /* Fork a child */ + /* Make sure Spell Check goes forward only */ + reverse_search_set = ISSET(REVERSE_SEARCH); + UNSET(REVERSE_SEARCH); - if ((pid = fork()) == 0) { - close(fd[0]); - dup2(fd[1], fileno(stdout)); - dup2(fd[1], fileno(stderr)); - /* If execl() returns at all, there was an error. */ - - execl("/bin/sh","sh","-c",command,0); - exit(0); - } +#ifndef NANO_SMALL + /* Make sure the marking highlight is off during Spell Check */ + mark_set = ISSET(MARK_ISSET); + UNSET(MARK_ISSET); +#endif - /* Else continue as parent */ + /* save the current search/replace strings */ + search_init_globals(); + save_search = last_search; + save_replace = last_replace; - close(fd[1]); + /* set search/replace strings to mis-spelt word */ + last_search = mallocstrcpy(NULL, word); + last_replace = mallocstrcpy(NULL, word); - if (pid == -1) { - close(fd[0]); - statusbar(_("Could not fork")); - return 1; - } + /* start from the top of file */ + current = fileage; + current_x = beginx_top = -1; - /* before we start reading the forked command's output, we set - * things up so that ^C will cancel the new process */ - if (sigaction(SIGINT, NULL, &newaction)==-1) { - cancel_sigs = 1; - nperror("sigaction"); - } else { - newaction.sa_handler = cancel_fork; - if (sigaction(SIGINT, &newaction, &oldaction)==-1) { - cancel_sigs = 1; - nperror("sigaction"); - } - } - /* note that now oldaction is the previous SIGINT signal handler, to - * be restored later */ + search_last_line = FALSE; - /* if the platform supports disabling individual control characters */ -#ifdef _POSIX_VDISABLE - if (!cancel_sigs && tcgetattr(0, &term) == -1) { - cancel_sigs = 2; - nperror("tcgetattr"); - } - if (!cancel_sigs) { - newterm = term; - /* Grab oldterm's VINTR key :-) */ - newterm.c_cc[VINTR] = oldterm.c_cc[VINTR]; - if (tcsetattr(0, TCSANOW, &newterm) == -1) { - cancel_sigs = 2; - nperror("tcsetattr"); - } - } -#endif /* _POSIX_VDISABLE */ + edit_update(fileage, TOP); - f = fdopen(fd[0], "rb"); - if (!f) - nperror("fdopen"); - - read_file(f, "stdin", 0); - set_modified(); + while (1) { + /* make sure word is still mis-spelt (i.e. when multi-errors) */ + if (findnextstr(TRUE, FALSE, fileage, beginx_top, word) != NULL) { - if (wait(NULL) == -1) - nperror("wait"); + /* find whole words only */ + if (!is_whole_word(current_x, current->data, word)) + continue; -#ifdef _POSIX_VDISABLE - if (!cancel_sigs && tcsetattr(0, TCSANOW, &term) == -1) - nperror("tcsetattr"); -#endif /* _POSIX_VDISABLE */ + do_replace_highlight(TRUE, word); - if (cancel_sigs!=1 && sigaction(SIGINT, &oldaction, NULL) == -1) - nperror("sigaction"); + /* allow replace word to be corrected */ + i = statusq(0, spell_list, last_replace, _("Edit a replacement")); - return 0; -} -#endif /* NANO_SMALL */ + do_replace_highlight(FALSE, word); -int do_exit(void) -{ - int i; + /* start from the start of this line again */ + current = fileage; + current_x = beginx_top; - if (!ISSET(MODIFIED)) { + search_last_line = FALSE; -#ifdef ENABLE_MULTIBUFFER - if (!close_open_file()) { - display_main_list(); - return 1; + if (strcmp(word, answer)) { + j = i; + do_replace_loop(word, fileage, &beginx_top, TRUE, &j); + } } - else -#endif - finish(0); + break; } - if (ISSET(TEMP_OPT)) { - i = 1; - } else { - i = do_yesno(0, 0, - _ - ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? ")); - } + /* restore the search/replace strings */ + free(last_search); last_search=save_search; + free(last_replace); last_replace=save_replace; -#ifdef DEBUG - dump_buffer(fileage); -#endif + /* restore where we were */ + current = begin; + current_x = beginx - 1; - if (i == 1) { - if (do_writeout(filename, 1, 0) > 0) { + /* restore Search/Replace direction */ + if (reverse_search_set) + SET(REVERSE_SEARCH); -#ifdef ENABLE_MULTIBUFFER - if (!close_open_file()) { - display_main_list(); - return 1; - } - else +#ifndef NANO_SMALL + /* restore marking highlight */ + if (mark_set) + SET(MARK_ISSET); #endif - finish(0); - } - } else if (i == 0) { -#ifdef ENABLE_MULTIBUFFER - if (!close_open_file()) { - display_main_list(); - return 1; - } - else -#endif - finish(0); - } else - statusbar(_("Cancelled")); + edit_update(current, CENTER); - display_main_list(); - return 1; + if (i == -1) + return FALSE; + + return TRUE; } -#ifndef DISABLE_MOUSE -#ifdef NCURSES_MOUSE_VERSION -void do_mouse(void) +/* Integrated spell checking using 'spell' program. */ +int do_int_speller(char *tempfile_name) { - MEVENT mevent; - int currslen; - const shortcut *s = currshortcut; + char *read_buff, *read_buff_ptr, *read_buff_word; + size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread; + int in_fd[2], tempfile_fd, spell_status; + pid_t pid_spell; - if (getmouse(&mevent) == ERR) - return; + /* Create a pipe to spell program */ - /* If mouse not in edit or bottom window, return */ - if (wenclose(edit, mevent.y, mevent.x)) { + if (pipe(in_fd) == -1) + return FALSE; - /* Don't let people screw with the marker when they're in a - * subfunction. */ - if (currshortcut != main_list) - return; + /* A new process to run spell in */ - /* Subtract out size of topwin. Perhaps we need a constant - * somewhere? */ - mevent.y -= 2; + if ((pid_spell = fork()) == 0) { - /* Selecting where the cursor is sets the mark. Selecting - * beyond the line length with the cursor at the end of the line - * sets the mark as well. */ - if ((mevent.y == current_y) && - ((mevent.x == current_x) || (current_x == strlen(current->data) - && (mevent.x > - strlen(current->data))))) { - if (ISSET(VIEW_MODE)) { - print_view_warning(); - return; - } - do_mark(); - } else if (mevent.y > current_y) { - while (mevent.y > current_y) { - if (current->next != NULL) - current = current->next; - else - break; - current_y++; - } - } else if (mevent.y < current_y) { - while (mevent.y < current_y) { - if (current->prev != NULL) - current = current->prev; - else - break; - current_y--; - } - } - current_x = actual_x(current, mevent.x); - placewewant = current_x; - update_cursor(); - edit_refresh(); - } else if (wenclose(bottomwin, mevent.y, mevent.x) && !ISSET(NO_HELP)) { - int i, k; + /* Child continues, (i.e. future spell process) */ - if (currshortcut == main_list) - currslen = MAIN_VISIBLE; - else - currslen = length_of_list(currshortcut); + close(in_fd[0]); - if (currslen < 2) - k = COLS / 6; - else - k = COLS / ((currslen + (currslen %2)) / 2); + /* replace the standard in with the tempfile */ - /* Determine what shortcut list was clicked */ - mevent.y -= (editwinrows + 3); + if ((tempfile_fd = open(tempfile_name, O_RDONLY)) == -1) { + close(in_fd[1]); + exit(1); + } + + if (dup2(tempfile_fd, STDIN_FILENO) != STDIN_FILENO) { + close(tempfile_fd); + close(in_fd[1]); + exit(1); + } + close(tempfile_fd); - if (mevent.y < 0) /* They clicked on the statusbar */ - return; + /* send spell's standard out to the pipe */ - /* Don't select stuff beyond list length */ - if (mevent.x / k >= currslen) - return; + if (dup2(in_fd[1], STDOUT_FILENO) != STDOUT_FILENO) { + close(in_fd[1]); + exit(1); + } + close(in_fd[1]); - for (i = 0; i < (mevent.x / k) * 2 + mevent.y; i++) - s = s->next; + /* Start spell program, we are using the PATH here!?!? */ + execlp("spell", "spell", NULL); - /* And ungetch that value */ - ungetch(s->val); + /* Should not be reached, if spell is found!!! */ - /* And if it's an alt-key sequence, we should probably send alt - too ;-) */ - if (s->val >= 'a' && s->val <= 'z') - ungetch(27); + exit(1); } -} -#endif -#endif -/* Handler for SIGHUP */ -RETSIGTYPE handle_hup(int signal) -{ - die(_("Received SIGHUP")); -} + /* Parent continues here */ -/* What do we do when we catch the suspend signal */ -RETSIGTYPE do_suspend(int signal) -{ - endwin(); - printf("\n\n\n\n\nUse \"fg\" to return to nano\n"); - fflush(stdout); + close(in_fd[1]); - /* Restore the terminal settings for the disabled keys */ - tcsetattr(0, TCSANOW, &oldterm); + /* Child process was not forked successfully */ - /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but - then we could be (and were) interrupted in the middle of the call. - So we do it the mutt way instead */ - kill(0, SIGSTOP); -} + if (pid_spell < 0) { + close(in_fd[0]); + return FALSE; + } -/* Restore the suspend handler when we come back into the prog */ -RETSIGTYPE do_cont(int signal) -{ - /* Now we just update the screen instead of having to reenable the - SIGTSTP handler. */ + /* Get system pipe buffer size */ - doupdate(); - /* The Hurd seems to need this, otherwise a ^Y after a ^Z will - start suspending again. */ - signal_init(); + if ((pipe_buff_size = fpathconf(in_fd[0], _PC_PIPE_BUF)) < 1) { + close(in_fd[0]); + return FALSE; + } -#ifndef NANO_SMALL - /* Perhaps the user resized the window while we slept. */ - handle_sigwinch(0); -#endif -} + /* Read-in the returned spelling errors */ -#ifndef NANO_SMALL -void handle_sigwinch(int s) -{ - const char *tty = ttyname(0); - int fd; - int result = 0; - struct winsize win; + read_buff_read = 0; + read_buff_size = pipe_buff_size + 1; + read_buff = read_buff_ptr = charalloc(read_buff_size); - if (!tty) - return; - fd = open(tty, O_RDWR); - if (fd == -1) - return; - result = ioctl(fd, TIOCGWINSZ, &win); - close(fd); - if (result == -1) - return; + while ((bytesread = read(in_fd[0], read_buff_ptr, pipe_buff_size)) > 0) { + read_buff_read += bytesread; + read_buff_size += pipe_buff_size; + read_buff = read_buff_ptr = nrealloc(read_buff, read_buff_size); + read_buff_ptr += read_buff_read; + } - /* Could check whether the COLS or LINES changed, and return - * otherwise. EXCEPT, that COLS and LINES are ncurses global - * variables, and in some cases ncurses has already updated them. - * But not in all cases, argh. */ - COLS = win.ws_col; - LINES = win.ws_row; - if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS) - die_too_small(); + *read_buff_ptr = (char) NULL; + close(in_fd[0]); -#ifndef DISABLE_WRAPJUSTIFY - fill = wrap_at; - if (fill <= 0) - fill += COLS; - if (fill < MIN_FILL_LENGTH) - die_too_small(); -#endif + /* Process the spelling errors */ - hblank = nrealloc(hblank, COLS + 1); - memset(hblank, ' ', COLS); - hblank[COLS] = '\0'; + read_buff_word = read_buff_ptr = read_buff; -#ifdef HAVE_RESIZETERM - resizeterm(LINES, COLS); -#ifdef HAVE_WRESIZE - if (wresize(topwin, 2, COLS) == ERR) - die(_("Cannot resize top win")); - if (mvwin(topwin, 0, 0) == ERR) - die(_("Cannot move top win")); - if (wresize(edit, editwinrows, COLS) == ERR) - die(_("Cannot resize edit win")); - if (mvwin(edit, 2, 0) == ERR) - die(_("Cannot move edit win")); - if (wresize(bottomwin, 3 - no_help(), COLS) == ERR) - die(_("Cannot resize bottom win")); - if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR) - die(_("Cannot move bottom win")); -#endif /* HAVE_WRESIZE */ -#endif /* HAVE_RESIZETERM */ + while (*read_buff_ptr) { - fix_editbot(); + if ((*read_buff_ptr == '\n') || (*read_buff_ptr == '\r')) { + *read_buff_ptr = (char) NULL; + if (read_buff_word != read_buff_ptr) { + if (!do_int_spell_fix(read_buff_word)) { + read_buff_word = read_buff_ptr; + break; + } + } + read_buff_word = read_buff_ptr + 1; + } + read_buff_ptr++; + } - if (current_y > editwinrows - 1) - edit_update(editbot, CENTER); - erase(); + /* special case where last word doesn't end with \n or \r */ + if (read_buff_word != read_buff_ptr) + do_int_spell_fix(read_buff_word); - /* Do these b/c width may have changed... */ - refresh(); - titlebar(NULL); - edit_refresh(); - display_main_list(); - blank_statusbar(); - total_refresh(); + free(read_buff); + replace_abort(); - /* Turn cursor back on for sure */ - curs_set(1); + /* Process end of spell process */ - /* Jump back to main loop */ - siglongjmp(jmpbuf, 1); + wait(&spell_status); + if (WIFEXITED(spell_status)) { + if (WEXITSTATUS(spell_status) != 0) + return FALSE; + } else + return FALSE; + + return TRUE; } -#endif -void signal_init(void) +/* External spell checking. */ +int do_alt_speller(char *tempfile_name) { -#ifdef _POSIX_VDISABLE - struct termios term; + int alt_spell_status, lineno_cur = current->lineno; + int x_cur = current_x, y_cur = current_y, pww_cur = placewewant; + pid_t pid_spell; + char *ptr; + static int arglen = 3; + static char **spellargs = (char **)NULL; +#ifndef NANO_SMALL + int 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) { + mbb_lineno_cur = mark_beginbuf->lineno; + UNSET(MARK_ISSET); + } #endif - /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */ - memset(&act, 0, sizeof(struct sigaction)); - act.sa_handler = SIG_IGN; - sigaction(SIGINT, &act, NULL); + endwin(); - /* Trap SIGHUP cuz we want to write the file out. */ - act.sa_handler = handle_hup; - sigaction(SIGHUP, &act, NULL); + /* Set up an argument list to pass the execvp function */ + if (spellargs == NULL) { + spellargs = nmalloc(arglen * sizeof(char *)); -#ifndef NANO_SMALL - act.sa_handler = handle_sigwinch; - sigaction(SIGWINCH, &act, NULL); -#endif + spellargs[0] = strtok(alt_speller, " "); + while ((ptr = strtok(NULL, " ")) != NULL) { + arglen++; + spellargs = nrealloc(spellargs, arglen * sizeof(char *)); + spellargs[arglen - 3] = ptr; + } + spellargs[arglen - 1] = NULL; + } + spellargs[arglen - 2] = tempfile_name; -#ifdef _POSIX_VDISABLE - tcgetattr(0, &term); + /* Start a new process for the alternate speller */ + if ((pid_spell = fork()) == 0) { + /* Start alternate spell program; we are using the PATH here!?!? */ + execvp(spellargs[0], spellargs); -#ifdef VDSUSP - term.c_cc[VDSUSP] = _POSIX_VDISABLE; -#endif /* VDSUSP */ + /* Should not be reached, if alternate speller is found!!! */ + exit(1); + } -#endif /* _POSIX_VDISABLE */ + /* Could not fork?? */ + if (pid_spell < 0) + return FALSE; + + /* Wait for alternate speller to complete */ + + wait(&alt_spell_status); + if (!WIFEXITED(alt_spell_status) || WEXITSTATUS(alt_spell_status) != 0) + return FALSE; + + refresh(); + free_filestruct(fileage); + global_init(1); + open_file(tempfile_name, 0, 1); + +#ifndef NANO_SMALL + if (mark_set) { + do_gotopos(mbb_lineno_cur, mark_beginx, y_cur, 0); + mark_beginbuf = current; + mark_beginx = current_x; + /* In case the line got shorter, assign mark_beginx. */ + SET(MARK_ISSET); + } +#endif - if (!ISSET(SUSPEND)) { + /* go back to the old position, mark the file as modified, and make + sure that the titlebar is refreshed */ + do_gotopos(lineno_cur, x_cur, y_cur, pww_cur); + set_modified(); + clearok(topwin, FALSE); + titlebar(NULL); -/* Insane! */ -#ifdef _POSIX_VDISABLE - term.c_cc[VSUSP] = _POSIX_VDISABLE; -#else - act.sa_handler = SIG_IGN; - sigaction(SIGTSTP, &act, NULL); + return TRUE; +} #endif - } else { - /* If we don't do this, it seems other stuff interrupts the - suspend handler! Try using nano with mutt without this - line. */ - sigfillset(&act.sa_mask); +int do_spell(void) +{ +#ifdef DISABLE_SPELLER + nano_disabled_msg(); + return (TRUE); +#else + char *temp; + int spell_res; - act.sa_handler = do_suspend; - sigaction(SIGTSTP, &act, NULL); + if ((temp = safe_tempnam(0, "nano.")) == NULL) { + statusbar(_("Could not create a temporary filename: %s"), + strerror(errno)); + return 0; + } - act.sa_handler = do_cont; - sigaction(SIGCONT, &act, NULL); + if (write_file(temp, 1, 0, 0) == -1) { + statusbar(_("Spell checking failed: unable to write temp file!")); + free(temp); + return 0; } -#ifdef _POSIX_VDISABLE - tcsetattr(0, TCSANOW, &term); +#ifdef ENABLE_MULTIBUFFER + /* update the current open_files entry before spell-checking, in case + any problems occur */ + add_open_file(1); #endif -} - -void window_init(void) -{ - if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS) - die_too_small(); - /* Set up the main text window */ - edit = newwin(editwinrows, COLS, 2, 0); + if (alt_speller) + spell_res = do_alt_speller(temp); + else + spell_res = do_int_speller(temp); - /* And the other windows */ - topwin = newwin(2, COLS, 0, 0); - bottomwin = newwin(3 - no_help(), COLS, LINES - 3 + no_help(), 0); + remove(temp); -#ifdef PDCURSES - /* Oops, I guess we need this again. - Moved here so the keypad still works after a Meta-X, for example */ - keypad(edit, TRUE); - keypad(bottomwin, TRUE); -#endif -} + if (spell_res) + statusbar(_("Finished checking spelling")); + else + statusbar(_("Spell checking failed")); -void mouse_init(void) -{ -#ifndef DISABLE_MOUSE -#ifdef NCURSES_MOUSE_VERSION - if (ISSET(USE_MOUSE)) { - keypad_on(edit, 1); - keypad_on(bottomwin, 1); + free(temp); + return spell_res; - mousemask(BUTTON1_RELEASED, NULL); - mouseinterval(50); - } else - mousemask(0, NULL); -#endif #endif } -int do_tab(void) -{ - do_char('\t'); - return 1; -} - #if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY) /* The "indentation" of a line is the white-space between the quote part * and the non-white-space of the line. */ -size_t indent_length(const char *line) { +size_t indent_length(const char *line) +{ size_t len = 0; assert(line != NULL); @@ -2067,17 +2047,11 @@ size_t quote_length(const char *line) } #endif /* !HAVE_REGEX_H */ -#ifdef HAVE_REGEX_H -# define IFREG(a, b) a, b -#else -# define IFREG(a, b) a -#endif - /* a_line and b_line are lines of text. The quotation part of a_line is * the first a_quote characters. Check that the quotation part of * b_line is the same. */ int quotes_match(const char *a_line, size_t a_quote, - IFREG(const char *b_line, const regex_t *qreg)) + IFREG(const char *b_line, const regex_t *qreg)) { /* Here is the assumption about a_quote: */ assert(a_quote == quote_length(IFREG(a_line, qreg))); @@ -2088,7 +2062,7 @@ int quotes_match(const char *a_line, size_t a_quote, /* We assume a_line and b_line have no quote part. Then, we return whether * b_line could follow a_line in a paragraph. */ size_t indents_match(const char *a_line, size_t a_indent, - const char *b_line, size_t b_indent) + const char *b_line, size_t b_indent) { assert(a_indent == indent_length(a_line)); assert(b_indent == indent_length(b_line)); @@ -2101,7 +2075,7 @@ size_t indents_match(const char *a_line, size_t a_indent, * copies of the lines in place, too. We return the new copy of * first_line. */ filestruct *backup_lines(filestruct *first_line, size_t par_len, - size_t quote_len) + size_t quote_len) { /* We put the original lines, not copies, into the cut buffer, just * out of a misguided sense of consistency, so if you un-cut, you @@ -2515,7 +2489,7 @@ int do_justify(void) reset_cursor(); /* Now get a keystroke and see if it's unjustify; if not, unget the - * keystroke and return */ + * keystroke and return. */ #ifndef DISABLE_MOUSE #ifdef NCURSES_MOUSE_VERSION @@ -2585,207 +2559,249 @@ int do_justify(void) #endif } -#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) +int do_exit(void) { - size_t allocsize = 1; /* space needed for help_text */ - char *ptr = NULL; -#ifndef NANO_SMALL - const toggle *t; + int i; + + if (!ISSET(MODIFIED)) { + +#ifdef ENABLE_MULTIBUFFER + if (!close_open_file()) { + display_main_list(); + return 1; + } + else #endif - const shortcut *s; + finish(0); + } - /* First set up the initial help text for the current function */ - if (currshortcut == whereis_list || currshortcut == replace_list - || currshortcut == replace_list_2) - ptr = _("Search Command Help Text\n\n " - "Enter the words or characters you would like to search " - "for, then hit 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 " - "If using Pico Mode via the -p or --pico flags, the " - "Meta-P toggle, or a nanorc file, the previous search " - "string will be shown in brackets after the Search: prompt. " - "Hitting Enter without entering any text will perform the " - "previous search. Otherwise, the previous string will be " - "placed before the cursor, and can be edited or deleted " - "before hitting enter.\n\n The following function keys are " - "available in Search mode:\n\n"); - else if (currshortcut == goto_list) - ptr = _("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"); - else if (currshortcut == insertfile_list) - ptr = _("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 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).\n\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"); - else if (currshortcut == writefile_list) - ptr = _("Write File Help Text\n\n " - "Type the name that you wish to save the current file " - "as and hit Enter to save the file.\n\n If you have " - "selected text with Ctrl-^, 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"); -#ifndef DISABLE_BROWSER - else if (currshortcut == browser_list) - ptr = _("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"); - else if (currshortcut == gotodir_list) - ptr = _("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"); + if (ISSET(TEMP_OPT)) { + i = 1; + } else { + i = do_yesno(0, 0, + _ + ("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? ")); + } + +#ifdef DEBUG + dump_buffer(fileage); #endif - else if (currshortcut == spell_list) - ptr = _("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.\n\n The following other functions are " - "available in Spell Check mode:\n\n"); + + if (i == 1) { + if (do_writeout(filename, 1, 0) > 0) { + +#ifdef ENABLE_MULTIBUFFER + if (!close_open_file()) { + display_main_list(); + return 1; + } + else +#endif + finish(0); + } + } else if (i == 0) { + +#ifdef ENABLE_MULTIBUFFER + if (!close_open_file()) { + display_main_list(); + return 1; + } + else +#endif + finish(0); + } else + statusbar(_("Cancelled")); + + display_main_list(); + return 1; +} + +void signal_init(void) +{ +#ifdef _POSIX_VDISABLE + struct termios term; +#endif + + /* Trap SIGINT and SIGQUIT cuz we want them to do useful things. */ + memset(&act, 0, sizeof(struct sigaction)); + act.sa_handler = SIG_IGN; + sigaction(SIGINT, &act, NULL); + + /* Trap SIGHUP cuz we want to write the file out. */ + act.sa_handler = handle_hup; + sigaction(SIGHUP, &act, NULL); + #ifndef NANO_SMALL - else if (currshortcut == extcmd_list) - ptr = _("External 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 multibuffer mode).\n\n The following keys are " - "available in this mode:\n\n"); + act.sa_handler = handle_sigwinch; + sigaction(SIGWINCH, &act, NULL); #endif - else /* Default to the main help list */ - ptr = _(" 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 " - "The notation for shortcuts is as follows: Control-key " - "sequences are notated with a caret (^) symbol and are entered " - "with the Control (Ctrl) key. 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. The " - "following keystrokes are available in the main editor window. " - "Alternative keys are shown in parentheses:\n\n"); - allocsize += strlen(ptr); +#ifdef _POSIX_VDISABLE + tcgetattr(0, &term); - /* The space needed for the shortcut lists, at most COLS characters, - * plus '\n'. */ - allocsize += (COLS + 1) * length_of_list(currshortcut); +#ifdef VDSUSP + term.c_cc[VDSUSP] = _POSIX_VDISABLE; +#endif /* VDSUSP */ -#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 at most - * COLS - 24 characters, plus '\n'.*/ - if (currshortcut == main_list) - for (t = toggles; t != NULL; t = t->next) - allocsize += COLS - 17; -#endif /* !NANO_SMALL */ +#endif /* _POSIX_VDISABLE */ - /* help_text has been freed and set to NULL unless the user resized - * while in the help screen. */ - free(help_text); + if (!ISSET(SUSPEND)) { - /* Allocate space for the help text */ - help_text = charalloc(allocsize); +/* Insane! */ +#ifdef _POSIX_VDISABLE + term.c_cc[VSUSP] = _POSIX_VDISABLE; +#else + act.sa_handler = SIG_IGN; + sigaction(SIGTSTP, &act, NULL); +#endif - /* Now add the text we want */ - strcpy(help_text, ptr); - ptr = help_text + strlen(help_text); + } else { + /* If we don't do this, it seems other stuff interrupts the + suspend handler! Try using nano with mutt without this + line. */ + sigfillset(&act.sa_mask); - /* Now add our shortcut info */ - for (s = currshortcut; s != NULL; s = s->next) { - /* true if the character in s->altval is shown in first column */ - int meta_shortcut = 0; + act.sa_handler = do_suspend; + sigaction(SIGTSTP, &act, NULL); - if (s->val > 0 && s->val < 32) - ptr += sprintf(ptr, "^%c", s->val + 64); -#ifndef NANO_SMALL - else if (s->val == NANO_CONTROL_SPACE) - ptr += sprintf(ptr, "^%.6s", _("Space")); - else if (s->altval == NANO_ALT_SPACE) { - meta_shortcut = 1; - ptr += sprintf(ptr, "M-%.5s", _("Space")); - } + act.sa_handler = do_cont; + sigaction(SIGCONT, &act, NULL); + } + +#ifdef _POSIX_VDISABLE + tcsetattr(0, TCSANOW, &term); #endif - else if (s->altval > 0) { - meta_shortcut = 1; - ptr += sprintf(ptr, "M-%c", s->altval - - (('A' <= s->altval && s->altval <= 'Z') || - 'a' <= s->altval ? 32 : 0)); - } - /* Hack */ - else if (s->val >= 'a') { - meta_shortcut = 1; - ptr += sprintf(ptr, "M-%c", s->val - 32); - } +} - *(ptr++) = '\t'; +/* Handler for SIGHUP */ +RETSIGTYPE handle_hup(int signal) +{ + die(_("Received SIGHUP")); +} - if (s->misc1 > KEY_F0 && s->misc1 <= KEY_F(64)) - ptr += sprintf(ptr, "(F%d)", s->misc1 - KEY_F0); +/* What do we do when we catch the suspend signal */ +RETSIGTYPE do_suspend(int signal) +{ + endwin(); + printf("\n\n\n\n\nUse \"fg\" to return to nano\n"); + fflush(stdout); - *(ptr++) = '\t'; + /* Restore the terminal settings for the disabled keys */ + tcsetattr(0, TCSANOW, &oldterm); - if (!meta_shortcut && s->altval > 0) - ptr += sprintf(ptr, "(M-%c)", s->altval - - (('A' <= s->altval && s->altval <= 'Z') || 'a' <= s->altval - ? 32 : 0)); + /* We used to re-enable the default SIG_DFL and raise SIGTSTP, but + then we could be (and were) interrupted in the middle of the call. + So we do it the mutt way instead */ + kill(0, SIGSTOP); +} - *(ptr++) = '\t'; +/* Restore the suspend handler when we come back into the prog */ +RETSIGTYPE do_cont(int signal) +{ + /* Now we just update the screen instead of having to reenable the + SIGTSTP handler. */ - assert(s->help != NULL); - ptr += sprintf(ptr, "%.*s\n", COLS - 24, s->help); - } + doupdate(); + /* The Hurd seems to need this, otherwise a ^Y after a ^Z will + start suspending again. */ + signal_init(); #ifndef NANO_SMALL - /* And the toggles... */ - if (currshortcut == main_list) - for (t = toggles; t != NULL; t = t->next) { - ptr += sprintf(ptr, "M-%c\t\t\t", t->val - 32); - assert(t->desc != NULL); - ptr += sprintf(ptr, _("%.*s enable/disable\n"), COLS - 24, t->desc); - } + /* Perhaps the user resized the window while we slept. */ + handle_sigwinch(0); +#endif +} + +#ifndef NANO_SMALL +void handle_sigwinch(int s) +{ + const char *tty = ttyname(0); + int fd; + int result = 0; + struct winsize win; + + if (!tty) + return; + fd = open(tty, O_RDWR); + if (fd == -1) + return; + result = ioctl(fd, TIOCGWINSZ, &win); + close(fd); + if (result == -1) + return; + + /* Could check whether the COLS or LINES changed, and return + * otherwise. EXCEPT, that COLS and LINES are ncurses global + * variables, and in some cases ncurses has already updated them. + * But not in all cases, argh. */ + COLS = win.ws_col; + LINES = win.ws_row; + if ((editwinrows = LINES - 5 + no_help()) < MIN_EDITOR_ROWS) + die_too_small(); + +#ifndef DISABLE_WRAPJUSTIFY + fill = wrap_at; + if (fill <= 0) + fill += COLS; + if (fill < MIN_FILL_LENGTH) + die_too_small(); +#endif + + hblank = nrealloc(hblank, COLS + 1); + memset(hblank, ' ', COLS); + hblank[COLS] = '\0'; + +#ifdef HAVE_RESIZETERM + resizeterm(LINES, COLS); +#ifdef HAVE_WRESIZE + if (wresize(topwin, 2, COLS) == ERR) + die(_("Cannot resize top win")); + if (mvwin(topwin, 0, 0) == ERR) + die(_("Cannot move top win")); + if (wresize(edit, editwinrows, COLS) == ERR) + die(_("Cannot resize edit win")); + if (mvwin(edit, 2, 0) == ERR) + die(_("Cannot move edit win")); + if (wresize(bottomwin, 3 - no_help(), COLS) == ERR) + die(_("Cannot resize bottom win")); + if (mvwin(bottomwin, LINES - 3 + no_help(), 0) == ERR) + die(_("Cannot move bottom win")); +#endif /* HAVE_WRESIZE */ +#endif /* HAVE_RESIZETERM */ + + fix_editbot(); + + if (current_y > editwinrows - 1) + edit_update(editbot, CENTER); + erase(); + + /* Do these b/c width may have changed... */ + refresh(); + titlebar(NULL); + edit_refresh(); + display_main_list(); + blank_statusbar(); + total_refresh(); + + /* Turn cursor back on for sure */ + curs_set(1); + + /* Jump back to main loop */ + siglongjmp(jmpbuf, 1); +} #endif /* !NANO_SMALL */ - /* If all went well, we didn't overwrite the allocated space for - help_text. */ - assert(strlen(help_text) < allocsize); +/* If the NumLock key has made the keypad go awry, print an error + message; hopefully we can address it later. */ +void print_numlock_warning(void) +{ + static int didmsg = 0; + if (!didmsg) { + statusbar(_ + ("NumLock glitch detected. Keypad will malfunction with NumLock off")); + didmsg = 1; + } } -#endif #ifndef NANO_SMALL void do_toggle(const toggle *which) @@ -2833,18 +2849,6 @@ void do_toggle(const toggle *which) } #endif /* !NANO_SMALL */ -/* If the NumLock key has made the keypad go awry, print an error - message; hopefully we can address it later. */ -void print_numlock_warning(void) -{ - static int didmsg = 0; - if (!didmsg) { - statusbar(_ - ("NumLock glitch detected. Keypad will malfunction with NumLock off")); - didmsg = 1; - } -} - /* This function returns the correct keystroke, given the A,B,C or D input key. This is a common sequence of many terms which send Esc-O-[A-D] or Esc-[-[A-D]. */ @@ -3460,7 +3464,7 @@ int main(int argc, char *argv[]) /* Look through the main shortcut list to see if we've hit a shortcut key */ - + #if !defined(DISABLE_BROWSER) || !defined(DISABLE_MOUSE) || !defined (DISABLE_HELP) for (s = currshortcut; s != NULL && !keyhandled; s = s->next) { #else @@ -3474,6 +3478,10 @@ int main(int argc, char *argv[]) else s->func(); keyhandled = 1; + /* rarely, the value of s can change after s->func(), + leading to problems; get around this by breaking out + explicitly once we successfully handle a shortcut */ + break; } } /* If we're in raw mode or using Alt-Alt-x, we have to catch @@ -3489,7 +3497,6 @@ int main(int argc, char *argv[]) keyhandled = 1; } - #ifndef USE_SLANG /* Hack, make insert key do something useful, like insert file */ if (kbinput == KEY_IC) { diff --git a/nano.h b/nano.h index bc34f89f..74179e6f 100644 --- a/nano.h +++ b/nano.h @@ -326,6 +326,7 @@ know what you're doing */ #define NANO_TOFILES_KEY NANO_CONTROL_T #define NANO_APPEND_KEY NANO_ALT_A #define NANO_PREPEND_KEY NANO_ALT_P +#define NANO_LOAD_KEY NANO_ALT_F #define NANO_OPENPREV_KEY NANO_ALT_LCARAT #define NANO_OPENNEXT_KEY NANO_ALT_RCARAT #define NANO_OPENPREV_ALTKEY NANO_ALT_COMMA diff --git a/proto.h b/proto.h index c8079e61..63ba5800 100644 --- a/proto.h +++ b/proto.h @@ -59,13 +59,7 @@ extern char *operating_dir; extern char *full_operating_dir; #endif #ifndef DISABLE_SPELLER -extern char *alt_speller; -#endif -#ifndef DISABLE_TABCOMP -char *real_dir_from_tilde(char *buf); -#endif -#ifndef DISABLE_BROWSER -char *do_browse_from(char *inpath); +extern char *alt_speller; #endif extern struct stat fileinfo; @@ -116,23 +110,28 @@ extern toggle *toggles; /* Public functions in color.c */ #ifdef ENABLE_COLOR -void set_colorpairs(void); void do_colorinit(void); void update_color(void); #endif /* ENABLE_COLOR */ /* Public functions in cut.c */ -int do_cut_text(void); -int do_uncut_text(void); filestruct *get_cutbottom(void); void add_to_cutbuffer(filestruct *inptr); void cut_marked_segment(filestruct *top, size_t top_x, filestruct *bot, size_t bot_x, int destructive); +int do_cut_text(void); +int 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, int len); int write_file(char *name, int tmpfile, int append, int nonamechange); -int open_file(const char *filename, int insert, int quiet); int read_file(FILE *f, const char *filename, int quiet); +int open_file(const char *filename, int insert, int quiet); +char *get_next_filename(const char *name); +int do_insertfile(int loading_file); +int do_insertfile_void(void); #ifdef ENABLE_MULTIBUFFER openfilestruct *make_new_opennode(openfilestruct *prevnode); void splice_opennode(openfilestruct *begin, openfilestruct *newnode, openfilestruct *end); @@ -140,157 +139,299 @@ void unlink_opennode(const openfilestruct *fileptr); void delete_opennode(openfilestruct *fileptr); void free_openfilestruct(openfilestruct *src); int add_open_file(int update); -int close_open_file(void); +int load_open_file(void); +int open_prevfile(int closing_file); int open_prevfile_void(void); +int open_nextfile(int closing_file); int open_nextfile_void(void); +int close_open_file(void); +#endif +#if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR) +char *get_full_path(char *origpath); +#endif +#ifndef DISABLE_SPELLER +char *check_writable_directory(char *path); +char *safe_tempnam(const char *dirname, const char *filename_prefix); #endif #ifndef DISABLE_OPERATINGDIR int check_operating_dir(char *currpath, int allow_tabcomp); #endif +int write_file(char *name, int tmp, int append, int nonamechange); int do_writeout(char *path, int exiting, int append); -char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list); -void new_file(void); int do_writeout_void(void); -int do_insertfile_void(void); -char *get_next_filename(const char *name); -#ifndef DISABLE_SPELLER -char *safe_tempnam(const char *dirname, const char *filename_prefix); +#ifndef DISABLE_TABCOMP +char *real_dir_from_tilde(char *buf); +#endif +int append_slash_if_dir(char *buf, int *lastwastab, int *place); +char **username_tab_completion(char *buf, int *num_matches); +char **cwd_tab_completion(char *buf, int *num_matches); +char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list); +#ifndef DISABLE_BROWSER +struct stat filestat(const char *path); +int diralphasort(const void *va, const void *vb); +void free_charptrarray(char **array, int len); +char *tail(char *foo); +void striponedir(char *foo); +char **browser_init(char *path, int *longest, int *numents); +char *do_browser(char *inpath); +char *do_browse_from(char *inpath); #endif /* Public functions in global.c */ int length_of_list(const shortcut *s); +void sc_init_one(shortcut **shortcutage, int key, const char *desc, +#ifndef DISABLE_HELP + const char *help, +#endif + int alt, int misc1, int misc2, int view, int (*func) (void)); +#ifndef NANO_SMALL +void toggle_init_one(int val, const char *desc, int flag); +void toggle_init(void); +#ifdef DEBUG +void free_toggles(void); +#endif +#endif +void free_shortcutage(shortcut **shortcutage); void shortcut_init(int unjustify); #ifdef DEBUG void thanks_for_all_the_fish(void); #endif /* Public functions in move.c */ -int do_first_line(void); -int do_last_line(void); -size_t xplustabs(void); -size_t actual_x(const filestruct *fileptr, size_t xplus); -size_t strnlenpt(const char *buf, size_t size); -size_t strlenpt(const char *buf); -void reset_cursor(void); -void blank_bottombars(void); -void blank_edit(void); -void blank_statusbar(void); -void blank_statusbar_refresh(void); -void check_statblank(void); -void titlebar(const char *path); -void bottombars(const shortcut *s); -void set_modified(void); +int do_home(void); +int do_end(void); +void page_up(void); +int do_page_up(void); +int do_page_down(void); int do_up(void); int do_down(void); int do_left(void); int do_right(void); -void page_up(void); -int do_page_up(void); -int do_page_down(void); -int do_home(void); -int do_end(void); /* Public functions in nano.c */ -void renumber(filestruct *fileptr); +RETSIGTYPE finish(int sigage); +void die(const char *msg, ...); +void die_save_file(const char *die_filename); +void die_too_small(void); +void print_view_warning(void); +void global_init(int save_cutbuffer); +void window_init(void); +void mouse_init(void); +#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 *end); +void unlink_node(const filestruct *fileptr); +void delete_node(filestruct *fileptr); +filestruct *copy_filestruct(const filestruct *src); void free_filestruct(filestruct *src); -int no_help(void); void renumber_all(void); -int open_pipe(const char *command); -int do_prev_word(void); -int do_next_word(void); -void delete_node(filestruct *fileptr); -void wrap_reset(void); +void renumber(filestruct *fileptr); +void print1opt(const char *shortflag, const char *longflag, + const char *desc); +void usage(void); +void version(void); void do_early_abort(void); -void die(const char *msg, ...); -void splice_node(filestruct *begin, filestruct *newnode, filestruct *end); +int no_help(void); +#if defined(DISABLE_JUSTIFY) || defined(DISABLE_SPELLER) || defined(DISABLE_HELP) || defined(NANO_SMALL) void nano_disabled_msg(void); -void window_init(void); +#endif +#ifndef NANO_SMALL +RETSIGTYPE cancel_fork(int signal); +int open_pipe(const char *command); +#endif +#ifndef DISABLE_MOUSE +#ifdef NCURSES_MOUSE_VERSION void do_mouse(void); -void print_view_warning(void); -int do_exit(void); -int do_spell(void); -int do_mark(void); -int do_delete(void); +#endif +#endif +void do_char(char ch); int do_backspace(void); +int do_delete(void); int do_tab(void); -int do_justify(void); int do_enter(void); +int do_next_word(void); +int do_prev_word(void); +int do_mark(void); +void wrap_reset(void); +#ifndef DISABLE_WRAPPING int do_wrap(filestruct *inptr); +#endif +#ifndef DISABLE_SPELLER +int do_int_spell_fix(const char *word); +int do_int_speller(char *tempfile_name); +int do_alt_speller(char *tempfile_name); +#endif +int do_spell(void); +#if !defined(DISABLE_WRAPPING) && !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY) +size_t indent_length(const char *line); +#endif +#ifndef DISABLE_JUSTIFY +int justify_format(int changes_allowed, filestruct *line, size_t skip); +#ifdef HAVE_REGEX_H +size_t quote_length(const char *line, const regex_t *qreg); +#else +size_t quote_length(const char *line); +#endif +#ifdef HAVE_REGEX_H +# define IFREG(a, b) a, b +#else +# define IFREG(a, b) a +#endif +int quotes_match(const char *a_line, size_t a_quote, + IFREG(const char *b_line, const regex_t *qreg)); +size_t indents_match(const char *a_line, size_t a_indent, + const char *b_line, size_t b_indent); +filestruct *backup_lines(filestruct *first_line, size_t par_len, + size_t quote_len); +int break_line(const char *line, int goal, int force); +#endif /* !DISABLE_JUSTIFY */ +int do_justify(void); +int do_exit(void); void signal_init(void); +RETSIGTYPE handle_hup(int signal); +RETSIGTYPE do_suspend(int signal); +RETSIGTYPE do_cont(int signal); +#ifndef NANO_SMALL void handle_sigwinch(int s); -void die_save_file(const char *die_filename); -size_t indent_length(const char *line); - -filestruct *copy_node(const filestruct *src); -filestruct *copy_filestruct(const filestruct *src); -filestruct *make_new_node(filestruct *prevnode); -#ifndef DISABLE_HELP -void help_init(void); #endif +void print_numlock_warning(void); +#ifndef NANO_SMALL +void do_toggle(const toggle *which); +#endif +int ABCD(int input); /* Public functions in rcfile.c */ #ifdef ENABLE_NANORC +void rcfile_error(const char *msg, ...); +void rcfile_msg(const char *msg, ...); +char *parse_next_word(char *ptr); +char *parse_argument(char *ptr); +#ifdef ENABLE_COLOR +int colortoint(const char *colorname, int *bright); +char *parse_next_regex(char *ptr); +void parse_syntax(char *ptr); +void parse_colors(char *ptr); +#endif /* ENABLE_COLOR */ +void parse_rcfile(FILE *rcstream); void do_rcfile(void); -#endif +#endif /* ENABLE_NANORC */ /* Public functions in search.c */ -int do_gotoline(int line, int save_pos); +#ifdef HAVE_REGEX_H +void regexp_init(const char *regexp); +void regexp_cleanup(void); +#endif +void not_found_msg(const char *str); +void search_abort(void); +void search_init_globals(void); +int search_init(int replacing); int is_whole_word(int curr_pos, const char *datastr, const char *searchword); +filestruct *findnextstr(int quiet, int bracket_mode, + const filestruct *begin, int beginx, + const char *needle); +int do_search(void); +void replace_abort(void); +#ifdef HAVE_REGEX_H +int replace_regexp(char *string, int create_flag); +#endif +char *replace_line(void); +void print_replaced(int num); int do_replace_loop(const char *prevanswer, const filestruct *begin, int *beginx, int wholewords, int *i); -int do_find_bracket(void); +int do_replace(void); +void goto_abort(void); +int do_gotoline(int line, int save_pos); +int do_gotoline_void(void); #if defined (ENABLE_MULTIBUFFER) || !defined (DISABLE_SPELLER) void do_gotopos(int line, int pos_x, int pos_y, int pos_placewewant); #endif -void search_init_globals(void); -void replace_abort(void); -int do_gotoline_void(void); -int do_search(void); -int do_replace(void); -filestruct *findnextstr(int quiet, int bracket_mode, const filestruct *begin, - int beginx, const char *needle); +int do_find_bracket(void); /* Public functions in utils.c */ -const char *stristr(const char *haystack, const char *needle); -const char *strstrwrapper(const char *haystack, const char *needle, - const char *rev_start, int line_pos); int is_cntrl_char(int c); int num_of_digits(int n); -int check_wildcard_match(const char *text, const char *pattern); void align(char **strp); void null_at(char **data, size_t index); void unsunder(char *str, size_t true_len); void sunder(char *str); +#ifndef NANO_SMALL +const char *revstrstr(const char *haystack, const char *needle, + const char *rev_start); +const char *revstristr(const char *haystack, const char *needle, + const char *rev_start); +#endif +const char *stristr(const char *haystack, const char *needle); +const char *strstrwrapper(const char *haystack, const char *needle, + const char *rev_start, int line_pos); void nperror(const char *s); -char *mallocstrcpy(char *dest, const char *src); void *nmalloc(size_t howmuch); +char *charalloc(size_t howmuch); void *nrealloc(void *ptr, size_t howmuch); +char *mallocstrcpy(char *dest, const char *src); void new_magicline(void); -char *charalloc(size_t howmuch); +#ifndef DISABLE_TABCOMP +int check_wildcard_match(const char *text, const char *pattern); +#endif /* Public functions in winio.c */ -int do_yesno(int all, int leavecursor, const char *msg, ...); -int statusq(int allowtabs, const shortcut *s, const char *def, - const char *msg, ...); -void do_replace_highlight(int highlight_flag, const char *word); +int do_first_line(void); +int do_last_line(void); +int xpt(const filestruct *fileptr, int index); +size_t xplustabs(void); +size_t actual_x(const filestruct *fileptr, size_t xplus); +size_t strnlenpt(const char *buf, size_t size); +size_t strlenpt(const char *buf); +void blank_bottombars(void); +void blank_bottomwin(void); +void blank_edit(void); +void blank_statusbar(void); +void blank_statusbar_refresh(void); +void check_statblank(void); +void nanoget_repaint(const char *buf, const char *inputbuf, int x); +int nanogetstr(int allowtabs, const char *buf, const char *def, + const shortcut *s +#ifndef DISABLE_TABCOMP + , int *list +#endif + ); +void set_modified(void); +void titlebar(const char *path); +void bottombars(const shortcut *s); +void onekey(const char *keystroke, const char *desc, int len); +int get_page_start_virtual(int page); +int get_page_from_virtual(int virtual); +int get_page_end_virtual(int page); +int get_page_start(int column); +void reset_cursor(void); +void add_marked_sameline(int begin, int end, filestruct *fileptr, int y, + int virt_cur_x, int this_page); +void edit_add(filestruct *fileptr, int yval, int start, int virt_cur_x, + int virt_mark_beginx, int this_page); +void update_line(filestruct *fileptr, int index); +void update_cursor(void); +void center_cursor(void); void edit_refresh(void); void edit_refresh_clearok(void); void edit_update(filestruct *fileptr, topmidbotnone location); -void update_cursor(void); +int statusq(int tabs, const shortcut *s, const char *def, + const char *msg, ...); +int do_yesno(int all, int leavecursor, const char *msg, ...); +int total_refresh(void); +void display_main_list(void); +void statusbar(const char *msg, ...); +int do_cursorpos(int constant); +int do_cursorpos_void(void); +int do_help(void); +int keypad_on(WINDOW *win, int newval); +void do_replace_highlight(int highlight_flag, const char *word); +void fix_editbot(void); #ifdef DEBUG void dump_buffer(const filestruct *inptr); void dump_buffer_reverse(void); #endif -void update_line(filestruct *fileptr, int index); -void fix_editbot(void); -void statusbar(const char *msg, ...); -void center_cursor(void); -void display_main_list(void); #ifdef NANO_EXTRA void do_credits(void); #endif -int do_cursorpos(int constant); -int do_cursorpos_void(void); -int total_refresh(void); -int do_help(void); -int keypad_on(WINDOW *win, int newval); diff --git a/rcfile.c b/rcfile.c index 6b7b1e7f..26c5e359 100644 --- a/rcfile.c +++ b/rcfile.c @@ -188,24 +188,6 @@ char *parse_argument(char *ptr) #ifdef ENABLE_COLOR -char *parse_next_regex(char *ptr) -{ - while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n')) - && *ptr != '\n' && *ptr != '\0') - ptr++; - - if (*ptr == '\0') - return NULL; - - /* Null terminate and advance ptr */ - *ptr++ = '\0'; - - while (*ptr == ' ' || *ptr == '\t') - ptr++; - - return ptr; -} - int colortoint(const char *colorname, int *bright) { int mcolor = 0; @@ -245,6 +227,24 @@ int colortoint(const char *colorname, int *bright) return mcolor; } +char *parse_next_regex(char *ptr) +{ + while ((*ptr != '"' || (*(ptr + 1) != ' ' && *(ptr + 1) != '\n')) + && *ptr != '\n' && *ptr != '\0') + ptr++; + + if (*ptr == '\0') + return NULL; + + /* Null terminate and advance ptr */ + *ptr++ = '\0'; + + while (*ptr == ' ' || *ptr == '\t') + ptr++; + + return ptr; +} + void parse_syntax(char *ptr) { syntaxtype *tmpsyntax = NULL; diff --git a/search.c b/search.c index fe080bd2..319cfa18 100644 --- a/search.c +++ b/search.c @@ -53,6 +53,33 @@ void regexp_cleanup(void) } #endif +void not_found_msg(const char *str) +{ + if (strlen(str) <= COLS / 2) + statusbar(_("\"%s\" not found"), str); + else { + char *foo = mallocstrcpy(NULL, str); + + foo[COLS / 2] = '\0'; + statusbar(_("\"%s...\" not found"), foo); + free(foo); + } +} + +void search_abort(void) +{ + UNSET(KEEP_CUTBUFFER); + display_main_list(); + wrefresh(bottomwin); + if (ISSET(MARK_ISSET)) + edit_refresh_clearok(); + +#ifdef HAVE_REGEX_H + if (ISSET(REGEXP_COMPILED)) + regexp_cleanup(); +#endif +} + void search_init_globals(void) { if (last_search == NULL) { @@ -67,10 +94,11 @@ void search_init_globals(void) /* Set up the system variables for a search or replace. Returns -1 on abort, 0 on success, and 1 on rerun calling program - Return -2 to run opposite program (search -> replace, replace -> search) + Return -2 to run opposite program (search -> replace, replace -> + search). - replacing = 1 if we call from do_replace, 0 if called from do_search func. -*/ + replacing = 1 if we call from do_replace, 0 if called from do_search + func. */ int search_init(int replacing) { int i = 0; @@ -196,19 +224,6 @@ int search_init(int replacing) return 0; } -void not_found_msg(const char *str) -{ - if (strlen(str) <= COLS / 2) - statusbar(_("\"%s\" not found"), str); - else { - char *foo = mallocstrcpy(NULL, str); - - foo[COLS / 2] = '\0'; - statusbar(_("\"%s...\" not found"), foo); - free(foo); - } -} - int is_whole_word(int curr_pos, const char *datastr, const char *searchword) { size_t sln = curr_pos + strlen(searchword); @@ -223,7 +238,8 @@ static int past_editbuff; /* findnextstr() is now searching lines not displayed */ filestruct *findnextstr(int quiet, int bracket_mode, - const filestruct *begin, int beginx, const char *needle) + const filestruct *begin, int beginx, + const char *needle) { filestruct *fileptr = current; const char *searchstr, *rev_start = NULL, *found = NULL; @@ -363,20 +379,6 @@ filestruct *findnextstr(int quiet, int bracket_mode, return fileptr; } -void search_abort(void) -{ - UNSET(KEEP_CUTBUFFER); - display_main_list(); - wrefresh(bottomwin); - if (ISSET(MARK_ISSET)) - edit_refresh_clearok(); - -#ifdef HAVE_REGEX_H - if (ISSET(REGEXP_COMPILED)) - regexp_cleanup(); -#endif -} - /* Search for a string. */ int do_search(void) { @@ -430,14 +432,6 @@ int do_search(void) return 1; } -void print_replaced(int num) -{ - if (num > 1) - statusbar(_("Replaced %d occurrences"), num); - else if (num == 1) - statusbar(_("Replaced 1 occurrence")); -} - void replace_abort(void) { /* Identical to search_abort, so we'll call it here. If it @@ -561,6 +555,14 @@ char *replace_line(void) return copy; } +void print_replaced(int num) +{ + if (num > 1) + statusbar(_("Replaced %d occurrences"), num); + else if (num == 1) + statusbar(_("Replaced 1 occurrence")); +} + /* step through each replace word and prompt user before replacing word */ int do_replace_loop(const char *prevanswer, const filestruct *begin, int *beginx, int wholewords, int *i) diff --git a/utils.c b/utils.c index 83ea2670..acd67a11 100644 --- a/utils.c +++ b/utils.c @@ -97,7 +97,7 @@ void sunder(char *str) /* None of this is needed if we're using NANO_SMALL! */ #ifndef NANO_SMALL const char *revstrstr(const char *haystack, const char *needle, - const char *rev_start) + const char *rev_start) { for(; rev_start >= haystack ; rev_start--) { const char *r, *q; @@ -111,7 +111,7 @@ const char *revstrstr(const char *haystack, const char *needle, } const char *revstristr(const char *haystack, const char *needle, - const char *rev_start) + const char *rev_start) { for (; rev_start >= haystack; rev_start--) { const char *r = rev_start, *q = needle; @@ -147,7 +147,7 @@ const char *stristr(const char *haystack, const char *needle) } const char *strstrwrapper(const char *haystack, const char *needle, - const char *rev_start, int line_pos) + const char *rev_start, int line_pos) { #ifdef HAVE_REGEX_H if (ISSET(USE_REGEXP)) { @@ -195,7 +195,8 @@ const char *strstrwrapper(const char *haystack, const char *needle, /* This is a wrapper for the perror function. The wrapper takes care of * ncurses, calls perror (which writes to STDERR), then refreshes the * screen. Note that nperror causes the window to flicker once. */ -void nperror(const char *s) { +void nperror(const char *s) +{ /* leave ncurses mode, go to the terminal */ if (endwin() != ERR) { perror(s); /* print the error */ diff --git a/winio.c b/winio.c index 2657f391..57609c31 100644 --- a/winio.c +++ b/winio.c @@ -155,6 +155,15 @@ void blank_bottombars(void) } } +void blank_bottomwin(void) +{ + if (ISSET(NO_HELP)) + return; + + mvwaddstr(bottomwin, 1, 0, hblank); + mvwaddstr(bottomwin, 2, 0, hblank); +} + void blank_edit(void) { int i; @@ -210,11 +219,11 @@ void nanoget_repaint(const char *buf, const char *inputbuf, int x) /* Get the input from the kb; this should only be called from * statusq(). */ int nanogetstr(int allowtabs, const char *buf, const char *def, - const shortcut *s + const shortcut *s #ifndef DISABLE_TABCOMP - , int *list + , int *list #endif - ) + ) { int kbinput; int x; @@ -241,7 +250,8 @@ int nanogetstr(int allowtabs, const char *buf, const char *def, nanoget_repaint(buf, answer, x); - /* Make sure any editor screen updates are displayed before getting input */ + /* Make sure any editor screen updates are displayed before getting + input */ wrefresh(edit); while ((kbinput = wgetch(bottomwin)) != 13) { @@ -253,7 +263,8 @@ int nanogetstr(int allowtabs, const char *buf, const char *def, if (kbinput == t->val && kbinput < 32) { #ifndef DISABLE_HELP - /* Have to do this here, it would be too late to do it in statusq */ + /* Have to do this here, it would be too late to do it + in statusq() */ if (kbinput == NANO_HELP_KEY || kbinput == NANO_HELP_FKEY) { do_help(); break; @@ -435,6 +446,16 @@ int nanogetstr(int allowtabs, const char *buf, const char *def, return 0; } +/* If modified is not already set, set it and update titlebar. */ +void set_modified(void) +{ + if (!ISSET(MODIFIED)) { + SET(MODIFIED); + titlebar(NULL); + wrefresh(topwin); + } +} + void titlebar(const char *path) { int namelen, space; @@ -483,35 +504,6 @@ void titlebar(const char *path) reset_cursor(); } -/* Write a shortcut key to the help area at the bottom of the window. - * keystroke is e.g. "^G" and desc is e.g. "Get Help". - * We are careful to write exactly len characters, even if len is - * very small and keystroke and desc are long. */ -void onekey(const char *keystroke, const char *desc, int len) -{ - wattron(bottomwin, A_REVERSE); - waddnstr(bottomwin, keystroke, len); - wattroff(bottomwin, A_REVERSE); - len -= strlen(keystroke); - if (len > 0) { - waddch(bottomwin, ' '); - len--; - waddnstr(bottomwin, desc, len); - len -= strlen(desc); - for (; len > 0; len--) - waddch(bottomwin, ' '); - } -} - -void clear_bottomwin(void) -{ - if (ISSET(NO_HELP)) - return; - - mvwaddstr(bottomwin, 1, 0, hblank); - mvwaddstr(bottomwin, 2, 0, hblank); -} - void bottombars(const shortcut *s) { int i, j, numcols; @@ -530,7 +522,7 @@ void bottombars(const shortcut *s) /* There will be this many columns of shortcuts */ numcols = (slen + (slen % 2)) / 2; - clear_bottomwin(); + blank_bottomwin(); for (i = 0; i < numcols; i++) { for (j = 0; j <= 1; j++) { @@ -562,20 +554,30 @@ void bottombars(const shortcut *s) wrefresh(bottomwin); } -/* If modified is not already set, set it and update titlebar. */ -void set_modified(void) +/* Write a shortcut key to the help area at the bottom of the window. + * keystroke is e.g. "^G" and desc is e.g. "Get Help". + * We are careful to write exactly len characters, even if len is + * very small and keystroke and desc are long. */ +void onekey(const char *keystroke, const char *desc, int len) { - if (!ISSET(MODIFIED)) { - SET(MODIFIED); - titlebar(NULL); - wrefresh(topwin); + wattron(bottomwin, A_REVERSE); + waddnstr(bottomwin, keystroke, len); + wattroff(bottomwin, A_REVERSE); + len -= strlen(keystroke); + if (len > 0) { + waddch(bottomwin, ' '); + len--; + waddnstr(bottomwin, desc, len); + len -= strlen(desc); + for (; len > 0; len--) + waddch(bottomwin, ' '); } } -/* And so start the display update routines */ -/* Given a column, this returns the "page" it is on */ -/* "page" in the case of the display columns, means which set of 80 */ -/* characters is viewable (e.g.: page 1 shows from 1 to COLS) */ +/* And so start the display update routines. Given a column, this + * returns the "page" it is on. "page", in the case of the display + * columns, means which set of 80 characters is viewable (e.g. page 1 + * shows from 1 to COLS). */ int get_page_from_virtual(int virtual) { int page = 2; @@ -637,12 +639,10 @@ void reset_cursor(void) } #ifndef NANO_SMALL -/* This takes care of the case where there is a mark that covers only */ -/* the current line. */ - -/* It expects a line with no tab characters (i.e.: the type that edit_add */ -/* deals with */ -void add_marked_sameline(int begin, int end, filestruct * fileptr, int y, +/* This takes care of the case where there is a mark that covers only + * the current line. It expects a line with no tab characters (i.e. + * the type that edit_add() deals with. */ +void add_marked_sameline(int begin, int end, filestruct *fileptr, int y, int virt_cur_x, int this_page) { /* @@ -691,12 +691,10 @@ void add_marked_sameline(int begin, int end, filestruct * fileptr, int y, } #endif -/* edit_add takes care of the job of actually painting a line into the - * edit window. - * - * Called only from update_line. Expects a converted-to-not-have-tabs - * line */ -void edit_add(filestruct * fileptr, int yval, int start, int virt_cur_x, +/* edit_add() takes care of the job of actually painting a line into + * the edit window. Called only from update_line(). Expects a + * converted-to-not-have-tabs line. */ +void edit_add(filestruct *fileptr, int yval, int start, int virt_cur_x, int virt_mark_beginx, int this_page) { @@ -1007,12 +1005,10 @@ void edit_add(filestruct * fileptr, int yval, int start, int virt_cur_x, /* * Just update one line in the edit buffer. Basically a wrapper for - * edit_add - * - * index gives us a place in the string to update starting from. - * Likely args are current_x or 0. + * edit_add(). index gives us a place in the string to update starting + * from. Likely args are current_x or 0. */ -void update_line(filestruct * fileptr, int index) +void update_line(filestruct *fileptr, int index) { filestruct *filetmp; int line = 0, col = 0; @@ -1112,6 +1108,28 @@ void update_line(filestruct * fileptr, int index) free(tmp); } +/* This function updates current, based on where current_y is; + * reset_cursor() does the opposite. */ +void update_cursor(void) +{ + int i = 0; + +#ifdef DEBUG + fprintf(stderr, _("Moved to (%d, %d) in edit buffer\n"), current_y, + current_x); +#endif + + current = edittop; + while (i < current_y && current->next != NULL) { + current = current->next; + i++; + } + +#ifdef DEBUG + fprintf(stderr, _("current->data = \"%s\"\n"), current->data); +#endif +} + void center_cursor(void) { current_y = editwinrows / 2; @@ -1194,28 +1212,6 @@ void edit_update(filestruct *fileptr, topmidbotnone location) edit_refresh(); } -/* This function updates current, based on where current_y is; - * reset_cursor() does the opposite. */ -void update_cursor(void) -{ - int i = 0; - -#ifdef DEBUG - fprintf(stderr, _("Moved to (%d, %d) in edit buffer\n"), current_y, - current_x); -#endif - - current = edittop; - while (i < current_y && current->next != NULL) { - current = current->next; - i++; - } - -#ifdef DEBUG - fprintf(stderr, _("current->data = \"%s\"\n"), current->data); -#endif -} - /* * Ask a question on the statusbar. Answer will be stored in answer * global. Returns -1 on aborted enter, -2 on a blank string, and 0 @@ -1278,8 +1274,9 @@ int statusq(int tabs, const shortcut *s, const char *def, } /* - * Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0 for - * N, 2 for All (if all is non-zero when passed in) and -1 for abort (^C) + * Ask a simple yes/no question on the statusbar. Returns 1 for Y, 0 + * for N, 2 for All (if all is non-zero when passed in) and -1 for + * abort (^C). */ int do_yesno(int all, int leavecursor, const char *msg, ...) { @@ -1303,7 +1300,7 @@ int do_yesno(int all, int leavecursor, const char *msg, ...) allstr = _("Aa"); /* Write the bottom of the screen */ - clear_bottomwin(); + blank_bottomwin(); /* Remove gettext call for keybindings until we clear the thing up */ if (!ISSET(NO_HELP)) { @@ -1412,6 +1409,28 @@ int do_yesno(int all, int leavecursor, const char *msg, ...) return ok; } +int total_refresh(void) +{ + clearok(edit, TRUE); + clearok(topwin, TRUE); + clearok(bottomwin, TRUE); + wnoutrefresh(edit); + wnoutrefresh(topwin); + wnoutrefresh(bottomwin); + doupdate(); + clearok(edit, FALSE); + clearok(topwin, FALSE); + clearok(bottomwin, FALSE); + edit_refresh(); + titlebar(NULL); + return 1; +} + +void display_main_list(void) +{ + bottombars(main_list); +} + void statusbar(const char *msg, ...) { va_list ap; @@ -1452,28 +1471,6 @@ void statusbar(const char *msg, ...) statblank = 25; } -void display_main_list(void) -{ - bottombars(main_list); -} - -int total_refresh(void) -{ - clearok(edit, TRUE); - clearok(topwin, TRUE); - clearok(bottomwin, TRUE); - wnoutrefresh(edit); - wnoutrefresh(topwin); - wnoutrefresh(bottomwin); - doupdate(); - clearok(edit, FALSE); - clearok(topwin, FALSE); - clearok(bottomwin, FALSE); - edit_refresh(); - titlebar(NULL); - return 1; -} - int do_cursorpos(int constant) { filestruct *fileptr; @@ -1703,45 +1700,20 @@ int do_help(void) return 1; } -#ifdef DEBUG -/* Dump the current file structure to stderr */ -void dump_buffer(const filestruct *inptr) { - if (inptr == fileage) - fprintf(stderr, _("Dumping file buffer to stderr...\n")); - else if (inptr == cutbuffer) - fprintf(stderr, _("Dumping cutbuffer to stderr...\n")); - else - fprintf(stderr, _("Dumping a buffer to stderr...\n")); - - while (inptr != NULL) { - fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data); - inptr = inptr->next; - } -} -#endif /* DEBUG */ - -#ifdef DEBUG -void dump_buffer_reverse(void) { - const filestruct *fileptr = filebot; - - while (fileptr != NULL) { - fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data); - fileptr = fileptr->prev; - } -} -#endif /* DEBUG */ - -/* Fix editbot, based on the assumption that edittop is correct */ -void fix_editbot(void) +int keypad_on(WINDOW * win, int newval) { - int i; - - editbot = edittop; - for (i = 0; i < editwinrows && editbot->next != NULL; i++) - editbot = editbot->next; +/* This is taken right from aumix. Don't sue me. */ +#ifdef HAVE_USEKEYPAD + int old = win->_use_keypad; + keypad(win, newval); + return old; +#else + keypad(win, newval); + return 1; +#endif /* HAVE_USEKEYPAD */ } -/* highlight the current word being replaced or spell checked */ +/* Highlight the current word being replaced or spell checked. */ void do_replace_highlight(int highlight_flag, const char *word) { char *highlight_word = NULL; @@ -1786,6 +1758,44 @@ void do_replace_highlight(int highlight_flag, const char *word) free(highlight_word); } +/* Fix editbot, based on the assumption that edittop is correct. */ +void fix_editbot(void) +{ + int i; + + editbot = edittop; + for (i = 0; i < editwinrows && editbot->next != NULL; i++) + editbot = editbot->next; +} + +#ifdef DEBUG +/* Dump the current file structure to stderr */ +void dump_buffer(const filestruct *inptr) { + if (inptr == fileage) + fprintf(stderr, _("Dumping file buffer to stderr...\n")); + else if (inptr == cutbuffer) + fprintf(stderr, _("Dumping cutbuffer to stderr...\n")); + else + fprintf(stderr, _("Dumping a buffer to stderr...\n")); + + while (inptr != NULL) { + fprintf(stderr, "(%d) %s\n", inptr->lineno, inptr->data); + inptr = inptr->next; + } +} +#endif /* DEBUG */ + +#ifdef DEBUG +void dump_buffer_reverse(void) { + const filestruct *fileptr = filebot; + + while (fileptr != NULL) { + fprintf(stderr, "(%d) %s\n", fileptr->lineno, fileptr->data); + fileptr = fileptr->prev; + } +} +#endif /* DEBUG */ + #ifdef NANO_EXTRA #define CREDIT_LEN 52 #define XLCREDIT_LEN 8 @@ -1904,16 +1914,3 @@ void do_credits(void) total_refresh(); } #endif - -int keypad_on(WINDOW * win, int newval) -{ -/* This is taken right from aumix. Don't sue me. */ -#ifdef HAVE_USEKEYPAD - int old = win->_use_keypad; - keypad(win, newval); - return old; -#else - keypad(win, newval); - return 1; -#endif /* HAVE_USEKEYPAD */ -} -- 2.39.5