"git@gitlab.caltech.edu:cs24-19fa/git_rec_nano.git" did not exist on "0362c58b376cec6810fa7b9792a97c66708ccb4e"
Commit ad40fdba authored by David Lawrence Ramsey's avatar David Lawrence Ramsey
Browse files

DLR: prototype overhaul, etc.

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