diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-03-23 03:49:03 +0000 |
---|---|---|
committer | <> | 2015-03-25 17:06:51 +0000 |
commit | fb040ea36cb8e2158ccd9100600652f94ae90af1 (patch) | |
tree | dba72a74e84a997c23fa0af7c07a4d831be2deb7 /src | |
parent | 8b74abeb02c01ddc768c465a826360cf33cec063 (diff) | |
download | nano-tarball-fb040ea36cb8e2158ccd9100600652f94ae90af1.tar.gz |
Imported from /home/lorry/working-area/delta_nano-tarball/nano-2.4.0.tar.gz.HEADnano-2.4.0master
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/Makefile.in | 248 | ||||
-rw-r--r-- | src/browser.c | 569 | ||||
-rw-r--r-- | src/chars.c | 64 | ||||
-rw-r--r-- | src/color.c | 213 | ||||
-rw-r--r-- | src/cut.c | 70 | ||||
-rw-r--r-- | src/files.c | 816 | ||||
-rw-r--r-- | src/global.c | 1995 | ||||
-rw-r--r-- | src/help.c | 226 | ||||
-rw-r--r-- | src/move.c | 77 | ||||
-rw-r--r-- | src/nano.c | 801 | ||||
-rw-r--r-- | src/nano.h | 661 | ||||
-rw-r--r-- | src/prompt.c | 655 | ||||
-rw-r--r-- | src/proto.h | 257 | ||||
-rw-r--r-- | src/rcfile.c | 710 | ||||
-rw-r--r-- | src/search.c | 170 | ||||
-rw-r--r-- | src/text.c | 1391 | ||||
-rw-r--r-- | src/utils.c | 48 | ||||
-rw-r--r-- | src/winio.c | 649 |
19 files changed, 5168 insertions, 4457 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index f0b21c0..df65845 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,4 @@ -localedir = $(datadir)/locale -INCLUDES = -DLOCALEDIR=\"$(localedir)\" -DSYSCONFDIR=\"$(sysconfdir)\" - -ACLOCAL_AMFLAGS = -I m4 +AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" -DSYSCONFDIR=\"$(sysconfdir)\" bin_PROGRAMS = nano nano_SOURCES = browser.c \ diff --git a/src/Makefile.in b/src/Makefile.in index acb3389..1837b1b 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,9 +1,8 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -16,6 +15,51 @@ @SET_MAKE@ VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -34,12 +78,13 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -target_triplet = @target@ bin_PROGRAMS = nano$(EXEEXT) subdir = src -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_define_dir.m4 \ + $(top_srcdir)/m4/ax_check_compile_flag.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glib-2.0.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/isc-posix.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ @@ -60,21 +105,64 @@ am_nano_OBJECTS = browser.$(OBJEXT) chars.$(OBJEXT) color.$(OBJEXT) \ utils.$(OBJEXT) winio.$(OBJEXT) nano_OBJECTS = $(am_nano_OBJECTS) nano_DEPENDENCIES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = SOURCES = $(nano_SOURCES) DIST_SOURCES = $(nano_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ @@ -120,6 +208,11 @@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGMERGE = @MSGMERGE@ +NCURSESW_CFLAGS = @NCURSESW_CFLAGS@ +NCURSESW_CONFIG = @NCURSESW_CONFIG@ +NCURSESW_LIBS = @NCURSESW_LIBS@ +NCURSES_CFLAGS = @NCURSES_CFLAGS@ +NCURSES_LIBS = @NCURSES_LIBS@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ @@ -131,6 +224,8 @@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKGDATADIR = @PKGDATADIR@ PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ @@ -160,6 +255,7 @@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ +haveit = @haveit@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -171,7 +267,7 @@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ -localedir = $(datadir)/locale +localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ @@ -184,16 +280,11 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ -target = @target@ target_alias = @target_alias@ -target_cpu = @target_cpu@ -target_os = @target_os@ -target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -INCLUDES = -DLOCALEDIR=\"$(localedir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -ACLOCAL_AMFLAGS = -I m4 +AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" -DSYSCONFDIR=\"$(sysconfdir)\" nano_SOURCES = browser.c \ chars.c \ color.c \ @@ -249,14 +340,18 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) - test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ - while read p p1; do if test -f $$p; \ - then echo "$$p"; echo "$$p"; else :; fi; \ + while read p p1; do if test -f $$p \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ - sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ @@ -277,16 +372,18 @@ uninstall-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ - -e 's/$$/$(EXEEXT)/' `; \ + -e 's/$$/$(EXEEXT)/' \ + `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) -nano$(EXEEXT): $(nano_OBJECTS) $(nano_DEPENDENCIES) + +nano$(EXEEXT): $(nano_OBJECTS) $(nano_DEPENDENCIES) $(EXTRA_nano_DEPENDENCIES) @rm -f nano$(EXEEXT) - $(LINK) $(nano_OBJECTS) $(nano_LDADD) $(LIBS) + $(AM_V_CCLD)$(LINK) $(nano_OBJECTS) $(nano_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -311,39 +408,28 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/winio.Po@am__quote@ .c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ + $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ @@ -355,15 +441,11 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $$unique; \ fi; \ fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique @@ -372,6 +454,21 @@ GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags @@ -423,10 +520,15 @@ install-am: all-am installcheck: installcheck-am install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi mostlyclean-generic: clean-generic: @@ -511,19 +613,19 @@ uninstall-am: uninstall-binPROGRAMS $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-exec-am install-strip uninstall-am -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ - clean-generic ctags distclean distclean-compile \ - distclean-generic distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-binPROGRAMS \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-exec-hook install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-binPROGRAMS \ - uninstall-hook +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ + clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ + distclean distclean-compile distclean-generic distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-binPROGRAMS install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-exec-hook install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-hook install-exec-hook: diff --git a/src/browser.c b/src/browser.c index c43796b..1accb98 100644 --- a/src/browser.c +++ b/src/browser.c @@ -1,9 +1,9 @@ -/* $Id: browser.c 4461 2009-12-09 17:09:37Z astyanax $ */ +/* $Id: browser.c 5086 2014-07-31 20:49:32Z bens $ */ /************************************************************************** * browser.c * * * - * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 * - * Free Software Foundation, Inc. * + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, * + * 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -50,9 +50,7 @@ char *do_browser(char *path, DIR *dir) { char *retval = NULL; int kbinput; - bool meta_key, func_key, old_const_update = ISSET(CONST_UPDATE); - bool abort = FALSE; - /* Whether we should abort the file browser. */ + bool old_const_update = ISSET(CONST_UPDATE); char *prev_dir = NULL; /* The directory we were in, if any, before backing up via * browsing to "..". */ @@ -60,14 +58,12 @@ char *do_browser(char *path, DIR *dir) /* The last answer the user typed at the statusbar prompt. */ size_t old_selected; /* The selected file we had before the current selected file. */ - const sc *s; - const subnfunc *f; + functionptrtype func; + /* The function of the key the user typed in. */ curs_set(0); blank_statusbar(); -#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE) currmenu = MBROWSER; -#endif bottombars(MBROWSER); wnoutrefresh(bottomwin); @@ -108,7 +104,7 @@ char *do_browser(char *path, DIR *dir) titlebar(path); - while (!abort) { + while (TRUE) { struct stat st; int i; size_t fileline = selected / width; @@ -124,239 +120,220 @@ char *do_browser(char *path, DIR *dir) old_selected = selected; - kbinput = get_kbinput(edit, &meta_key, &func_key); + kbinput = get_kbinput(edit); #ifndef DISABLE_MOUSE - if (kbinput == KEY_MOUSE) { - - int mouse_x, mouse_y; - - /* We can click on the edit window to select a - * filename. */ - if (get_mouseinput(&mouse_x, &mouse_y, TRUE) == 0 && - wmouse_trafo(edit, &mouse_y, &mouse_x, FALSE)) { - /* longest is the width of each column. There - * are two spaces between each column. */ - selected = (fileline / editwinrows) * + if (kbinput == KEY_MOUSE) { + int mouse_x, mouse_y; + + /* We can click on the edit window to select a + * filename. */ + if (get_mouseinput(&mouse_x, &mouse_y, TRUE) == 0 && + wmouse_trafo(edit, &mouse_y, &mouse_x, FALSE)) { + /* longest is the width of each column. There + * are two spaces between each column. */ + selected = (fileline / editwinrows) * (editwinrows * width) + (mouse_y * width) + (mouse_x / (longest + 2)); - /* If they clicked beyond the end of a row, - * select the filename at the end of that - * row. */ - if (mouse_x > width * (longest + 2)) - selected--; - - /* If we're off the screen, select the last - * filename. */ - if (selected > filelist_len - 1) - selected = filelist_len - 1; - - /* If we selected the same filename as last - * time, put back the Enter key so that it's - * read in. */ - if (old_selected == selected) - unget_kbinput(sc_seq_or(DO_ENTER, 0), FALSE, FALSE); - } + /* If they clicked beyond the end of a row, + * select the filename at the end of that + * row. */ + if (mouse_x > width * (longest + 2)) + selected--; + + /* If we're off the screen, select the last + * filename. */ + if (selected > filelist_len - 1) + selected = filelist_len - 1; + + /* If we selected the same filename as last + * time, put back the Enter key so that it's + * read in. */ + if (old_selected == selected) + unget_kbinput(sc_seq_or(do_enter_void, 0), FALSE, FALSE); + } } #endif /* !DISABLE_MOUSE */ - parse_browser_input(&kbinput, &meta_key, &func_key); - s = get_shortcut(MBROWSER, &kbinput, &meta_key, &func_key); - if (!s) - continue; - f = sctofunc((sc *) s); - if (!f) - break; - - if (f->scfunc == TOTAL_REFRESH) { - total_redraw(); - } else if (f->scfunc == DO_HELP_VOID) { + func = parse_browser_input(&kbinput); + + if (func == total_refresh) { + total_redraw(); + } else if (func == do_help_void) { #ifndef DISABLE_HELP - do_browser_help(); + do_help_void(); curs_set(0); #else - nano_disabled_msg(); + nano_disabled_msg(); #endif + } else if (func == do_search) { /* Search for a filename. */ - } else if (f->scfunc == DO_SEARCH) { - curs_set(1); - do_filesearch(); - curs_set(0); + curs_set(1); + do_filesearch(); + curs_set(0); + } else if (func == do_research) { /* Search for another filename. */ - } else if (f->scfunc == DO_RESEARCH) { - do_fileresearch(); - } else if (f->scfunc == DO_PAGE_UP) { - if (selected >= (editwinrows + fileline % editwinrows) * - width) - selected -= (editwinrows + fileline % editwinrows) * - width; - else - selected = 0; - } else if (f->scfunc == DO_PAGE_DOWN) { - selected += (editwinrows - fileline % editwinrows) * - width; - if (selected > filelist_len - 1) - selected = filelist_len - 1; - } else if (f->scfunc == FIRST_FILE_MSG) { - if (meta_key) - selected = 0; - } else if (f->scfunc == LAST_FILE_MSG) { - if (meta_key) - selected = filelist_len - 1; + do_fileresearch(); + } else if (func == do_page_up) { + if (selected >= (editwinrows + fileline % editwinrows) * width) + selected -= (editwinrows + fileline % editwinrows) * width; + else + selected = 0; + } else if (func == do_page_down) { + selected += (editwinrows - fileline % editwinrows) * width; + if (selected > filelist_len - 1) + selected = filelist_len - 1; + } else if (func == do_first_file) { + selected = 0; + } else if (func == do_last_file) { + selected = filelist_len - 1; + } else if (func == goto_dir_void) { /* Go to a specific directory. */ - } else if (f->scfunc == GOTO_DIR_MSG) { - curs_set(1); - - i = do_prompt(TRUE, + curs_set(1); + i = do_prompt(TRUE, #ifndef DISABLE_TABCOMP FALSE, #endif MGOTODIR, ans, - &meta_key, &func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES NULL, #endif - browser_refresh, N_("Go To Directory")); + /* TRANSLATORS: This is a prompt. */ + browser_refresh, _("Go To Directory")); - curs_set(0); -#if !defined(DISABLE_HELP) || !defined(DISABLE_MOUSE) - currmenu = MBROWSER; -#endif - bottombars(MBROWSER); - - /* If the directory begins with a newline (i.e. an - * encoded null), treat it as though it's blank. */ - if (i < 0 || *answer == '\n') { - /* We canceled. Indicate that on the statusbar, and - * blank out ans, since we're done with it. */ - statusbar(_("Cancelled")); - ans = mallocstrcpy(ans, ""); - continue; - } else if (i != 0) { - /* Put back the "Go to Directory" key and save - * answer in ans, so that the file list is displayed - * again, the prompt is displayed again, and what we - * typed before at the prompt is displayed again. */ - unget_kbinput(sc_seq_or(DO_GOTOLINECOLUMN_VOID, 0), FALSE, FALSE); - ans = mallocstrcpy(ans, answer); - continue; - } - - /* We have a directory. Blank out ans, since we're done - * with it. */ + curs_set(0); + currmenu = MBROWSER; + bottombars(MBROWSER); + + /* If the directory begins with a newline (i.e. an + * encoded null), treat it as though it's blank. */ + if (i < 0 || *answer == '\n') { + /* We canceled. Indicate that on the statusbar, and + * blank out ans, since we're done with it. */ + statusbar(_("Cancelled")); ans = mallocstrcpy(ans, ""); + continue; + } else if (i != 0) { + /* Put back the "Go to Directory" key and save + * answer in ans, so that the file list is displayed + * again, the prompt is displayed again, and what we + * typed before at the prompt is displayed again. */ + unget_kbinput(sc_seq_or(do_gotolinecolumn_void, 0), FALSE, FALSE); + ans = mallocstrcpy(ans, answer); + continue; + } + + /* We have a directory. Blank out ans, since we're done + * with it. */ + ans = mallocstrcpy(ans, ""); - /* Convert newlines to nulls, just before we go to the - * directory. */ - sunder(answer); - align(&answer); + /* Convert newlines to nulls, just before we go to the + * directory. */ + sunder(answer); + align(&answer); - new_path = real_dir_from_tilde(answer); + new_path = real_dir_from_tilde(answer); - if (new_path[0] != '/') { - new_path = charealloc(new_path, strlen(path) + - strlen(answer) + 1); - sprintf(new_path, "%s%s", path, answer); - } + if (new_path[0] != '/') { + new_path = charealloc(new_path, strlen(path) + + strlen(answer) + 1); + sprintf(new_path, "%s%s", path, answer); + } #ifndef DISABLE_OPERATINGDIR - if (check_operating_dir(new_path, FALSE)) { - statusbar( - _("Can't go outside of %s in restricted mode"), - operating_dir); - free(new_path); - continue; - } + if (check_operating_dir(new_path, FALSE)) { + statusbar(_("Can't go outside of %s in restricted mode"), + operating_dir); + free(new_path); + continue; + } #endif - dir = opendir(new_path); - if (dir == NULL) { - /* We can't open this directory for some reason. - * Complain. */ - statusbar(_("Error reading %s: %s"), answer, - strerror(errno)); - beep(); - free(new_path); - continue; - } - - /* Start over again with the new path value. */ - free(path); - path = new_path; - goto change_browser_directory; - } else if (f->scfunc == DO_UP_VOID) { - if (selected >= width) - selected -= width; - } else if (f->scfunc == DO_LEFT) { - if (selected > 0) - selected--; - } else if (f->scfunc == DO_DOWN_VOID) { - if (selected + width <= filelist_len - 1) - selected += width; - } else if (f->scfunc == DO_RIGHT) { - if (selected < filelist_len - 1) - selected++; - } else if (f->scfunc == DO_ENTER) { - /* We can't move up from "/". */ - if (strcmp(filelist[selected], "/..") == 0) { - statusbar(_("Can't move up a directory")); - beep(); - continue; - } + dir = opendir(new_path); + if (dir == NULL) { + /* We can't open this directory for some reason. + * Complain. */ + statusbar(_("Error reading %s: %s"), answer, + strerror(errno)); + beep(); + free(new_path); + continue; + } + + /* Start over again with the new path value. */ + free(path); + path = new_path; + goto change_browser_directory; + } else if (func == do_up_void) { + if (selected >= width) + selected -= width; + } else if (func == do_down_void) { + if (selected + width <= filelist_len - 1) + selected += width; + } else if (func == do_left) { + if (selected > 0) + selected--; + } else if (func == do_right) { + if (selected < filelist_len - 1) + selected++; + } else if (func == do_enter_void) { + /* We can't move up from "/". */ + if (strcmp(filelist[selected], "/..") == 0) { + statusbar(_("Can't move up a directory")); + beep(); + continue; + } #ifndef DISABLE_OPERATINGDIR - /* Note: The selected file can be outside the operating - * directory if it's ".." or if it's a symlink to a - * directory outside the operating directory. */ - if (check_operating_dir(filelist[selected], FALSE)) { - statusbar( - _("Can't go outside of %s in restricted mode"), - operating_dir); - beep(); - continue; - } + /* Note: The selected file can be outside the operating + * directory if it's ".." or if it's a symlink to a + * directory outside the operating directory. */ + if (check_operating_dir(filelist[selected], FALSE)) { + statusbar(_("Can't go outside of %s in restricted mode"), + operating_dir); + beep(); + continue; + } #endif - if (stat(filelist[selected], &st) == -1) { - /* We can't open this file for some reason. - * Complain. */ - statusbar(_("Error reading %s: %s"), - filelist[selected], strerror(errno)); - beep(); - continue; - } + if (stat(filelist[selected], &st) == -1) { + /* We can't open this file for some reason. + * Complain. */ + statusbar(_("Error reading %s: %s"), + filelist[selected], strerror(errno)); + beep(); + continue; + } - /* If we've successfully opened a file, we're done, so + if (!S_ISDIR(st.st_mode)) { + /* We've successfully opened a file, we're done, so * get out. */ - if (!S_ISDIR(st.st_mode)) { - retval = mallocstrcpy(NULL, filelist[selected]); - abort = TRUE; - continue; - /* If we've successfully opened a directory, and it's - * "..", save the current directory in prev_dir, so that - * we can select it later. */ - } else if (strcmp(tail(filelist[selected]), "..") == 0) - prev_dir = mallocstrcpy(NULL, - striponedir(filelist[selected])); - - dir = opendir(filelist[selected]); - if (dir == NULL) { - /* We can't open this directory for some reason. - * Complain. */ - statusbar(_("Error reading %s: %s"), - filelist[selected], strerror(errno)); - beep(); - continue; - } - - path = mallocstrcpy(path, filelist[selected]); - - /* Start over again with the new path value. */ - goto change_browser_directory; - /* Abort the file browser. */ - } else if (f->scfunc == DO_EXIT) { - abort = TRUE; + retval = mallocstrcpy(NULL, filelist[selected]); + break; + } else if (strcmp(tail(filelist[selected]), "..") == 0) + /* We've successfully opened the parent directory, + * save the current directory in prev_dir, so that + * we can easily return to it by hitting Enter. */ + prev_dir = mallocstrcpy(NULL, striponedir(filelist[selected])); + + dir = opendir(filelist[selected]); + if (dir == NULL) { + /* We can't open this directory for some reason. + * Complain. */ + statusbar(_("Error reading %s: %s"), + filelist[selected], strerror(errno)); + beep(); + continue; + } + + path = mallocstrcpy(path, filelist[selected]); + + /* Start over again with the new path value. */ + goto change_browser_directory; + } else if (func == do_exit) { + /* Exit from the file browser. */ + break; } } titlebar(NULL); @@ -460,7 +437,7 @@ void browser_init(const char *path, DIR *dir) /* Don't show the "." entry. */ if (strcmp(nextdir->d_name, ".") == 0) - continue; + continue; d_len = strlenpt(nextdir->d_name); if (d_len > longest) @@ -487,7 +464,7 @@ void browser_init(const char *path, DIR *dir) while ((nextdir = readdir(dir)) != NULL && i < filelist_len) { /* Don't show the "." entry. */ if (strcmp(nextdir->d_name, ".") == 0) - continue; + continue; filelist[i] = charalloc(path_len + strlen(nextdir->d_name) + 1); sprintf(filelist[i], "%s%s", path, nextdir->d_name); @@ -539,48 +516,33 @@ void browser_init(const char *path, DIR *dir) width = longest; } -/* Determine the shortcut key corresponding to the values of kbinput - * (the key itself), meta_key (whether the key is a meta sequence), and - * func_key (whether the key is a function key), if any. In the - * process, convert certain non-shortcut keys into their corresponding - * shortcut keys. */ -void parse_browser_input(int *kbinput, bool *meta_key, bool *func_key) +/* Return the function that is bound to the given key, accepting certain + * plain characters too, for compatibility with Pico. */ +functionptrtype parse_browser_input(int *kbinput) { - get_shortcut(MBROWSER, kbinput, meta_key, func_key); - - /* Pico compatibility. */ - if (!*meta_key) { + if (!meta_key) { switch (*kbinput) { case ' ': - *kbinput = sc_seq_or(DO_PAGE_DOWN, 0); - break; + return do_page_down; case '-': - *kbinput = sc_seq_or(DO_PAGE_UP, 0); - break; + return do_page_up; case '?': -#ifndef DISABLE_HELP - *kbinput = sc_seq_or(DO_HELP_VOID, 0); -#endif - break; - /* Cancel equivalent to Exit here. */ + return do_help_void; case 'E': case 'e': - *kbinput = sc_seq_or(DO_EXIT, 0); - break; + return do_exit; case 'G': case 'g': - *kbinput = sc_seq_or(GOTO_DIR_MSG, 0); - break; + return goto_dir_void; case 'S': case 's': - *kbinput = sc_seq_or(DO_ENTER, 0); - break; + return do_enter_void; case 'W': case 'w': - *kbinput = sc_seq_or(DO_SEARCH, 0); - break; + return do_search; } } + return func_from_key(kbinput); } /* Set width to the number of files that we can display per line, if @@ -619,8 +581,7 @@ void browser_refresh(void) /* The maximum length of the file information in * columns: seven for "--", "(dir)", or the file size, * and 12 for "(parent dir)". */ - bool dots = (COLS >= 15 && filetaillen >= longest - - foomaxlen - 1); + bool dots = (COLS >= 15 && filetaillen >= longest - foomaxlen - 1); /* Do we put an ellipsis before the filename? Don't set * this to TRUE if we have fewer than 15 columns (i.e. * one column for padding, plus seven columns for a @@ -635,7 +596,7 @@ void browser_refresh(void) /* Start highlighting the currently selected file or * directory. */ if (i == selected) - wattron(edit, reverse_attr); + wattron(edit, hilite_attribute); blank_line(edit, line, col, longest); @@ -710,7 +671,7 @@ void browser_refresh(void) /* Finish highlighting the currently selected file or * directory. */ if (i == selected) - wattroff(edit, reverse_attr); + wattroff(edit, hilite_attribute); free(foo); @@ -760,8 +721,6 @@ int filesearch_init(void) { int i = 0; char *buf; - bool meta_key, func_key; - const sc *s; static char *backupstring = NULL; /* The search string we'll be using. */ @@ -794,29 +753,10 @@ int filesearch_init(void) TRUE, #endif MWHEREISFILE, backupstring, - &meta_key, &func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES &search_history, #endif - browser_refresh, "%s%s%s%s%s%s", _("Search"), -#ifndef NANO_TINY - /* This string is just a modifier for the search prompt; no - * grammar is implied. */ - ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : -#endif - "", -#ifdef HAVE_REGEX_H - /* This string is just a modifier for the search prompt; no - * grammar is implied. */ - ISSET(USE_REGEXP) ? _(" [Regexp]") : -#endif - "", -#ifndef NANO_TINY - /* This string is just a modifier for the search prompt; no - * grammar is implied. */ - ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : -#endif - "", "", buf); + browser_refresh, "%s%s", _("Search"), buf); /* Release buf now that we don't need it anymore. */ free(buf); @@ -829,36 +769,6 @@ int filesearch_init(void) *answer == '\0')) { statusbar(_("Cancelled")); return -1; - } else { - s = get_shortcut(MBROWSER, &i, &meta_key, &func_key); - if (i == -2 || i == 0) { -#ifdef HAVE_REGEX_H - /* Use last_search if answer is an empty string, or - * answer if it isn't. */ - if (ISSET(USE_REGEXP) && !regexp_init((i == -2) ? - last_search : answer)) - return -1; -#endif - } else -#ifndef NANO_TINY - if (s && s->scfunc == CASE_SENS_MSG) { - TOGGLE(CASE_SENSITIVE); - backupstring = mallocstrcpy(backupstring, answer); - return 1; - } else if (s && s->scfunc == BACKWARDS_MSG) { - TOGGLE(BACKWARDS_SEARCH); - backupstring = mallocstrcpy(backupstring, answer); - return 1; - } else -#endif -#ifdef HAVE_REGEX_H - if (s && s->scfunc == REGEXP_MSG) { - TOGGLE(USE_REGEXP); - backupstring = mallocstrcpy(backupstring, answer); - return 1; - } else -#endif - return -1; } return 0; @@ -877,11 +787,6 @@ bool findnextfile(bool no_sameline, size_t begin, const char *needle) /* The filename we display, minus the path. */ const char *rev_start = filetail, *found = NULL; -#ifndef NANO_TINY - if (ISSET(BACKWARDS_SEARCH)) - rev_start += strlen(rev_start); -#endif - /* Look for needle in the current filename we're searching. */ while (TRUE) { found = strstrwrapper(filetail, needle, rev_start); @@ -898,27 +803,14 @@ bool findnextfile(bool no_sameline, size_t begin, const char *needle) return FALSE; } - /* Move to the previous or next filename in the list. If we've - * reached the start or end of the list, wrap around. */ -#ifndef NANO_TINY - if (ISSET(BACKWARDS_SEARCH)) { - if (currselected > 0) - currselected--; - else { - currselected = filelist_len - 1; - statusbar(_("Search Wrapped")); - } - } else { -#endif - if (currselected < filelist_len - 1) - currselected++; - else { - currselected = 0; - statusbar(_("Search Wrapped")); - } -#ifndef NANO_TINY + /* Move to the next filename in the list. If we've reached the + * end of the list, wrap around. */ + if (currselected < filelist_len - 1) + currselected++; + else { + currselected = 0; + statusbar(_("Search Wrapped")); } -#endif /* We've reached the original starting file. */ if (currselected == begin) @@ -927,10 +819,6 @@ bool findnextfile(bool no_sameline, size_t begin, const char *needle) filetail = tail(filelist[currselected]); rev_start = filetail; -#ifndef NANO_TINY - if (ISSET(BACKWARDS_SEARCH)) - rev_start += strlen(rev_start); -#endif } /* We've definitely found something. */ @@ -947,37 +835,28 @@ void findnextfile_wrap_reset(void) } /* Abort the current filename search. Clean up by setting the current - * shortcut list to the browser shortcut list, displaying it, and - * decompiling the compiled regular expression we used in the last - * search, if any. */ + * shortcut list to the browser shortcut list, and displaying it. */ void filesearch_abort(void) { currmenu = MBROWSER; bottombars(MBROWSER); -#ifdef HAVE_REGEX_H - regexp_cleanup(); -#endif } /* Search for a filename. */ void do_filesearch(void) { size_t begin = selected; - int i; bool didfind; - i = filesearch_init(); - if (i == -1) /* Cancel, blank search string, or regcomp() - * failed. */ - filesearch_abort(); -#if !defined(NANO_TINY) || defined(HAVE_REGEX_H) - else if (i == 1) /* Case Sensitive, Backwards, or Regexp search - * toggle. */ - do_filesearch(); -#endif + UNSET(CASE_SENSITIVE); + UNSET(USE_REGEXP); + UNSET(BACKWARDS_SEARCH); - if (i != 0) + if (filesearch_init() != 0) { + /* Cancelled or a blank search string. */ + filesearch_abort(); return; + } /* If answer is now "", copy last_search into answer. */ if (*answer == '\0') @@ -985,7 +864,7 @@ void do_filesearch(void) else last_search = mallocstrcpy(last_search, answer); -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES /* If answer is not "", add this search string to the search history * list. */ if (answer[0] != '\0') @@ -1018,12 +897,6 @@ void do_fileresearch(void) search_init_globals(); if (last_search[0] != '\0') { -#ifdef HAVE_REGEX_H - /* Since answer is "", use last_search! */ - if (ISSET(USE_REGEXP) && !regexp_init(last_search)) - return; -#endif - findnextfile_wrap_reset(); didfind = findnextfile(FALSE, begin, answer); @@ -1070,7 +943,7 @@ char *striponedir(const char *path) tmp = strrchr(retval, '/'); if (tmp != NULL) - null_at(&retval, tmp - retval); + null_at(&retval, tmp - retval); return retval; } diff --git a/src/chars.c b/src/chars.c index 7d56117..088d612 100644 --- a/src/chars.c +++ b/src/chars.c @@ -1,9 +1,9 @@ -/* $Id: chars.c 4453 2009-12-02 03:36:22Z astyanax $ */ +/* $Id: chars.c 5147 2015-03-22 11:20:02Z bens $ */ /************************************************************************** * chars.c * * * - * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 * - * Free Software Foundation, Inc. * + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, * + * 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -54,7 +54,19 @@ bool using_utf8(void) { return use_utf8; } -#endif +#endif /* ENABLE_UTF8 */ + +/* Concatenate two allocated strings. */ +char* addstrings(char* str1, size_t len1, char* str2, size_t len2) +{ + str1 = charealloc(str1, len1 + len2 + 1); + str1[len1] = '\0'; + strncat(&str1[len1], str2, len2); + free(str2); + + return str1; +} + #ifndef HAVE_ISBLANK /* This function is equivalent to isblank(). */ @@ -79,12 +91,12 @@ bool is_byte(int c) return ((unsigned int)c == (unsigned char)c); } -static void mbtowc_reset(void) +void mbtowc_reset(void) { IGNORE_CALL_RESULT(mbtowc(NULL, NULL, 0)); } -static void wctomb_reset(void) +void wctomb_reset(void) { IGNORE_CALL_RESULT(wctomb(NULL, 0)); } @@ -184,9 +196,8 @@ bool is_punct_mbchar(const char *c) #ifdef ENABLE_UTF8 if (use_utf8) { wchar_t wc; - int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX); - if (c_mb_len < 0) { + if (mbtowc(&wc, c, MB_CUR_MAX) < 0) { mbtowc_reset(); wc = bad_wchar; } @@ -473,22 +484,24 @@ int parse_mbchar(const char *buf, char *chr, size_t *col) * before the one at pos. */ size_t move_mbleft(const char *buf, size_t pos) { - size_t pos_prev = pos; + size_t before, char_len = 0; assert(buf != NULL && pos <= strlen(buf)); /* There is no library function to move backward one multibyte - * character. Here is the naive, O(pos) way to do it. */ - while (TRUE) { - int buf_mb_len = parse_mbchar(buf + pos - pos_prev, NULL, NULL); - - if (pos_prev <= buf_mb_len) - break; + * character. So we just start groping for one at the farthest + * possible point. */ + if (mb_cur_max() > pos) + before = 0; + else + before = pos - mb_cur_max(); - pos_prev -= buf_mb_len; + while (before < pos) { + char_len = parse_mbchar(buf + before, NULL, NULL); + before += char_len; } - return pos - pos_prev; + return before - char_len; } /* Return the index in buf of the beginning of the multibyte character @@ -630,7 +643,7 @@ char *mbstrcasestr(const char *haystack, const char *needle) return NULL; } else #endif - return strcasestr(haystack, needle); + return (char *) strcasestr(haystack, needle); } #if !defined(NANO_TINY) || !defined(DISABLE_TABCOMP) @@ -788,9 +801,8 @@ char *mbstrchr(const char *s, const char *c) char *s_mb = charalloc(MB_CUR_MAX); const char *q = s; wchar_t ws, wc; - int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX); - if (c_mb_len < 0) { + if (mbtowc(&wc, c, MB_CUR_MAX) < 0) { mbtowc_reset(); wc = (unsigned char)*c; bad_c_mb = TRUE; @@ -820,7 +832,7 @@ char *mbstrchr(const char *s, const char *c) return (char *)q; } else #endif - return strchr(s, *c); + return (char *) strchr(s, *c); } #endif /* !NANO_TINY || !DISABLE_JUSTIFY */ @@ -840,7 +852,7 @@ char *mbstrpbrk(const char *s, const char *accept) return NULL; } else #endif - return strpbrk(s, accept); + return (char *) strpbrk(s, accept); } /* This function is equivalent to strpbrk(), except in that it scans the @@ -893,7 +905,7 @@ char *mbrevstrpbrk(const char *s, const char *accept, const char } #endif /* !NANO_TINY */ -#if defined(ENABLE_NANORC) && (!defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)) +#if !defined(DISABLE_NANORC) && (!defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)) /* Return TRUE if the string s contains one or more blank characters, * and FALSE otherwise. */ bool has_blank_chars(const char *s) @@ -935,7 +947,7 @@ bool has_blank_mbchars(const char *s) #endif return has_blank_chars(s); } -#endif /* ENABLE_NANORC && (!NANO_TINY || !DISABLE_JUSTIFY) */ +#endif /* !DISABLE_NANORC && (!NANO_TINY || !DISABLE_JUSTIFY) */ #ifdef ENABLE_UTF8 /* Return TRUE if wc is valid Unicode, and FALSE otherwise. */ @@ -947,7 +959,7 @@ bool is_valid_unicode(wchar_t wc) } #endif -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC /* Check if the string s is a valid multibyte string. Return TRUE if it * is, and FALSE otherwise. */ bool is_valid_mbstring(const char *s) @@ -960,4 +972,4 @@ bool is_valid_mbstring(const char *s) #endif TRUE; } -#endif /* ENABLE_NANORC */ +#endif /* !DISABLE_NANORC */ diff --git a/src/color.c b/src/color.c index 9d7ecff..13e2995 100644 --- a/src/color.c +++ b/src/color.c @@ -1,9 +1,9 @@ -/* $Id: color.c 4453 2009-12-02 03:36:22Z astyanax $ */ +/* $Id: color.c 5038 2014-06-30 17:49:53Z bens $ */ /************************************************************************** * color.c * * * - * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 * - * Free Software Foundation, Inc. * + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, * + * 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -25,18 +25,59 @@ #include <stdio.h> #include <string.h> +#include <errno.h> -#ifdef ENABLE_COLOR +#ifdef HAVE_MAGIC_H +#include <magic.h> +#endif + +#ifndef DISABLE_COLOR /* For each syntax list entry, go through the list of colors and assign * the color pairs. */ void set_colorpairs(void) { const syntaxtype *this_syntax = syntaxes; + bool defok = FALSE; + short fg, bg; + size_t i; + + start_color(); + +#ifdef HAVE_USE_DEFAULT_COLORS + /* Use the default colors, if available. */ + defok = (use_default_colors() != ERR); +#endif + + for (i = 0; i < NUMBER_OF_ELEMENTS; i++) { + bool bright = FALSE; + + if (parse_color_names(specified_color_combo[i], &fg, &bg, &bright)) { + if (fg == -1 && !defok) + fg = COLOR_WHITE; + if (bg == -1 && !defok) + bg = COLOR_BLACK; + init_pair(i + 1, fg, bg); + interface_color_pair[i].bright = bright; + interface_color_pair[i].pairnum = COLOR_PAIR(i + 1); + } + else { + interface_color_pair[i].bright = FALSE; + if (i != FUNCTION_TAG) + interface_color_pair[i].pairnum = hilite_attribute; + else + interface_color_pair[i].pairnum = A_NORMAL; + } + + if (specified_color_combo[i] != NULL) { + free(specified_color_combo[i]); + specified_color_combo[i] = NULL; + } + } for (; this_syntax != NULL; this_syntax = this_syntax->next) { colortype *this_color = this_syntax->color; - int color_pair = 1; + int clr_pair = NUMBER_OF_ELEMENTS + 1; for (; this_color != NULL; this_color = this_color->next) { const colortype *beforenow = this_syntax->color; @@ -51,8 +92,8 @@ void set_colorpairs(void) if (beforenow != this_color) this_color->pairnum = beforenow->pairnum; else { - this_color->pairnum = color_pair; - color_pair++; + this_color->pairnum = clr_pair; + clr_pair++; } } } @@ -66,14 +107,8 @@ void color_init(void) if (has_colors()) { const colortype *tmpcolor; #ifdef HAVE_USE_DEFAULT_COLORS - bool defok; -#endif - - start_color(); - -#ifdef HAVE_USE_DEFAULT_COLORS /* Use the default colors, if available. */ - defok = (use_default_colors() != ERR); + bool defok = (use_default_colors() != ERR); #endif for (tmpcolor = openfile->colorstrings; tmpcolor != NULL; @@ -102,18 +137,33 @@ void color_init(void) } } +/* Clean up a regex we previously compiled. */ +void nfreeregex(regex_t **r) +{ + assert(r != NULL); + + regfree(*r); + free(*r); + *r = NULL; +} + /* Update the color information based on the current filename. */ void color_update(void) { syntaxtype *tmpsyntax; syntaxtype *defsyntax = NULL; colortype *tmpcolor, *defcolor = NULL; + regexlisttype *e; assert(openfile != NULL); openfile->syntax = NULL; openfile->colorstrings = NULL; + /* If the rcfiles were not read, or contained no syntaxes, get out. */ + if (syntaxes == NULL) + return; + /* If we specified a syntax override string, use it. */ if (syntaxstr != NULL) { /* If the syntax override is "none", it's the same as not having @@ -135,11 +185,10 @@ void color_update(void) /* If we didn't specify a syntax override string, or if we did and * there was no syntax by that name, get the syntax based on the - * file extension, and then look in the header. */ + * file extension, then try the headerline, and then try magic. */ if (openfile->colorstrings == NULL) { for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { - exttype *e; /* If this is the default syntax, it has no associated * extensions, which we've checked for elsewhere. Skip over @@ -161,75 +210,117 @@ void color_update(void) regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED); } - /* Set colorstrings if we matched the extension - * regex. */ - if (regexec(e->ext, openfile->filename, 0, NULL, - 0) == 0) { + /* Set colorstrings if we match the extension regex. */ + if (regexec(e->ext, openfile->filename, 0, NULL, 0) == 0) { openfile->syntax = tmpsyntax; openfile->colorstrings = tmpsyntax->color; - } - - if (openfile->colorstrings != NULL) break; + } /* Decompile e->ext_regex's specified regex if we aren't * going to use it. */ - if (not_compiled) { - regfree(e->ext); - free(e->ext); - e->ext = NULL; - } + if (not_compiled) + nfreeregex(&e->ext); } } - /* If we haven't matched anything yet, try the headers */ + /* Check the headerline if the extension didn't match anything. */ if (openfile->colorstrings == NULL) { #ifdef DEBUG - fprintf(stderr, "No match for file extensions, looking at headers...\n"); + fprintf(stderr, "No result from file extension, trying headerline...\n"); #endif for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { - exttype *e; for (e = tmpsyntax->headers; e != NULL; e = e->next) { bool not_compiled = (e->ext == NULL); - /* e->ext_regex has already been checked for validity - * elsewhere. Compile its specified regex if we haven't - * already. */ if (not_compiled) { e->ext = (regex_t *)nmalloc(sizeof(regex_t)); regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED); } - - /* Set colorstrings if we matched the extension - * regex. */ #ifdef DEBUG - fprintf(stderr, "Comparing header regex \"%s\" to fileage \"%s\"...\n", e->ext_regex, openfile->fileage->data); + fprintf(stderr, "Comparing header regex \"%s\" to fileage \"%s\"...\n", + e->ext_regex, openfile->fileage->data); #endif + /* Set colorstrings if we match the header-line regex. */ if (regexec(e->ext, openfile->fileage->data, 0, NULL, 0) == 0) { openfile->syntax = tmpsyntax; openfile->colorstrings = tmpsyntax->color; + break; } - if (openfile->colorstrings != NULL) - break; + if (not_compiled) + nfreeregex(&e->ext); + } + } + } + +#ifdef HAVE_LIBMAGIC + /* Check magic if we don't have an answer yet. */ + if (openfile->colorstrings == NULL) { + struct stat fileinfo; + magic_t cookie = NULL; + const char *magicstring = NULL; +#ifdef DEBUG + fprintf(stderr, "No result from headerline either, trying libmagic...\n"); +#endif + if (stat(openfile->filename, &fileinfo) == 0) { + /* Open the magic database and get a diagnosis of the file. */ + cookie = magic_open(MAGIC_SYMLINK | +#ifdef DEBUG + MAGIC_DEBUG | MAGIC_CHECK | +#endif + MAGIC_ERROR); + if (cookie == NULL || magic_load(cookie, NULL) < 0) + statusbar(_("magic_load() failed: %s"), strerror(errno)); + else { + magicstring = magic_file(cookie, openfile->filename); + if (magicstring == NULL) { + statusbar(_("magic_file(%s) failed: %s"), + openfile->filename, magic_error(cookie)); + } +#ifdef DEBUG + fprintf(stderr, "Returned magic string is: %s\n", magicstring); +#endif + } + } + + /* Now try and find a syntax that matches the magicstring. */ + for (tmpsyntax = syntaxes; tmpsyntax != NULL; + tmpsyntax = tmpsyntax->next) { + + for (e = tmpsyntax->magics; e != NULL; e = e->next) { + bool not_compiled = (e->ext == NULL); - /* Decompile e->ext_regex's specified regex if we aren't - * going to use it. */ if (not_compiled) { - regfree(e->ext); - free(e->ext); - e->ext = NULL; + e->ext = (regex_t *)nmalloc(sizeof(regex_t)); + regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED); } +#ifdef DEBUG + fprintf(stderr, "Matching regex \"%s\" against \"%s\"\n", e->ext_regex, magicstring); +#endif + /* Set colorstrings if we match the magic-string regex. */ + if (magicstring && regexec(e->ext, magicstring, 0, NULL, 0) == 0) { + openfile->syntax = tmpsyntax; + openfile->colorstrings = tmpsyntax->color; + break; + } + + if (not_compiled) + nfreeregex(&e->ext); } + if (openfile->syntax != NULL) + break; } + if (stat(openfile->filename, &fileinfo) == 0) + magic_close(cookie); } +#endif /* HAVE_LIBMAGIC */ } - - /* If we didn't get a syntax based on the file extension, and we - * have a default syntax, use it. */ + /* If we didn't find any syntax yet, and we do have a default one, + * use it. */ if (openfile->colorstrings == NULL && defcolor != NULL) { openfile->syntax = defsyntax; openfile->colorstrings = defcolor; @@ -255,7 +346,7 @@ void color_update(void) } /* Reset the multicolor info cache for records for any lines which need - to be recalculated */ + * to be recalculated. */ void reset_multis_after(filestruct *fileptr, int mindex) { filestruct *oof; @@ -301,11 +392,10 @@ void reset_multis_before(filestruct *fileptr, int mindex) else break; } - edit_refresh_needed = TRUE; } -/* Reset one multiline regex info */ +/* Reset one multiline regex info. */ void reset_multis_for_id(filestruct *fileptr, int num) { reset_multis_before(fileptr, num); @@ -313,9 +403,9 @@ void reset_multis_for_id(filestruct *fileptr, int num) fileptr->multidata[num] = -1; } -/* Reset multi line strings around a filestruct ptr, trying to be smart about stopping - force = reset everything regardless, useful when we don't know how much screen state - has changed */ +/* Reset multi-line strings around a filestruct ptr, trying to be smart + * about stopping. Bool force means: reset everything regardless, useful + * when we don't know how much screen state has changed. */ void reset_multis(filestruct *fileptr, bool force) { int nobegin, noend; @@ -327,7 +417,7 @@ void reset_multis(filestruct *fileptr, bool force) for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) { - /* If it's not a multi-line regex, amscray */ + /* If it's not a multi-line regex, amscray. */ if (tmpcolor->end == NULL) continue; @@ -338,10 +428,10 @@ void reset_multis(filestruct *fileptr, bool force) } /* Figure out where the first begin and end are to determine if - things changed drastically for the precalculated multi values */ - nobegin = regexec(tmpcolor->start, fileptr->data, 1, &startmatch, 0); - noend = regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0); - if (fileptr->multidata[tmpcolor->id] == CWHOLELINE) { + * things changed drastically for the precalculated multi values. */ + nobegin = regexec(tmpcolor->start, fileptr->data, 1, &startmatch, 0); + noend = regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0); + if (fileptr->multidata[tmpcolor->id] == CWHOLELINE) { if (nobegin && noend) continue; } else if (fileptr->multidata[tmpcolor->id] == CNONE) { @@ -353,8 +443,9 @@ void reset_multis(filestruct *fileptr, bool force) continue; } - /* If we got here assume the worst */ + /* If we got here, assume the worst. */ reset_multis_for_id(fileptr, tmpcolor->id); } } -#endif /* ENABLE_COLOR */ + +#endif /* !DISABLE_COLOR */ @@ -1,9 +1,9 @@ -/* $Id: cut.c 4453 2009-12-02 03:36:22Z astyanax $ */ +/* $Id: cut.c 5112 2015-02-03 22:49:57Z astyanax $ */ /************************************************************************** * cut.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -37,6 +37,12 @@ void cutbuffer_reset(void) keep_cutbuffer = FALSE; } +/* Return the status of cutbuffer preservation. */ +inline bool keeping_cutbuffer(void) +{ + return keep_cutbuffer; +} + /* If we aren't on the last line of the file, move all the text of the * current line, plus the newline at the end, into the cutbuffer. If we * are, move all of the text of the current line into the cutbuffer. In @@ -44,6 +50,11 @@ void cutbuffer_reset(void) * current line. */ void cut_line(void) { +#ifndef NANO_TINY + if (!openfile->mark_begin) + openfile->mark_begin = openfile->current; +#endif + if (openfile->current != openfile->filebot) move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, 0, openfile->current->next, 0); @@ -109,11 +120,11 @@ void cut_to_eof(void) /* Move text from the current filestruct into the cutbuffer. If * copy_text is TRUE, copy the text back into the filestruct afterward. - * If cut_till_end is TRUE, move all text from the current cursor + * If cut_till_eof is TRUE, move all text from the current cursor * position to the end of the file into the cutbuffer. */ void do_cut_text( #ifndef NANO_TINY - bool copy_text, bool cut_till_end, bool undoing + bool copy_text, bool cut_till_eof, bool undoing #else void #endif @@ -125,7 +136,7 @@ void do_cut_text( * it. */ size_t cb_save_len = 0; /* The length of the string at the current end of the cutbuffer, - * before we add text to it. */ + * before we add text to it. */ bool old_no_newlines = ISSET(NO_NEWLINES); #endif @@ -162,9 +173,8 @@ void do_cut_text( keep_cutbuffer = TRUE; #ifndef NANO_TINY - - if (cut_till_end) { - /* If cut_till_end is TRUE, move all text up to the end of the + if (cut_till_eof) { + /* If cut_till_eof is TRUE, move all text up to the end of the * file into the cutbuffer. */ cut_to_eof(); } else if (openfile->mark_set) { @@ -190,10 +200,10 @@ void do_cut_text( if (cutbuffer != NULL) { if (cb_save != NULL) { cb_save->data += cb_save_len; - copy_from_filestruct(cb_save, cutbottom); + copy_from_filestruct(cb_save); cb_save->data -= cb_save_len; } else - copy_from_filestruct(cutbuffer, cutbottom); + copy_from_filestruct(cutbuffer); /* Set the current place we want to where the text from the * cutbuffer ends. */ @@ -205,16 +215,18 @@ void do_cut_text( if (!old_no_newlines) UNSET(NO_NEWLINES); } else if (!undoing) - update_undo(CUT); -#endif - /* Leave the text in the cutbuffer, and mark the file as - * modified. */ + update_undo(cut_till_eof ? CUT_EOF : CUT); + + /* Leave the text in the cutbuffer, and mark the file as + * modified. */ + if (!copy_text) +#endif /* !NANO_TINY */ set_modified(); /* Update the screen. */ edit_refresh_needed = TRUE; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR reset_multis(openfile->current, FALSE); #endif @@ -238,18 +250,26 @@ void do_cut_text_void(void) #ifndef NANO_TINY /* Move text from the current filestruct into the cutbuffer, and copy it - * back into the filestruct afterward. */ + * back into the filestruct afterward. If the mark is set or the cursor + * was moved, blow away previous contents of the cutbuffer. */ void do_copy_text(void) { + static struct filestruct *next_contiguous_line = NULL; + bool mark_set = openfile->mark_set; + + if (mark_set || openfile->current != next_contiguous_line) + cutbuffer_reset(); + do_cut_text(TRUE, FALSE, FALSE); + + /* If the mark was set, blow away the cutbuffer on the next copy. */ + next_contiguous_line = (mark_set ? NULL : openfile->current); } /* Cut from the current cursor position to the end of the file. */ -void do_cut_till_end(void) +void do_cut_till_eof(void) { -#ifndef NANO_TINY - add_undo(CUT); -#endif + add_undo(CUT_EOF); do_cut_text(FALSE, TRUE, FALSE); } #endif /* !NANO_TINY */ @@ -264,12 +284,16 @@ void do_uncut_text(void) return; #ifndef NANO_TINY - update_undo(UNCUT); + add_undo(PASTE); #endif /* Add a copy of the text in the cutbuffer to the current filestruct * at the current cursor position. */ - copy_from_filestruct(cutbuffer, cutbottom); + copy_from_filestruct(cutbuffer); + +#ifndef NANO_TINY + update_undo(PASTE); +#endif /* Set the current place we want to where the text from the * cutbuffer ends. */ @@ -281,7 +305,7 @@ void do_uncut_text(void) /* Update the screen. */ edit_refresh_needed = TRUE; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR reset_multis(openfile->current, FALSE); #endif diff --git a/src/files.c b/src/files.c index c5b9d6a..bd07597 100644 --- a/src/files.c +++ b/src/files.c @@ -1,9 +1,9 @@ -/* $Id: files.c 4520 2010-11-12 06:23:14Z astyanax $ */ +/* $Id: files.c 5118 2015-02-15 16:28:08Z bens $ */ /************************************************************************** * files.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -31,6 +31,7 @@ #include <errno.h> #include <ctype.h> #include <pwd.h> +#include <libgen.h> /* Add an entry to the openfile openfilestruct. This should only be * called from open_buffer(). */ @@ -46,6 +47,8 @@ void make_new_buffer(void) } else { splice_opennode(openfile, make_new_opennode(), openfile->next); openfile = openfile->next; + /* More than one file open, show Close in help lines. */ + exitfunc->desc = close_tag; } /* Initialize the new buffer. */ @@ -77,8 +80,9 @@ void initialize_buffer(void) openfile->current_stat = NULL; openfile->undotop = NULL; openfile->current_undo = NULL; + openfile->lock_filename = NULL; #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR openfile->colorstrings = NULL; #endif } @@ -96,19 +100,229 @@ void initialize_buffer_text(void) openfile->edittop = openfile->fileage; openfile->current = openfile->fileage; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR openfile->fileage->multidata = NULL; #endif openfile->totsize = 0; } +#ifndef NANO_TINY +/* Actually write the lockfile. This function will ALWAYS annihilate + * any previous version of the file. We'll borrow INSECURE_BACKUP here + * to decide about lockfile paranoia here as well... + * + * Args: + * lockfilename: file name for lock + * origfilename: name of the file the lock is for + * modified: whether to set the modified bit in the file + * + * Returns: 1 on success, 0 on failure (but continue loading), -1 on + * failure and abort. */ +int write_lockfile(const char *lockfilename, const char *origfilename, bool modified) +{ + int cflags, fd; + FILE *filestream; + pid_t mypid; + uid_t myuid; + struct passwd *mypwuid; + struct stat fileinfo; + char *lockdata = charalloc(1024); + char myhostname[32]; + ssize_t lockdatalen = 1024; + ssize_t wroteamt; + + /* Run things which might fail first before we try and blow away the + * old state. */ + myuid = geteuid(); + if ((mypwuid = getpwuid(myuid)) == NULL) { + statusbar(_("Couldn't determine my identity for lock file (getpwuid() failed)")); + return -1; + } + mypid = getpid(); + + if (gethostname(myhostname, 31) < 0) { + statusbar(_("Couldn't determine hostname for lock file: %s"), strerror(errno)); + return -1; + } + + /* Check if the lock exists before we try to delete it...*/ + if (stat(lockfilename, &fileinfo) != -1) + if (delete_lockfile(lockfilename) < 0) + return -1; + + if (ISSET(INSECURE_BACKUP)) + cflags = O_WRONLY | O_CREAT | O_APPEND; + else + cflags = O_WRONLY | O_CREAT | O_EXCL | O_APPEND; + + fd = open(lockfilename, cflags, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + /* Maybe we just don't have write access. Print an error message + and continue. */ + if (fd < 0) { + statusbar(_("Error writing lock file %s: %s"), lockfilename, + strerror(errno)); + return 0; + } + + /* Now we've got a safe file stream. If the previous open() call + * failed, this will return NULL. */ + filestream = fdopen(fd, "wb"); + + if (fd < 0 || filestream == NULL) { + statusbar(_("Error writing lock file %s: %s"), lockfilename, + strerror(errno)); + return -1; + } + + /* Okay, so at the moment we're following this state for how to + * store the lock data: + * + * byte 0 - 0x62 + * byte 1 - 0x30 + * bytes 2-12 - program name which created the lock + * bytes 24,25 - little endian store of creator program's PID + * (b24 = 256^0 column, b25 = 256^1 column) + * bytes 28-44 - username of who created the lock + * bytes 68-100 - hostname of where the lock was created + * bytes 108-876 - filename the lock is for + * byte 1007 - 0x55 if file is modified + * + * Looks like VIM also stores undo state in this file, so we're + * gonna have to figure out how to slap a 'OMG don't use recover on + * our lockfile' message in here... + * + * This is likely very wrong, so this is a WIP. */ + memset(lockdata, 0, lockdatalen); + lockdata[0] = 0x62; + lockdata[1] = 0x30; + lockdata[24] = mypid % 256; + lockdata[25] = mypid / 256; + snprintf(&lockdata[2], 11, "nano %s", VERSION); + strncpy(&lockdata[28], mypwuid->pw_name, 16); + strncpy(&lockdata[68], myhostname, 31); + strncpy(&lockdata[108], origfilename, 768); + if (modified == TRUE) + lockdata[1007] = 0x55; + + wroteamt = fwrite(lockdata, sizeof(char), lockdatalen, filestream); + if (wroteamt < lockdatalen) { + statusbar(_("Error writing lock file %s: %s"), + lockfilename, ferror(filestream)); + return -1; + } + +#ifdef DEBUG + fprintf(stderr, "In write_lockfile(), write successful (wrote %lu bytes)\n", (unsigned long)wroteamt); +#endif + + if (fclose(filestream) == EOF) { + statusbar(_("Error writing lock file %s: %s"), + lockfilename, strerror(errno)); + return -1; + } + + openfile->lock_filename = lockfilename; + + return 1; +} + +/* Less exciting, delete the lockfile. Return -1 if unsuccessful and + * complain on the statusbar, 1 otherwise. */ +int delete_lockfile(const char *lockfilename) +{ + if (unlink(lockfilename) < 0 && errno != ENOENT) { + statusbar(_("Error deleting lock file %s: %s"), lockfilename, + strerror(errno)); + return -1; + } + return 1; +} + +/* Deal with lockfiles. Return -1 on refusing to override the lockfile, + * and 1 on successfully creating it; 0 means we were not successful in + * creating the lockfile but we should continue to load the file and + * complain to the user. */ +int do_lockfile(const char *filename) +{ + char *lockdir = dirname((char *) mallocstrcpy(NULL, filename)); + char *lockbase = basename((char *) mallocstrcpy(NULL, filename)); + size_t lockfilesize = strlen(filename) + strlen(locking_prefix) + + strlen(locking_suffix) + 3; + char *lockfilename = charalloc(lockfilesize); + char *lockfiledir = NULL; + static char lockprog[11], lockuser[17]; + struct stat fileinfo; + int lockfd, lockpid; + + snprintf(lockfilename, lockfilesize, "%s/%s%s%s", lockdir, + locking_prefix, lockbase, locking_suffix); +#ifdef DEBUG + fprintf(stderr, "lock file name is %s\n", lockfilename); +#endif + if (stat(lockfilename, &fileinfo) != -1) { + ssize_t readtot = 0; + ssize_t readamt = 0; + char *lockbuf = charalloc(8192); + char *promptstr = charalloc(128); + int ans; + if ((lockfd = open(lockfilename, O_RDONLY)) < 0) { + statusbar(_("Error opening lock file %s: %s"), + lockfilename, strerror(errno)); + return -1; + } + do { + readamt = read(lockfd, &lockbuf[readtot], BUFSIZ); + readtot += readamt; + } while (readtot < 8192 && readamt > 0); + + if (readtot < 48) { + statusbar(_("Error reading lock file %s: Not enough data read"), + lockfilename); + return -1; + } + strncpy(lockprog, &lockbuf[2], 10); + lockpid = (unsigned char)lockbuf[25] * 256 + (unsigned char)lockbuf[24]; + strncpy(lockuser, &lockbuf[28], 16); +#ifdef DEBUG + fprintf(stderr, "lockpid = %d\n", lockpid); + fprintf(stderr, "program name which created this lock file should be %s\n", + lockprog); + fprintf(stderr, "user which created this lock file should be %s\n", + lockuser); +#endif + /* TRANSLATORS: The second %s is the name of the user, the third that of the editor. */ + sprintf(promptstr, _("File %s is being edited (by %s with %s, PID %d); continue?"), + filename, lockuser, lockprog, lockpid); + ans = do_yesno_prompt(FALSE, promptstr); + if (ans < 1) { + blank_statusbar(); + return -1; + } + } else { + lockfiledir = mallocstrcpy(NULL, lockfilename); + lockfiledir = dirname(lockfiledir); + if (stat(lockfiledir, &fileinfo) == -1) { + statusbar(_("Error writing lock file: Directory \'%s\' doesn't exist"), + lockfiledir); + return 0; + } + } + + + return write_lockfile(lockfilename, filename, FALSE); +} +#endif /* !NANO_TINY */ + /* If it's not "", filename is a file to open. We make a new buffer, if * necessary, and then open and read the file, if applicable. */ void open_buffer(const char *filename, bool undoable) { + bool quiet = FALSE; bool new_buffer = (openfile == NULL -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER || ISSET(MULTIBUFFER) #endif ); @@ -128,16 +342,34 @@ void open_buffer(const char *filename, bool undoable) } #endif - /* If the filename isn't blank, open the file. Otherwise, treat it - * as a new file. */ - rc = (filename[0] != '\0') ? open_file(filename, new_buffer, &f) : - -2; - /* If we're loading into a new buffer, add a new entry to * openfile. */ - if (new_buffer) + if (new_buffer) { make_new_buffer(); +#ifndef NANO_TINY + if (ISSET(LOCKING) && filename[0] != '\0') { + int lockstatus = do_lockfile(filename); + if (lockstatus < 0) { +#ifndef DISABLE_MULTIBUFFER + if (openfile->next) { + close_buffer(TRUE); + return; + } +#endif + } else if (lockstatus == 0) { + quiet = TRUE; + } + } +#endif + } + + + /* If the filename isn't blank, and we are not in NOREAD_MODE, + * open the file. Otherwise, treat it as a new file. */ + rc = (filename[0] != '\0' && !ISSET(NOREAD_MODE)) ? + open_file(filename, new_buffer, quiet, &f) : -2; + /* If we have a file, and we're loading into a new buffer, update * the filename. */ if (rc != -1 && new_buffer) @@ -164,7 +396,7 @@ void open_buffer(const char *filename, bool undoable) openfile->placewewant = 0; } -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR /* If we're loading into a new buffer, update the colors to account * for it, if applicable. */ if (new_buffer) @@ -188,7 +420,7 @@ void replace_buffer(const char *filename) /* If the filename isn't blank, open the file. Otherwise, treat it * as a new file. */ - rc = (filename[0] != '\0') ? open_file(filename, TRUE, &f) : -2; + rc = (filename[0] != '\0') ? open_file(filename, TRUE, FALSE, &f) : -2; /* Reinitialize the text of the current buffer. */ free_filestruct(openfile->fileage); @@ -211,7 +443,7 @@ void display_buffer(void) /* Update the titlebar, since the filename may have changed. */ titlebar(NULL); -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR /* Make sure we're using the buffer's associated colors, if * applicable. */ color_init(); @@ -221,17 +453,18 @@ void display_buffer(void) edit_refresh(); } -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER /* Switch to the next file buffer if next_buf is TRUE. Otherwise, * switch to the previous file buffer. */ -void switch_to_prevnext_buffer(bool next_buf) +void switch_to_prevnext_buffer(bool next_buf, bool quiet) { assert(openfile != NULL); /* If only one file buffer is open, indicate it on the statusbar and * get out. */ if (openfile == openfile->next) { - statusbar(_("No more open file buffers")); + if (quiet == FALSE) + statusbar(_("No more open file buffers")); return; } @@ -247,31 +480,35 @@ void switch_to_prevnext_buffer(bool next_buf) display_buffer(); /* Indicate the switch on the statusbar. */ - statusbar(_("Switched to %s"), - ((openfile->filename[0] == '\0') ? _("New Buffer") : - openfile->filename)); + if (quiet == FALSE) + statusbar(_("Switched to %s"), + ((openfile->filename[0] == '\0') ? _("New Buffer") : + openfile->filename)); #ifdef DEBUG dump_filestruct(openfile->current); #endif + display_main_list(); } /* Switch to the previous entry in the openfile filebuffer. */ void switch_to_prev_buffer_void(void) { - switch_to_prevnext_buffer(FALSE); + switch_to_prevnext_buffer(FALSE, FALSE); } /* Switch to the next entry in the openfile filebuffer. */ void switch_to_next_buffer_void(void) { - switch_to_prevnext_buffer(TRUE); + switch_to_prevnext_buffer(TRUE, FALSE); } /* Delete an entry from the openfile filebuffer, and switch to the one * after it. Return TRUE on success, or FALSE if there are no more open - * file buffers. */ -bool close_buffer(void) + * file buffers. + * quiet - should we print messages switching bufers + */ +bool close_buffer(bool quiet) { assert(openfile != NULL); @@ -279,24 +516,29 @@ bool close_buffer(void) if (openfile == openfile->next) return FALSE; +#ifndef DISABLE_HISTORIES + update_poshistory(openfile->filename, openfile->current->lineno, xplustabs() + 1); +#endif + /* Switch to the next file buffer. */ - switch_to_next_buffer_void(); + switch_to_prevnext_buffer(TRUE, quiet); /* Close the file buffer we had open before. */ unlink_opennode(openfile->prev); - display_main_list(); + /* If only one buffer is open now, show Exit in the help lines. */ + if (openfile == openfile->next) + exitfunc->desc = exit_tag; return TRUE; } -#endif /* ENABLE_MULTIBUFFER */ +#endif /* !DISABLE_MULTIBUFFER */ -/* A bit of a copy and paste from open_file(), is_file_writable() - * just checks whether the file is appendable as a quick - * permissions check, and we tend to err on the side of permissiveness - * (reporting TRUE when it might be wrong) to not fluster users - * editing on odd filesystems by printing incorrect warnings. - */ +/* A bit of a copy and paste from open_file(), is_file_writable() just + * checks whether the file is appendable as a quick permissions check, + * and we tend to err on the side of permissiveness (reporting TRUE when + * it might be wrong) to not fluster users editing on odd filesystems by + * printing incorrect warnings. */ int is_file_writable(const char *filename) { struct stat fileinfo, fileinfo2; @@ -305,7 +547,6 @@ int is_file_writable(const char *filename) char *full_filename; bool ans = TRUE; - if (ISSET(VIEW_MODE)) return TRUE; @@ -315,7 +556,7 @@ int is_file_writable(const char *filename) full_filename = get_full_path(filename); /* Okay, if we can't stat the path due to a component's - permissions, just try the relative one */ + permissions, just try the relative one. */ if (full_filename == NULL || (stat(full_filename, &fileinfo) == -1 && stat(filename, &fileinfo2) != -1)) full_filename = mallocstrcpy(NULL, filename); @@ -356,7 +597,7 @@ filestruct *read_line(char *buf, filestruct *prevnode, bool fileptr->data[buf_len - 1] = '\0'; #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR fileptr->multidata = NULL; #endif @@ -389,9 +630,9 @@ filestruct *read_line(char *buf, filestruct *prevnode, bool /* Read an open file into the current buffer. f should be set to the * open file, and filename should be set to the name of the file. - * undoable means do we want to create undo records to try and undo this. - * Will also attempt to check file writability if fd > 0 and checkwritable == TRUE - */ + * undoable means do we want to create undo records to try and undo + * this. Will also attempt to check file writability if fd > 0 and + * checkwritable == TRUE. */ void read_file(FILE *f, int fd, const char *filename, bool undoable, bool checkwritable) { size_t num_lines = 0; @@ -674,9 +915,9 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable, bool checkw * found". * * Return -2 if we say "New File", -1 if the file isn't opened, and the - * fd opened otherwise. The file might still have an error while reading + * fd opened otherwise. The file might still have an error while reading * with a 0 return value. *f is set to the opened file. */ -int open_file(const char *filename, bool newfie, FILE **f) +int open_file(const char *filename, bool newfie, bool quiet, FILE **f) { struct stat fileinfo, fileinfo2; int fd; @@ -688,22 +929,25 @@ int open_file(const char *filename, bool newfie, FILE **f) full_filename = get_full_path(filename); /* Okay, if we can't stat the path due to a component's - permissions, just try the relative one */ - if (full_filename == NULL + permissions, just try the relative one. */ + if (full_filename == NULL || (stat(full_filename, &fileinfo) == -1 && stat(filename, &fileinfo2) != -1)) full_filename = mallocstrcpy(NULL, filename); + if (stat(full_filename, &fileinfo) == -1) { - /* Well, maybe we can open the file even if the OS - says its not there */ + /* Well, maybe we can open the file even if the OS says it's + * not there. */ if ((fd = open(filename, O_RDONLY)) != -1) { - statusbar(_("Reading File")); + if (!quiet) + statusbar(_("Reading File")); free(full_filename); return 0; } if (newfie) { - statusbar(_("New File")); + if (!quiet) + statusbar(_("New File")); return -2; } statusbar(_("\"%s\" not found"), filename); @@ -722,7 +966,7 @@ int open_file(const char *filename, bool newfie, FILE **f) statusbar(_("Error reading %s: %s"), filename, strerror(errno)); beep(); - return -1; + return -1; } else { /* The file is A-OK. Open it. */ *f = fdopen(fd, "rb"); @@ -800,8 +1044,7 @@ void do_insertfile( filestruct *edittop_save = openfile->edittop; size_t current_x_save = openfile->current_x; ssize_t current_y_save = openfile->current_y; - bool edittop_inside = FALSE, meta_key = FALSE, func_key = FALSE; - const sc *s; + bool edittop_inside = FALSE; #ifndef NANO_TINY bool right_side_up = FALSE, single_line = FALSE; #endif @@ -812,22 +1055,21 @@ void do_insertfile( #ifndef NANO_TINY if (execute) { msg = -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER ISSET(MULTIBUFFER) ? _("Command to execute in new buffer [from %s] ") : #endif _("Command to execute [from %s] "); - } else { -#endif + } else +#endif /* NANO_TINY */ + { msg = -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER ISSET(MULTIBUFFER) ? _("File to insert into new buffer [from %s] ") : #endif _("File to insert [from %s] "); -#ifndef NANO_TINY } -#endif i = do_prompt(TRUE, #ifndef DISABLE_TABCOMP @@ -837,8 +1079,7 @@ void do_insertfile( execute ? MEXTCMD : #endif MINSERTFILE, ans, - &meta_key, &func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES NULL, #endif edit_refresh, msg, @@ -853,7 +1094,7 @@ void do_insertfile( * filename or command begins with a newline (i.e. an encoded * null), treat it as though it's blank. */ if (i == -1 || ((i == -2 || *answer == '\n') -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER && !ISSET(MULTIBUFFER) #endif )) { @@ -861,32 +1102,29 @@ void do_insertfile( break; } else { size_t pww_save = openfile->placewewant; + functionptrtype func = func_from_key(&i); ans = mallocstrcpy(ans, answer); - s = get_shortcut(currmenu, &i, &meta_key, &func_key); - #ifndef NANO_TINY -#ifdef ENABLE_MULTIBUFFER - - if (s && s->scfunc == NEW_BUFFER_MSG) { +#ifndef DISABLE_MULTIBUFFER + if (func == new_buffer_void) { /* Don't allow toggling if we're in view mode. */ if (!ISSET(VIEW_MODE)) TOGGLE(MULTIBUFFER); + else + beep(); continue; - } else + } #endif - if (s && s->scfunc == EXT_CMD_MSG) { + if (func == flip_execute_void) { execute = !execute; continue; } -#ifndef DISABLE_BROWSER - else -#endif #endif /* !NANO_TINY */ #ifndef DISABLE_BROWSER - if (s && s->scfunc == TO_FILES_MSG) { + if (func == to_files_void) { char *tmp = do_browse_from(answer); if (tmp == NULL) @@ -903,28 +1141,28 @@ void do_insertfile( /* If we don't have a file yet, go back to the statusbar * prompt. */ if (i != 0 -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER && (i != -2 || !ISSET(MULTIBUFFER)) #endif ) continue; #ifndef NANO_TINY - /* Keep track of whether the mark begins inside the - * partition and will need adjustment. */ - if (openfile->mark_set) { - filestruct *top, *bot; - size_t top_x, bot_x; + /* Keep track of whether the mark begins inside the + * partition and will need adjustment. */ + if (openfile->mark_set) { + filestruct *top, *bot; + size_t top_x, bot_x; - mark_order((const filestruct **)&top, &top_x, + mark_order((const filestruct **)&top, &top_x, (const filestruct **)&bot, &bot_x, &right_side_up); - single_line = (top == bot); - } + single_line = (top == bot); + } #endif -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER if (!ISSET(MULTIBUFFER)) { #endif /* If we're not inserting into a new buffer, partition @@ -937,7 +1175,7 @@ void do_insertfile( openfile->current_x); edittop_inside = (openfile->edittop == openfile->fileage); -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER } #endif @@ -948,7 +1186,7 @@ void do_insertfile( #ifndef NANO_TINY if (execute) { -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER if (ISSET(MULTIBUFFER)) /* Open a blank buffer. */ open_buffer("", FALSE); @@ -957,7 +1195,7 @@ void do_insertfile( /* Save the command's output in the current buffer. */ execute_command(answer); -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER if (ISSET(MULTIBUFFER)) { /* Move back to the beginning of the first line of * the buffer. */ @@ -980,12 +1218,20 @@ void do_insertfile( } #endif -#ifdef ENABLE_MULTIBUFFER - if (ISSET(MULTIBUFFER)) +#if !defined(DISABLE_MULTIBUFFER) && !defined(DISABLE_HISTORIES) + if (ISSET(MULTIBUFFER)) { /* Update the screen to account for the current * buffer. */ display_buffer(); - else + + ssize_t savedposline, savedposcol; + if (ISSET(POS_HISTORY) && +#ifndef NANO_TINY + !execute && +#endif + check_poshistory(answer, &savedposline, &savedposcol)) + do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE, FALSE); + } else #endif { filestruct *top_save = openfile->fileage; @@ -1056,8 +1302,6 @@ void do_insertfile( break; } } - shortcut_init(FALSE); - free(ans); } @@ -1066,13 +1310,12 @@ void do_insertfile( * allow inserting a file into a new buffer. */ void do_insertfile_void(void) { - if (ISSET(RESTRICTED)) { - nano_disabled_msg(); + nano_disabled_msg(); return; } -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER if (ISSET(VIEW_MODE) && !ISSET(MULTIBUFFER)) statusbar(_("Key invalid in non-multibuffer mode")); else @@ -1100,7 +1343,7 @@ char *get_full_path(const char *origpath) bool path_only; if (origpath == NULL) - return NULL; + return NULL; /* Get the current directory. If it doesn't exist, back up and try * again until we get a directory that does, and use that as the @@ -1366,6 +1609,22 @@ bool check_operating_dir(const char *currpath, bool allow_tabcomp) #endif #ifndef NANO_TINY +/* Although this sucks, it sucks less than having a single 'my system is + * messed up and I'm blanket allowing insecure file writing operations'. */ +int prompt_failed_backupwrite(const char *filename) +{ + static int i; + static char *prevfile = NULL; /* What was the last file we were + * passed so we don't keep asking + * this? Though maybe we should... */ + if (prevfile == NULL || strcmp(filename, prevfile)) { + i = do_yesno_prompt(FALSE, + _("Failed to write backup file, continue saving? (Say N if unsure) ")); + prevfile = mallocstrcpy(prevfile, filename); + } + return i; +} + void init_backup_dir(void) { char *full_backup_dir; @@ -1387,7 +1646,7 @@ void init_backup_dir(void) backup_dir = full_backup_dir; } } -#endif +#endif /* !NANO_TINY */ /* Read from inn, write to out. We assume inn is opened for reading, * and out for writing. We return 0 on success, -1 on read error, or -2 @@ -1447,12 +1706,14 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type /* The file descriptor we use. */ mode_t original_umask = 0; /* Our umask, from when nano started. */ +#ifndef NANO_TINY bool realexists; /* The result of stat(). TRUE if the file exists, FALSE * otherwise. If name is a link that points nowhere, realexists * is FALSE. */ struct stat st; /* The status fields filled in by stat(). */ +#endif bool anyexists; /* The result of lstat(). The same as realexists, unless name * is a link. */ @@ -1464,7 +1725,6 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type /* The actual file, realname, we are writing to. */ char *tempname = NULL; /* The temp file name we write to on prepend. */ - int backup_cflags; assert(name != NULL); @@ -1502,17 +1762,18 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type goto cleanup_and_exit; } - /* Save the state of the file at the end of the symlink (if there is - * one). */ +#ifndef NANO_TINY + /* Check whether the file (at the end of the symlink) exists. */ realexists = (stat(realname, &st) != -1); -#ifndef NANO_TINY - /* if we have not stat()d this file before (say, the user just - * specified it interactively), stat and save the value - * or else we will chase null pointers when we do - * modtime checks, preserve file times, etc. during backup */ - if (openfile->current_stat == NULL && !tmp && realexists) + /* If we haven't stat()d this file before (say, the user just + * specified it interactively), stat and save the value now, + * or else we will chase null pointers when we do modtime checks, + * preserve file times, and so on, during backup. */ + if (openfile->current_stat == NULL && !tmp && realexists) { + openfile->current_stat = (struct stat *)nmalloc(sizeof(struct stat)); stat(realname, openfile->current_stat); + } /* We backup only if the backup toggle is set, the file isn't * temporary, and the file already exists. Furthermore, if we @@ -1527,6 +1788,7 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type char *backupname; struct utimbuf filetime; int copy_status; + int backup_cflags; /* Save the original file's access and modification times. */ filetime.actime = openfile->current_stat->st_atime; @@ -1582,10 +1844,11 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type _("Too many backup files?")); free(backuptemp); free(backupname); - /* If we can't write to the backup, DONT go on, since - whatever caused the backup file to fail (e.g. disk - full may well cause the real file write to fail, which - means we could lose both the backup and the original! */ + /* If we can't write to the backup, DON'T go on, since + * whatever caused the backup file to fail (e.g. disk + * full may well cause the real file write to fail, + * which means we could lose both the backup and the + * original! */ goto cleanup_and_exit; } else { free(backupname); @@ -1597,9 +1860,11 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type } /* First, unlink any existing backups. Next, open the backup - file with O_CREAT and O_EXCL. If it succeeds, we - have a file descriptor to a new backup file. */ + * file with O_CREAT and O_EXCL. If it succeeds, we have a file + * descriptor to a new backup file. */ if (unlink(backupname) < 0 && errno != ENOENT && !ISSET(INSECURE_BACKUP)) { + if (prompt_failed_backupwrite(backupname)) + goto skip_backup; statusbar(_("Error writing backup file %s: %s"), backupname, strerror(errno)); free(backupname); @@ -1608,13 +1873,13 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type if (ISSET(INSECURE_BACKUP)) backup_cflags = O_WRONLY | O_CREAT | O_APPEND; - else + else backup_cflags = O_WRONLY | O_CREAT | O_EXCL | O_APPEND; backup_fd = open(backupname, backup_cflags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); /* Now we've got a safe file stream. If the previous open() - call failed, this will return NULL. */ + * call failed, this will return NULL. */ backup_file = fdopen(backup_fd, "wb"); if (backup_fd < 0 || backup_file == NULL) { @@ -1624,11 +1889,13 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type goto cleanup_and_exit; } - /* We shouldn't worry about chown()ing something if we're not - root, since it's likely to fail! */ + /* We shouldn't worry about chown()ing something if we're not + * root, since it's likely to fail! */ if (geteuid() == NANO_ROOT_UID && fchown(backup_fd, openfile->current_stat->st_uid, openfile->current_stat->st_gid) == -1 - && !ISSET(INSECURE_BACKUP)) { + && !ISSET(INSECURE_BACKUP)) { + if (prompt_failed_backupwrite(backupname)) + goto skip_backup; statusbar(_("Error writing backup file %s: %s"), backupname, strerror(errno)); free(backupname); @@ -1636,7 +1903,10 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type goto cleanup_and_exit; } - if (fchmod(backup_fd, openfile->current_stat->st_mode) == -1 && !ISSET(INSECURE_BACKUP)) { + if (fchmod(backup_fd, openfile->current_stat->st_mode) == -1 + && !ISSET(INSECURE_BACKUP)) { + if (prompt_failed_backupwrite(backupname)) + goto skip_backup; statusbar(_("Error writing backup file %s: %s"), backupname, strerror(errno)); free(backupname); @@ -1664,12 +1934,14 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type /* And set its metadata. */ if (utime(backupname, &filetime) == -1 && !ISSET(INSECURE_BACKUP)) { + if (prompt_failed_backupwrite(backupname)) + goto skip_backup; statusbar(_("Error writing backup file %s: %s"), backupname, strerror(errno)); - /* If we can't write to the backup, DONT go on, since - whatever caused the backup file to fail (e.g. disk - full may well cause the real file write to fail, which - means we could lose both the backup and the original! */ + /* If we can't write to the backup, DON'T go on, since + * whatever caused the backup file to fail (e.g. disk full + * may well cause the real file write to fail, which means + * we could lose both the backup and the original! */ goto cleanup_and_exit; } @@ -1874,7 +2146,7 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type if (!nonamechange) { openfile->filename = mallocstrcpy(openfile->filename, realname); -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR /* We might have changed the filename, so update the colors * to account for it, and then make sure we're using * them. */ @@ -1894,7 +2166,8 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type if (openfile->current_stat == NULL) openfile->current_stat = (struct stat *)nmalloc(sizeof(struct stat)); - stat(realname, openfile->current_stat); + if (!openfile->mark_set) + stat(realname, openfile->current_stat); #endif statusbar(P_("Wrote %lu line", "Wrote %lu lines", @@ -1960,23 +2233,24 @@ bool write_marked_file(const char *name, FILE *f_open, bool tmp, return retval; } + #endif /* !NANO_TINY */ /* Write the current file to disk. If the mark is on, write the current * marked selection to disk. If exiting is TRUE, write the file to disk * regardless of whether the mark is on, and without prompting if the - * TEMP_FILE flag is set. Return TRUE on success or FALSE on error. */ + * TEMP_FILE flag is set and the current file has a name. Return TRUE + * on success or FALSE on error. */ bool do_writeout(bool exiting) { int i; append_type append = OVERWRITE; char *ans; /* The last answer the user typed at the statusbar prompt. */ -#ifdef NANO_EXTRA +#ifndef DISABLE_EXTRA static bool did_credits = FALSE; #endif - bool retval = FALSE, meta_key = FALSE, func_key = FALSE; - const sc *s; + bool retval = FALSE; currmenu = MWRITEFILE; @@ -2030,8 +2304,7 @@ bool do_writeout(bool exiting) TRUE, #endif MWRITEFILE, ans, - &meta_key, &func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES NULL, #endif edit_refresh, "%s%s%s", msg, @@ -2049,11 +2322,12 @@ bool do_writeout(bool exiting) retval = FALSE; break; } else { + functionptrtype func = func_from_key(&i); + ans = mallocstrcpy(ans, answer); - s = get_shortcut(currmenu, &i, &meta_key, &func_key); #ifndef DISABLE_BROWSER - if (s && s->scfunc == TO_FILES_MSG) { + if (func == to_files_void) { char *tmp = do_browse_from(answer); if (tmp == NULL) @@ -2065,26 +2339,26 @@ bool do_writeout(bool exiting) } else #endif /* !DISABLE_BROWSER */ #ifndef NANO_TINY - if (s && s->scfunc == DOS_FORMAT_MSG) { + if (func == dos_format_void) { openfile->fmt = (openfile->fmt == DOS_FILE) ? NIX_FILE : DOS_FILE; continue; - } else if (s && s->scfunc == MAC_FORMAT_MSG) { + } else if (func == mac_format_void) { openfile->fmt = (openfile->fmt == MAC_FILE) ? NIX_FILE : MAC_FILE; continue; - } else if (s && s->scfunc == BACKUP_FILE_MSG) { + } else if (func == backup_file_void) { TOGGLE(BACKUP_FILE); continue; } else #endif /* !NANO_TINY */ - if (s && s->scfunc == PREPEND_MSG) { + if (func == prepend_void) { append = (append == PREPEND) ? OVERWRITE : PREPEND; continue; - } else if (s && s->scfunc == APPEND_MSG) { + } else if (func == append_void) { append = (append == APPEND) ? OVERWRITE : APPEND; continue; - } else if (s && s->scfunc == DO_HELP_VOID) { + } else if (func == do_help_void) { continue; } @@ -2092,7 +2366,7 @@ bool do_writeout(bool exiting) fprintf(stderr, "filename is %s\n", answer); #endif -#ifdef NANO_EXTRA +#ifndef DISABLE_EXTRA /* If the current file has been modified, we've pressed * Ctrl-X at the edit window to exit, we've pressed "y" at * the "Save modified buffer" prompt to save, we've entered @@ -2165,10 +2439,13 @@ bool do_writeout(bool exiting) } } #ifndef NANO_TINY - /* Complain if the file exists, the name hasn't changed, and the - stat information we had before does not match what we have now */ - else if (name_exists && openfile->current_stat && (openfile->current_stat->st_mtime < st.st_mtime || - openfile->current_stat->st_dev != st.st_dev || openfile->current_stat->st_ino != st.st_ino)) { + /* Complain if the file exists, the name hasn't changed, + * and the stat information we had before does not match + * what we have now. */ + else if (name_exists && openfile->current_stat && + (openfile->current_stat->st_mtime < st.st_mtime || + openfile->current_stat->st_dev != st.st_dev || + openfile->current_stat->st_ino != st.st_ino)) { i = do_yesno_prompt(FALSE, _("File was modified since you opened it, continue saving ? ")); if (i == 0 || i == -1) @@ -2275,7 +2552,7 @@ int diralphasort(const void *va, const void *vb) /* Standard function brain damage: We should be sorting * alphabetically and case-insensitively according to the current * locale, but there's no standard strcasecoll() function, so we - * have to use multibyte strcasecmp() instead, */ + * have to use multibyte strcasecmp() instead. */ return mbstrcasecmp(a, b); } @@ -2372,9 +2649,6 @@ char **cwd_tab_completion(const char *buf, bool allow_files, size_t *num_matches, size_t buf_len) { char *dirname = mallocstrcpy(NULL, buf), *filename; -#ifndef DISABLE_OPERATINGDIR - size_t dirnamelen; -#endif size_t filenamelen; char **matches = NULL; DIR *dir; @@ -2413,9 +2687,6 @@ char **cwd_tab_completion(const char *buf, bool allow_files, size_t return NULL; } -#ifndef DISABLE_OPERATINGDIR - dirnamelen = strlen(dirname); -#endif filenamelen = strlen(filename); while ((nextdir = readdir(dir)) != NULL) { @@ -2656,29 +2927,96 @@ const char *tail(const char *foo) return tmp; } -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) -/* Return $HOME/.nano_history, or NULL if we can't find the home +#ifndef DISABLE_HISTORIES +/* Return the constructed dirfile path, or NULL if we can't find the home * directory. The string is dynamically allocated, and should be * freed. */ -char *histfilename(void) +char *construct_filename(const char *str) { - char *nanohist = NULL; + char *newstr = NULL; if (homedir != NULL) { size_t homelen = strlen(homedir); - nanohist = charalloc(homelen + 15); - strcpy(nanohist, homedir); - strcpy(nanohist + homelen, "/.nano_history"); + newstr = charalloc(homelen + strlen(str) + 1); + strcpy(newstr, homedir); + strcpy(newstr + homelen, str); } - return nanohist; + return newstr; +} + +char *histfilename(void) +{ + return construct_filename("/.nano/search_history"); +} + +/* Construct the legacy history filename. + * (Deprecate in 2.5, delete later.) */ +char *legacyhistfilename(void) +{ + return construct_filename("/.nano_history"); +} + +char *poshistfilename(void) +{ + return construct_filename("/.nano/filepos_history"); } -/* Load histories from ~/.nano_history. */ +void history_error(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, _(msg), ap); + va_end(ap); + + fprintf(stderr, _("\nPress Enter to continue\n")); + while (getchar() != '\n') + ; +} + +/* Now that we have more than one history file, let's just rely on a + * .nano dir for this stuff. Return 1 if the dir exists or was + * successfully created, and return 0 otherwise. */ +int check_dotnano(void) +{ + struct stat dirstat; + char *nanodir = construct_filename("/.nano"); + + if (stat(nanodir, &dirstat) == -1) { + if (mkdir(nanodir, S_IRWXU | S_IRWXG | S_IRWXO) == -1) { + history_error(N_("Unable to create directory %s: %s\n" + "It is required for saving/loading search history or cursor positions.\n"), + nanodir, strerror(errno)); + return 0; + } + } else if (!S_ISDIR(dirstat.st_mode)) { + history_error(N_("Path %s is not a directory and needs to be.\n" + "Nano will be unable to load or save search history or cursor positions.\n"), + nanodir); + return 0; + } + return 1; +} + +/* Load the search and replace histories from ~/.nano/search_history. */ void load_history(void) { char *nanohist = histfilename(); + char *legacyhist = legacyhistfilename(); + struct stat hstat; + + if (stat(legacyhist, &hstat) != -1 && stat(nanohist, &hstat) == -1) { + if (rename(legacyhist, nanohist) == -1) + history_error(N_("Detected a legacy nano history file (%s) which I tried to move\n" + "to the preferred location (%s) but encountered an error: %s"), + legacyhist, nanohist, strerror(errno)); + else + history_error(N_("Detected a legacy nano history file (%s) which I moved\n" + "to the preferred location (%s)\n(see the nano FAQ about this change)"), + legacyhist, nanohist); + } /* Assume do_rcfile() has reported a missing home directory. */ if (nanohist != NULL) { @@ -2688,12 +3026,8 @@ void load_history(void) if (errno != ENOENT) { /* Don't save history when we quit. */ UNSET(HISTORYLOG); - rcfile_error(N_("Error reading %s: %s"), nanohist, + history_error(N_("Error reading %s: %s"), nanohist, strerror(errno)); - fprintf(stderr, - _("\nPress Enter to continue starting nano.\n")); - while (getchar() != '\n') - ; } } else { /* Load a history list (first the search history, then the @@ -2718,8 +3052,11 @@ void load_history(void) fclose(hist); free(line); + if (search_history->prev != NULL) + last_search = mallocstrcpy(NULL, search_history->prev->data); } free(nanohist); + free(legacyhist); } } @@ -2745,7 +3082,7 @@ bool writehist(FILE *hist, filestruct *h) return TRUE; } -/* Save histories to ~/.nano_history. */ +/* Save the search and replace histories to ~/.nano/search_history. */ void save_history(void) { char *nanohist; @@ -2761,7 +3098,7 @@ void save_history(void) FILE *hist = fopen(nanohist, "wb"); if (hist == NULL) - rcfile_error(N_("Error writing %s: %s"), nanohist, + history_error(N_("Error writing %s: %s"), nanohist, strerror(errno)); else { /* Make sure no one else can read from or write to the @@ -2770,7 +3107,7 @@ void save_history(void) if (!writehist(hist, searchage) || !writehist(hist, replaceage)) - rcfile_error(N_("Error writing %s: %s"), nanohist, + history_error(N_("Error writing %s: %s"), nanohist, strerror(errno)); fclose(hist); @@ -2779,4 +3116,155 @@ void save_history(void) free(nanohist); } } -#endif /* !NANO_TINY && ENABLE_NANORC */ + +/* Save the recorded last file positions to ~/.nano/filepos_history. */ +void save_poshistory(void) +{ + char *poshist; + char *statusstr = NULL; + poshiststruct *posptr; + + poshist = poshistfilename(); + + if (poshist != NULL) { + FILE *hist = fopen(poshist, "wb"); + + if (hist == NULL) + history_error(N_("Error writing %s: %s"), poshist, + strerror(errno)); + else { + /* Make sure no one else can read from or write to the + * history file. */ + chmod(poshist, S_IRUSR | S_IWUSR); + + for (posptr = poshistory; posptr != NULL; posptr = posptr->next) { + statusstr = charalloc(strlen(posptr->filename) + 2 * sizeof(ssize_t) + 4); + sprintf(statusstr, "%s %ld %ld\n", posptr->filename, (long)posptr->lineno, + (long)posptr->xno); + if (fwrite(statusstr, sizeof(char), strlen(statusstr), hist) < strlen(statusstr)) + history_error(N_("Error writing %s: %s"), poshist, + strerror(errno)); + free(statusstr); + } + fclose(hist); + } + free(poshist); + } +} + +/* Update the recorded last file positions, given a filename, a line + * and a column. If no entry is found, add a new one at the end. */ +void update_poshistory(char *filename, ssize_t lineno, ssize_t xpos) +{ + poshiststruct *posptr, *posprev = NULL; + char *fullpath = get_full_path(filename); + + if (fullpath == NULL) + return; + + for (posptr = poshistory; posptr != NULL; posptr = posptr->next) { + if (!strcmp(posptr->filename, fullpath)) { + posptr->lineno = lineno; + posptr->xno = xpos; + return; + } + posprev = posptr; + } + + /* Didn't find it, make a new node yo! */ + posptr = (poshiststruct *)nmalloc(sizeof(poshiststruct)); + posptr->filename = mallocstrcpy(NULL, fullpath); + posptr->lineno = lineno; + posptr->xno = xpos; + posptr->next = NULL; + + if (!poshistory) + poshistory = posptr; + else + posprev->next = posptr; + + free(fullpath); +} + +/* Check the recorded last file positions to see if the given file + * matches an existing entry. If so, return 1 and set line and column + * to the retrieved values. Otherwise, return 0. */ +int check_poshistory(const char *file, ssize_t *line, ssize_t *column) +{ + poshiststruct *posptr; + char *fullpath = get_full_path(file); + + if (fullpath == NULL) + return 0; + + for (posptr = poshistory; posptr != NULL; posptr = posptr->next) { + if (!strcmp(posptr->filename, fullpath)) { + *line = posptr->lineno; + *column = posptr->xno; + free(fullpath); + return 1; + } + } + free(fullpath); + return 0; +} + +/* Load the recorded file positions from ~/.nano/filepos_history. */ +void load_poshistory(void) +{ + char *nanohist = poshistfilename(); + + /* Assume do_rcfile() has reported a missing home directory. */ + if (nanohist != NULL) { + FILE *hist = fopen(nanohist, "rb"); + + if (hist == NULL) { + if (errno != ENOENT) { + /* Don't save history when we quit. */ + UNSET(POS_HISTORY); + history_error(N_("Error reading %s: %s"), nanohist, + strerror(errno)); + } + } else { + char *line = NULL, *lineptr, *xptr; + size_t buf_len = 0; + ssize_t read, lineno, xno; + poshiststruct *posptr; + + /* Read and parse each line, and put the data into the + * positions history structure. */ + while ((read = getline(&line, &buf_len, hist)) >= 0) { + if (read > 0 && line[read - 1] == '\n') { + read--; + line[read] = '\0'; + } + if (read > 0) + unsunder(line, read); + lineptr = parse_next_word(line); + xptr = parse_next_word(lineptr); + lineno = atoi(lineptr); + xno = atoi(xptr); + if (poshistory == NULL) { + poshistory = (poshiststruct *)nmalloc(sizeof(poshiststruct)); + poshistory->filename = mallocstrcpy(NULL, line); + poshistory->lineno = lineno; + poshistory->xno = xno; + poshistory->next = NULL; + } else { + for (posptr = poshistory; posptr->next != NULL; posptr = posptr->next) + ; + posptr->next = (poshiststruct *)nmalloc(sizeof(poshiststruct)); + posptr->next->filename = mallocstrcpy(NULL, line); + posptr->next->lineno = lineno; + posptr->next->xno = xno; + posptr->next->next = NULL; + } + } + + fclose(hist); + free(line); + } + free(nanohist); + } +} +#endif /* !DISABLE_HISTORIES */ diff --git a/src/global.c b/src/global.c index ae14a49..9e7fec8 100644 --- a/src/global.c +++ b/src/global.c @@ -1,9 +1,9 @@ -/* $Id: global.c 4520 2010-11-12 06:23:14Z astyanax $ */ +/* $Id: global.c 5143 2015-03-20 12:22:49Z bens $ */ /************************************************************************** * global.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -38,6 +38,11 @@ bool jump_buf_main = FALSE; * SIGWINCH? */ #endif +bool meta_key; + /* Whether the current keystroke is a Meta key. */ +bool func_key; + /* Whether the current keystroke is an extended keypad value. */ + #ifndef DISABLE_WRAPJUSTIFY ssize_t fill = 0; /* The column where we will wrap lines. */ @@ -67,7 +72,7 @@ WINDOW *bottomwin; int editwinrows = 0; /* How many rows does the edit window take up? */ int maxrows = 0; - /* How many usable lines are there (due to soft wrapping) */ + /* How many usable lines there are (due to soft wrapping). */ filestruct *cutbuffer = NULL; /* The buffer where we store cut text. */ @@ -88,7 +93,7 @@ char *matchbrackets = NULL; * searches. */ #endif -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) char *whitespace = NULL; /* The characters used when displaying the first characters of * tabs and spaces. */ @@ -118,7 +123,7 @@ size_t quotelen; #endif bool nodelay_mode = FALSE; - /* Are we in nodelay mode (checking for a cancel wile doing something */ + /* Are we checking for a cancel wile doing something? */ char *answer = NULL; /* The answer string used by the statusbar prompt. */ @@ -130,6 +135,11 @@ ssize_t tabsize = -1; #ifndef NANO_TINY char *backup_dir = NULL; /* The directory where we store backup files. */ + +const char *locking_prefix = "."; + /* Prefix of how to store the vim-style lock file. */ +const char *locking_suffix = ".swp"; + /* Suffix of the vim-style lock file. */ #endif #ifndef DISABLE_OPERATINGDIR char *operating_dir = NULL; @@ -144,29 +154,31 @@ char *alt_speller = NULL; /* The command to use for the alternate spell checker. */ #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR syntaxtype *syntaxes = NULL; /* The global list of color syntaxes. */ char *syntaxstr = NULL; /* The color syntax name specified on the command line. */ - #endif -bool edit_refresh_needed = NULL; - /* Did a command mangle enough of the buffer refresh that we - should repaint the screen */ +bool edit_refresh_needed = FALSE; + /* Did a command mangle enough of the buffer refresh that we + * should repaint the screen? */ -const shortcut *currshortcut; - /* The current shortcut list we're using. */ int currmenu; - /* The currently loaded menu */ - + /* The currently loaded menu. */ sc *sclist = NULL; - /* New shortcut key struct */ + /* Pointer to the start of the shortcuts list. */ subnfunc *allfuncs = NULL; - /* New struct for the function list */ - -#ifndef NANO_TINY + /* Pointer to the start of the functions list. */ +subnfunc *tailfunc; + /* Pointer to the last function in the list. */ +subnfunc *exitfunc; + /* Pointer to the special Exit/Close item. */ +subnfunc *uncutfunc; + /* Pointer to the special Uncut/Unjustify item. */ + +#ifndef DISABLE_HISTORIES filestruct *search_history = NULL; /* The search string history list. */ filestruct *searchage = NULL; @@ -179,6 +191,8 @@ filestruct *replaceage = NULL; /* The top of the replace string history list. */ filestruct *replacebot = NULL; /* The bottom of the replace string history list. */ +poshiststruct *poshistory; + /* The cursor position history list. */ #endif /* Regular expressions. */ @@ -190,13 +204,19 @@ regmatch_t regmatches[10]; * maximum, used in regular expression searches. */ #endif -int reverse_attr = A_REVERSE; +int hilite_attribute = A_REVERSE; /* The curses attribute we use for reverse video. */ +#ifndef DISABLE_COLOR +char* specified_color_combo[] = {}; + /* The color combinations as specified in the rcfile. */ +#endif +color_pair interface_color_pair[] = {}; + /* The processed color pairs for the interface elements. */ char *homedir = NULL; /* The user's home directory, from $HOME or /etc/passwd. */ -/* Return the number of entries in the shortcut list s for a given menu. */ +/* Return the number of entries in the shortcut list for a given menu. */ size_t length_of_list(int menu) { subnfunc *f; @@ -213,35 +233,70 @@ size_t length_of_list(int menu) return i; } -/* Set type of function based on the string */ -function_type strtokeytype(const char *str) +/* To make the functions and shortcuts lists clearer. */ +#define VIEW TRUE /* Is allowed in view mode. */ +#define NOVIEW FALSE +#define BLANKAFTER TRUE /* A blank line after this one. */ +#define TOGETHER FALSE + +/* Just throw this here. */ +void case_sens_void(void) +{ +} +void regexp_void(void) +{ +} +void backwards_void(void) +{ +} +void gototext_void(void) +{ +} +#ifndef DISABLE_BROWSER +void to_files_void(void) +{ +} +void goto_dir_void(void) +{ +} +#endif +void dos_format_void(void) +{ +} +void mac_format_void(void) +{ +} +void append_void(void) +{ +} +void prepend_void(void) +{ +} +void backup_file_void(void) +{ +} +void new_buffer_void(void) +{ +} +void flip_replace_void(void) +{ +} +void flip_execute_void(void) { - if (str[0] == 'M' || str[0] == 'm') - return META; - else if (str[0] == '^') - return CONTROL; - else if (str[0] == 'F' || str[0] == 'F') - return FKEY; - else - return RAW; } -/* Add a string to the new function list strict. - Does not allow updates, yet anyway */ -void add_to_funcs(short func, int menus, const char *desc, const char *help, +/* Add a function to the function list. */ +void add_to_funcs(void (*func)(void), int menus, const char *desc, const char *help, bool blank_after, bool viewok) { - subnfunc *f; + subnfunc *f = (subnfunc *)nmalloc(sizeof(subnfunc)); + + if (allfuncs == NULL) + allfuncs = f; + else + tailfunc->next = f; + tailfunc = f; - if (allfuncs == NULL) { - allfuncs = (subnfunc *) nmalloc(sizeof(subnfunc)); - f = allfuncs; - } else { - for (f = allfuncs; f->next != NULL; f = f->next) - ; - f->next = (subnfunc *)nmalloc(sizeof(subnfunc)); - f = f->next; - } f->next = NULL; f->scfunc = func; f->menus = menus; @@ -253,94 +308,104 @@ void add_to_funcs(short func, int menus, const char *desc, const char *help, #endif #ifdef DEBUG - fprintf(stderr, "Added func \"%s\"", f->desc); + fprintf(stderr, "Added func %ld (%s) for menus %x\n", (long)func, f->desc, menus); #endif } -const sc *first_sc_for(int menu, short func) { - const sc *s; - const sc *metasc = NULL; +/* Add a key combo to the shortcut list. */ +void add_to_sclist(int menu, const char *scstring, void (*func)(void), int toggle) +{ + static sc *tailsc; + sc *s = (sc *)nmalloc(sizeof(sc)); - for (s = sclist; s != NULL; s = s->next) { - if ((s->menu & menu) && s->scfunc == func) { - /* try to use a meta sequence as a last resort. Otherwise - we will run into problems when we try and handle things like - the arrow keys, home, etc, if for some reason the user bound - them to a meta sequence first *shrug* */ - if (s->type == META) { - metasc = s; - continue; - } /* otherwise it was something else, use it */ - return s; - } - } + /* Start the list, or tack on the next item. */ + if (sclist == NULL) + sclist = s; + else + tailsc->next = s; + tailsc = s; + s->next = NULL; - /* If we're here we may have found only meta sequences, if so use one */ - if (metasc) - return metasc; + /* Fill in the data. */ + s->menu = menu; + s->scfunc = func; + s->toggle = toggle; + s->keystr = (char *) scstring; + s->type = strtokeytype(scstring); + assign_keyinfo(s); #ifdef DEBUG - fprintf(stderr, "Whoops, returning null given func %ld in menu %d\n", (long) func, menu); + fprintf(stderr, "Setting sequence to %d for shortcut \"%s\" in menu %x\n", s->seq, scstring, (int)s->menu); #endif - /* Otherwise... */ - return NULL; } - -/* Add a string to the new shortcut list implementation - Allows updates to existing entries in the list */ -void add_to_sclist(int menu, const char *scstring, short func, int toggle, int execute) +/* Assign one function's shortcuts to another function. */ +void replace_scs_for(void (*oldfunc)(void), void (*newfunc)(void)) { sc *s; - if (sclist == NULL) { - sclist = (sc *) nmalloc(sizeof(sc)); - s = sclist; - s->next = NULL; - } else { - for (s = sclist; s->next != NULL; s = s->next) - if (s->menu == menu && s->keystr == scstring) - break; + for (s = sclist; s != NULL; s = s->next) + if (s->scfunc == oldfunc) + s->scfunc = newfunc; +} - if (s->menu != menu || s->keystr != scstring) { /* i.e. this is not a replace... */ -#ifdef DEBUG - fprintf(stderr, "No match found...\n"); -#endif - s->next = (sc *)nmalloc(sizeof(sc)); - s = s->next; - s->next = NULL; - } - } +/* Return the first shortcut in the list of shortcuts that + * matches the given func in the given menu. */ +const sc *first_sc_for(int menu, void (*func)(void)) +{ + const sc *s; - s->type = strtokeytype(scstring); - s->menu = menu; - s->toggle = toggle; - s->keystr = (char *) scstring; - s->scfunc = func; - s->execute = execute; - assign_keyinfo(s); + for (s = sclist; s != NULL; s = s->next) + if ((s->menu & menu) && s->scfunc == func) + return s; #ifdef DEBUG - fprintf(stderr, "list val = %d\n", (int) s->menu); - fprintf(stderr, "Hey, set sequence to %d for shortcut \"%s\"\n", s->seq, scstring); + fprintf(stderr, "Whoops, returning null given func %ld in menu %x\n", (long)func, menu); #endif + /* Otherwise... */ + return NULL; } /* Return the given menu's first shortcut sequence, or the default value - (2nd arg). Assumes currmenu for the menu to check*/ -int sc_seq_or (short func, int defaultval) + * (2nd arg). Assumes currmenu for the menu to check. */ +int sc_seq_or(void (*func)(void), int defaultval) { const sc *s = first_sc_for(currmenu, func); - if (s) + if (s) { + meta_key = (s->type == META); return s->seq; + } /* else */ return defaultval; +} +/* Return a pointer to the function that is bound to the given key. */ +functionptrtype func_from_key(int *kbinput) +{ + const sc *s = get_shortcut(kbinput); + + if (s) + return s->scfunc; + else + return NULL; +} + +/* Return the type of command key based on the given string. */ +key_type strtokeytype(const char *str) +{ + if (str[0] == '^') + return CONTROL; + else if (str[0] == 'M') + return META; + else if (str[0] == 'F') + return FKEY; + else + return RAWINPUT; } -/* Assign the info to the shortcut struct - Assumes keystr is already assigned, naturally */ +/* Assign the info to the shortcut struct. + * Assumes keystr is already assigned, naturally. */ void assign_keyinfo(sc *s) { if (s->type == CONTROL) { @@ -352,163 +417,102 @@ void assign_keyinfo(sc *s) } else if (s->type == FKEY) { assert(strlen(s->keystr) > 1); s->seq = KEY_F0 + atoi(&s->keystr[1]); - } else /* raw */ + } else /* RAWINPUT */ s->seq = (int) s->keystr[0]; - /* Override some keys which don't bind as nicely as we'd like */ + /* Override some keys which don't bind as easily as we'd like. */ if (s->type == CONTROL && (!strcasecmp(&s->keystr[1], "space"))) s->seq = 0; else if (s->type == META && (!strcasecmp(&s->keystr[2], "space"))) s->seq = (int) ' '; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kup"))) - s->seq = KEY_UP; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kdown"))) - s->seq = KEY_DOWN; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kleft"))) - s->seq = KEY_LEFT; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kright"))) - s->seq = KEY_RIGHT; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kinsert"))) - s->seq = KEY_IC; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kdel"))) - s->seq = KEY_DC; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kbsp"))) - s->seq = KEY_BACKSPACE; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kenter"))) - s->seq = KEY_ENTER; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kpup"))) - s->seq = KEY_PPAGE; - else if (s->type == RAW && (!strcasecmp(s->keystr, "kpdown"))) - s->seq = KEY_NPAGE; + else if (s->type == RAWINPUT) { + if (!strcasecmp(s->keystr, "Up")) + s->seq = KEY_UP; + else if (!strcasecmp(s->keystr, "Down")) + s->seq = KEY_DOWN; + else if (!strcasecmp(s->keystr, "Left")) + s->seq = KEY_LEFT; + else if (!strcasecmp(s->keystr, "Right")) + s->seq = KEY_RIGHT; + else if (!strcasecmp(s->keystr, "Ins")) + s->seq = KEY_IC; + else if (!strcasecmp(s->keystr, "Del")) + s->seq = KEY_DC; + else if (!strcasecmp(s->keystr, "Bsp")) + s->seq = KEY_BACKSPACE; + else if (!strcasecmp(s->keystr, "Enter")) + s->seq = KEY_ENTER; + else if (!strcasecmp(s->keystr, "PgUp")) + s->seq = KEY_PPAGE; + else if (!strcasecmp(s->keystr, "PgDn")) + s->seq = KEY_NPAGE; #ifdef KEY_HOME - else if (s->type == RAW && (!strcasecmp(s->keystr, "khome"))) - s->seq = KEY_HOME; + else if (!strcasecmp(s->keystr, "Home")) + s->seq = KEY_HOME; #endif #ifdef KEY_END - else if (s->type == RAW && (!strcasecmp(s->keystr, "kend"))) - s->seq = KEY_END; + else if (!strcasecmp(s->keystr, "End")) + s->seq = KEY_END; #endif - + } } #ifdef DEBUG - void print_sclist(void) { sc *s; const subnfunc *f; - for (s = sclist; s->next != NULL; s = s->next) { + for (s = sclist; s != NULL; s = s->next) { f = sctofunc(s); - if (f) - fprintf(stderr, "Shortcut \"%s\", function: %s, menus %d\n", s->keystr, f->desc, f->menus); + if (f) + fprintf(stderr, "Shortcut \"%s\", function: %s, menus %x\n", s->keystr, f->desc, f->menus); else - fprintf(stderr, "Hmm, didnt find a func for \"%s\"\n", s->keystr); + fprintf(stderr, "Hmm, didn't find a func for \"%s\"\n", s->keystr); } - } #endif - -/* Stuff we need to make at least static here so we can access it below */ -/* TRANSLATORS: Try to keep the next five strings at most 10 characters. */ -const char *cancel_msg = N_("Cancel"); -const char *replace_msg = N_("Replace"); -const char *no_replace_msg = N_("No Replace"); - +/* TRANSLATORS: Try to keep the next four strings at most 10 characters. */ +const char *exit_tag = N_("Exit"); +const char *close_tag = N_("Close"); +const char *uncut_tag = N_("Uncut Text"); +#ifndef DISABLE_JUSITIFY +const char *unjust_tag = N_("Unjustify"); +#endif #ifndef NANO_TINY -const char *case_sens_msg = N_("Case Sens"); -const char *backwards_msg = N_("Backwards"); +/* TRANSLATORS: Try to keep this at most 12 characters. */ +const char *whereis_next_tag = N_("WhereIs Next"); #endif -#ifdef HAVE_REGEX_H -const char *regexp_msg = N_("Regexp"); -#endif - -/* Stuff we want to just stun out if we're in TINY mode */ -#ifdef NANO_TINY -const char *gototext_msg = ""; -const char *do_para_begin_msg = ""; -const char *do_para_end_msg = ""; -const char *case_sens_msg = ""; -const char *backwards_msg = ""; -const char *do_cut_till_end = ""; -const char *dos_format_msg = ""; -const char *mac_format_msg = ""; -const char *append_msg = ""; -const char *prepend_msg = ""; -const char *backup_file_msg = ""; -const char *to_files_msg = ""; -const char *first_file_msg = ""; -const char *whereis_next_msg = ""; -const char *last_file_msg = ""; -const char *new_buffer_msg = ""; -const char *goto_dir_msg; -const char *ext_cmd_msg = ""; - -#else -/* TRANSLATORS: Try to keep the next five strings at most 10 characters. */ -const char *prev_history_msg = N_("PrevHstory"); -const char *next_history_msg = N_("NextHstory"); -const char *gototext_msg = N_("Go To Text"); -/* TRANSLATORS: Try to keep the next three strings at most 12 characters. */ -const char *whereis_next_msg = N_("WhereIs Next"); -#ifndef DISABLE_BROWSER -const char *first_file_msg = N_("First File"); -const char *last_file_msg = N_("Last File"); -/* TRANSLATORS: Try to keep the next nine strings at most 16 characters. */ -const char *to_files_msg = N_("To Files"); -#endif -const char *dos_format_msg = N_("DOS Format"); -const char *mac_format_msg = N_("Mac Format"); -const char *append_msg = N_("Append"); -const char *prepend_msg = N_("Prepend"); -const char *backup_file_msg = N_("Backup File"); -const char *ext_cmd_msg = N_("Execute Command"); -#ifdef ENABLE_MULTIBUFFER -const char *new_buffer_msg = N_("New Buffer"); -#endif -const char *goto_dir_msg = N_("Go To Dir"); - -#endif /* NANO_TINY */ - -/* Initialize all shortcut lists. If unjustify is TRUE, replace the - * Uncut shortcut in the main shortcut list with UnJustify. */ -void shortcut_init(bool unjustify) +/* Initialize the list of functions and the list of shortcuts. */ +void shortcut_init(void) { - /* TRANSLATORS: Try to keep the following strings at most 10 characters. */ - const char *get_help_msg = N_("Get Help"); - const char *exit_msg = N_("Exit"); - const char *whereis_msg = N_("Where Is"); - const char *prev_page_msg = N_("Prev Page"); - const char *next_page_msg = N_("Next Page"); - const char *first_line_msg = N_("First Line"); - const char *last_line_msg = N_("Last Line"); - const char *suspend_msg = N_("Suspend"); + /* TRANSLATORS: Try to keep the next eight strings at most 10 characters. */ + const char *whereis_tag = N_("Where Is"); + const char *replace_tag = N_("Replace"); + const char *gotoline_tag = N_("Go To Line"); + const char *prev_line_tag = N_("Prev Line"); + const char *next_line_tag = N_("Next Line"); + const char *read_file_tag = N_("Read File"); #ifndef DISABLE_JUSTIFY - const char *beg_of_par_msg = N_("Beg of Par"); - const char *end_of_par_msg = N_("End of Par"); - const char *fulljstify_msg = N_("FullJstify"); -#endif - const char *refresh_msg = N_("Refresh"); -#ifndef NANO_TINY - const char *insert_file_msg = N_("Insert File"); + const char *fulljustify_tag = N_("FullJstify"); #endif - const char *go_to_line_msg = N_("Go To Line"); + const char *refresh_tag = N_("Refresh"); -#ifndef DISABLE_JUSTIFY - const char *nano_justify_msg = N_("Justify the current paragraph"); -#endif #ifndef DISABLE_HELP +#ifndef DISABLE_JUSTIFY /* TRANSLATORS: The next long series of strings are shortcut descriptions; * they are best kept shorter than 56 characters, but may be longer. */ + const char *nano_justify_msg = N_("Justify the current paragraph"); +#endif const char *nano_cancel_msg = N_("Cancel the current function"); const char *nano_help_msg = N_("Display this help text"); const char *nano_exit_msg = -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER N_("Close the current file buffer / Exit from nano") #else - N_("Exit from nano") + N_("Exit from nano") #endif ; const char *nano_writeout_msg = @@ -517,22 +521,25 @@ void shortcut_init(bool unjustify) N_("Insert another file into the current one"); const char *nano_whereis_msg = N_("Search for a string or a regular expression"); - const char *nano_prevpage_msg = N_("Go to previous screen"); - const char *nano_nextpage_msg = N_("Go to next screen"); +#ifndef DISABLE_BROWSER + const char *nano_browser_whereis_msg = + N_("Search for a string"); +#endif + const char *nano_prevpage_msg = N_("Go one screenful up"); + const char *nano_nextpage_msg = N_("Go one screenful down"); const char *nano_cut_msg = N_("Cut the current line and store it in the cutbuffer"); const char *nano_uncut_msg = N_("Uncut from the cutbuffer into the current line"); - const char *nano_cursorpos_msg = - N_("Display the position of the cursor"); - const char *nano_spell_msg = - N_("Invoke the spell checker, if available"); - const char *nano_replace_msg = - N_("Replace a string or a regular expression"); - const char *nano_gotoline_msg = N_("Go to line and column number"); + const char *nano_cursorpos_msg = N_("Display the position of the cursor"); +#ifndef DISABLE_SPELLER + const char *nano_spell_msg = N_("Invoke the spell checker, if available"); +#endif + const char *nano_replace_msg = N_("Replace a string or a regular expression"); + const char *nano_gotoline_msg = N_("Go to line and column number"); #ifndef NANO_TINY - const char *nano_mark_msg = N_("Mark text at the cursor position"); - const char *nano_whereis_next_msg = N_("Repeat last search"); + const char *nano_mark_msg = N_("Mark text starting from the cursor position"); + const char *nano_whereis_next_msg = N_("Repeat the last search"); const char *nano_copy_msg = N_("Copy the current line and store it in the cutbuffer"); const char *nano_indent_msg = N_("Indent the current line"); @@ -556,10 +563,8 @@ void shortcut_init(bool unjustify) const char *nano_paraend_msg = N_("Go just beyond end of paragraph; then of next paragraph"); #endif - const char *nano_firstline_msg = - N_("Go to the first line of the file"); - const char *nano_lastline_msg = - N_("Go to the last line of the file"); + const char *nano_firstline_msg = N_("Go to the first line of the file"); + const char *nano_lastline_msg = N_("Go to the last line of the file"); #ifndef NANO_TINY const char *nano_bracket_msg = N_("Go to the matching bracket"); const char *nano_scrollup_msg = @@ -567,24 +572,18 @@ void shortcut_init(bool unjustify) const char *nano_scrolldown_msg = N_("Scroll down one line without scrolling the cursor"); #endif -#ifdef ENABLE_MULTIBUFFER - const char *nano_prevfile_msg = - N_("Switch to the previous file buffer"); - const char *nano_nextfile_msg = - N_("Switch to the next file buffer"); -#endif - const char *nano_verbatim_msg = - N_("Insert the next keystroke verbatim"); - const char *nano_tab_msg = - N_("Insert a tab at the cursor position"); - const char *nano_enter_msg = - N_("Insert a newline at the cursor position"); - const char *nano_delete_msg = - N_("Delete the character under the cursor"); +#ifndef DISABLE_MULTIBUFFER + const char *nano_prevfile_msg = N_("Switch to the previous file buffer"); + const char *nano_nextfile_msg = N_("Switch to the next file buffer"); +#endif + const char *nano_verbatim_msg = N_("Insert the next keystroke verbatim"); + const char *nano_tab_msg = N_("Insert a tab at the cursor position"); + const char *nano_enter_msg = N_("Insert a newline at the cursor position"); + const char *nano_delete_msg = N_("Delete the character under the cursor"); const char *nano_backspace_msg = N_("Delete the character to the left of the cursor"); #ifndef NANO_TINY - const char *nano_cut_till_end_msg = + const char *nano_cut_till_eof_msg = N_("Cut from the cursor position to the end of the file"); #endif #ifndef DISABLE_JUSTIFY @@ -608,7 +607,7 @@ void shortcut_init(bool unjustify) const char *nano_regexp_msg = N_("Toggle the use of regular expressions"); #endif -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES const char *nano_prev_history_msg = N_("Recall the previous search/replace string"); const char *nano_next_history_msg = @@ -620,28 +619,28 @@ void shortcut_init(bool unjustify) #ifndef NANO_TINY const char *nano_dos_msg = N_("Toggle the use of DOS format"); const char *nano_mac_msg = N_("Toggle the use of Mac format"); -#endif const char *nano_append_msg = N_("Toggle appending"); const char *nano_prepend_msg = N_("Toggle prepending"); -#ifndef NANO_TINY - const char *nano_backup_msg = - N_("Toggle backing up of the original file"); + const char *nano_backup_msg = N_("Toggle backing up of the original file"); const char *nano_execute_msg = N_("Execute external command"); #endif -#if !defined(NANO_TINY) && defined(ENABLE_MULTIBUFFER) - const char *nano_multibuffer_msg = - N_("Toggle the use of a new buffer"); +#ifndef DISABLE_MULTIBUFFER + const char *nano_multibuffer_msg = N_("Toggle the use of a new buffer"); #endif #ifndef DISABLE_BROWSER const char *nano_exitbrowser_msg = N_("Exit from the file browser"); - const char *nano_firstfile_msg = - N_("Go to the first file in the list"); - const char *nano_lastfile_msg = - N_("Go to the last file in the list"); - const char *nano_forwardfile_msg = N_("Go to the next file in the list"); + const char *nano_firstfile_msg = N_("Go to the first file in the list"); + const char *nano_lastfile_msg = N_("Go to the last file in the list"); const char *nano_backfile_msg = N_("Go to the previous file in the list"); + const char *nano_forwardfile_msg = N_("Go to the next file in the list"); const char *nano_gotodir_msg = N_("Go to directory"); #endif +#ifndef DISABLE_COLOR + const char *nano_lint_msg = N_("Invoke the linter, if available"); + const char *nano_prevlint_msg = N_("Go to previous linter msg"); + const char *nano_nextlint_msg = N_("Go to next linter msg"); + const char *nano_formatter_msg = N_("Invoke formatter, if available"); +#endif #endif /* !DISABLE_HELP */ #ifndef DISABLE_HELP @@ -652,306 +651,271 @@ void shortcut_init(bool unjustify) while (allfuncs != NULL) { subnfunc *f = allfuncs; - allfuncs = (allfuncs)->next; + allfuncs = allfuncs->next; free(f); } - add_to_funcs(DO_HELP_VOID, - (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR), - get_help_msg, IFSCHELP(nano_help_msg), FALSE, VIEW); + /* Start populating the different menus with functions. */ - add_to_funcs( CANCEL_MSG, - (MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MWHEREISFILE|MGOTODIR|MYESNO), - cancel_msg, IFSCHELP(nano_cancel_msg), FALSE, VIEW); + add_to_funcs(do_help_void, MMOST, + /* TRANSLATORS: Try to keep the following strings at most 10 characters. */ + N_("Get Help"), IFSCHELP(nano_help_msg), TOGETHER, VIEW); - add_to_funcs(DO_EXIT, MMAIN, -#ifdef ENABLE_MULTIBUFFER - /* TRANSLATORS: Try to keep this at most 10 characters. */ - openfile != NULL && openfile != openfile->next ? N_("Close") : -#endif - exit_msg, IFSCHELP(nano_exit_msg), FALSE, VIEW); + add_to_funcs(do_cancel, ((MMOST & ~MMAIN & ~MBROWSER) | MYESNO), + N_("Cancel"), IFSCHELP(nano_cancel_msg), TOGETHER, VIEW); + + add_to_funcs(do_exit, MMAIN, + exit_tag, IFSCHELP(nano_exit_msg), TOGETHER, VIEW); + /* Remember the entry for Exit, to be able to replace it with Close. */ + exitfunc = tailfunc; #ifndef DISABLE_BROWSER - add_to_funcs(DO_EXIT, MBROWSER, exit_msg, IFSCHELP(nano_exitbrowser_msg), FALSE, VIEW); + add_to_funcs(do_exit, MBROWSER, + exit_tag, IFSCHELP(nano_exitbrowser_msg), TOGETHER, VIEW); #endif - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_WRITEOUT_VOID, MMAIN, N_("WriteOut"), - IFSCHELP(nano_writeout_msg), FALSE, NOVIEW); - -#ifndef DISABLE_JUSTIFY - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_JUSTIFY_VOID, MMAIN, N_("Justify"), - nano_justify_msg, TRUE, NOVIEW); -#endif + add_to_funcs(do_writeout_void, MMAIN, + N_("Write Out"), IFSCHELP(nano_writeout_msg), TOGETHER, NOVIEW); /* We allow inserting files in view mode if multibuffers are * available, so that we can view multiple files. If we're using * restricted mode, inserting files is disabled, since it allows * reading from or writing to files not specified on the command * line. */ - - add_to_funcs(DO_INSERTFILE_VOID, - /* TRANSLATORS: Try to keep this at most 10 characters. */ - MMAIN, N_("Read File"), IFSCHELP(nano_insert_msg), FALSE, -#ifdef ENABLE_MULTIBUFFER + add_to_funcs(do_insertfile_void, MMAIN, + read_file_tag, IFSCHELP(nano_insert_msg), BLANKAFTER, +#ifndef DISABLE_MULTIBUFFER VIEW); #else NOVIEW); #endif - add_to_funcs(DO_SEARCH, MMAIN|MBROWSER, whereis_msg, - IFSCHELP(nano_whereis_msg), FALSE, VIEW); + add_to_funcs(do_search, MMAIN, + whereis_tag, IFSCHELP(nano_whereis_msg), TOGETHER, VIEW); - add_to_funcs(DO_PAGE_UP, MMAIN|MHELP|MBROWSER, - prev_page_msg, IFSCHELP(nano_prevpage_msg), FALSE, VIEW); - add_to_funcs(DO_PAGE_DOWN, MMAIN|MHELP|MBROWSER, - next_page_msg, IFSCHELP(nano_nextpage_msg), TRUE, VIEW); + add_to_funcs(do_replace, MMAIN, + replace_tag, IFSCHELP(nano_replace_msg), TOGETHER, NOVIEW); +#ifndef DISABLE_BROWSER + add_to_funcs(do_search, MBROWSER, + whereis_tag, IFSCHELP(nano_browser_whereis_msg), TOGETHER, VIEW); - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_CUT_TEXT_VOID, MMAIN, N_("Cut Text"), IFSCHELP(nano_cut_msg), - FALSE, NOVIEW); - - if (unjustify) - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_UNCUT_TEXT, MMAIN, N_("UnJustify"), "", - FALSE, NOVIEW); + add_to_funcs(goto_dir_void, MBROWSER, + N_("Go To Dir"), IFSCHELP(nano_gotodir_msg), BLANKAFTER, VIEW); +#endif - else - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_UNCUT_TEXT, MMAIN, N_("UnCut Text"), IFSCHELP(nano_uncut_msg), - FALSE, NOVIEW); +#ifndef DISABLE_HELP + /* The description ("x") and blank_after (0) are irrelevant, + * because the help viewer does not have a help text. */ + add_to_funcs(do_exit, MHELP, exit_tag, "x", 0, VIEW); -#ifndef NANO_TINY - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_CURSORPOS_VOID, MMAIN, N_("Cur Pos"), IFSCHELP(nano_cursorpos_msg), - FALSE, VIEW); -#endif + add_to_funcs(total_refresh, MHELP, refresh_tag, "x", 0, VIEW); - /* If we're using restricted mode, spell checking is disabled - * because it allows reading from or writing to files not specified - * on the command line. */ -#ifndef DISABLE_SPELLER - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_SPELL, MMAIN, N_("To Spell"), IFSCHELP(nano_spell_msg), - TRUE, NOVIEW); + add_to_funcs(do_up_void, MHELP, prev_line_tag, "x", 0, VIEW); + add_to_funcs(do_down_void, MHELP, next_line_tag, "x" , 0, VIEW); #endif - add_to_funcs(DO_FIRST_LINE, - (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE), - first_line_msg, IFSCHELP(nano_firstline_msg), FALSE, VIEW); + add_to_funcs(do_cut_text_void, MMAIN, + N_("Cut Text"), IFSCHELP(nano_cut_msg), TOGETHER, NOVIEW); - add_to_funcs(DO_LAST_LINE, - (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE), - last_line_msg, IFSCHELP(nano_lastline_msg), TRUE, VIEW); + add_to_funcs(do_uncut_text, MMAIN, + uncut_tag, IFSCHELP(nano_uncut_msg), BLANKAFTER, NOVIEW); + /* Remember the entry for Uncut, to be able to replace it with Unjustify. */ + uncutfunc = tailfunc; +#ifndef DISABLE_JUSTIFY + add_to_funcs(do_justify_void, MMAIN, + N_("Justify"), IFSCHELP(nano_justify_msg), TOGETHER, NOVIEW); +#endif - add_to_funcs(DO_GOTOLINECOLUMN_VOID, (MMAIN|MWHEREIS), - go_to_line_msg, IFSCHELP(nano_gotoline_msg), FALSE, VIEW); +#ifndef DISABLE_SPELLER + add_to_funcs(do_spell, MMAIN, + N_("To Spell"), IFSCHELP(nano_spell_msg), TOGETHER, NOVIEW); +#endif -#ifdef NANO_TINY - /* TRANSLATORS: Try to keep this at most 10 characters. */ - add_to_funcs(DO_CURSORPOS_VOID, MMAIN, N_("Cur Pos"), IFSCHELP(nano_cursorpos_msg), - FALSE, VIEW); +#ifndef DISABLE_COLOR + add_to_funcs(do_linter, MMAIN, + N_("To Linter"), IFSCHELP(nano_lint_msg), TOGETHER, NOVIEW); + add_to_funcs(do_formatter, MMAIN, + N_("Formatter"), IFSCHELP(nano_formatter_msg), BLANKAFTER, NOVIEW); #endif +#ifndef NANO_TINY + add_to_funcs(case_sens_void, MWHEREIS|MREPLACE, + N_("Case Sens"), IFSCHELP(nano_case_msg), TOGETHER, VIEW); +#endif - add_to_funcs(DO_REPLACE, (MMAIN|MWHEREIS), replace_msg, IFSCHELP(nano_replace_msg), +#ifdef HAVE_REGEX_H + add_to_funcs(regexp_void, MWHEREIS|MREPLACE, + N_("Regexp"), IFSCHELP(nano_regexp_msg), TOGETHER, VIEW); +#endif #ifndef NANO_TINY - FALSE, -#else - TRUE, + add_to_funcs(backwards_void, MWHEREIS|MREPLACE, + N_("Backwards"), IFSCHELP(nano_reverse_msg), TOGETHER, VIEW); #endif - NOVIEW); -#ifndef NANO_TINY + add_to_funcs(flip_replace_void, MWHEREIS, + replace_tag, IFSCHELP(nano_replace_msg), TOGETHER, VIEW); - add_to_funcs(DO_MARK, MMAIN, N_("Mark Text"), - IFSCHELP(nano_mark_msg), FALSE, VIEW); + add_to_funcs(flip_replace_void, MREPLACE, + N_("No Replace"), IFSCHELP(nano_whereis_msg), TOGETHER, VIEW); - add_to_funcs(DO_RESEARCH, (MMAIN|MBROWSER), whereis_next_msg, - IFSCHELP(nano_whereis_next_msg), TRUE, VIEW); +#ifndef DISABLE_JUSTIFY + add_to_funcs(do_full_justify, MWHEREIS, + fulljustify_tag, IFSCHELP(nano_fulljustify_msg), TOGETHER, NOVIEW); +#endif - add_to_funcs(DO_COPY_TEXT, MMAIN, N_("Copy Text"), - IFSCHELP(nano_copy_msg), FALSE, NOVIEW); + add_to_funcs(do_cursorpos_void, MMAIN, + N_("Cur Pos"), IFSCHELP(nano_cursorpos_msg), TOGETHER, VIEW); - add_to_funcs(DO_INDENT_VOID, MMAIN, N_("Indent Text"), - IFSCHELP(nano_indent_msg), FALSE, NOVIEW); +#if !defined(NANO_TINY) || defined(DISABLE_COLOR) + /* Conditionally placing this one here or further on, to keep the + * help items nicely paired in most conditions. */ + add_to_funcs(do_gotolinecolumn_void, MMAIN|MWHEREIS, + gotoline_tag, IFSCHELP(nano_gotoline_msg), BLANKAFTER, VIEW); +#endif - add_to_funcs(DO_UNINDENT, MMAIN, N_("Unindent Text"), - IFSCHELP(nano_unindent_msg), FALSE, NOVIEW); + add_to_funcs(do_page_up, MMAIN|MHELP|MBROWSER, + N_("Prev Page"), IFSCHELP(nano_prevpage_msg), TOGETHER, VIEW); + add_to_funcs(do_page_down, MMAIN|MHELP|MBROWSER, + N_("Next Page"), IFSCHELP(nano_nextpage_msg), TOGETHER, VIEW); - if (ISSET(UNDOABLE)) { - add_to_funcs(DO_UNDO, MMAIN, N_("Undo"), - IFSCHELP(nano_undo_msg), FALSE, NOVIEW); + add_to_funcs(do_first_line, MMAIN|MHELP|MWHEREIS|MREPLACE|MREPLACEWITH|MGOTOLINE, + N_("First Line"), IFSCHELP(nano_firstline_msg), TOGETHER, VIEW); + add_to_funcs(do_last_line, MMAIN|MHELP|MWHEREIS|MREPLACE|MREPLACEWITH|MGOTOLINE, + N_("Last Line"), IFSCHELP(nano_lastline_msg), BLANKAFTER, VIEW); - add_to_funcs(DO_REDO, MMAIN, N_("Redo"), - IFSCHELP(nano_redo_msg), TRUE, NOVIEW); - } +#ifndef NANO_TINY + add_to_funcs(do_research, MMAIN, + whereis_next_tag, IFSCHELP(nano_whereis_next_msg), TOGETHER, VIEW); -#endif + add_to_funcs(do_find_bracket, MMAIN, + N_("To Bracket"), IFSCHELP(nano_bracket_msg), TOGETHER, VIEW); - add_to_funcs(DO_RIGHT, MMAIN, N_("Forward"), IFSCHELP(nano_forward_msg), - FALSE, VIEW); + add_to_funcs(do_mark, MMAIN, + N_("Mark Text"), IFSCHELP(nano_mark_msg), TOGETHER, VIEW); -#ifndef DISABLE_BROWSER - add_to_funcs(DO_RIGHT, MBROWSER, N_("Forward"), IFSCHELP(nano_forwardfile_msg), - FALSE, VIEW); -#endif + add_to_funcs(do_copy_text, MMAIN, + N_("Copy Text"), IFSCHELP(nano_copy_msg), BLANKAFTER, NOVIEW); - add_to_funcs(DO_RIGHT, MALL, "", "", FALSE, VIEW); + add_to_funcs(do_indent_void, MMAIN, + N_("Indent Text"), IFSCHELP(nano_indent_msg), TOGETHER, NOVIEW); + add_to_funcs(do_unindent, MMAIN, + N_("Unindent Text"), IFSCHELP(nano_unindent_msg), BLANKAFTER, NOVIEW); - add_to_funcs(DO_LEFT, MMAIN, N_("Back"), IFSCHELP(nano_back_msg), - FALSE, VIEW); + add_to_funcs(do_undo, MMAIN, + N_("Undo"), IFSCHELP(nano_undo_msg), TOGETHER, NOVIEW); + add_to_funcs(do_redo, MMAIN, + N_("Redo"), IFSCHELP(nano_redo_msg), BLANKAFTER, NOVIEW); +#endif /* !NANO_TINY */ + + add_to_funcs(do_left, MMAIN, + N_("Back"), IFSCHELP(nano_back_msg), TOGETHER, VIEW); + add_to_funcs(do_right, MMAIN, + N_("Forward"), IFSCHELP(nano_forward_msg), TOGETHER, VIEW); #ifndef DISABLE_BROWSER - add_to_funcs(DO_LEFT, MBROWSER, N_("Back"), IFSCHELP(nano_backfile_msg), - FALSE, VIEW); + add_to_funcs(do_left, MBROWSER, + N_("Back"), IFSCHELP(nano_backfile_msg), TOGETHER, VIEW); + add_to_funcs(do_right, MBROWSER, + N_("Forward"), IFSCHELP(nano_forwardfile_msg), TOGETHER, VIEW); #endif - add_to_funcs(DO_LEFT, MALL, "", "", FALSE, VIEW); - #ifndef NANO_TINY - add_to_funcs(DO_NEXT_WORD_VOID, MMAIN, N_("Next Word"), - IFSCHELP(nano_nextword_msg), FALSE, VIEW); - - add_to_funcs(DO_PREV_WORD_VOID, MMAIN, N_("Prev Word"), - IFSCHELP(nano_prevword_msg), FALSE, VIEW); + add_to_funcs(do_prev_word_void, MMAIN, + N_("Prev Word"), IFSCHELP(nano_prevword_msg), TOGETHER, VIEW); + add_to_funcs(do_next_word_void, MMAIN, + N_("Next Word"), IFSCHELP(nano_nextword_msg), TOGETHER, VIEW); #endif - add_to_funcs(DO_UP_VOID, (MMAIN|MHELP|MBROWSER), N_("Prev Line"), - IFSCHELP(nano_prevline_msg), FALSE, VIEW); - - add_to_funcs(DO_DOWN_VOID, (MMAIN|MHELP|MBROWSER), N_("Next Line"), - IFSCHELP(nano_nextline_msg), TRUE, VIEW); - - add_to_funcs(DO_HOME, MMAIN, N_("Home"), IFSCHELP(nano_home_msg), - FALSE, VIEW); + add_to_funcs(do_home, MMAIN, + N_("Home"), IFSCHELP(nano_home_msg), TOGETHER, VIEW); + add_to_funcs(do_end, MMAIN, + N_("End"), IFSCHELP(nano_end_msg), TOGETHER, VIEW); - add_to_funcs(DO_END, MMAIN, N_("End"), IFSCHELP(nano_end_msg), - FALSE, VIEW); + add_to_funcs(do_up_void, MMAIN|MBROWSER, + prev_line_tag, IFSCHELP(nano_prevline_msg), TOGETHER, VIEW); + add_to_funcs(do_down_void, MMAIN|MBROWSER, + next_line_tag, IFSCHELP(nano_nextline_msg), BLANKAFTER, VIEW); #ifndef DISABLE_JUSTIFY - add_to_funcs(DO_PARA_BEGIN_VOID, (MMAIN|MWHEREIS), beg_of_par_msg, - IFSCHELP(nano_parabegin_msg), FALSE, VIEW); - - add_to_funcs(DO_PARA_END_VOID, (MMAIN|MWHEREIS), end_of_par_msg, - IFSCHELP(nano_paraend_msg), FALSE, VIEW); + add_to_funcs(do_para_begin_void, MMAIN|MWHEREIS, + N_("Beg of Par"), IFSCHELP(nano_parabegin_msg), TOGETHER, VIEW); + add_to_funcs(do_para_end_void, MMAIN|MWHEREIS, + N_("End of Par"), IFSCHELP(nano_paraend_msg), TOGETHER, VIEW); #endif #ifndef NANO_TINY - add_to_funcs(DO_FIND_BRACKET, MMAIN, _("Find Other Bracket"), - IFSCHELP(nano_bracket_msg), FALSE, VIEW); - - add_to_funcs(DO_SCROLL_UP, MMAIN, N_("Scroll Up"), - IFSCHELP(nano_scrollup_msg), FALSE, VIEW); - - add_to_funcs(DO_SCROLL_DOWN, MMAIN, N_("Scroll Down"), - IFSCHELP(nano_scrolldown_msg), FALSE, VIEW); -#endif - -#ifdef ENABLE_MULTIBUFFER - add_to_funcs(SWITCH_TO_PREV_BUFFER_VOID, MMAIN, _("Previous File"), - IFSCHELP(nano_prevfile_msg), FALSE, VIEW); - add_to_funcs(SWITCH_TO_NEXT_BUFFER_VOID, MMAIN, N_("Next File"), - IFSCHELP(nano_nextfile_msg), TRUE, VIEW); -#endif - - add_to_funcs(DO_VERBATIM_INPUT, MMAIN, N_("Verbatim Input"), - IFSCHELP(nano_verbatim_msg), FALSE, NOVIEW); - add_to_funcs(DO_VERBATIM_INPUT, MWHEREIS|MREPLACE|MREPLACE2|MEXTCMD|MSPELL, - "", "", FALSE, NOVIEW); - - add_to_funcs(DO_TAB, MMAIN, N_("Tab"), IFSCHELP(nano_tab_msg), - FALSE, NOVIEW); - add_to_funcs(DO_TAB, MALL, "", "", FALSE, NOVIEW); - add_to_funcs(DO_ENTER, MMAIN, N_("Enter"), IFSCHELP(nano_enter_msg), - FALSE, NOVIEW); - add_to_funcs(DO_ENTER, MALL, "", "", FALSE, NOVIEW); - add_to_funcs(DO_DELETE, MMAIN, N_("Delete"), IFSCHELP(nano_delete_msg), - FALSE, NOVIEW); - add_to_funcs(DO_DELETE, MALL, "", "", FALSE, NOVIEW); - add_to_funcs(DO_BACKSPACE, MMAIN, N_("Backspace"), IFSCHELP(nano_backspace_msg), -#ifndef NANO_TINY - FALSE, -#else - TRUE, + add_to_funcs(do_scroll_up, MMAIN, + N_("Scroll Up"), IFSCHELP(nano_scrollup_msg), TOGETHER, VIEW); + add_to_funcs(do_scroll_down, MMAIN, + N_("Scroll Down"), IFSCHELP(nano_scrolldown_msg), BLANKAFTER, VIEW); #endif - NOVIEW); - add_to_funcs(DO_BACKSPACE, MALL, "", "", -#ifndef NANO_TINY - FALSE, -#else - TRUE, +#ifndef DISABLE_MULTIBUFFER + add_to_funcs(switch_to_prev_buffer_void, MMAIN, + N_("Prev File"), IFSCHELP(nano_prevfile_msg), TOGETHER, VIEW); + add_to_funcs(switch_to_next_buffer_void, MMAIN, + N_("Next File"), IFSCHELP(nano_nextfile_msg), BLANKAFTER, VIEW); #endif - NOVIEW); -#ifndef NANO_TINY - add_to_funcs(DO_CUT_TILL_END, MMAIN, N_("CutTillEnd"), - IFSCHELP(nano_cut_till_end_msg), TRUE, NOVIEW); +#if defined(NANO_TINY) && !defined(DISABLE_COLOR) + add_to_funcs(do_gotolinecolumn_void, MMAIN|MWHEREIS, + gotoline_tag, IFSCHELP(nano_gotoline_msg), BLANKAFTER, VIEW); #endif - add_to_funcs(XON_COMPLAINT, MMAIN, "", "", FALSE, VIEW); - add_to_funcs(XOFF_COMPLAINT, MMAIN, "", "", FALSE, VIEW); - -#ifndef DISABLE_JUSTIFY - add_to_funcs(DO_FULL_JUSTIFY, (MMAIN|MWHEREIS), fulljstify_msg, - IFSCHELP(nano_fulljustify_msg), FALSE, NOVIEW); -#endif + add_to_funcs(do_verbatim_input, MMAIN, + N_("Verbatim"), IFSCHELP(nano_verbatim_msg), TOGETHER, NOVIEW); + add_to_funcs(do_tab, MMAIN, + N_("Tab"), IFSCHELP(nano_tab_msg), TOGETHER, NOVIEW); + add_to_funcs(do_enter_void, MMAIN, + N_("Enter"), IFSCHELP(nano_enter_msg), TOGETHER, NOVIEW); + add_to_funcs(do_delete, MMAIN, + N_("Delete"), IFSCHELP(nano_delete_msg), TOGETHER, NOVIEW); + add_to_funcs(do_backspace, MMAIN, + N_("Backspace"), IFSCHELP(nano_backspace_msg), #ifndef NANO_TINY - add_to_funcs(DO_WORDLINECHAR_COUNT, MMAIN, N_("Word Count"), - IFSCHELP(nano_wordcount_msg), FALSE, VIEW); + TOGETHER, +#else + BLANKAFTER, #endif - - add_to_funcs(TOTAL_REFRESH, (MMAIN|MHELP), refresh_msg, - IFSCHELP(nano_refresh_msg), FALSE, VIEW); - - add_to_funcs(DO_SUSPEND_VOID, MMAIN, suspend_msg, - IFSCHELP(nano_suspend_msg), TRUE, VIEW); + NOVIEW); #ifndef NANO_TINY - add_to_funcs( CASE_SENS_MSG, - (MWHEREIS|MREPLACE|MWHEREISFILE), - case_sens_msg, IFSCHELP(nano_case_msg), FALSE, VIEW); - - add_to_funcs( BACKWARDS_MSG, - (MWHEREIS|MREPLACE|MWHEREISFILE), - backwards_msg, IFSCHELP(nano_reverse_msg), FALSE, VIEW); + add_to_funcs(do_cut_till_eof, MMAIN, + N_("CutTillEnd"), IFSCHELP(nano_cut_till_eof_msg), BLANKAFTER, NOVIEW); #endif -#ifdef HAVE_REGEX_H - add_to_funcs( REGEXP_MSG, - (MWHEREIS|MREPLACE|MWHEREISFILE), - regexp_msg, IFSCHELP(nano_regexp_msg), FALSE, VIEW); +#ifndef DISABLE_JUSTIFY + add_to_funcs(do_full_justify, MMAIN, + fulljustify_tag, IFSCHELP(nano_fulljustify_msg), TOGETHER, NOVIEW); #endif #ifndef NANO_TINY - add_to_funcs( PREV_HISTORY_MSG, - (MWHEREIS|MREPLACE|MREPLACE2|MWHEREISFILE), - prev_history_msg, IFSCHELP(nano_prev_history_msg), FALSE, VIEW); - - add_to_funcs( NEXT_HISTORY_MSG, - (MWHEREIS|MREPLACE|MREPLACE2|MWHEREISFILE), - next_history_msg, IFSCHELP(nano_next_history_msg), FALSE, VIEW); + add_to_funcs(do_wordlinechar_count, MMAIN, + N_("Word Count"), IFSCHELP(nano_wordcount_msg), TOGETHER, VIEW); #endif - add_to_funcs( NO_REPLACE_MSG, MREPLACE, - no_replace_msg, IFSCHELP(nano_whereis_msg), FALSE, VIEW); + add_to_funcs(total_refresh, MMAIN, + refresh_tag, IFSCHELP(nano_refresh_msg), TOGETHER, VIEW); - add_to_funcs( GOTOTEXT_MSG, MGOTOLINE, - gototext_msg, IFSCHELP(nano_whereis_msg), TRUE, VIEW); + add_to_funcs(do_suspend_void, MMAIN, + N_("Suspend"), IFSCHELP(nano_suspend_msg), BLANKAFTER, VIEW); -#ifndef DISABLE_BROWSER - if (!ISSET(RESTRICTED)) - add_to_funcs( TO_FILES_MSG, - (MGOTOLINE|MINSERTFILE), - to_files_msg, IFSCHELP(nano_tofiles_msg), FALSE, VIEW); +#ifndef DISABLE_HISTORIES + add_to_funcs(get_history_older_void, + (MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE), + N_("PrevHstory"), IFSCHELP(nano_prev_history_msg), TOGETHER, VIEW); + add_to_funcs(get_history_newer_void, + (MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE), + N_("NextHstory"), IFSCHELP(nano_next_history_msg), TOGETHER, VIEW); #endif + add_to_funcs(gototext_void, MGOTOLINE, + N_("Go To Text"), IFSCHELP(nano_whereis_msg), BLANKAFTER, VIEW); + #ifndef NANO_TINY /* If we're using restricted mode, the DOS format, Mac format, * append, prepend, and backup toggles are disabled. The first and @@ -959,393 +923,287 @@ void shortcut_init(bool unjustify) * and fourth are disabled because they allow writing to files not * specified on the command line, and the fifth is useless since * backups are disabled. */ - if (!ISSET(RESTRICTED)) - add_to_funcs( DOS_FORMAT_MSG, MWRITEFILE, - dos_format_msg, IFSCHELP(nano_dos_msg), FALSE, NOVIEW); + if (!ISSET(RESTRICTED)) { + add_to_funcs(dos_format_void, MWRITEFILE, + N_("DOS Format"), IFSCHELP(nano_dos_msg), TOGETHER, NOVIEW); - if (!ISSET(RESTRICTED)) - add_to_funcs( MAC_FORMAT_MSG, MWRITEFILE, - mac_format_msg, IFSCHELP(nano_mac_msg), FALSE, NOVIEW); + add_to_funcs(mac_format_void, MWRITEFILE, + N_("Mac Format"), IFSCHELP(nano_mac_msg), TOGETHER, NOVIEW); - if (!ISSET(RESTRICTED)) - add_to_funcs( APPEND_MSG, MWRITEFILE, - append_msg, IFSCHELP(nano_append_msg), FALSE, NOVIEW); + add_to_funcs(append_void, MWRITEFILE, + N_("Append"), IFSCHELP(nano_append_msg), TOGETHER, NOVIEW); + add_to_funcs(prepend_void, MWRITEFILE, + N_("Prepend"), IFSCHELP(nano_prepend_msg), TOGETHER, NOVIEW); - if (!ISSET(RESTRICTED)) - add_to_funcs( PREPEND_MSG, MWRITEFILE, - prepend_msg, IFSCHELP(nano_prepend_msg), FALSE, NOVIEW); + add_to_funcs(backup_file_void, MWRITEFILE, + N_("Backup File"), IFSCHELP(nano_backup_msg), TOGETHER, NOVIEW); + } - if (!ISSET(RESTRICTED)) - add_to_funcs( BACKUP_FILE_MSG, MWRITEFILE, - backup_file_msg, IFSCHELP(nano_backup_msg), FALSE, NOVIEW); -#endif + /* If we're using restricted mode, file insertion is disabled, and + * thus command execution and the multibuffer toggle have no place. */ + if (!ISSET(RESTRICTED)) { + add_to_funcs(flip_execute_void, MINSERTFILE, + N_("Execute Command"), IFSCHELP(nano_execute_msg), TOGETHER, NOVIEW); -#ifndef NANO_TINY - /* If we're using restricted mode, command execution is disabled. - * It's useless since inserting files is disabled. */ - if (!ISSET(RESTRICTED)) - add_to_funcs( EXT_CMD_MSG, MINSERTFILE, - ext_cmd_msg, IFSCHELP(nano_execute_msg), FALSE, NOVIEW); + add_to_funcs(flip_execute_void, MEXTCMD, + read_file_tag, IFSCHELP(nano_insert_msg), TOGETHER, NOVIEW); -#ifdef ENABLE_MULTIBUFFER - /* If we're using restricted mode, the multibuffer toggle is - * disabled. It's useless since inserting files is disabled. */ - if (!ISSET(RESTRICTED)) - add_to_funcs( NEW_BUFFER_MSG, MINSERTFILE, - new_buffer_msg, IFSCHELP(nano_multibuffer_msg), FALSE, NOVIEW); +#ifndef DISABLE_MULTIBUFFER + add_to_funcs(new_buffer_void, MINSERTFILE|MEXTCMD, + N_("New Buffer"), IFSCHELP(nano_multibuffer_msg), TOGETHER, NOVIEW); #endif + } +#endif /* !NANO_TINY */ - add_to_funcs( INSERT_FILE_MSG, MEXTCMD, - insert_file_msg, IFSCHELP(nano_insert_msg), FALSE, VIEW); - -#ifdef ENABLE_MULTIBUFFER - add_to_funcs( NEW_BUFFER_MSG, MEXTCMD, - new_buffer_msg, IFSCHELP(nano_multibuffer_msg), FALSE, NOVIEW); +#ifndef DISABLE_BROWSER + if (!ISSET(RESTRICTED)) + add_to_funcs(to_files_void, MWRITEFILE|MINSERTFILE, + N_("To Files"), IFSCHELP(nano_tofiles_msg), TOGETHER, VIEW); + + add_to_funcs(do_first_file, (MBROWSER|MWHEREISFILE), + N_("First File"), IFSCHELP(nano_firstfile_msg), TOGETHER, VIEW); + add_to_funcs(do_last_file, (MBROWSER|MWHEREISFILE), + N_("Last File"), IFSCHELP(nano_lastfile_msg), TOGETHER, VIEW); +#endif + +#if !defined(NANO_TINY) && !defined(DISABLE_BROWSER) + add_to_funcs(do_research, MBROWSER, + whereis_next_tag, IFSCHELP(nano_whereis_next_msg), TOGETHER, VIEW); +#endif + +#ifndef DISABLE_COLOR + /* TRANSLATORS: Try to keep the next two strings at most 20 characters. */ + add_to_funcs(do_page_up, MLINTER, + N_("Prev Lint Msg"), IFSCHELP(nano_prevlint_msg), TOGETHER, VIEW); + add_to_funcs(do_page_down, MLINTER, + N_("Next Lint Msg"), IFSCHELP(nano_nextlint_msg), TOGETHER, VIEW); +#endif + + /* Start associating key combos with functions in specific menus. */ + + add_to_sclist(MMOST, "^G", do_help_void, 0); + add_to_sclist(MMOST, "F1", do_help_void, 0); + add_to_sclist(MMAIN|MHELP|MBROWSER, "^X", do_exit, 0); + add_to_sclist(MMAIN|MHELP|MBROWSER, "F2", do_exit, 0); + add_to_sclist(MMAIN, "^O", do_writeout_void, 0); + add_to_sclist(MMAIN, "F3", do_writeout_void, 0); + add_to_sclist(MMAIN, "^R", do_insertfile_void, 0); + add_to_sclist(MMAIN, "F5", do_insertfile_void, 0); + add_to_sclist(MMAIN, "Ins", do_insertfile_void, 0); + add_to_sclist(MMAIN|MBROWSER, "^W", do_search, 0); + add_to_sclist(MMAIN|MBROWSER, "F6", do_search, 0); + add_to_sclist(MMAIN, "^\\", do_replace, 0); + add_to_sclist(MMAIN, "M-R", do_replace, 0); + add_to_sclist(MMAIN, "F14", do_replace, 0); + add_to_sclist(MMOST, "^K", do_cut_text_void, 0); + add_to_sclist(MMOST, "F9", do_cut_text_void, 0); + add_to_sclist(MMAIN, "^U", do_uncut_text, 0); + add_to_sclist(MMAIN, "F10", do_uncut_text, 0); +#ifndef DISABLE_JUSTIFY + add_to_sclist(MMAIN, "^J", do_justify_void, 0); + add_to_sclist(MMAIN, "F4", do_justify_void, 0); #endif +#ifndef DISABLE_SPELLER + add_to_sclist(MMAIN, "^T", do_spell, 0); + add_to_sclist(MMAIN, "F12", do_spell, 0); +#else +#ifndef DISABLE_COLOR + add_to_sclist(MMAIN, "^T", do_linter, 0); + add_to_sclist(MMAIN, "F12", do_linter, 0); + add_to_sclist(MMAIN, "^T", do_formatter, 0); + add_to_sclist(MMAIN, "F12", do_formatter, 0); +#endif +#endif + add_to_sclist(MMAIN, "^C", do_cursorpos_void, 0); + add_to_sclist(MMAIN, "F11", do_cursorpos_void, 0); + add_to_sclist(MMAIN, "^_", do_gotolinecolumn_void, 0); + add_to_sclist(MMAIN, "M-G", do_gotolinecolumn_void, 0); + add_to_sclist(MMAIN, "F13", do_gotolinecolumn_void, 0); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "^Y", do_page_up, 0); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "F7", do_page_up, 0); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "PgUp", do_page_up, 0); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "^V", do_page_down, 0); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "F8", do_page_down, 0); + add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE|MLINTER, "PgDn", do_page_down, 0); + add_to_sclist(MMAIN|MHELP, "M-\\", do_first_line, 0); + add_to_sclist(MMAIN|MHELP, "M-|", do_first_line, 0); + add_to_sclist(MMAIN|MHELP, "M-/", do_last_line, 0); + add_to_sclist(MMAIN|MHELP, "M-?", do_last_line, 0); +#ifndef NANO_TINY + add_to_sclist(MMAIN|MBROWSER, "M-W", do_research, 0); + add_to_sclist(MMAIN|MBROWSER, "F16", do_research, 0); + add_to_sclist(MMAIN, "M-]", do_find_bracket, 0); + add_to_sclist(MMAIN, "^^", do_mark, 0); + add_to_sclist(MMAIN, "M-A", do_mark, 0); + add_to_sclist(MMAIN, "F15", do_mark, 0); + add_to_sclist(MMAIN, "M-^", do_copy_text, 0); + add_to_sclist(MMAIN, "M-6", do_copy_text, 0); + add_to_sclist(MMAIN, "M-}", do_indent_void, 0); + add_to_sclist(MMAIN, "M-{", do_unindent, 0); + add_to_sclist(MMAIN, "M-U", do_undo, 0); + add_to_sclist(MMAIN, "M-E", do_redo, 0); +#endif + add_to_sclist(MMOST, "^B", do_left, 0); + add_to_sclist(MMOST, "Left", do_left, 0); + add_to_sclist(MMOST, "^F", do_right, 0); + add_to_sclist(MMOST, "Right", do_right, 0); +#ifndef NANO_TINY + add_to_sclist(MMOST, "M-Space", do_prev_word_void, 0); + add_to_sclist(MMOST, "^Space", do_next_word_void, 0); +#endif + add_to_sclist(MMOST, "^A", do_home, 0); + add_to_sclist(MMOST, "Home", do_home, 0); + add_to_sclist(MMOST, "^E", do_end, 0); + add_to_sclist(MMOST, "End", do_end, 0); + add_to_sclist(MMAIN|MHELP|MBROWSER, "^P", do_up_void, 0); + add_to_sclist(MMAIN|MHELP|MBROWSER, "Up", do_up_void, 0); + add_to_sclist(MMAIN|MHELP|MBROWSER, "^N", do_down_void, 0); + add_to_sclist(MMAIN|MHELP|MBROWSER, "Down", do_down_void, 0); +#ifndef DISABLE_JUSTIFY + add_to_sclist(MMAIN, "M-(", do_para_begin_void, 0); + add_to_sclist(MMAIN, "M-9", do_para_begin_void, 0); + add_to_sclist(MMAIN, "M-)", do_para_end_void, 0); + add_to_sclist(MMAIN, "M-0", do_para_end_void, 0); #endif - -#ifndef DISABLE_HELP - add_to_funcs( REFRESH_MSG, MHELP, - refresh_msg, nano_refresh_msg, FALSE, VIEW); - - add_to_funcs(DO_EXIT, MHELP, exit_msg, IFSCHELP(nano_exit_msg), FALSE, VIEW); - - +#ifndef NANO_TINY + add_to_sclist(MMAIN, "M--", do_scroll_up, 0); + add_to_sclist(MMAIN, "M-_", do_scroll_up, 0); + add_to_sclist(MMAIN, "M-+", do_scroll_down, 0); + add_to_sclist(MMAIN, "M-=", do_scroll_down, 0); +#endif +#ifndef DISABLE_MULTIBUFFER + add_to_sclist(MMAIN, "M-<", switch_to_prev_buffer_void, 0); + add_to_sclist(MMAIN, "M-,", switch_to_prev_buffer_void, 0); + add_to_sclist(MMAIN, "M->", switch_to_next_buffer_void, 0); + add_to_sclist(MMAIN, "M-.", switch_to_next_buffer_void, 0); +#endif + add_to_sclist(MMOST, "M-V", do_verbatim_input, 0); +#ifndef NANO_TINY + add_to_sclist(MMAIN, "M-T", do_cut_till_eof, 0); + add_to_sclist(MMAIN, "M-D", do_wordlinechar_count, 0); #endif +#ifndef DISABLE_JUSTIFY + add_to_sclist(MMAIN|MWHEREIS, "M-J", do_full_justify, 0); +#endif + add_to_sclist(MMAIN|MHELP, "^L", total_refresh, 0); + add_to_sclist(MMAIN, "^Z", do_suspend_void, 0); -#ifndef DISABLE_BROWSER - - add_to_funcs( FIRST_FILE_MSG, - (MBROWSER|MWHEREISFILE), - first_file_msg, IFSCHELP(nano_firstfile_msg), FALSE, VIEW); +#ifndef NANO_TINY + /* Group of "Appearance" toggles. */ + add_to_sclist(MMAIN, "M-X", do_toggle_void, NO_HELP); + add_to_sclist(MMAIN, "M-C", do_toggle_void, CONST_UPDATE); + add_to_sclist(MMAIN, "M-O", do_toggle_void, MORE_SPACE); + add_to_sclist(MMAIN, "M-S", do_toggle_void, SMOOTH_SCROLL); + add_to_sclist(MMAIN, "M-$", do_toggle_void, SOFTWRAP); + add_to_sclist(MMAIN, "M-P", do_toggle_void, WHITESPACE_DISPLAY); +#ifndef DISABLE_COLOR + add_to_sclist(MMAIN, "M-Y", do_toggle_void, NO_COLOR_SYNTAX); +#endif - add_to_funcs( LAST_FILE_MSG, - (MBROWSER|MWHEREISFILE), - last_file_msg, IFSCHELP(nano_lastfile_msg), FALSE, VIEW); + /* Group of "Editing-behavior" toggles. */ + add_to_sclist(MMAIN, "M-H", do_toggle_void, SMART_HOME); + add_to_sclist(MMAIN, "M-I", do_toggle_void, AUTOINDENT); + add_to_sclist(MMAIN, "M-K", do_toggle_void, CUT_TO_END); +#ifndef DISABLE_WRAPPING + add_to_sclist(MMAIN, "M-L", do_toggle_void, NO_WRAP); +#endif + add_to_sclist(MMAIN, "M-Q", do_toggle_void, TABS_TO_SPACES); - add_to_funcs( GOTO_DIR_MSG, MBROWSER, - goto_dir_msg, IFSCHELP(nano_gotodir_msg), FALSE, VIEW); + /* Group of "Peripheral-feature" toggles. */ + add_to_sclist(MMAIN, "M-B", do_toggle_void, BACKUP_FILE); +#ifndef DISABLE_MULTIBUFFER + add_to_sclist(MMAIN, "M-F", do_toggle_void, MULTIBUFFER); +#endif +#ifndef DISABLE_MOUSE + add_to_sclist(MMAIN, "M-M", do_toggle_void, USE_MOUSE); #endif + add_to_sclist(MMAIN, "M-N", do_toggle_void, NO_CONVERT); + add_to_sclist(MMAIN, "M-Z", do_toggle_void, SUSPEND); +#endif /* !NANO_TINY */ - currmenu = MMAIN; + add_to_sclist(MMAIN, "^Q", xon_complaint, 0); + add_to_sclist(MMAIN, "^S", xoff_complaint, 0); + + add_to_sclist(((MMOST & ~MMAIN & ~MBROWSER) | MYESNO), "^C", do_cancel, 0); - add_to_sclist(MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR, - "^G", DO_HELP_VOID, 0, TRUE); - add_to_sclist(MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR, - "F1", DO_HELP_VOID, 0, TRUE); - add_to_sclist(MMAIN|MHELP|MBROWSER, "^X", DO_EXIT, 0, TRUE); - add_to_sclist(MMAIN|MHELP|MBROWSER, "F2", DO_EXIT, 0, TRUE); - add_to_sclist(MMAIN, "^_", DO_GOTOLINECOLUMN_VOID, 0, TRUE); - add_to_sclist(MMAIN, "F13", DO_GOTOLINECOLUMN_VOID, 0, TRUE); - add_to_sclist(MMAIN, "M-G", DO_GOTOLINECOLUMN_VOID, 0, TRUE); - add_to_sclist(MMAIN, "^O", DO_WRITEOUT_VOID, 0, TRUE); - add_to_sclist(MMAIN, "F3", DO_WRITEOUT_VOID, 0, TRUE); -#ifndef DISABLE_JUSTIFY - add_to_sclist(MMAIN, "^J", DO_JUSTIFY_VOID, 0, TRUE); - add_to_sclist(MMAIN, "F4", DO_JUSTIFY_VOID, 0, TRUE); -#endif - add_to_sclist(MMAIN, "^R", DO_INSERTFILE_VOID, 0, TRUE); - add_to_sclist(MMAIN, "F5", DO_INSERTFILE_VOID, 0, TRUE); - add_to_sclist(MMAIN, "kinsert", DO_INSERTFILE_VOID, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER, "^W", DO_SEARCH, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER, "F6", DO_SEARCH, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "^Y", DO_PAGE_UP, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "F7", DO_PAGE_UP, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "kpup", DO_PAGE_UP, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "^V", DO_PAGE_DOWN, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "F8", DO_PAGE_DOWN, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER|MHELP|MWHEREISFILE, "kpdown", DO_PAGE_DOWN, 0, TRUE); - add_to_sclist(MMAIN, "^K", DO_CUT_TEXT_VOID, 0, TRUE); - add_to_sclist(MMAIN, "F9", DO_CUT_TEXT_VOID, 0, TRUE); - add_to_sclist(MMAIN, "^U", DO_UNCUT_TEXT, 0, TRUE); - add_to_sclist(MMAIN, "F10", DO_UNCUT_TEXT, 0, TRUE); - add_to_sclist(MMAIN, "^C", DO_CURSORPOS_VOID, 0, TRUE); - add_to_sclist(MMAIN, "F11", DO_CURSORPOS_VOID, 0, TRUE); -#ifndef DISABLE_SPELLER - add_to_sclist(MMAIN, "^T", DO_SPELL, 0, TRUE); - add_to_sclist(MMAIN, "F12", DO_SPELL, 0, TRUE); -#endif - add_to_sclist(MMAIN, "^\\", DO_REPLACE, 0, TRUE); - add_to_sclist(MMAIN, "F14", DO_REPLACE, 0, TRUE); - add_to_sclist(MMAIN, "M-R", DO_REPLACE, 0, TRUE); - add_to_sclist(MWHEREIS, "^R", DO_REPLACE, 0, FALSE); - add_to_sclist(MREPLACE, "^R", NO_REPLACE_MSG, 0, FALSE); - add_to_sclist(MWHEREIS, "^T", DO_GOTOLINECOLUMN_VOID, 0, FALSE); -#ifndef NANO_TINY - add_to_sclist(MMAIN, "^^", DO_MARK, 0, TRUE); - add_to_sclist(MMAIN, "F15", DO_MARK, 0, TRUE); - add_to_sclist(MMAIN, "M-A", DO_MARK, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER, "M-W", DO_RESEARCH, 0, TRUE); - add_to_sclist(MMAIN|MBROWSER, "F16", DO_RESEARCH, 0, TRUE); - add_to_sclist(MMAIN, "M-^", DO_COPY_TEXT, 0, TRUE); - add_to_sclist(MMAIN, "M-6", DO_COPY_TEXT, 0, TRUE); - add_to_sclist(MMAIN, "M-}", DO_INDENT_VOID, 0, TRUE); - add_to_sclist(MMAIN, "M-{", DO_UNINDENT, 0, TRUE); - if (ISSET(UNDOABLE)) { - add_to_sclist(MMAIN, "M-U", DO_UNDO, 0, TRUE); - add_to_sclist(MMAIN, "M-E", DO_REDO, 0, TRUE); - } - add_to_sclist(MALL, "^F", DO_RIGHT, 0, TRUE); - add_to_sclist(MALL, "^B", DO_LEFT, 0, TRUE); - add_to_sclist(MMAIN, "^Space", DO_NEXT_WORD_VOID, 0, TRUE); - add_to_sclist(MMAIN, "M-Space", DO_PREV_WORD_VOID, 0, TRUE); -#endif - add_to_sclist(MALL, "kright", DO_RIGHT, 0, TRUE); - add_to_sclist(MALL, "kleft", DO_LEFT, 0, TRUE); - add_to_sclist(MMAIN, "^Q", XON_COMPLAINT, 0, TRUE); - add_to_sclist(MMAIN, "^S", XOFF_COMPLAINT, 0, TRUE); - add_to_sclist(MMAIN|MHELP|MBROWSER, "^P", DO_UP_VOID, 0, TRUE); - add_to_sclist(MMAIN|MHELP|MBROWSER, "kup", DO_UP_VOID, 0, TRUE); - add_to_sclist(MMAIN|MHELP|MBROWSER, "^N", DO_DOWN_VOID, 0, TRUE); - add_to_sclist(MMAIN|MHELP|MBROWSER, "kdown", DO_DOWN_VOID, 0, TRUE); - add_to_sclist(MALL, "^A", DO_HOME, 0, TRUE); - add_to_sclist(MALL, "khome", DO_HOME, 0, TRUE); - add_to_sclist(MALL, "^E", DO_END, 0, TRUE); - add_to_sclist(MALL, "kend", DO_END, 0, TRUE); #ifndef NANO_TINY - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2|MWHEREISFILE, "^P", PREV_HISTORY_MSG, 0, FALSE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2|MWHEREISFILE, "kup", PREV_HISTORY_MSG, 0, FALSE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2|MWHEREISFILE, "^N", NEXT_HISTORY_MSG, 0, FALSE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2|MWHEREISFILE, "kdown", NEXT_HISTORY_MSG, 0, FALSE); + add_to_sclist(MWHEREIS|MREPLACE, "M-B", backwards_void, 0); + add_to_sclist(MWHEREIS|MREPLACE, "M-C", case_sens_void, 0); #endif + add_to_sclist(MWHEREIS|MREPLACE, "M-R", regexp_void, 0); + add_to_sclist(MWHEREIS|MREPLACE, "^R", flip_replace_void, 0); + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MGOTOLINE, "^Y", do_first_line, 0); + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MGOTOLINE, "^V", do_last_line, 0); #ifndef DISABLE_JUSTIFY - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2, - "^W", DO_PARA_BEGIN_VOID, 0, TRUE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2, - "^O", DO_PARA_END_VOID, 0, TRUE); - add_to_sclist(MALL, "M-(", DO_PARA_BEGIN_VOID, 0, TRUE); - add_to_sclist(MALL, "M-9", DO_PARA_BEGIN_VOID, 0, TRUE); - add_to_sclist(MALL, "M-)", DO_PARA_END_VOID, 0, TRUE); - add_to_sclist(MALL, "M-0", DO_PARA_END_VOID, 0, TRUE); -#endif - add_to_sclist(MWHEREIS, - "M-C", CASE_SENS_MSG, 0, FALSE); - add_to_sclist(MREPLACE, - "M-C", CASE_SENS_MSG, 0, FALSE); - add_to_sclist(MREPLACE2, - "M-C", CASE_SENS_MSG, 0, FALSE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2, - "M-B", BACKWARDS_MSG, 0, FALSE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2, - "M-R", REGEXP_MSG, 0, FALSE); - - add_to_sclist(MMAIN, "M-\\", DO_FIRST_LINE, 0, TRUE); - add_to_sclist(MMAIN, "M-|", DO_FIRST_LINE, 0, TRUE); - add_to_sclist(MMAIN, "M-/", DO_LAST_LINE, 0, TRUE); - add_to_sclist(MMAIN, "M-?", DO_LAST_LINE, 0, TRUE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MHELP, - "^Y", DO_FIRST_LINE, 0, TRUE); - add_to_sclist(MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MHELP, - "^V", DO_LAST_LINE, 0, TRUE); - - add_to_sclist(MBROWSER|MWHEREISFILE, "M-\\", FIRST_FILE_MSG, 0, TRUE); - add_to_sclist(MBROWSER|MWHEREISFILE, "M-|", FIRST_FILE_MSG, 0, TRUE); - add_to_sclist(MBROWSER|MWHEREISFILE, "M-/", LAST_FILE_MSG, 0, TRUE); - add_to_sclist(MBROWSER|MWHEREISFILE, "M-?", LAST_FILE_MSG, 0, TRUE); - add_to_sclist(MBROWSER|MWHEREISFILE, "^_", GOTO_DIR_MSG, 0, TRUE); - add_to_sclist(MBROWSER|MWHEREISFILE, "F13", GOTO_DIR_MSG, 0, TRUE); - add_to_sclist(MBROWSER|MWHEREISFILE, "M-G", GOTO_DIR_MSG, 0, TRUE); -#ifndef NANO_TINY - add_to_sclist(MMAIN, "M-]", DO_FIND_BRACKET, 0, TRUE); - add_to_sclist(MMAIN, "M--", DO_SCROLL_UP, 0, TRUE); - add_to_sclist(MMAIN, "M-_", DO_SCROLL_UP, 0, TRUE); - add_to_sclist(MMAIN, "M-+", DO_SCROLL_DOWN, 0, TRUE); - add_to_sclist(MMAIN, "M-=", DO_SCROLL_DOWN, 0, TRUE); + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH, "^W", do_para_begin_void, 0); + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH, "^O", do_para_end_void, 0); #endif - -#ifdef ENABLE_MULTIBUFFER - add_to_sclist(MMAIN, "M-<", SWITCH_TO_PREV_BUFFER_VOID, 0, TRUE); - add_to_sclist(MMAIN, "M-,", SWITCH_TO_PREV_BUFFER_VOID, 0, TRUE); - add_to_sclist(MMAIN, "M->", SWITCH_TO_NEXT_BUFFER_VOID, 0, TRUE); - add_to_sclist(MMAIN, "M-.", SWITCH_TO_NEXT_BUFFER_VOID, 0, TRUE); + add_to_sclist(MWHEREIS, "^T", do_gotolinecolumn_void, 0); + add_to_sclist(MGOTOLINE, "^T", gototext_void, 0); +#ifndef DISABLE_HISTORIES + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "^P", get_history_older_void, 0); + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "Up", get_history_older_void, 0); + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "^N", get_history_newer_void, 0); + add_to_sclist(MWHEREIS|MREPLACE|MREPLACEWITH|MWHEREISFILE, "Down", get_history_newer_void, 0); #endif - add_to_sclist(MALL, "M-V", DO_VERBATIM_INPUT, 0, TRUE); -#ifndef NANO_TINY - add_to_sclist(MALL, "M-T", DO_CUT_TILL_END, 0, TRUE); -#ifndef DISABLE_JUSTIFY - add_to_sclist(MALL, "M-J", DO_FULL_JUSTIFY, 0, TRUE); -#endif - add_to_sclist(MMAIN, "M-D", DO_WORDLINECHAR_COUNT, 0, TRUE); - add_to_sclist(MMAIN, "M-X", DO_TOGGLE, NO_HELP, TRUE); - add_to_sclist(MMAIN, "M-C", DO_TOGGLE, CONST_UPDATE, TRUE); - add_to_sclist(MMAIN, "M-O", DO_TOGGLE, MORE_SPACE, TRUE); - add_to_sclist(MMAIN, "M-S", DO_TOGGLE, SMOOTH_SCROLL, TRUE); - add_to_sclist(MMAIN, "M-P", DO_TOGGLE, WHITESPACE_DISPLAY, TRUE); - add_to_sclist(MMAIN, "M-Y", DO_TOGGLE, NO_COLOR_SYNTAX, TRUE); - add_to_sclist(MMAIN, "M-H", DO_TOGGLE, SMART_HOME, TRUE); - add_to_sclist(MMAIN, "M-I", DO_TOGGLE, AUTOINDENT, TRUE); - add_to_sclist(MMAIN, "M-K", DO_TOGGLE, CUT_TO_END, TRUE); - add_to_sclist(MMAIN, "M-L", DO_TOGGLE, NO_WRAP, TRUE); - add_to_sclist(MMAIN, "M-Q", DO_TOGGLE, TABS_TO_SPACES, TRUE); - add_to_sclist(MMAIN, "M-B", DO_TOGGLE, BACKUP_FILE, TRUE); - add_to_sclist(MMAIN, "M-F", DO_TOGGLE, MULTIBUFFER, TRUE); - add_to_sclist(MMAIN, "M-M", DO_TOGGLE, USE_MOUSE, TRUE); - add_to_sclist(MMAIN, "M-N", DO_TOGGLE, NO_CONVERT, TRUE); - add_to_sclist(MMAIN, "M-Z", DO_TOGGLE, SUSPEND, TRUE); - add_to_sclist(MMAIN, "M-$", DO_TOGGLE, SOFTWRAP, TRUE); -#endif - add_to_sclist(MGOTOLINE, "^T", GOTOTEXT_MSG, 0, FALSE); - add_to_sclist(MINSERTFILE|MEXTCMD, "M-F", NEW_BUFFER_MSG, 0, FALSE); - add_to_sclist((MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MWHEREISFILE|MGOTODIR|MYESNO), - "^C", CANCEL_MSG, 0, FALSE); - add_to_sclist(MHELP, "^X", DO_EXIT, 0, TRUE); - add_to_sclist(MHELP, "F2", DO_EXIT, 0, TRUE); - add_to_sclist(MWRITEFILE, "M-D", DOS_FORMAT_MSG, 0, FALSE); - add_to_sclist(MWRITEFILE, "M-M", MAC_FORMAT_MSG, 0, FALSE); - add_to_sclist(MWRITEFILE, "M-A", APPEND_MSG, 0, FALSE); - add_to_sclist(MWRITEFILE, "M-P", PREPEND_MSG, 0, FALSE); - add_to_sclist(MWRITEFILE, "M-B", BACKUP_FILE_MSG, 0, FALSE); - add_to_sclist(MWRITEFILE, "^T", TO_FILES_MSG, 0, FALSE); - add_to_sclist(MINSERTFILE, "^T", TO_FILES_MSG, 0, FALSE); - add_to_sclist(MINSERTFILE, "^X", EXT_CMD_MSG, 0, FALSE); - add_to_sclist(MMAIN, "^Z", DO_SUSPEND_VOID, 0, FALSE); - add_to_sclist(MMAIN, "^L", TOTAL_REFRESH, 0, TRUE); - add_to_sclist(MALL, "^I", DO_TAB, 0, TRUE); - add_to_sclist(MALL, "^M", DO_ENTER, 0, TRUE); - add_to_sclist(MALL, "kenter", DO_ENTER, 0, TRUE); - add_to_sclist(MALL, "^D", DO_DELETE, 0, TRUE); - add_to_sclist(MALL, "kdel", DO_DELETE, 0, TRUE); - add_to_sclist(MALL, "^H", DO_BACKSPACE, 0, TRUE); - add_to_sclist(MALL, "kbsp", DO_BACKSPACE, 0, TRUE); +#ifndef DISABLE_BROWSER + add_to_sclist(MBROWSER|MWHEREISFILE, "M-\\", do_first_file, 0); + add_to_sclist(MBROWSER|MWHEREISFILE, "M-|", do_first_file, 0); + add_to_sclist(MBROWSER|MWHEREISFILE, "M-/", do_last_file, 0); + add_to_sclist(MBROWSER|MWHEREISFILE, "M-?", do_last_file, 0); + add_to_sclist(MBROWSER|MWHEREISFILE, "^_", goto_dir_void, 0); + add_to_sclist(MBROWSER|MWHEREISFILE, "M-G", goto_dir_void, 0); + add_to_sclist(MBROWSER|MWHEREISFILE, "F13", goto_dir_void, 0); +#endif + add_to_sclist(MWRITEFILE, "M-D", dos_format_void, 0); + add_to_sclist(MWRITEFILE, "M-M", mac_format_void, 0); + add_to_sclist(MWRITEFILE, "M-A", append_void, 0); + add_to_sclist(MWRITEFILE, "M-P", prepend_void, 0); + add_to_sclist(MWRITEFILE, "M-B", backup_file_void, 0); +#ifndef DISABLE_BROWSER + add_to_sclist(MWRITEFILE|MINSERTFILE, "^T", to_files_void, 0); +#endif + add_to_sclist(MINSERTFILE|MEXTCMD, "^X", flip_execute_void, 0); + add_to_sclist(MINSERTFILE|MEXTCMD, "M-F", new_buffer_void, 0); + add_to_sclist(MHELP|MBROWSER, "^C", do_exit, 0); +#ifndef DISABLE_HELP + add_to_sclist(MHELP, "^G", do_exit, 0); +#endif + add_to_sclist(MMOST, "^I", do_tab, 0); + add_to_sclist(MMOST, "^M", do_enter_void, 0); + add_to_sclist(MMOST, "Enter", do_enter_void, 0); + add_to_sclist(MMOST, "^D", do_delete, 0); + add_to_sclist(MMOST, "Del", do_delete, 0); + add_to_sclist(MMOST, "^H", do_backspace, 0); + add_to_sclist(MMOST, "Bsp", do_backspace, 0); #ifdef DEBUG print_sclist(); #endif - } -/* Given a function alias, execute the proper - function, and then me */ -void iso_me_harder_funcmap(short func) +#ifndef DISABLE_COLOR +void set_lint_or_format_shortcuts(void) { - if (func == TOTAL_REFRESH) - total_refresh(); - else if (func == DO_HELP_VOID) - do_help_void(); - else if (func == DO_SEARCH) - do_search(); - else if (func == DO_PAGE_UP) - do_page_up(); - else if (func == DO_PAGE_DOWN) - do_page_down(); - else if (func == DO_UP_VOID) - do_up_void(); - else if (func == DO_LEFT) - do_left(); - else if (func == DO_DOWN_VOID) - do_down_void(); - else if (func == DO_RIGHT) - do_right(); - else if (func == DO_ENTER) - do_enter(FALSE); - else if (func == DO_EXIT) - do_exit(); - else if (func == DO_FIRST_LINE) - do_first_line(); - else if (func == DO_LAST_LINE) - do_last_line(); - else if (func == DO_BACKSPACE) - do_backspace(); - else if (func == DO_DELETE) - do_delete(); - else if (func == DO_TAB) - do_tab(); - else if (func == DO_VERBATIM_INPUT) - do_verbatim_input(); -#ifdef ENABLE_MULTIBUFFER - else if (func == SWITCH_TO_NEXT_BUFFER_VOID) - switch_to_next_buffer_void(); - else if (func == SWITCH_TO_PREV_BUFFER_VOID) - switch_to_prev_buffer_void(); -#endif - else if (func == DO_END) - do_end(); - else if (func == DO_HOME) - do_home(); - else if (func == DO_SUSPEND_VOID) - do_suspend_void(); - else if (func == DO_WRITEOUT_VOID) - do_writeout_void(); - else if (func == DO_INSERTFILE_VOID) - do_insertfile_void(); - else if (func == DO_CUT_TEXT_VOID) - do_cut_text_void(); - else if (func == DO_UNCUT_TEXT) - do_uncut_text(); - else if (func == DO_CURSORPOS_VOID) - do_cursorpos_void(); - else if (func == DO_GOTOLINECOLUMN_VOID) - do_gotolinecolumn_void(); - else if (func == DO_REPLACE) - do_replace(); - else if (func == XOFF_COMPLAINT) - xoff_complaint(); - else if (func == XON_COMPLAINT) - xon_complaint(); - else if (func == DO_CUT_TEXT) - do_cut_text_void(); -#ifndef NANO_TINY - else if (func == DO_CUT_TILL_END) - do_cut_till_end(); - else if (func == DO_REDO) - do_redo(); - else if (func == DO_UNDO) - do_undo(); - else if (func == DO_WORDLINECHAR_COUNT) - do_wordlinechar_count(); - else if (func == DO_FIND_BRACKET) - do_find_bracket(); - else if (func == DO_PREV_WORD_VOID) - do_prev_word_void(); -#ifndef DISABLE_JUSTIFY - else if (func == DO_JUSTIFY_VOID) - do_justify_void(); - else if (func == DO_PARA_BEGIN_VOID) - do_para_begin_void(); - else if (func == DO_PARA_END_VOID) - do_para_end_void(); - else if (func == DO_FULL_JUSTIFY) - do_full_justify(); -#endif - else if (func == DO_MARK) - do_mark(); - else if (func == DO_RESEARCH) - do_research(); - else if (func == DO_COPY_TEXT) - do_copy_text(); - else if (func == DO_INDENT_VOID) - do_indent_void(); - else if (func == DO_UNINDENT) - do_unindent(); - else if (func == DO_SCROLL_UP) - do_scroll_up(); - else if (func == DO_SCROLL_DOWN) - do_scroll_down(); - else if (func == DO_NEXT_WORD_VOID) - do_next_word_void(); #ifndef DISABLE_SPELLER - else if (func == DO_SPELL) - do_spell(); -#endif - else if (func == DO_NEXT_WORD) - do_next_word_void(); - else if (func == DO_PREV_WORD) - do_prev_word_void(); + if (openfile->syntax->formatter) { + replace_scs_for(do_spell, do_formatter); + replace_scs_for(do_linter, do_formatter); + } else { + replace_scs_for(do_spell, do_linter); + replace_scs_for(do_formatter, do_linter); + } #endif } - -/* Free the given shortcut. */ -void free_shortcutage(shortcut **shortcutage) +void set_spell_shortcuts(void) { - assert(shortcutage != NULL); - - while (*shortcutage != NULL) { - shortcut *ps = *shortcutage; - *shortcutage = (*shortcutage)->next; - free(ps); - } +#ifndef DISABLE_SPELLER + replace_scs_for(do_formatter, do_spell); + replace_scs_for(do_linter, do_spell); +#endif } +#endif const subnfunc *sctofunc(sc *s) { @@ -1358,12 +1216,14 @@ const subnfunc *sctofunc(sc *s) } #ifndef NANO_TINY -/* Now lets come up with a single (hopefully) - function to get a string for each flag */ +/* Now let's come up with a single (hopefully) function to get a string + * for each flag. */ const char *flagtostr(int flag) { - switch (flag) { + switch (flag) { case NO_HELP: + /* TRANSLATORS: The next seventeen strings are toggle descriptions; + * they are best kept shorter than 40 characters, but may be longer. */ return N_("Help mode"); case CONST_UPDATE: return N_("Constant cursor position display"); @@ -1371,6 +1231,8 @@ const char *flagtostr(int flag) return N_("Use of one more line for editing"); case SMOOTH_SCROLL: return N_("Smooth scrolling"); + case SOFTWRAP: + return N_("Soft wrapping of overlong lines"); case WHITESPACE_DISPLAY: return N_("Whitespace display"); case NO_COLOR_SYNTAX: @@ -1382,7 +1244,7 @@ const char *flagtostr(int flag) case CUT_TO_END: return N_("Cut to end"); case NO_WRAP: - return N_("Long line wrapping"); + return N_("Hard wrapping of overlong lines"); case TABS_TO_SPACES: return N_("Conversion of typed tabs to spaces"); case BACKUP_FILE: @@ -1395,270 +1257,254 @@ const char *flagtostr(int flag) return N_("No conversion from DOS/Mac format"); case SUSPEND: return N_("Suspension"); - case SOFTWRAP: - return N_("Soft line wrapping"); default: return "?????"; } } -#endif /* NANO_TINY */ +#endif /* !NANO_TINY */ -/* Interpret the string given by the rc file and return a - shortcut struct, complete with proper value for execute */ -sc *strtosc(int menu, char *input) +#ifndef DISABLE_NANORC +/* Interpret a function string given in the rc file, and return a + * shortcut struct with the corresponding function filled in. */ +sc *strtosc(char *input) { - sc *s; + sc *s; s = (sc *)nmalloc(sizeof(sc)); - s->execute = TRUE; /* overridden as needed below */ - #ifndef DISABLE_HELP if (!strcasecmp(input, "help")) - s->scfunc = DO_HELP_VOID; - else -#endif - if (!strcasecmp(input, "cancel")) { - s->scfunc = CANCEL_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "exit")) - s->scfunc = DO_EXIT; + s->scfunc = do_help_void; + else +#endif + if (!strcasecmp(input, "cancel")) + s->scfunc = do_cancel; + else if (!strcasecmp(input, "exit")) + s->scfunc = do_exit; else if (!strcasecmp(input, "writeout")) - s->scfunc = DO_WRITEOUT_VOID; + s->scfunc = do_writeout_void; else if (!strcasecmp(input, "insert")) - s->scfunc = DO_INSERTFILE_VOID; + s->scfunc = do_insertfile_void; else if (!strcasecmp(input, "whereis")) - s->scfunc = DO_SEARCH; - else if (!strcasecmp(input, "up")) - s->scfunc = DO_UP_VOID; - else if (!strcasecmp(input, "down")) - s->scfunc = DO_DOWN_VOID; - else if (!strcasecmp(input, "pageup") - || !strcasecmp(input, "prevpage")) - s->scfunc = DO_PAGE_UP; - else if (!strcasecmp(input, "pagedown") - || !strcasecmp(input, "nextpage")) - s->scfunc = DO_PAGE_DOWN; + s->scfunc = do_search; +#ifndef NANO_TINY + else if (!strcasecmp(input, "searchagain") || + !strcasecmp(input, "research")) + s->scfunc = do_research; +#endif + else if (!strcasecmp(input, "replace")) + s->scfunc = do_replace; else if (!strcasecmp(input, "cut")) - s->scfunc = DO_CUT_TEXT_VOID; + s->scfunc = do_cut_text_void; else if (!strcasecmp(input, "uncut")) - s->scfunc = DO_UNCUT_TEXT; + s->scfunc = do_uncut_text; +#ifndef NANO_TINY + else if (!strcasecmp(input, "cutrestoffile")) + s->scfunc = do_cut_till_eof; + else if (!strcasecmp(input, "copytext")) + s->scfunc = do_copy_text; + else if (!strcasecmp(input, "mark")) + s->scfunc = do_mark; +#endif +#ifndef DISABLE_SPELLER + else if (!strcasecmp(input, "tospell") || + !strcasecmp(input, "speller")) + s->scfunc = do_spell; +#endif else if (!strcasecmp(input, "curpos") || - !strcasecmp(input, "cursorpos")) - s->scfunc = DO_CURSORPOS_VOID; - else if (!strcasecmp(input, "firstline")) - s->scfunc = DO_FIRST_LINE; - else if (!strcasecmp(input, "lastline")) - s->scfunc = DO_LAST_LINE; + !strcasecmp(input, "cursorpos")) + s->scfunc = do_cursorpos_void; else if (!strcasecmp(input, "gotoline")) - s->scfunc = DO_GOTOLINECOLUMN_VOID; - else if (!strcasecmp(input, "replace")) - s->scfunc = DO_REPLACE; + s->scfunc = do_gotolinecolumn_void; #ifndef DISABLE_JUSTIFY else if (!strcasecmp(input, "justify")) - s->scfunc = DO_JUSTIFY_VOID; + s->scfunc = do_justify_void; + else if (!strcasecmp(input, "fulljustify")) + s->scfunc = do_full_justify; else if (!strcasecmp(input, "beginpara")) - s->scfunc = DO_PARA_BEGIN_VOID; + s->scfunc = do_para_begin_void; else if (!strcasecmp(input, "endpara")) - s->scfunc = DO_PARA_END_VOID; - else if (!strcasecmp(input, "fulljustify")) - s->scfunc = DO_FULL_JUSTIFY; + s->scfunc = do_para_end_void; #endif #ifndef NANO_TINY - else if (!strcasecmp(input, "mark")) - s->scfunc = DO_MARK; - else if (!strcasecmp(input, "searchagain") || - !strcasecmp(input, "research")) - s->scfunc = DO_RESEARCH; - else if (!strcasecmp(input, "copytext")) - s->scfunc = DO_COPY_TEXT; else if (!strcasecmp(input, "indent")) - s->scfunc = DO_INDENT_VOID; + s->scfunc = do_indent_void; else if (!strcasecmp(input, "unindent")) - s->scfunc = DO_UNINDENT; + s->scfunc = do_unindent; else if (!strcasecmp(input, "scrollup")) - s->scfunc = DO_SCROLL_UP; + s->scfunc = do_scroll_up; else if (!strcasecmp(input, "scrolldown")) - s->scfunc = DO_SCROLL_DOWN; - else if (!strcasecmp(input, "nextword")) - s->scfunc = DO_NEXT_WORD_VOID; - else if (!strcasecmp(input, "suspend")) - s->scfunc = DO_SUSPEND_VOID; + s->scfunc = do_scroll_down; else if (!strcasecmp(input, "prevword")) - s->scfunc = DO_PREV_WORD_VOID; + s->scfunc = do_prev_word_void; + else if (!strcasecmp(input, "nextword")) + s->scfunc = do_next_word_void; else if (!strcasecmp(input, "findbracket")) - s->scfunc = DO_FIND_BRACKET; + s->scfunc = do_find_bracket; else if (!strcasecmp(input, "wordcount")) - s->scfunc = DO_WORDLINECHAR_COUNT; + s->scfunc = do_wordlinechar_count; else if (!strcasecmp(input, "undo")) - s->scfunc = DO_UNDO; + s->scfunc = do_undo; else if (!strcasecmp(input, "redo")) - s->scfunc = DO_REDO; - else if (!strcasecmp(input, "prevhistory")) { - s->scfunc = PREV_HISTORY_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "nexthistory")) { - s->scfunc = NEXT_HISTORY_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "nohelp") || - !strcasecmp(input, "nohelp")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = NO_HELP; - } else if (!strcasecmp(input, "constupdate")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = CONST_UPDATE; - } else if (!strcasecmp(input, "morespace")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = MORE_SPACE; - } else if (!strcasecmp(input, "smoothscroll")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = SMOOTH_SCROLL; - } else if (!strcasecmp(input, "whitespacedisplay")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = WHITESPACE_DISPLAY; - } else if (!strcasecmp(input, "nosyntax")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = NO_COLOR_SYNTAX; - } else if (!strcasecmp(input, "smarthome")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = SMART_HOME; - } else if (!strcasecmp(input, "autoindent")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = AUTOINDENT; - } else if (!strcasecmp(input, "cuttoend")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = CUT_TO_END; - } else if (!strcasecmp(input, "nowrap")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = NO_WRAP; - } else if (!strcasecmp(input, "tabstospaces")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = TABS_TO_SPACES; - } else if (!strcasecmp(input, "backupfile")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = BACKUP_FILE; - } else if (!strcasecmp(input, "mutlibuffer")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = MULTIBUFFER; - } else if (!strcasecmp(input, "mouse")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = USE_MOUSE; - } else if (!strcasecmp(input, "noconvert")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = NO_CONVERT; - } else if (!strcasecmp(input, "suspendenable")) { - s->scfunc = DO_TOGGLE; - s->execute = FALSE; - s->toggle = SUSPEND; - } -#endif /* NANO_TINY */ - else if (!strcasecmp(input, "right") || - !strcasecmp(input, "forward")) - s->scfunc = DO_RIGHT; + s->scfunc = do_redo; +#endif else if (!strcasecmp(input, "left") || - !strcasecmp(input, "back")) - s->scfunc = DO_LEFT; + !strcasecmp(input, "back")) + s->scfunc = do_left; + else if (!strcasecmp(input, "right") || + !strcasecmp(input, "forward")) + s->scfunc = do_right; else if (!strcasecmp(input, "up") || - !strcasecmp(input, "prevline")) - s->scfunc = DO_UP_VOID; + !strcasecmp(input, "prevline")) + s->scfunc = do_up_void; else if (!strcasecmp(input, "down") || - !strcasecmp(input, "nextline")) - s->scfunc = DO_DOWN_VOID; + !strcasecmp(input, "nextline")) + s->scfunc = do_down_void; else if (!strcasecmp(input, "home")) - s->scfunc = DO_HOME; + s->scfunc = do_home; else if (!strcasecmp(input, "end")) - s->scfunc = DO_END; -#ifdef ENABLE_MULTIBUFFER + s->scfunc = do_end; + else if (!strcasecmp(input, "pageup") || + !strcasecmp(input, "prevpage")) + s->scfunc = do_page_up; + else if (!strcasecmp(input, "pagedown") || + !strcasecmp(input, "nextpage")) + s->scfunc = do_page_down; + else if (!strcasecmp(input, "firstline")) + s->scfunc = do_first_line; + else if (!strcasecmp(input, "lastline")) + s->scfunc = do_last_line; +#ifndef DISABLE_MULTIBUFFER else if (!strcasecmp(input, "prevbuf")) - s->scfunc = SWITCH_TO_PREV_BUFFER_VOID; + s->scfunc = switch_to_prev_buffer_void; else if (!strcasecmp(input, "nextbuf")) - s->scfunc = SWITCH_TO_NEXT_BUFFER_VOID; + s->scfunc = switch_to_next_buffer_void; #endif else if (!strcasecmp(input, "verbatim")) - s->scfunc = DO_VERBATIM_INPUT; + s->scfunc = do_verbatim_input; else if (!strcasecmp(input, "tab")) - s->scfunc = DO_TAB; + s->scfunc = do_tab; else if (!strcasecmp(input, "enter")) - s->scfunc = DO_ENTER; + s->scfunc = do_enter_void; else if (!strcasecmp(input, "delete")) - s->scfunc = DO_DELETE; + s->scfunc = do_delete; else if (!strcasecmp(input, "backspace")) - s->scfunc = DO_BACKSPACE; + s->scfunc = do_backspace; else if (!strcasecmp(input, "refresh")) - s->scfunc = TOTAL_REFRESH; - else if (!strcasecmp(input, "casesens")) { - s->scfunc = CASE_SENS_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "regexp") || - !strcasecmp(input, "regex")) { - s->scfunc = REGEXP_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "dontreplace")) { - s->scfunc = NO_REPLACE_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "gototext")) { - s->scfunc = GOTOTEXT_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "browser") || - !strcasecmp(input, "tofiles")) { - s->scfunc = TO_FILES_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "dosformat")) { - s->scfunc = DOS_FORMAT_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "macformat")) { - s->scfunc = MAC_FORMAT_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "append")) { - s->scfunc = APPEND_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "prepend")) { - s->scfunc = PREPEND_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "backup")) { - s->scfunc = BACKUP_FILE_MSG; - s->execute = FALSE; -#ifdef ENABLE_MULTIBUFFER - } else if (!strcasecmp(input, "newbuffer")) { - s->scfunc = NEW_BUFFER_MSG; - s->execute = FALSE; -#endif - } else if (!strcasecmp(input, "firstfile")) { - s->scfunc = FIRST_FILE_MSG; - s->execute = FALSE; - } else if (!strcasecmp(input, "lastfile")) { - s->scfunc = LAST_FILE_MSG; - s->execute = FALSE; - } else { - free(s); - return NULL; + s->scfunc = total_refresh; + else if (!strcasecmp(input, "suspend")) + s->scfunc = do_suspend_void; + else if (!strcasecmp(input, "casesens")) + s->scfunc = case_sens_void; +#ifndef NANO_TINY + else if (!strcasecmp(input, "regexp") || + !strcasecmp(input, "regex")) + s->scfunc = regexp_void; + else if (!strcasecmp(input, "backwards")) + s->scfunc = backwards_void; +#endif + else if (!strcasecmp(input, "flipreplace") || + !strcasecmp(input, "dontreplace")) + s->scfunc = flip_replace_void; + else if (!strcasecmp(input, "gototext")) + s->scfunc = gototext_void; +#ifndef DISABLE_HISTORIES + else if (!strcasecmp(input, "prevhistory")) + s->scfunc = get_history_older_void; + else if (!strcasecmp(input, "nexthistory")) + s->scfunc = get_history_newer_void; +#endif + else if (!strcasecmp(input, "dosformat")) + s->scfunc = dos_format_void; + else if (!strcasecmp(input, "macformat")) + s->scfunc = mac_format_void; + else if (!strcasecmp(input, "append")) + s->scfunc = append_void; + else if (!strcasecmp(input, "prepend")) + s->scfunc = prepend_void; + else if (!strcasecmp(input, "backup")) + s->scfunc = backup_file_void; +#ifndef ENABLE_TINY + else if (!strcasecmp(input, "flipexecute")) + s->scfunc = flip_execute_void; +#endif +#ifndef DISABLE_MULTIBUFFER + else if (!strcasecmp(input, "flipnewbuffer") || + !strcasecmp(input, "newbuffer")) + s->scfunc = new_buffer_void; +#endif +#ifndef DISABLE_BROWSER + else if (!strcasecmp(input, "tofiles") || + !strcasecmp(input, "browser")) + s->scfunc = to_files_void; + else if (!strcasecmp(input, "gotodir")) + s->scfunc = goto_dir_void; + else if (!strcasecmp(input, "firstfile")) + s->scfunc = do_first_file; + else if (!strcasecmp(input, "lastfile")) + s->scfunc = do_last_file; +#endif +#ifndef NANO_TINY + else { + s->scfunc = do_toggle_void; + if (!strcasecmp(input, "nohelp")) + s->toggle = NO_HELP; + else if (!strcasecmp(input, "constupdate")) + s->toggle = CONST_UPDATE; + else if (!strcasecmp(input, "morespace")) + s->toggle = MORE_SPACE; + else if (!strcasecmp(input, "smoothscroll")) + s->toggle = SMOOTH_SCROLL; + else if (!strcasecmp(input, "softwrap")) + s->toggle = SOFTWRAP; + else if (!strcasecmp(input, "whitespacedisplay")) + s->toggle = WHITESPACE_DISPLAY; +#ifndef DISABLE_COLOR + else if (!strcasecmp(input, "nosyntax")) + s->toggle = NO_COLOR_SYNTAX; +#endif + else if (!strcasecmp(input, "smarthome")) + s->toggle = SMART_HOME; + else if (!strcasecmp(input, "autoindent")) + s->toggle = AUTOINDENT; + else if (!strcasecmp(input, "cuttoend")) + s->toggle = CUT_TO_END; +#ifndef DISABLE_WRAPPING + else if (!strcasecmp(input, "nowrap")) + s->toggle = NO_WRAP; +#endif + else if (!strcasecmp(input, "tabstospaces")) + s->toggle = TABS_TO_SPACES; + else if (!strcasecmp(input, "backupfile")) + s->toggle = BACKUP_FILE; +#ifndef DISABLE_MULTIBUFFER + else if (!strcasecmp(input, "multibuffer")) + s->toggle = MULTIBUFFER; +#endif +#ifndef DISABLE_MOUSE + else if (!strcasecmp(input, "mouse")) + s->toggle = USE_MOUSE; +#endif + else if (!strcasecmp(input, "noconvert")) + s->toggle = NO_CONVERT; + else if (!strcasecmp(input, "suspendenable")) + s->toggle = SUSPEND; +#endif /* !NANO_TINY */ + else { + free(s); + return NULL; + } +#ifndef NANO_TINY } - +#endif return s; - } -#ifdef ENABLE_NANORC -/* Same thing as abnove but for the menu */ +/* Interpret a menu name and return the corresponding menu flag. */ int strtomenu(char *input) { if (!strcasecmp(input, "all")) - return MALL; + return (MMOST|MHELP|MYESNO); else if (!strcasecmp(input, "main")) return MMAIN; else if (!strcasecmp(input, "search")) @@ -1666,8 +1512,8 @@ int strtomenu(char *input) else if (!strcasecmp(input, "replace")) return MREPLACE; else if (!strcasecmp(input, "replace2") || - !strcasecmp(input, "replacewith")) - return MREPLACE2; + !strcasecmp(input, "replacewith")) + return MREPLACEWITH; else if (!strcasecmp(input, "gotoline")) return MGOTOLINE; else if (!strcasecmp(input, "writeout")) @@ -1675,22 +1521,29 @@ int strtomenu(char *input) else if (!strcasecmp(input, "insert")) return MINSERTFILE; else if (!strcasecmp(input, "externalcmd") || - !strcasecmp(input, "extcmd")) + !strcasecmp(input, "extcmd")) return MEXTCMD; +#ifndef DISABLE_HELP else if (!strcasecmp(input, "help")) return MHELP; - else if (!strcasecmp(input, "spell")) +#endif +#ifndef DISABLE_SPELLER + else if (!strcasecmp(input, "spell") || !strcasecmp(input, "formatter")) return MSPELL; +#endif + else if (!strcasecmp(input, "linter")) + return MLINTER; +#ifndef DISABLE_BROWSER else if (!strcasecmp(input, "browser")) return MBROWSER; else if (!strcasecmp(input, "whereisfile")) return MWHEREISFILE; else if (!strcasecmp(input, "gotodir")) return MGOTODIR; - +#endif return -1; } -#endif +#endif /* !DISABLE_NANORC */ #ifdef DEBUG @@ -1740,12 +1593,10 @@ void thanks_for_all_the_fish(void) if (jusbuffer != NULL) free_filestruct(jusbuffer); #endif -#ifdef DEBUG /* Free the memory associated with each open file buffer. */ if (openfile != NULL) free_openfilestruct(openfile); -#endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR if (syntaxstr != NULL) free(syntaxstr); while (syntaxes != NULL) { @@ -1753,8 +1604,7 @@ void thanks_for_all_the_fish(void) free(syntaxes->desc); while (syntaxes->extensions != NULL) { - exttype *bob = syntaxes->extensions; - + regexlisttype *bob = syntaxes->extensions; syntaxes->extensions = bob->next; free(bob->ext_regex); if (bob->ext != NULL) { @@ -1763,6 +1613,26 @@ void thanks_for_all_the_fish(void) } free(bob); } + while (syntaxes->headers != NULL) { + regexlisttype *bob = syntaxes->headers; + syntaxes->headers = bob->next; + free(bob->ext_regex); + if (bob->ext != NULL) { + regfree(bob->ext); + free(bob->ext); + } + free(bob); + } + while (syntaxes->magics != NULL) { + regexlisttype *bob = syntaxes->magics; + syntaxes->magics = bob->next; + free(bob->ext_regex); + if (bob->ext != NULL) { + regfree(bob->ext); + free(bob->ext); + } + free(bob); + } while (syntaxes->color != NULL) { colortype *bob = syntaxes->color; @@ -1783,18 +1653,29 @@ void thanks_for_all_the_fish(void) syntaxes = syntaxes->next; free(bill); } -#endif /* ENABLE_COLOR */ -#ifndef NANO_TINY +#endif /* !DISABLE_COLOR */ +#ifndef DISABLE_HISTORIES /* Free the search and replace history lists. */ if (searchage != NULL) free_filestruct(searchage); if (replaceage != NULL) free_filestruct(replaceage); #endif -#ifdef ENABLE_NANORC + /* Free the functions and shortcuts lists. */ + while (allfuncs != NULL) { + subnfunc *f = allfuncs; + allfuncs = allfuncs->next; + free(f); + } + while (sclist != NULL) { + sc *s = sclist; + sclist = sclist->next; + free(s); + } +#ifndef DISABLE_NANORC if (homedir != NULL) free(homedir); #endif } -#endif /* DEBUG */ +#endif /* DEBUG */ @@ -1,9 +1,9 @@ -/* $Id: help.c 4453 2009-12-02 03:36:22Z astyanax $ */ +/* $Id: help.c 5051 2014-07-02 09:29:05Z bens $ */ /************************************************************************** * help.c * * * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * - * 2009 Free Software Foundation, Inc. * + * 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -37,29 +37,24 @@ static char *help_text = NULL; void do_help(void (*refresh_func)(void)) { int kbinput = ERR; - bool meta_key, func_key, old_no_help = ISSET(NO_HELP); - bool abort = FALSE; - /* Whether we should abort the help browser. */ + bool old_no_help = ISSET(NO_HELP); size_t line = 0; /* The line number in help_text of the first displayed help * line. This variable is zero-based. */ size_t last_line = 0; /* The line number in help_text of the last help line. This * variable is zero-based. */ -#ifndef DISABLE_MOUSE - /* The current shortcut list. */ int oldmenu = currmenu; -#endif + /* The menu we were called from. */ const char *ptr; /* The current line of the help text. */ size_t old_line = (size_t)-1; /* The line we were on before the current line. */ - const sc *s; - const subnfunc *f; + functionptrtype func; + /* The function of the key the user typed in. */ curs_set(0); blank_edit(); - wattroff(bottomwin, reverse_attr); blank_statusbar(); /* Set help_text as the string to display. */ @@ -67,11 +62,9 @@ void do_help(void (*refresh_func)(void)) assert(help_text != NULL); -#ifndef DISABLE_MOUSE /* Set currmenu to allow clicking on the help screen's shortcut * list, after help_init() is called. */ currmenu = MHELP; -#endif if (ISSET(NO_HELP)) { /* Make sure that the help screen's shortcut list will actually @@ -94,7 +87,7 @@ void do_help(void (*refresh_func)(void)) if (last_line > 0) last_line--; - while (!abort) { + while (TRUE) { size_t i; /* Display the help text if we don't have a key, or if the help @@ -126,62 +119,46 @@ void do_help(void (*refresh_func)(void)) old_line = line; - kbinput = get_kbinput(edit, &meta_key, &func_key); + kbinput = get_kbinput(edit); #ifndef DISABLE_MOUSE - if (kbinput == KEY_MOUSE) { - int mouse_x, mouse_y; - get_mouseinput(&mouse_x, &mouse_y, TRUE); - continue; - /* Redraw the screen. */ + if (kbinput == KEY_MOUSE) { + int mouse_x, mouse_y; + get_mouseinput(&mouse_x, &mouse_y, TRUE); + continue; /* Redraw the screen. */ } #endif - parse_help_input(&kbinput, &meta_key, &func_key); - s = get_shortcut(MHELP, &kbinput, &meta_key, &func_key); - if (!s) - continue; - f = sctofunc((sc *) s); - if (!f) - continue; - - if (f->scfunc == TOTAL_REFRESH) { - total_redraw(); - break; - } else if (f->scfunc == DO_PAGE_UP) { - if (line > editwinrows - 2) - line -= editwinrows - 2; - else - line = 0; - } else if (f->scfunc == DO_PAGE_DOWN) { - if (line + (editwinrows - 1) < last_line) - line += editwinrows - 2; - } else if (f->scfunc == DO_UP_VOID) { - if (line > 0) - line--; - } else if (f->scfunc == DO_DOWN_VOID) { - if (line + (editwinrows - 1) < last_line) - line++; - } else if (f->scfunc == DO_FIRST_LINE) { - if (meta_key) - line = 0; - break; - } else if (f->scfunc == DO_LAST_LINE) { - if (meta_key) { - if (line + (editwinrows - 1) < last_line) - line = last_line - (editwinrows - 1); - } - break; - /* Abort the help browser. */ - } else if (f->scfunc == DO_EXIT) { - abort = TRUE; - break; + func = parse_help_input(&kbinput); + + if (func == total_refresh) { + total_redraw(); + } else if (func == do_page_up) { + if (line > editwinrows - 2) + line -= editwinrows - 2; + else + line = 0; + } else if (func == do_page_down) { + if (line + (editwinrows - 1) < last_line) + line += editwinrows - 2; + } else if (func == do_up_void) { + if (line > 0) + line--; + } else if (func == do_down_void) { + if (line + (editwinrows - 1) < last_line) + line++; + } else if (func == do_first_line) { + line = 0; + } else if (func == do_last_line) { + if (line + (editwinrows - 1) < last_line) + line = last_line - (editwinrows - 1); + } else if (func == do_exit) { + /* Exit from the help browser. */ + break; } } -#ifndef DISABLE_MOUSE currmenu = oldmenu; -#endif if (old_no_help) { blank_bottombars(); @@ -201,14 +178,6 @@ void do_help(void (*refresh_func)(void)) help_text = NULL; } -#ifndef DISABLE_BROWSER -/* Start the help browser for the file browser. */ -void do_browser_help(void) -{ - do_help(&browser_refresh); -} -#endif - /* This function allocates help_text, and stores the help string in it. * help_text should be NULL initially. */ void help_init(void) @@ -224,7 +193,7 @@ void help_init(void) int scsfound = 0; #ifndef NANO_TINY -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC bool old_whitespace = ISSET(WHITESPACE_DISPLAY); UNSET(WHITESPACE_DISPLAY); @@ -232,7 +201,7 @@ void help_init(void) #endif /* First, set up the initial help text for the current function. */ - if (currmenu == MWHEREIS || currmenu == MREPLACE || currmenu == MREPLACE2) { + if (currmenu == MWHEREIS || currmenu == MREPLACE || currmenu == MREPLACEWITH) { htx[0] = N_("Search Command Help Text\n\n " "Enter the words or characters you would like to " "search for, and then press Enter. If there is a " @@ -392,24 +361,23 @@ void help_init(void) if (htx[2] != NULL) allocsize += strlen(htx[2]); - /* Count the shortcut help text. Each entry has up to three keys, - * which fill 24 columns, plus translated text, plus one or two - * \n's. */ + /* Calculate the length of the shortcut help text. Each entry has + * one or two keys, which fill 16 columns, plus translated text, + * plus one or two \n's. */ for (f = allfuncs; f != NULL; f = f->next) - if (f->menus & currmenu) - allocsize += (24 * mb_cur_max()) + strlen(f->help) + 2; + if (f->menus & currmenu) + allocsize += (16 * mb_cur_max()) + strlen(f->help) + 2; #ifndef NANO_TINY /* If we're on the main list, we also count the toggle help text. - * Each entry has "M-%c\t\t\t", which fills 24 columns, plus a - * space, plus translated text, plus one or two '\n's. */ + * Each entry has "M-%c\t\t", five chars which fill 16 columns, + * plus a space, plus translated text, plus one or two '\n's. */ if (currmenu == MMAIN) { size_t endis_len = strlen(_("enable/disable")); for (s = sclist; s != NULL; s = s->next) - if (s->scfunc == DO_TOGGLE) - allocsize += strlen(_(flagtostr(s->toggle))) + endis_len + 9; - + if (s->scfunc == do_toggle_void) + allocsize += strlen(_(flagtostr(s->toggle))) + endis_len + 8; } #endif @@ -433,39 +401,36 @@ void help_init(void) /* Now add our shortcut info. */ for (f = allfuncs; f != NULL; f = f->next) { - if ((f->menus & currmenu) == 0) + if ((f->menus & currmenu) == 0) continue; - if (!f->desc || !strcmp(f->desc, "")) - continue; - - /* Lets just try and use the first 3 shortcuts - from the new struct... */ - for (s = sclist, scsfound = 0; s != NULL; s = s->next) { + /* Let's simply show the first two shortcuts from the list. */ + for (s = sclist, scsfound = 0; s != NULL; s = s->next) { - if (scsfound == 3) - continue; - - if (s->type == RAW) + if (s->type == RAWINPUT) continue; if ((s->menu & currmenu) == 0) continue; - if (s->scfunc == f->scfunc) { + if (s->scfunc == f->scfunc) { scsfound++; - - if (scsfound == 1) - ptr += sprintf(ptr, "%s", s->keystr); - else - ptr += sprintf(ptr, "(%s)", s->keystr); - *(ptr++) = '\t'; + /* Make the first column narrower (6) than the second (10), + * but allow it to spill into the second, for "M-Space". */ + if (scsfound == 1) { + sprintf(ptr, "%s ", s->keystr); + ptr += 6; + } else { + ptr += sprintf(ptr, "(%s)\t", s->keystr); + break; + } } } - /* Pad with tabs if we didnt find 3 */ - for (; scsfound < 3; scsfound++) { - *(ptr++) = '\t'; - } + + if (scsfound == 0) + ptr += sprintf(ptr, "\t\t"); + else if (scsfound == 1) + ptr += 10; /* The shortcut's help text. */ ptr += sprintf(ptr, "%s\n", _(f->help)); @@ -477,48 +442,41 @@ void help_init(void) #ifndef NANO_TINY /* And the toggles... */ if (currmenu == MMAIN) - for (s = sclist; s != NULL; s = s->next) - if (s->scfunc == DO_TOGGLE) - ptr += sprintf(ptr, "(%s)\t\t\t%s %s\n", - s->keystr, _(flagtostr(s->toggle)), _("enable/disable")); - + for (s = sclist; s != NULL; s = s->next) { + if (s->scfunc == do_toggle_void) + ptr += sprintf(ptr, "%s\t\t%s %s\n", (s->menu == MMAIN ? s->keystr : ""), + _(flagtostr(s->toggle)), _("enable/disable")); + if (s->toggle == NO_COLOR_SYNTAX || s->toggle == TABS_TO_SPACES) + ptr += sprintf(ptr, "\n"); + } -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC if (old_whitespace) SET(WHITESPACE_DISPLAY); #endif -#endif +#endif /* !NANO_TINY */ /* If all went well, we didn't overwrite the allocated space for * help_text. */ assert(strlen(help_text) <= allocsize + 1); } -/* Determine the shortcut key corresponding to the values of kbinput - * (the key itself), meta_key (whether the key is a meta sequence), and - * func_key (whether the key is a function key), if any. In the - * process, convert certain non-shortcut keys into their corresponding - * shortcut keys. */ -void parse_help_input(int *kbinput, bool *meta_key, bool *func_key) +/* Return the function that is bound to the given key, accepting certain + * plain characters too, for consistency with the file browser. */ +functionptrtype parse_help_input(int *kbinput) { - get_shortcut(MHELP, kbinput, meta_key, func_key); - - if (!*meta_key) { + if (!meta_key) { switch (*kbinput) { - /* For consistency with the file browser. */ case ' ': - *kbinput = sc_seq_or(DO_PAGE_UP, 0); - break; + return do_page_down; case '-': - *kbinput = sc_seq_or(DO_PAGE_DOWN, 0);; - break; - /* Cancel is equivalent to Exit here. */ + return do_page_up; case 'E': case 'e': - *kbinput = sc_seq_or(DO_EXIT, 0);; - break; + return do_exit; } } + return func_from_key(kbinput); } /* Calculate the next line of help_text, starting at ptr. */ @@ -547,17 +505,21 @@ size_t help_line_len(const char *ptr) #endif /* !DISABLE_HELP */ -/* Start the help browser for the edit window. */ +/* Start the help browser. */ void do_help_void(void) { - #ifndef DISABLE_HELP - /* Start the help browser for the edit window. */ - do_help(&edit_refresh); + /* Start the help browser, with the correct refresher for afterwards. */ +#ifndef DISABLE_BROWSER + if (currmenu == MBROWSER || currmenu == MWHEREISFILE || currmenu == MGOTODIR) + do_help(&browser_refresh); + else +#endif + do_help(&edit_refresh); #else if (currmenu == MMAIN) nano_disabled_msg(); else beep(); -#endif +#endif /* !DISABLE_HELP */ } @@ -1,9 +1,9 @@ -/* $Id: move.c 4486 2010-03-21 04:56:37Z astyanax $ */ +/* $Id: move.c 5013 2014-06-23 18:20:12Z bens $ */ /************************************************************************** * move.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -33,7 +33,7 @@ void do_first_line(void) openfile->current_x = 0; openfile->placewewant = 0; - edit_refresh_needed = 1; + edit_refresh_needed = TRUE; } /* Move to the last line of the file. */ @@ -44,7 +44,7 @@ void do_last_line(void) openfile->placewewant = xplustabs(); openfile->current_y = editwinrows - 1; - edit_refresh_needed = 1; + edit_refresh_needed = TRUE; } /* Move up one page. */ @@ -55,7 +55,10 @@ void do_page_up(void) /* If there's less than a page of text left on the screen, put the * cursor at the beginning of the first line of the file, and then * update the edit window. */ - if (openfile->current->lineno == 1 || (!ISSET(SOFTWRAP) && + if (openfile->current->lineno == 1 || ( +#ifndef NANO_TINY + !ISSET(SOFTWRAP) && +#endif openfile->current->lineno <= editwinrows - 2)) { do_first_line(); return; @@ -63,7 +66,6 @@ void do_page_up(void) /* If we're not in smooth scrolling mode, put the cursor at the * beginning of the top line of the edit window, as Pico does. */ - #ifndef NANO_TINY if (!ISSET(SMOOTH_SCROLL)) { #endif @@ -76,20 +78,23 @@ void do_page_up(void) for (i = editwinrows - 2; i - skipped > 0 && openfile->current != openfile->fileage; i--) { openfile->current = openfile->current->prev; +#ifndef NANO_TINY if (ISSET(SOFTWRAP) && openfile->current) { skipped += strlenpt(openfile->current->data) / COLS; #ifdef DEBUG - fprintf(stderr, "do_page_up: i = %d, skipped = %d based on line %ld len %d\n", i, (unsigned long) skipped, -openfile->current->lineno, strlenpt(openfile->current->data)); + fprintf(stderr, "do_page_up: i = %d, skipped = %d based on line %ld len %lu\n", + i, skipped, (long)openfile->current->lineno, (unsigned long)strlenpt(openfile->current->data)); #endif } +#endif } openfile->current_x = actual_x(openfile->current->data, openfile->placewewant); #ifdef DEBUG - fprintf(stderr, "do_page_up: openfile->current->lineno = %lu, skipped = %d\n", (unsigned long) openfile->current->lineno, skipped); + fprintf(stderr, "do_page_up: openfile->current->lineno = %lu, skipped = %d\n", + (unsigned long)openfile->current->lineno, skipped); #endif /* Scroll the edit window up a page. */ @@ -125,7 +130,7 @@ void do_page_down(void) openfile->filebot; i--) { openfile->current = openfile->current->next; #ifdef DEBUG - fprintf(stderr, "do_page_down: moving to line %lu\n", (unsigned long) openfile->current->lineno); + fprintf(stderr, "do_page_down: moving to line %lu\n", (unsigned long)openfile->current->lineno); #endif } @@ -513,12 +518,12 @@ void do_up( * smooth scrolling mode, or up half a page if we're not. If * scroll_only is TRUE, scroll the edit window up one line * unconditionally. */ - if (openfile->current_y == 0 || (ISSET(SOFTWRAP) && openfile->edittop->lineno == openfile->current->next->lineno) + if (openfile->current_y == 0 #ifndef NANO_TINY - || scroll_only + || (ISSET(SOFTWRAP) && openfile->edittop->lineno == openfile->current->next->lineno) || scroll_only #endif ) - edit_scroll(UP_DIR, + edit_scroll(UPWARD, #ifndef NANO_TINY (ISSET(SMOOTH_SCROLL) || scroll_only) ? 1 : #endif @@ -563,13 +568,15 @@ void do_down( #endif ) { - bool onlastline = FALSE; +#ifndef NANO_TINY + int amount = 0, enough; + filestruct *topline; +#endif /* If we're at the bottom of the file, get out. */ - if (openfile->current == openfile->filebot) + if (openfile->current == openfile->filebot || !openfile->current->next) return; - assert(ISSET(SOFTWRAP) || openfile->current_y == openfile->current->lineno - openfile->edittop->lineno); /* Move the current line of the edit window down. */ @@ -577,34 +584,54 @@ void do_down( openfile->current_x = actual_x(openfile->current->data, openfile->placewewant); +#ifndef NANO_TINY if (ISSET(SOFTWRAP)) { - if (openfile->current->lineno - openfile->edittop->lineno >= maxrows) - onlastline = TRUE; + /* Compute the amount to scroll. */ + amount = (strlenpt(openfile->current->data) / COLS + openfile->current_y + 2 + + strlenpt(openfile->current->prev->data) / COLS - editwinrows); + topline = openfile->edittop; + /* Reduce the amount when there are overlong lines at the top. */ + for (enough = 1; enough < amount; enough++) { + if (amount <= strlenpt(topline->data) / COLS) { + amount = enough; + break; + } + amount -= strlenpt(topline->data) / COLS; + topline = topline->next; + } } +#endif - /* If scroll_only is FALSE and if we're on the first line of the + /* If scroll_only is FALSE and if we're on the last line of the * edit window, scroll the edit window down one line if we're in * smooth scrolling mode, or down half a page if we're not. If * scroll_only is TRUE, scroll the edit window down one line * unconditionally. */ - if (onlastline || openfile->current_y == editwinrows - 1 + if (openfile->current_y == editwinrows - 1 #ifndef NANO_TINY - || scroll_only + || amount > 0 || scroll_only #endif ) { - edit_scroll(DOWN_DIR, #ifndef NANO_TINY - (ISSET(SMOOTH_SCROLL) || scroll_only) ? 1 : + if (amount < 1 || scroll_only) + amount = 1; +#endif + edit_scroll(DOWNWARD, +#ifndef NANO_TINY + (ISSET(SMOOTH_SCROLL) || scroll_only) ? amount : #endif editwinrows / 2 + 1); - edit_refresh_needed = TRUE; } /* If we're above the last line of the edit window, update the line * we were on before and the line we're on now. The former needs to * be redrawn if we're not on the first page, and the latter needs * to be drawn unconditionally. */ - if (ISSET(SOFTWRAP) || openfile->current_y < editwinrows - 1) { + if (openfile->current_y < editwinrows - 1 +#ifndef NANO_TINY + || ISSET(SOFTWRAP) +#endif + ) { if (need_vertical_update(0)) update_line(openfile->current->prev, 0); update_line(openfile->current, openfile->current_x); @@ -1,9 +1,9 @@ -/* $Id: nano.c 4520 2010-11-12 06:23:14Z astyanax $ */ +/* $Id: nano.c 5141 2015-03-20 11:18:22Z bens $ */ /************************************************************************** * nano.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -48,7 +48,7 @@ static int oldinterval = -1; /* Used to store the user's original mouse click interval. */ #endif -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC static bool no_rcfiles = FALSE; /* Should we ignore all rcfiles? */ #endif @@ -68,7 +68,7 @@ filestruct *make_new_node(filestruct *prevnode) newnode->next = NULL; newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR newnode->multidata = NULL; #endif @@ -88,7 +88,7 @@ filestruct *copy_node(const filestruct *src) dst->next = src->next; dst->prev = src->prev; dst->lineno = src->lineno; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR dst->multidata = NULL; #endif @@ -127,7 +127,7 @@ void delete_node(filestruct *fileptr) if (fileptr->data != NULL) free(fileptr->data); -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR if (fileptr->multidata) free(fileptr->multidata); #endif @@ -178,7 +178,8 @@ void renumber(filestruct *fileptr) { ssize_t line; - assert(fileptr != NULL); + if (fileptr == NULL) + return; line = (fileptr->prev == NULL) ? 0 : fileptr->prev->lineno; @@ -297,6 +298,7 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot, bool edittop_inside; #ifndef NANO_TINY bool mark_inside = FALSE; + bool same_line = FALSE; #endif assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL); @@ -314,7 +316,7 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot, openfile->fileage->lineno && openfile->edittop->lineno <= openfile->filebot->lineno); #ifndef NANO_TINY - if (openfile->mark_set) + if (openfile->mark_set) { mark_inside = (openfile->mark_begin->lineno >= openfile->fileage->lineno && openfile->mark_begin->lineno <= @@ -323,6 +325,8 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot, openfile->mark_begin_x >= top_x) && (openfile->mark_begin != openfile->filebot || openfile->mark_begin_x <= bot_x)); + same_line = (openfile->mark_begin == openfile->fileage); + } #endif /* Get the number of characters in the text, and subtract it from @@ -357,10 +361,12 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot, *file_bot = openfile->filebot; } + openfile->fileage->next = NULL; + free_filestruct(openfile->fileage); + /* Renumber starting with the line after the original * file_bot. */ - if (file_bot_save->next != NULL) - renumber(file_bot_save->next); + renumber(file_bot_save->next); } /* Since the text has now been saved, remove it from the @@ -369,7 +375,7 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot, openfile->fileage->data = mallocstrcpy(NULL, ""); openfile->filebot = openfile->fileage; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR openfile->fileage->multidata = NULL; #endif @@ -382,7 +388,9 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot, if (mark_inside) { openfile->mark_begin = openfile->current; openfile->mark_begin_x = openfile->current_x; - } + } else if (same_line) + /* Update the content of this partially cut line. */ + openfile->mark_begin = openfile->current; #endif top_save = openfile->fileage; @@ -406,10 +414,9 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot, new_magicline(); } -/* Copy all the text from the filestruct beginning with file_top and - * ending with file_bot to the current filestruct at the current cursor - * position. */ -void copy_from_filestruct(filestruct *file_top, filestruct *file_bot) +/* Copy all text from the given filestruct to the current filestruct + * at the current cursor position. */ +void copy_from_filestruct(filestruct *somebuffer) { filestruct *top_save; size_t current_x_save = openfile->current_x; @@ -418,7 +425,7 @@ void copy_from_filestruct(filestruct *file_top, filestruct *file_bot) bool right_side_up = FALSE, single_line = FALSE; #endif - assert(file_top != NULL && file_bot != NULL); + assert(somebuffer != NULL); #ifndef NANO_TINY /* Keep track of whether the mark begins inside the partition and @@ -441,9 +448,10 @@ void copy_from_filestruct(filestruct *file_top, filestruct *file_bot) openfile->current_x, openfile->current, openfile->current_x); edittop_inside = (openfile->edittop == openfile->fileage); - /* Put the top and bottom of the filestruct at copies of file_top - * and file_bot. */ - openfile->fileage = copy_filestruct(file_top); + /* Put the top and bottom of the current filestruct at the top and + * bottom of a copy of the passed buffer. */ + free_filestruct(openfile->fileage); + openfile->fileage = copy_filestruct(somebuffer); openfile->filebot = openfile->fileage; while (openfile->filebot->next != NULL) openfile->filebot = openfile->filebot->next; @@ -465,7 +473,12 @@ void copy_from_filestruct(filestruct *file_top, filestruct *file_bot) } #ifndef NANO_TINY else if (openfile->mark_set) { - if (!right_side_up) { + if (right_side_up) { + if (single_line) + /* Get the new data, stuff was inserted on the mark line. */ + openfile->mark_begin = openfile->fileage; + /* The x is okay, it did not move. */ + } else { if (single_line) { openfile->mark_begin = openfile->current; openfile->mark_begin_x -= current_x_save; @@ -520,6 +533,7 @@ openfilestruct *make_new_opennode(void) #ifndef NANO_TINY newnode->current_stat = NULL; newnode->last_action = OTHER; + newnode->lock_filename = NULL; #endif return newnode; @@ -602,9 +616,13 @@ void finish(void) /* Restore the old terminal settings. */ tcsetattr(0, TCSANOW, &oldterm); -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) - if (!no_rcfiles && ISSET(HISTORYLOG)) +#ifndef DISABLE_HISTORIES + if (ISSET(HISTORYLOG)) save_history(); + if (ISSET(POS_HISTORY)) { + update_poshistory(openfile->filename, openfile->current->lineno, xplustabs() + 1); + save_poshistory(); + } #endif #ifdef DEBUG @@ -642,7 +660,7 @@ void die(const char *msg, ...) ); } -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER /* Save all of the other modified file buffers, if any. */ if (openfile != NULL) { openfilestruct *tmp = openfile; @@ -708,6 +726,8 @@ void die_save_file(const char *die_filename int shush; shush = chmod(retval, die_stat->st_mode); shush = chown(retval, die_stat->st_uid, die_stat->st_gid); + if (shush) + ; } #endif @@ -718,7 +738,7 @@ void die_save_file(const char *die_filename void window_init(void) { /* If the screen height is too small, get out. */ - editwinrows = LINES - 5 + no_more_space() + no_help(); + editwinrows = LINES - 5 + more_space() + no_help(); if (COLS < MIN_EDITOR_COLS || editwinrows < MIN_EDITOR_ROWS) die(_("Window size is too small for nano...\n")); @@ -739,10 +759,10 @@ void window_init(void) delwin(bottomwin); /* Set up the windows. */ - topwin = newwin(2 - no_more_space(), COLS, 0, 0); - edit = newwin(editwinrows, COLS, 2 - no_more_space(), 0); + topwin = newwin(2 - more_space(), COLS, 0, 0); + edit = newwin(editwinrows, COLS, 2 - more_space(), 0); bottomwin = newwin(3 - no_help(), COLS, editwinrows + (2 - - no_more_space()), 0); + more_space()), 0); /* Turn the keypad on for the windows, if necessary. */ if (!ISSET(REBIND_KEYPAD)) { @@ -810,7 +830,7 @@ void print_opt_full(const char *shortflag printf("\n"); } -/* Explain how to properly use nano and its command line options. */ +/* Explain how to properly use nano and its command-line options. */ void usage(void) { printf(_("Usage: nano [OPTIONS] [[+LINE,COLUMN] FILE]...\n\n")); @@ -821,8 +841,9 @@ void usage(void) _("Option\t\tMeaning\n") #endif ); - print_opt("-h, -?", "--help", N_("Show this message")); print_opt(_("+LINE,COLUMN"), "", + /* TRANSLATORS: The next forty or so strings are option descriptions + * for the --help output. Try to keep them at most 40 characters. */ N_("Start at line LINE, column COLUMN")); #ifndef NANO_TINY print_opt("-A", "--smarthome", N_("Enable smart home key")); @@ -836,14 +857,18 @@ void usage(void) print_opt("-E", "--tabstospaces", N_("Convert typed tabs to spaces")); #endif -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER print_opt("-F", "--multibuffer", N_("Enable multiple file buffers")); #endif -#ifdef ENABLE_NANORC #ifndef NANO_TINY + print_opt("-G", "--locking", + N_("Use (vim-style) lock files")); +#endif +#ifndef DISABLE_HISTORIES print_opt("-H", "--historylog", N_("Log & read search/replace string history")); #endif +#ifndef DISABLE_NANORC print_opt("-I", "--ignorercfiles", N_("Don't look at nanorc files")); #endif @@ -856,6 +881,10 @@ void usage(void) N_("Don't convert files from DOS/Mac format")); #endif print_opt("-O", "--morespace", N_("Use one more line for editing")); +#ifndef DISABLE_HISTORIES + print_opt("-P", "--poslog", + N_("Log & read location of cursor position")); +#endif #ifndef DISABLE_JUSTIFY print_opt(_("-Q <str>"), _("--quotestr=<str>"), N_("Quoting string")); @@ -876,13 +905,14 @@ void usage(void) print_opt("-W", "--wordbounds", N_("Detect word boundaries more accurately")); #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR print_opt(_("-Y <str>"), _("--syntax=<str>"), N_("Syntax definition to use for coloring")); #endif print_opt("-c", "--const", N_("Constantly show cursor position")); print_opt("-d", "--rebinddelete", N_("Fix Backspace/Delete confusion problem")); + print_opt("-h", "--help", N_("Show this help text")); #ifndef NANO_TINY print_opt("-i", "--autoindent", N_("Automatically indent new lines")); @@ -893,17 +923,20 @@ void usage(void) #ifndef DISABLE_MOUSE print_opt("-m", "--mouse", N_("Enable the use of the mouse")); #endif + print_opt("-n", "--noread", N_("Do not read the file (only write it)")); #ifndef DISABLE_OPERATINGDIR print_opt(_("-o <dir>"), _("--operatingdir=<dir>"), N_("Set operating directory")); #endif print_opt("-p", "--preserve", N_("Preserve XON (^Q) and XOFF (^S) keys")); +#ifndef DISABLE_NANORC print_opt("-q", "--quiet", N_("Silently ignore startup issues like rc file errors")); +#endif #ifndef DISABLE_WRAPJUSTIFY print_opt(_("-r <#cols>"), _("--fill=<#cols>"), - N_("Set wrapping point at column #cols")); + N_("Set hard-wrapping point at column #cols")); #endif #ifndef DISABLE_SPELLER print_opt(_("-s <prog>"), _("--speller=<prog>"), @@ -911,23 +944,15 @@ void usage(void) #endif print_opt("-t", "--tempfile", N_("Auto save on exit, don't prompt")); -#ifndef NANO_TINY - print_opt("-u", "--undo", N_("Allow generic undo [EXPERIMENTAL]")); -#endif - print_opt("-v", "--view", N_("View mode (read-only)")); #ifndef DISABLE_WRAPPING - print_opt("-w", "--nowrap", N_("Don't wrap long lines")); + print_opt("-w", "--nowrap", N_("Don't hard-wrap long lines")); #endif print_opt("-x", "--nohelp", N_("Don't show the two help lines")); print_opt("-z", "--suspend", N_("Enable suspension")); +#ifndef NANO_TINY print_opt("-$", "--softwrap", N_("Enable soft line wrapping")); - - /* This is a special case. */ - print_opt("-a, -b, -e,", "", NULL); - print_opt("-f, -g, -j", "", N_("(ignored, for Pico compatibility)")); - - exit(0); +#endif } /* Display the current version of nano, the date and time it was @@ -935,28 +960,86 @@ void usage(void) * it was compiled with. */ void version(void) { - printf(_(" GNU nano version %s (compiled %s, %s)\n"), VERSION, - __TIME__, __DATE__); - printf(" (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,\n"); - printf(" 2008, 2009 Free Software Foundation, Inc.\n"); + printf(_(" GNU nano, version %s\n"), VERSION); + printf(" (C) 1999..2015 Free Software Foundation, Inc.\n"); printf( _(" Email: nano@nano-editor.org Web: http://www.nano-editor.org/")); printf(_("\n Compiled options:")); +#ifdef NANO_TINY + printf(" --enable-tiny"); +#ifndef DISABLE_BROWSER + printf(" --enable-browser"); +#endif +#ifndef DISABLE_COLOR + printf(" --enable-color"); +#endif +#ifndef DISABLE_EXTRA + printf(" --enable-extra"); +#endif +#ifndef DISABLE_HELP + printf(" --enable-help"); +#endif +#ifndef DISABLE_HISTORIES + printf(" --enable-histories"); +#endif +#ifndef DISABLE_JUSTIFY + printf(" --enable-justify"); +#endif +#ifdef HAVE_LIBMAGIC + printf(" --enable-libmagic"); +#endif +#ifndef DISABLE_MOUSE + printf(" --enable-mouse"); +#endif +#ifndef DISABLE_NANORC + printf(" --enable-nanorc"); +#endif +#ifndef DISABLE_MULTIBUFFER + printf(" --enable-multibuffer"); +#endif +#ifndef DISABLE_OPERATINGDIR + printf(" --enable-operatingdir"); +#endif +#ifndef DISABLE_SPELLER + printf(" --enable-speller"); +#endif +#ifndef DISABLE_TABCOMP + printf(" --enable-tabcomp"); +#endif +#ifndef DISABLE_WRAPPING + printf(" --enable-wrapping"); +#endif +#else /* !NANO_TINY */ #ifdef DISABLE_BROWSER printf(" --disable-browser"); #endif +#ifdef DISABLE_COLOR + printf(" --disable-color"); +#endif +#ifdef DISABLE_EXTRA + printf(" --disable-extra"); +#endif #ifdef DISABLE_HELP printf(" --disable-help"); #endif +#ifdef DISABLE_HISTORIES + printf(" --disable-histories"); +#endif #ifdef DISABLE_JUSTIFY printf(" --disable-justify"); #endif +#ifndef HAVE_LIBMAGIC + printf(" --disable-libmagic"); +#endif #ifdef DISABLE_MOUSE printf(" --disable-mouse"); #endif -#ifndef ENABLE_NLS - printf(" --disable-nls"); +#ifdef DISABLE_MULTIBUFFER + printf(" --disable-multibuffer"); +#endif +#ifdef DISABLE_NANORC + printf(" --disable-nanorc"); #endif #ifdef DISABLE_OPERATINGDIR printf(" --disable-operatingdir"); @@ -970,29 +1053,21 @@ void version(void) #ifdef DISABLE_WRAPPING printf(" --disable-wrapping"); #endif +#endif /* !NANO_TINY */ + #ifdef DISABLE_ROOTWRAPPING printf(" --disable-wrapping-as-root"); #endif -#ifdef ENABLE_COLOR - printf(" --enable-color"); -#endif #ifdef DEBUG printf(" --enable-debug"); #endif -#ifdef NANO_EXTRA - printf(" --enable-extra"); -#endif -#ifdef ENABLE_MULTIBUFFER - printf(" --enable-multibuffer"); -#endif -#ifdef ENABLE_NANORC - printf(" --enable-nanorc"); -#endif -#ifdef NANO_TINY - printf(" --enable-tiny"); +#ifndef ENABLE_NLS + printf(" --disable-nls"); #endif #ifdef ENABLE_UTF8 printf(" --enable-utf8"); +#else + printf(" --disable-utf8"); #endif #ifdef USE_SLANG printf(" --with-slang"); @@ -1001,16 +1076,15 @@ void version(void) } /* Return 1 if the MORE_SPACE flag is set, and 0 otherwise. This is - * used to calculate the relative screen position while taking this flag - * into account, since it adds one line to the edit window. */ -int no_more_space(void) + * used to calculate the sizes and Y coordinates of the subwindows. */ +int more_space(void) { return ISSET(MORE_SPACE) ? 1 : 0; } /* Return 2 if the NO_HELP flag is set, and 0 otherwise. This is used - * to calculate the relative screen position while taking this flag into - * account, since it removes two lines from the edit window. */ + * to calculate the sizes and Y coordinates of the subwindows, because + * having NO_HELP adds two lines to the edit window. */ int no_help(void) { return ISSET(NO_HELP) ? 2 : 0; @@ -1024,9 +1098,10 @@ void nano_disabled_msg(void) /* If the current file buffer has been modified, and the TEMP_FILE flag * isn't set, ask whether or not to save the file buffer. If the - * TEMP_FILE flag is set, save it unconditionally. Then, if more than - * one file buffer is open, close the current file buffer and switch to - * the next one. If only one file buffer is open, exit from nano. */ + * TEMP_FILE flag is set and the current file has a name, save it + * unconditionally. Then, if more than one file buffer is open, close + * the current file buffer and switch to the next one. If only one file + * buffer is open, exit from nano. */ void do_exit(void) { int i; @@ -1035,13 +1110,31 @@ void do_exit(void) * save. */ if (!openfile->modified) i = 0; - /* If the TEMP_FILE flag is set, pretend the user chose to save. */ - else if (ISSET(TEMP_FILE)) + /* If the TEMP_FILE flag is set and the current file has a name, + * pretend the user chose to save. */ + else if (openfile->filename[0] != '\0' && ISSET(TEMP_FILE)) i = 1; /* Otherwise, ask the user whether or not to save. */ - else + else { + /* If the TEMP_FILE flag is set, and the current file doesn't + * have a name, handle it the same way Pico does. */ + if (ISSET(TEMP_FILE)) { + curs_set(0); + + /* Warn that the current file has no name. */ + statusbar(_("No file name")); + beep(); + + /* Ensure that we see the warning. */ + doupdate(); + napms(2000); + + curs_set(1); + } + i = do_yesno_prompt(FALSE, _("Save modified buffer (ANSWERING \"No\" WILL DESTROY CHANGES) ? ")); + } #ifdef DEBUG dump_filestruct(openfile->fileage); @@ -1050,62 +1143,68 @@ void do_exit(void) /* If the user chose not to save, or if the user chose to save and * the save succeeded, we're ready to exit. */ if (i == 0 || (i == 1 && do_writeout(TRUE))) { -#ifdef ENABLE_MULTIBUFFER + +#ifndef NANO_TINY + if (ISSET(LOCKING) && openfile->lock_filename) + delete_lockfile(openfile->lock_filename); +#endif + +#ifndef DISABLE_MULTIBUFFER /* Exit only if there are no more open file buffers. */ - if (!close_buffer()) + if (!close_buffer(FALSE)) #endif finish(); /* If the user canceled, we go on. */ } else if (i != 1) statusbar(_("Cancelled")); - shortcut_init(FALSE); display_main_list(); } - +/* Another placeholder for function mapping. */ +void do_cancel(void) +{ + ; +} static struct sigaction pager_oldaction, pager_newaction; /* Original and temporary handlers for SIGINT. */ static bool pager_sig_failed = FALSE; /* Did sigaction() fail without changing the signal handlers? */ static bool pager_input_aborted = FALSE; /* Did someone invoke the pager and abort it via ^C? */ - /* Things which need to be run regardless of whether - we finished the stdin pipe correctly or not */ + * we finished the stdin pipe correctly or not. */ void finish_stdin_pager(void) { FILE *f; int ttystdin; - /* Read whatever we did get from stdin */ + /* Read whatever we did get from stdin. */ f = fopen("/dev/stdin", "rb"); - if (f == NULL) - nperror("fopen"); + if (f == NULL) + nperror("fopen"); read_file(f, 0, "stdin", TRUE, FALSE); ttystdin = open("/dev/tty", O_RDONLY); if (!ttystdin) - die(_("Couldn't reopen stdin from keyboard, sorry\n")); + die(_("Couldn't reopen stdin from keyboard, sorry\n")); dup2(ttystdin,0); close(ttystdin); if (!pager_input_aborted) tcgetattr(0, &oldterm); if (!pager_sig_failed && sigaction(SIGINT, &pager_oldaction, NULL) == -1) - nperror("sigaction"); + nperror("sigaction"); terminal_init(); doupdate(); } - -/* Cancel reading from stdin like a pager */ +/* Cancel reading from stdin like a pager. */ RETSIGTYPE cancel_stdin_pager(int signal) { - /* Currently do nothing, just handle the intr silently */ pager_input_aborted = TRUE; } -/* Let nano read stdin for the first file at least */ +/* Let nano read stdin for the first file at least. */ void stdin_pager(void) { endwin(); @@ -1113,13 +1212,13 @@ void stdin_pager(void) tcsetattr(0, TCSANOW, &oldterm); fprintf(stderr, _("Reading from stdin, ^C to abort\n")); - /* Set things up so that Ctrl-C will cancel the new process. */ - /* Enable interpretation of the special control keys so that we get - * SIGINT when Ctrl-C is pressed. */ + /* Enable interpretation of the special control keys so that + * we get SIGINT when Ctrl-C is pressed. */ #ifndef NANO_TINY enable_signals(); #endif + /* Set things up so that SIGINT will cancel the new process. */ if (sigaction(SIGINT, NULL, &pager_newaction) == -1) { pager_sig_failed = TRUE; nperror("sigaction"); @@ -1135,8 +1234,6 @@ void stdin_pager(void) finish_stdin_pager(); } - - /* Initialize the signal handlers. */ void signal_init(void) { @@ -1274,7 +1371,7 @@ RETSIGTYPE handle_sigwinch(int signal) * otherwise. However, COLS and LINES are curses global variables, * and in some cases curses has already updated them. But not in * all cases. Argh. */ -#ifdef REDEFINIG_MACROS_OK +#ifdef REDEFINING_MACROS_OK COLS = win.ws_col; LINES = win.ws_row; #endif @@ -1332,11 +1429,11 @@ void allow_pending_sigwinch(bool allow) #endif /* !NANO_TINY */ #ifndef NANO_TINY -/* Handle the global toggle specified in which. */ +/* Handle the global toggle specified in flag. */ void do_toggle(int flag) { bool enabled; - char *desc; + const char *desc; TOGGLE(flag); @@ -1354,40 +1451,43 @@ void do_toggle(int flag) case SUSPEND: signal_init(); break; -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC case WHITESPACE_DISPLAY: titlebar(NULL); edit_refresh(); break; #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR case NO_COLOR_SYNTAX: - edit_refresh(); - break; #endif case SOFTWRAP: - total_refresh(); + edit_refresh(); break; } enabled = ISSET(flag); - if (flag == NO_HELP + if (flag == NO_HELP #ifndef DISABLE_WRAPPING || flag == NO_WRAP #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR || flag == NO_COLOR_SYNTAX #endif ) enabled = !enabled; - desc = _(flagtostr(flag)); - statusbar("%s %s", desc, enabled ? _("enabled") : - _("disabled")); + desc = (char *) _(flagtostr(flag)); + statusbar("%s %s", desc, enabled ? _("enabled") : _("disabled")); } #endif /* !NANO_TINY */ +/* Bleh. */ +void do_toggle_void(void) +{ + ; +} + /* Disable extended input and output processing in our terminal * settings. */ void disable_extended_io(void) @@ -1489,16 +1589,10 @@ void terminal_init(void) } /* Read in a character, interpret it as a shortcut or toggle if - * necessary, and return it. Set meta_key to TRUE if the character is a - * meta sequence, set func_key to TRUE if the character is a function - * key, set s_or_t to TRUE if the character is a shortcut or toggle - * key, set ran_func to TRUE if we ran a function associated with a - * shortcut key, and set finished to TRUE if we're done after running - * or trying to run a function associated with a shortcut key. If - * allow_funcs is FALSE, don't actually run any functions associated + * necessary, and return it. + * If allow_funcs is FALSE, don't actually run any functions associated * with shortcut keys. */ -int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool - *ran_func, bool *finished, bool allow_funcs) +int do_input(bool allow_funcs) { int input; /* The character we read in. */ @@ -1506,36 +1600,29 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool /* The input buffer. */ static size_t kbinput_len = 0; /* The length of the input buffer. */ - bool cut_copy = FALSE; - /* Are we cutting or copying text? */ + bool preserve = FALSE; + /* Preserve the contents of the cutbuffer? */ const sc *s; bool have_shortcut; - *s_or_t = FALSE; - *ran_func = FALSE; - *finished = FALSE; - /* Read in a character. */ - input = get_kbinput(edit, meta_key, func_key); + input = get_kbinput(edit); #ifndef DISABLE_MOUSE - if (allow_funcs) { - /* If we got a mouse click and it was on a shortcut, read in the - * shortcut character. */ - if (*func_key && input == KEY_MOUSE) { - if (do_mouse() == 1) - input = get_kbinput(edit, meta_key, func_key); - else { - *meta_key = FALSE; - *func_key = FALSE; - input = ERR; - } - } + if (func_key && input == KEY_MOUSE) { + /* We received a mouse click. */ + if (do_mouse() == 1) + /* The click was on a shortcut -- read in the character + * that it was converted into. */ + input = get_kbinput(edit); + else + /* The click was invalid or has been handled -- get out. */ + return ERR; } #endif /* Check for a shortcut in the main list. */ - s = get_shortcut(MMAIN, &input, meta_key, func_key); + s = get_shortcut(&input); /* If we got a shortcut from the main list, or a "universal" * edit window shortcut, set have_shortcut to TRUE. */ @@ -1544,11 +1631,11 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool /* If we got a non-high-bit control key, a meta key sequence, or a * function key, and it's not a shortcut or toggle, throw it out. */ if (!have_shortcut) { - if (is_ascii_cntrl_char(input) || *meta_key || *func_key) { + if (is_ascii_cntrl_char(input) || meta_key || func_key) { statusbar(_("Unknown Command")); beep(); - *meta_key = FALSE; - *func_key = FALSE; + meta_key = FALSE; + func_key = FALSE; input = ERR; } } @@ -1575,13 +1662,11 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool * output all the characters in the input buffer if it isn't * empty. Note that it should be empty if we're in view * mode. */ - if (have_shortcut || get_key_buffer_len() == 0) { + if (have_shortcut || get_key_buffer_len() == 0) { #ifndef DISABLE_WRAPPING /* If we got a shortcut or toggle, and it's not the shortcut - * for verbatim input, turn off prepending of wrapped - * text. */ - if (have_shortcut && (!have_shortcut || s == NULL || s->scfunc != - DO_VERBATIM_INPUT)) + * for verbatim input, turn off prepending of wrapped text. */ + if (have_shortcut && s->scfunc != do_verbatim_input) wrap_reset(); #endif @@ -1607,63 +1692,51 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool } if (have_shortcut) { - switch (input) { - /* Handle the normal edit window shortcuts, setting - * ran_func to TRUE if we try to run their associated - * functions and setting finished to TRUE to indicate - * that we're done after running or trying to run their - * associated functions. */ - default: - /* If the function associated with this shortcut is - * cutting or copying text, indicate this. */ - if (s->scfunc == DO_CUT_TEXT_VOID -#ifndef NANO_TINY - || s->scfunc == DO_COPY_TEXT || s->scfunc == - DO_CUT_TILL_END -#endif - ) - cut_copy = TRUE; - - if (s->scfunc != 0) { - const subnfunc *f = sctofunc((sc *) s); - *ran_func = TRUE; - if (ISSET(VIEW_MODE) && f && !f->viewok) - print_view_warning(); - else { + /* If the function associated with this shortcut is + * cutting or copying text, remember this. */ + if (s->scfunc == do_cut_text_void #ifndef NANO_TINY - if (s->scfunc == DO_TOGGLE) - do_toggle(s->toggle); - else { -#else - { + || s->scfunc == do_copy_text || s->scfunc == do_cut_till_eof #endif - iso_me_harder_funcmap(s->scfunc); -#ifdef ENABLE_COLOR - if (f && !f->viewok && openfile->syntax != NULL - && openfile->syntax->nmultis > 0) { - reset_multis(openfile->current, FALSE); - } -#endif - if (edit_refresh_needed) { + ) + preserve = TRUE; + + if (s->scfunc != 0) { + const subnfunc *f = sctofunc((sc *) s); + if (ISSET(VIEW_MODE) && f && !f->viewok) + print_view_warning(); + else { +#ifndef NANO_TINY + if (s->scfunc == do_toggle_void) { + do_toggle(s->toggle); + if (s->toggle != CUT_TO_END) + preserve = TRUE; + } else +#endif + { + /* Execute the function of the shortcut. */ + s->scfunc(); +#ifndef DISABLE_COLOR + if (f && !f->viewok && openfile->syntax != NULL + && openfile->syntax->nmultis > 0) + reset_multis(openfile->current, FALSE); +#endif + if (edit_refresh_needed) { #ifdef DEBUG - fprintf(stderr, "running edit_refresh() as edit_refresh_needed is true\n"); + fprintf(stderr, "running edit_refresh() as edit_refresh_needed is true\n"); #endif - edit_refresh(); - edit_refresh_needed = FALSE; - } - - } + edit_refresh(); + edit_refresh_needed = FALSE; } } - *finished = TRUE; - break; + } } } } - /* If we aren't cutting or copying text, blow away the text in the - * cutbuffer. */ - if (!cut_copy) + /* If we aren't cutting or copying text, and the key wasn't a toggle, + * blow away the text in the cutbuffer upon the next cutting action. */ + if (!preserve) cutbuffer_reset(); return input; @@ -1687,32 +1760,39 @@ int do_mouse(void) int mouse_x, mouse_y; int retval = get_mouseinput(&mouse_x, &mouse_y, TRUE); + if (retval != 0) + /* The click is wrong or already handled. */ + return retval; + /* We can click on the edit window to move the cursor. */ - if (retval == 0 && wmouse_trafo(edit, &mouse_y, &mouse_x, FALSE)) { + if (wmouse_trafo(edit, &mouse_y, &mouse_x, FALSE)) { bool sameline; /* Did they click on the line with the cursor? If they * clicked on the cursor, we set the mark. */ filestruct *current_save = openfile->current; +#ifndef NANO_TINY size_t current_x_save = openfile->current_x; +#endif size_t pww_save = openfile->placewewant; sameline = (mouse_y == openfile->current_y); #ifdef DEBUG - fprintf(stderr, "mouse_y = %d, current_y = %d\n", mouse_y, openfile->current_y); + fprintf(stderr, "mouse_y = %d, current_y = %ld\n", mouse_y, (long)openfile->current_y); #endif - if (ISSET(SOFTWRAP)) { - int i = 0; +#ifndef NANO_TINY + if (ISSET(SOFTWRAP)) { + size_t i = 0; for (openfile->current = openfile->edittop; openfile->current->next && i < mouse_y; openfile->current = openfile->current->next, i++) { openfile->current_y = i; i += strlenpt(openfile->current->data) / COLS; } - #ifdef DEBUG - fprintf(stderr, "do_mouse(): moving to current_y = %d, i %d\n", openfile->current_y, i); + fprintf(stderr, "do_mouse(): moving to current_y = %ld, index i = %lu\n", + (long)openfile->current_y, (unsigned long)i); fprintf(stderr, " openfile->current->data = \"%s\"\n", openfile->current->data); #endif @@ -1720,18 +1800,19 @@ int do_mouse(void) openfile->current = openfile->current->prev; openfile->current_x = actual_x(openfile->current->data, mouse_x + (mouse_y - openfile->current_y) * COLS); #ifdef DEBUG - fprintf(stderr, "do_mouse(): i > mouse_y, mouse_x = %d, current_x to = %d\n", mouse_x, openfile->current_x); + fprintf(stderr, "do_mouse(): i > mouse_y, mouse_x = %d, current_x to = %lu\n", + mouse_x, (unsigned long)openfile->current_x); #endif } else { openfile->current_x = actual_x(openfile->current->data, mouse_x); #ifdef DEBUG - fprintf(stderr, "do_mouse(): i <= mouse_y, mouse_x = %d, setting current_x to = %d\n", mouse_x, openfile->current_x); + fprintf(stderr, "do_mouse(): i <= mouse_y, mouse_x = %d, setting current_x to = %lu\n", + mouse_x, (unsigned long)openfile->current_x); #endif } - - openfile->placewewant = xplustabs(); - - } else { + } else +#endif /* NANO_TINY */ + { /* Move to where the click occurred. */ for (; openfile->current_y < mouse_y && openfile->current != openfile->filebot; openfile->current_y++) @@ -1742,38 +1823,42 @@ int do_mouse(void) openfile->current_x = actual_x(openfile->current->data, get_page_start(xplustabs()) + mouse_x); - - openfile->placewewant = xplustabs(); } + openfile->placewewant = xplustabs(); + #ifndef NANO_TINY /* Clicking where the cursor is toggles the mark, as does * clicking beyond the line length with the cursor at the end of * the line. */ if (sameline && openfile->current_x == current_x_save) do_mark(); + else #endif + /* The cursor moved; clean the cutbuffer on the next cut. */ + cutbuffer_reset(); edit_redraw(current_save, pww_save); } - return retval; + /* No more handling is needed. */ + return 2; } #endif /* !DISABLE_MOUSE */ -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR void alloc_multidata_if_needed(filestruct *fileptr) { if (!fileptr->multidata) - fileptr->multidata = (short *) nmalloc(openfile->syntax->nmultis * sizeof(short)); + fileptr->multidata = (short *)nmalloc(openfile->syntax->nmultis * sizeof(short)); } -/* Precalculate the multi-line start and end regex info so we can speed up - rendering (with any hope at all...) */ +/* Precalculate the multi-line start and end regex info so we can + * speed up rendering (with any hope at all...). */ void precalc_multicolorinfo(void) { #ifdef DEBUG - fprintf(stderr, "entering precalc_multicolorinfo()\n"); + fprintf(stderr, "Entering precalculation of multiline color info\n"); #endif if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) { const colortype *tmpcolor = openfile->colorstrings; @@ -1781,30 +1866,26 @@ void precalc_multicolorinfo(void) filestruct *fileptr, *endptr; time_t last_check = time(NULL), cur_check = 0; - /* Let us get keypresses to see if the user is trying to - start editing. We may want to throw up a statusbar - message before starting this later if it takes - too long to do this routine. For now silently - abort if they hit a key */ - nodelay(edit, FALSE); + /* Let us get keypresses to see if the user is trying to start + * editing. Later we may want to throw up a statusbar message + * before starting this if it takes too long to do this routine. + * For now silently abort if they hit a key. */ + nodelay(edit, TRUE); for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) { - /* If it's not a multi-line regex, amscray */ + /* If it's not a multi-line regex, amscray. */ if (tmpcolor->end == NULL) continue; #ifdef DEBUG - fprintf(stderr, "working on color id %d\n", tmpcolor->id); + fprintf(stderr, "Starting work on color id %d\n", tmpcolor->id); #endif - for (fileptr = openfile->fileage; fileptr != NULL; fileptr = fileptr->next) { int startx = 0; int nostart = 0; - - #ifdef DEBUG - fprintf(stderr, "working on lineno %lu\n", (unsigned long) fileptr->lineno); + fprintf(stderr, "working on lineno %ld... ", (long)fileptr->lineno); #endif alloc_multidata_if_needed(fileptr); @@ -1812,84 +1893,81 @@ void precalc_multicolorinfo(void) if ((cur_check = time(NULL)) - last_check > 1) { last_check = cur_check; if (wgetch(edit) != ERR) - goto precalc_cleanup; + goto precalc_cleanup; } - while ((nostart = regexec(tmpcolor->start, &fileptr->data[startx], 1, &startmatch, 0)) == 0) { - /* Look for end and start marking how many lines are encompassed - whcih should speed up rendering later */ + while ((nostart = regexec(tmpcolor->start, &fileptr->data[startx], 1, &startmatch, + (startx == 0) ? 0 : REG_NOTBOL)) == 0) { + /* Look for an end, and start marking how many lines are + * encompassed, which should speed up rendering later. */ startx += startmatch.rm_eo; #ifdef DEBUG - fprintf(stderr, "match found at pos %d...", startx); + fprintf(stderr, "start found at pos %lu... ", (unsigned long)startx); #endif - /* Look on this line first for end */ - if (regexec(tmpcolor->end, &fileptr->data[startx], 1, &endmatch, 0) == 0) { + /* Look first on this line for an end. */ + if (regexec(tmpcolor->end, &fileptr->data[startx], 1, &endmatch, + (startx == 0) ? 0 : REG_NOTBOL) == 0) { startx += endmatch.rm_eo; fileptr->multidata[tmpcolor->id] |= CSTARTENDHERE; #ifdef DEBUG - fprintf(stderr, "end found on this line\n"); + fprintf(stderr, "end found on this line\n"); #endif continue; } - /* Nice, we didn't find the end regex on this line. Let's start looking for it */ + /* Nice, we didn't find the end regex on this line. Let's start looking for it. */ for (endptr = fileptr->next; endptr != NULL; endptr = endptr->next) { - #ifdef DEBUG - fprintf(stderr, "advancing to line %lu to find end...\n", (unsigned long) endptr->lineno); + fprintf(stderr, "\nadvancing to line %ld to find end... ", (long)endptr->lineno); #endif - /* Check for keyboard input again */ + /* Check for keyboard input, again. */ if ((cur_check = time(NULL)) - last_check > 1) { last_check = cur_check; if (wgetch(edit) != ERR) - goto precalc_cleanup; + goto precalc_cleanup; } if (regexec(tmpcolor->end, endptr->data, 1, &endmatch, 0) == 0) - break; + break; } if (endptr == NULL) { #ifdef DEBUG - fprintf(stderr, "no end found, breaking out\n"); + fprintf(stderr, "no end found, breaking out\n"); #endif break; } - #ifdef DEBUG fprintf(stderr, "end found\n"); #endif - - /* We found it, we found it, la la la la la. Mark all the - lines in between and the ends properly */ + /* We found it, we found it, la la la la la. Mark all + * the lines in between and the end properly. */ fileptr->multidata[tmpcolor->id] |= CENDAFTER; #ifdef DEBUG - fprintf(stderr, "marking line %lu as CENDAFTER\n", (unsigned long) fileptr->lineno); + fprintf(stderr, "marking line %ld as CENDAFTER\n", (long)fileptr->lineno); #endif for (fileptr = fileptr->next; fileptr != endptr; fileptr = fileptr->next) { alloc_multidata_if_needed(fileptr); fileptr->multidata[tmpcolor->id] = CWHOLELINE; #ifdef DEBUG - fprintf(stderr, "marking intermediary line %lu as CWHOLELINE\n", (unsigned long) fileptr->lineno); + fprintf(stderr, "marking intermediary line %ld as CWHOLELINE\n", (long)fileptr->lineno); #endif } alloc_multidata_if_needed(endptr); + fileptr->multidata[tmpcolor->id] |= CBEGINBEFORE; #ifdef DEBUG - fprintf(stderr, "marking line %lu as BEGINBEFORE\n", (unsigned long) fileptr->lineno); + fprintf(stderr, "marking line %ld as CBEGINBEFORE\n", (long)fileptr->lineno); #endif - endptr->multidata[tmpcolor->id] |= CBEGINBEFORE; - /* We should be able to skip all the way to the line of the match. - This may introduce more bugs but it's the Right Thing to do */ - fileptr = endptr; + /* Skip to the end point of the match. */ startx = endmatch.rm_eo; #ifdef DEBUG - fprintf(stderr, "jumping to line %lu pos %d to continue\n", (unsigned long) endptr->lineno, startx); + fprintf(stderr, "jumping to line %ld pos %lu to continue\n", (long)fileptr->lineno, (unsigned long)startx); #endif } if (nostart && startx == 0) { #ifdef DEBUG - fprintf(stderr, "no start found on line %lu, continuing\n", (unsigned long) fileptr->lineno); + fprintf(stderr, "no match\n"); #endif fileptr->multidata[tmpcolor->id] = CNONE; continue; @@ -1900,22 +1978,29 @@ void precalc_multicolorinfo(void) precalc_cleanup: nodelay(edit, FALSE); } -#endif /* ENABLE_COLOR */ +#endif /* !DISABLE_COLOR */ /* The user typed output_len multibyte characters. Add them to the edit * buffer, filtering out all ASCII control characters if allow_cntrls is * TRUE. */ void do_output(char *output, size_t output_len, bool allow_cntrls) { - size_t current_len, orig_lenpt, i = 0; + size_t current_len, i = 0; +#ifndef NANO_TINY + size_t orig_lenpt = 0; +#endif + char *char_buf = charalloc(mb_cur_max()); int char_buf_len; assert(openfile->current != NULL && openfile->current->data != NULL); current_len = strlen(openfile->current->data); + +#ifndef NANO_TINY if (ISSET(SOFTWRAP)) orig_lenpt = strlenpt(openfile->current->data); +#endif while (i < output_len) { /* If allow_cntrls is TRUE, convert nulls and newlines @@ -1966,7 +2051,7 @@ void do_output(char *output, size_t output_len, bool allow_cntrls) set_modified(); #ifndef NANO_TINY - update_undo(ADD); + add_undo(ADD); /* Note that current_x has not yet been incremented. */ if (openfile->mark_set && openfile->current == @@ -1977,14 +2062,18 @@ void do_output(char *output, size_t output_len, bool allow_cntrls) openfile->current_x += char_buf_len; +#ifndef NANO_TINY + update_undo(ADD); +#endif + #ifndef DISABLE_WRAPPING /* If we're wrapping text, we need to call edit_refresh(). */ if (!ISSET(NO_WRAP)) - if (do_wrap(openfile->current, FALSE)) + if (do_wrap(openfile->current)) edit_refresh_needed = TRUE; #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR /* If color syntaxes are available and turned on, we need to * call edit_refresh(). */ if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) @@ -1992,18 +2081,19 @@ void do_output(char *output, size_t output_len, bool allow_cntrls) #endif } - /* Well we might also need a full refresh if we've changed the - line length to be a new multiple of COLS */ +#ifndef NANO_TINY + /* Well, we might also need a full refresh if we've changed the + * line length to be a new multiple of COLS. */ if (ISSET(SOFTWRAP) && edit_refresh_needed == FALSE) - if (strlenpt(openfile->current->data) / COLS != orig_lenpt / COLS) + if (strlenpt(openfile->current->data) / COLS != orig_lenpt / COLS) edit_refresh_needed = TRUE; +#endif free(char_buf); openfile->placewewant = xplustabs(); - -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR reset_multis(openfile->current, FALSE); #endif if (edit_refresh_needed == TRUE) { @@ -2016,15 +2106,13 @@ void do_output(char *output, size_t output_len, bool allow_cntrls) int main(int argc, char **argv) { int optchr; - ssize_t startline = 1; - /* Line to try and start at. */ - ssize_t startcol = 1; - /* Column to try and start at. */ + ssize_t startline = 0, startcol = 0; + /* Target line and column when specified on the command line. */ #ifndef DISABLE_WRAPJUSTIFY bool fill_used = FALSE; /* Was the fill option used? */ #endif -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER bool old_multibuffer; /* The old value of the multibuffer option, restored after we * load all files on the command line. */ @@ -2033,10 +2121,10 @@ int main(int argc, char **argv) const struct option long_options[] = { {"help", 0, NULL, 'h'}, {"boldtext", 0, NULL, 'D'}, -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER {"multibuffer", 0, NULL, 'F'}, #endif -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC {"ignorercfiles", 0, NULL, 'I'}, #endif {"rebindkeypad", 0, NULL, 'K'}, @@ -2048,7 +2136,7 @@ int main(int argc, char **argv) {"restricted", 0, NULL, 'R'}, {"tabsize", 1, NULL, 'T'}, {"version", 0, NULL, 'V'}, -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR {"syntax", 1, NULL, 'Y'}, #endif {"const", 0, NULL, 'c'}, @@ -2057,6 +2145,7 @@ int main(int argc, char **argv) #ifndef DISABLE_MOUSE {"mouse", 0, NULL, 'm'}, #endif + {"noread", 0, NULL, 'n'}, #ifndef DISABLE_OPERATINGDIR {"operatingdir", 1, NULL, 'o'}, #endif @@ -2080,8 +2169,10 @@ int main(int argc, char **argv) {"backup", 0, NULL, 'B'}, {"backupdir", 1, NULL, 'C'}, {"tabstospaces", 0, NULL, 'E'}, + {"locking", 0, NULL, 'G'}, {"historylog", 0, NULL, 'H'}, {"noconvert", 0, NULL, 'N'}, + {"poslog", 0, NULL, 'P'}, {"smooth", 0, NULL, 'S'}, {"quickblank", 0, NULL, 'U'}, {"undo", 0, NULL, 'u'}, @@ -2117,7 +2208,7 @@ int main(int argc, char **argv) textdomain(PACKAGE); #endif -#if !defined(ENABLE_NANORC) && defined(DISABLE_ROOTWRAPPING) +#if defined(DISABLE_NANORC) && defined(DISABLE_ROOTWRAPPING) /* If we don't have rcfile support, --disable-wrapping-as-root is * used, and we're root, turn wrapping off. */ if (geteuid() == NANO_ROOT_UID) @@ -2127,11 +2218,11 @@ int main(int argc, char **argv) while ((optchr = #ifdef HAVE_GETOPT_LONG getopt_long(argc, argv, - "h?ABC:DEFHIKLNOQ:RST:UVWY:abcdefgijklmo:pqr:s:tuvwxz$", + "ABC:DEFGHIKLNOPQ:RST:UVWY:abcdefghijklmno:pqr:s:tvwxz$", long_options, NULL) #else getopt(argc, argv, - "h?ABC:DEFHIKLNOQ:RST:UVWY:abcdefgijklmo:pqr:s:tuvwxz$") + "ABC:DEFGHIKLNOPQ:RST:UVWY:abcdefghijklmno:pqr:s:tvwxz$") #endif ) != -1) { switch (optchr) { @@ -2162,17 +2253,22 @@ int main(int argc, char **argv) SET(TABS_TO_SPACES); break; #endif -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER case 'F': SET(MULTIBUFFER); break; #endif -#ifdef ENABLE_NANORC #ifndef NANO_TINY + case 'G': + SET(LOCKING); + break; +#endif +#ifndef DISABLE_HISTORIES case 'H': SET(HISTORYLOG); break; #endif +#ifndef DISABLE_NANORC case 'I': no_rcfiles = TRUE; break; @@ -2191,6 +2287,11 @@ int main(int argc, char **argv) case 'O': SET(MORE_SPACE); break; +#ifndef DISABLE_HISTORIES + case 'P': + SET(POS_HISTORY); + break; +#endif #ifndef DISABLE_JUSTIFY case 'Q': quotestr = mallocstrcpy(quotestr, optarg); @@ -2224,7 +2325,7 @@ int main(int argc, char **argv) SET(WORD_BOUNDS); break; #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR case 'Y': syntaxstr = mallocstrcpy(syntaxstr, optarg); break; @@ -2251,6 +2352,9 @@ int main(int argc, char **argv) SET(USE_MOUSE); break; #endif + case 'n': + SET(NOREAD_MODE); + break; #ifndef DISABLE_OPERATINGDIR case 'o': operating_dir = mallocstrcpy(operating_dir, optarg); @@ -2259,9 +2363,11 @@ int main(int argc, char **argv) case 'p': SET(PRESERVE); break; +#ifndef DISABLE_NANORC case 'q': SET(QUIET); break; +#endif #ifndef DISABLE_WRAPJUSTIFY case 'r': if (!parse_num(optarg, &wrap_at)) { @@ -2280,22 +2386,15 @@ int main(int argc, char **argv) case 't': SET(TEMP_FILE); break; -#ifndef NANO_TINY - case 'u': - SET(UNDOABLE); - break; -#endif case 'v': SET(VIEW_MODE); break; #ifndef DISABLE_WRAPPING case 'w': SET(NO_WRAP); - - /* If both --fill and --nowrap are given on the command line, - the last option wins, */ + /* If both --fill and --nowrap are given on the + * command line, the last given option wins. */ fill_used = FALSE; - break; #endif case 'x': @@ -2309,8 +2408,12 @@ int main(int argc, char **argv) SET(SOFTWRAP); break; #endif - default: + case 'h': usage(); + exit(0); + default: + printf(_("Type '%s -h' for a list of available options.\n"), argv[0]); + exit(1); } } @@ -2319,26 +2422,27 @@ int main(int argc, char **argv) if (*(tail(argv[0])) == 'r') SET(RESTRICTED); - /* If we're using restricted mode, disable suspending, backups, and - * reading rcfiles, since they all would allow reading from or - * writing to files not specified on the command line. */ + /* If we're using restricted mode, disable suspending, backups, + * rcfiles, and history files, since they all would allow reading + * from or writing to files not specified on the command line. */ if (ISSET(RESTRICTED)) { UNSET(SUSPEND); UNSET(BACKUP_FILE); -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC no_rcfiles = TRUE; + UNSET(HISTORYLOG); + UNSET(POS_HISTORY); #endif } - - /* Set up the shortcut lists. - Need to do this before the rcfile */ - shortcut_init(FALSE); + /* Set up the function and shortcut lists. This needs to be done + * before reading the rcfile, to be able to rebind/unbind keys. */ + shortcut_init(); /* We've read through the command line options. Now back up the flags * and values that are set, and read the rcfile(s). If the values * haven't changed afterward, restore the backed-up values. */ -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC if (!no_rcfiles) { #ifndef DISABLE_OPERATINGDIR char *operating_dir_cpy = operating_dir; @@ -2421,11 +2525,11 @@ int main(int argc, char **argv) else if (geteuid() == NANO_ROOT_UID) SET(NO_WRAP); #endif -#endif /* ENABLE_NANORC */ +#endif /* !DISABLE_NANORC */ #ifndef DISABLE_WRAPPING /* Overwrite an rcfile "set nowrap" or --disable-wrapping-as-root - if a --fill option was given on the command line. */ + * if a --fill option was given on the command line. */ if (fill_used) UNSET(NO_WRAP); #endif @@ -2433,16 +2537,24 @@ int main(int argc, char **argv) /* If we're using bold text instead of reverse video text, set it up * now. */ if (ISSET(BOLD_TEXT)) - reverse_attr = A_BOLD; + hilite_attribute = A_BOLD; -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES /* Set up the search/replace history. */ history_init(); -#ifdef ENABLE_NANORC - if (!no_rcfiles && ISSET(HISTORYLOG)) + /* Verify that the home directory and ~/.nano subdir exist. */ + if (ISSET(HISTORYLOG) || ISSET(POS_HISTORY)) { + get_homedir(); + if (homedir == NULL || check_dotnano() == 0) { + UNSET(HISTORYLOG); + UNSET(POS_HISTORY); + } + } + if (ISSET(HISTORYLOG)) load_history(); -#endif -#endif + if (ISSET(POS_HISTORY)) + load_poshistory(); +#endif /* !DISABLE_HISTORIES */ #ifndef NANO_TINY /* Set up the backup directory (unless we're using restricted mode, @@ -2513,16 +2625,28 @@ int main(int argc, char **argv) /* If matchbrackets wasn't specified, set its default value. */ if (matchbrackets == NULL) matchbrackets = mallocstrcpy(NULL, "(<[{)>]}"); -#endif -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) - /* If whitespace wasn't specified, set its default value. */ +#ifndef DISABLE_NANORC + /* If whitespace wasn't specified, set its default value. If we're + * using UTF-8, it's Unicode 00BB (Right-Pointing Double Angle + * Quotation Mark) and Unicode 00B7 (Middle Dot). Otherwise, it's + * ">" and ".". */ if (whitespace == NULL) { - whitespace = mallocstrcpy(NULL, " "); - whitespace_len[0] = 1; - whitespace_len[1] = 1; +#ifdef ENABLE_UTF8 + if (using_utf8()) { + whitespace = mallocstrcpy(NULL, "\xC2\xBB\xC2\xB7"); + whitespace_len[0] = 2; + whitespace_len[1] = 2; + } else +#endif + { + whitespace = mallocstrcpy(NULL, ">."); + whitespace_len[0] = 1; + whitespace_len[1] = 1; + } } -#endif +#endif /* !DISABLE_NANORC */ +#endif /* !NANO_TINY */ /* If tabsize wasn't specified, set its default value. */ if (tabsize == -1) @@ -2557,6 +2681,19 @@ int main(int argc, char **argv) mouse_init(); #endif +#ifndef DISABLE_COLOR + set_colorpairs(); +#else + interface_color_pair[TITLE_BAR].pairnum = hilite_attribute; + interface_color_pair[STATUS_BAR].pairnum = hilite_attribute; + interface_color_pair[KEY_COMBO].pairnum = hilite_attribute; + interface_color_pair[FUNCTION_TAG].pairnum = A_NORMAL; + interface_color_pair[TITLE_BAR].bright = FALSE; + interface_color_pair[STATUS_BAR].bright = FALSE; + interface_color_pair[KEY_COMBO].bright = FALSE; + interface_color_pair[FUNCTION_TAG].bright = FALSE; +#endif + #ifdef DEBUG fprintf(stderr, "Main: open file\n"); #endif @@ -2575,7 +2712,7 @@ int main(int argc, char **argv) optind++; } -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER old_multibuffer = ISSET(MULTIBUFFER); SET(MULTIBUFFER); @@ -2583,7 +2720,7 @@ int main(int argc, char **argv) * new buffers. */ { int i = optind + 1; - ssize_t iline = 1, icol = 1; + ssize_t iline = 0, icol = 0; for (; i < argc; i++) { /* If there's a +LINE or +LINE,COLUMN flag here, it is @@ -2595,16 +2732,25 @@ int main(int argc, char **argv) else { open_buffer(argv[i], FALSE); - if (iline > 1 || icol > 1) { + if (iline > 0 || icol > 0) { do_gotolinecolumn(iline, icol, FALSE, FALSE, FALSE, FALSE); iline = 1; icol = 1; } +#ifndef DISABLE_HISTORIES + else { + /* See if we have a POS history to use if we haven't overridden it. */ + ssize_t savedposline, savedposcol; + if (check_poshistory(argv[i], &savedposline, &savedposcol)) + do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE, + FALSE); + } +#endif } } } -#endif +#endif /* !DISABLE_MULTIBUFFER */ /* Read the first file on the command line into either the current * buffer or a new buffer, depending on whether multibuffer mode is @@ -2621,7 +2767,7 @@ int main(int argc, char **argv) UNSET(VIEW_MODE); } -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER if (!old_multibuffer) UNSET(MULTIBUFFER); #endif @@ -2630,22 +2776,29 @@ int main(int argc, char **argv) fprintf(stderr, "Main: top and bottom win\n"); #endif -#ifdef ENABLE_COLOR - if (openfile->syntax && openfile->syntax->nmultis > 0) - precalc_multicolorinfo(); +#ifndef DISABLE_COLOR + if (openfile->syntax) + if (openfile->syntax->nmultis > 0) + precalc_multicolorinfo(); #endif - if (startline > 1 || startcol > 1) + if (startline > 0 || startcol > 0) do_gotolinecolumn(startline, startcol, FALSE, FALSE, FALSE, FALSE); +#ifndef DISABLE_HISTORIES + else { + /* See if we have a POS history to use if we haven't overridden it. */ + ssize_t savedposline, savedposcol; + if (check_poshistory(argv[optind], &savedposline, &savedposcol)) + do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE, FALSE); + } +#endif display_main_list(); display_buffer(); while (TRUE) { - bool meta_key, func_key, s_or_t, ran_func, finished; - /* Make sure the cursor is in the edit window. */ reset_cursor(); wnoutrefresh(edit); @@ -2674,11 +2827,9 @@ int main(int argc, char **argv) currmenu = MMAIN; /* Read in and interpret characters. */ - do_input(&meta_key, &func_key, &s_or_t, &ran_func, &finished, - TRUE); + do_input(TRUE); } /* We should never get here. */ assert(FALSE); } - @@ -1,9 +1,9 @@ -/* $Id: nano.h 4508 2010-06-21 03:10:10Z astyanax $ */ +/* $Id: nano.h 5100 2015-01-03 07:24:17Z astyanax $ */ /************************************************************************** * nano.h * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -31,8 +31,8 @@ #ifdef NEED_XOPEN_SOURCE_EXTENDED #ifndef _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED 1 -#endif /* _XOPEN_SOURCE_EXTENDED */ -#endif /* NEED_XOPEN_SOURCE_EXTENDED */ +#endif +#endif #ifdef __TANDEM /* Tandem NonStop Kernel support. */ @@ -54,13 +54,12 @@ #include <stdarg.h> #endif -/* Suppress warnings for __attribute__((warn_unused_result)) */ +/* Suppress warnings for __attribute__((warn_unused_result)). */ #define IGNORE_CALL_RESULT(call) do { if (call) {} } while(0) -/* Macros for flags. */ -#define FLAGOFF(flag) ((flag) / (sizeof(unsigned) * 8)) +/* Macros for flags, indexing each bit in a small array. */ +#define FLAGS(flag) flags[((flag) / (sizeof(unsigned) * 8))] #define FLAGMASK(flag) (1 << ((flag) % (sizeof(unsigned) * 8))) -#define FLAGS(flag) flags[FLAGOFF(flag)] #define SET(flag) FLAGS(flag) |= FLAGMASK(flag) #define UNSET(flag) FLAGS(flag) &= ~FLAGMASK(flag) #define ISSET(flag) ((FLAGS(flag) & FLAGMASK(flag)) != 0) @@ -85,6 +84,8 @@ #define KEY_DC SL_KEY_DELETE #define KEY_IC SL_KEY_IC /* Ncurses support. */ +#elif defined(HAVE_NCURSESW_NCURSES_H) +#include <ncursesw/ncurses.h> #elif defined(HAVE_NCURSES_H) #include <ncurses.h> #else @@ -174,7 +175,7 @@ typedef enum { } append_type; typedef enum { - UP_DIR, DOWN_DIR + UPWARD, DOWNWARD } scroll_dir; typedef enum { @@ -182,14 +183,26 @@ typedef enum { } update_type; typedef enum { - CONTROL, META, FKEY, RAW -} function_type; + CONTROL, META, FKEY, RAWINPUT +} key_type; typedef enum { - ADD, DEL, REPLACE, SPLIT, UNSPLIT, CUT, UNCUT, ENTER, INSERT, OTHER + ADD, DEL, BACK, CUT, CUT_EOF, REPLACE, +#ifndef DISABLE_WRAPPING + SPLIT_BEGIN, SPLIT_END, +#endif + JOIN, PASTE, INSERT, ENTER, OTHER } undo_type; -#ifdef ENABLE_COLOR +typedef struct color_pair { + int pairnum; + /* The color pair number used for this foreground color and + * background color. */ + bool bright; + /* Is this color A_BOLD? */ +} color_pair; + +#ifndef DISABLE_COLOR typedef struct colortype { short fg; /* This syntax's foreground color. */ @@ -212,48 +225,70 @@ typedef struct colortype { /* The compiled end (if any) of the regex string. */ struct colortype *next; /* Next set of colors. */ - int id; - /* basic id for assigning to lines later */ + int id; + /* Basic id for assigning to lines later. */ } colortype; -typedef struct exttype { +typedef struct regexlisttype { char *ext_regex; - /* The extensions that match this syntax. */ + /* The regexstrings for the things that match this syntax. */ regex_t *ext; - /* The compiled extensions that match this syntax. */ - struct exttype *next; - /* Next set of extensions. */ -} exttype; + /* The compiled regexes. */ + struct regexlisttype *next; + /* Next set of regexes. */ +} regexlisttype; typedef struct syntaxtype { char *desc; /* The name of this syntax. */ - exttype *extensions; + regexlisttype *extensions; /* The list of extensions that this syntax applies to. */ - exttype *headers; - /* Regexes to match on the 'header' (1st line) of the file */ + regexlisttype *headers; + /* The list of headerlines that this syntax applies to. */ + regexlisttype *magics; + /* The list of libmagic results that this syntax applies to. */ colortype *color; /* The colors used in this syntax. */ + char *linter; + /* The command to lint this type of file. */ + char *formatter; + /* Use this formatter command (for programming lang mainly) */ int nmultis; - /* How many multi line strings this syntax has */ + /* How many multi-line strings this syntax has. */ struct syntaxtype *next; /* Next syntax. */ } syntaxtype; -#define CNONE (1<<1) +typedef struct lintstruct { + ssize_t lineno; + /* Line number of the error. */ + ssize_t colno; + /* Column # of the error. */ + char *msg; + /* Error message text. */ + char *filename; + /* Filename. */ + struct lintstruct *next; + /* Next error. */ + struct lintstruct *prev; + /* Previous error. */ +} lintstruct; + + +#define CNONE (1<<1) /* Yay, regex doesn't apply to this line at all! */ -#define CBEGINBEFORE (1<<2) - /* regex starts on an earlier line, ends on this one */ -#define CENDAFTER (1<<3) - /* regex sraers on this line and ends on a later one */ -#define CWHOLELINE (1<<4) - /* whole line engulfed by the regex start < me, end > me */ -#define CSTARTENDHERE (1<<5) - /* regex starts and ends within this line */ +#define CBEGINBEFORE (1<<2) + /* Regex starts on an earlier line, ends on this one. */ +#define CENDAFTER (1<<3) + /* Regex starts on this line and ends on a later one. */ +#define CWHOLELINE (1<<4) + /* Whole line engulfed by the regex, start < me, end > me. */ +#define CSTARTENDHERE (1<<5) + /* Regex starts and ends within this line. */ #define CWTF (1<<6) - /* Something else */ + /* Something else. */ -#endif /* ENABLE_COLOR */ +#endif /* !DISABLE_COLOR */ /* Structure types. */ @@ -266,8 +301,9 @@ typedef struct filestruct { /* Next node. */ struct filestruct *prev; /* Previous node. */ -#ifdef ENABLE_COLOR - short *multidata; /* Array of which multi-line regexes apply to this line */ +#ifndef DISABLE_COLOR + short *multidata; + /* Array of which multi-line regexes apply to this line. */ #endif } filestruct; @@ -293,35 +329,40 @@ typedef struct partition { typedef struct undo { ssize_t lineno; undo_type type; - /* What type of undo was this */ - int begin; - /* Where did this action begin or end */ + /* What type of undo this was. */ + size_t begin; + /* Where did this action begin or end. */ char *strdata; - /* String type data we will use for ccopying the affected line back */ - char *strdata2; - /* Sigh, need this too it looks like */ + /* String type data we will use for copying the affected line back. */ int xflags; - /* Some flag data we need */ + /* Some flag data we need. */ - /* Cut specific stuff we need */ + /* Cut-specific stuff we need. */ filestruct *cutbuffer; - /* Copy of the cutbuffer */ + /* Copy of the cutbuffer. */ filestruct *cutbottom; - /* Copy of cutbottom */ + /* Copy of cutbottom. */ bool mark_set; - /* was the marker set when we cut */ - bool to_end; - /* was this a cut to end */ + /* Was the marker set when we cut? */ ssize_t mark_begin_lineno; /* copy copy copy */ - ssize_t mark_begin_x; - /* Another shadow variable */ + size_t mark_begin_x; + /* Another shadow variable. */ struct undo *next; } undo; +#endif /* !NANO_TINY */ - -#endif /* NANO_TINY */ - +#ifndef DISABLE_HISTORIES +typedef struct poshiststruct { + char *filename; + /* The file. */ + ssize_t lineno; + /* Line number we left off on. */ + ssize_t xno; + /* x position in the file we left off on. */ + struct poshiststruct *next; +} poshiststruct; +#endif typedef struct openfilestruct { char *filename; @@ -339,7 +380,7 @@ typedef struct openfilestruct { size_t current_x; /* The current file's x-coordinate position. */ size_t placewewant; - /* The current file's place we want. */ + /* The current file's x position we would like. */ ssize_t current_y; /* The current file's y-coordinate position. */ bool modified; @@ -357,14 +398,16 @@ typedef struct openfilestruct { struct stat *current_stat; /* The current file's stat. */ undo *undotop; - /* Top of the undo list */ + /* Top of the undo list. */ undo *current_undo; - /* The current (i.e. n ext) level of undo */ + /* The current (i.e. next) level of undo. */ undo_type last_action; + const char *lock_filename; + /* The path of the lockfile, if we created one. */ #endif -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR syntaxtype *syntax; - /* The syntax struct for this file, if any */ + /* The syntax struct for this file, if any. */ colortype *colorstrings; /* The current file's associated colors. */ #endif @@ -384,17 +427,6 @@ typedef struct shortcut { /* Whether there should be a blank line after the help entry * text for this function. */ #endif - /* Note: Key values that aren't used should be set to - * NANO_NO_KEY. */ - int ctrlval; - /* The special sentinel key or control key we want bound, if - * any. */ - int metaval; - /* The meta key we want bound, if any. */ - int funcval; - /* The function key we want bound, if any. */ - int miscval; - /* The other meta key we want bound, if any. */ bool viewok; /* Is this function allowed when in view mode? */ void (*func)(void); @@ -403,41 +435,40 @@ typedef struct shortcut { /* Next shortcut. */ } shortcut; -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC typedef struct rcoption { const char *name; /* The name of the rcfile option. */ long flag; /* The flag associated with it, if any. */ } rcoption; - #endif typedef struct sc { char *keystr; - /* The shortcut key for a function, ASCII version */ - function_type type; - /* What kind of function key is it for convenience later */ + /* The shortcut key for a function, ASCII version. */ + key_type type; + /* What kind of command key it is, for convenience later. */ int seq; - /* The actual sequence to check on the the type is determined */ + /* The actual sequence to check on the type is determined. */ int menu; - /* What list does this apply to */ - short scfunc; - /* The function we're going to run */ + /* What list this applies to. */ + void (*scfunc)(void); + /* The function we're going to run. */ int toggle; - /* If a toggle, what we're toggling */ + /* If a toggle, what we're toggling. */ bool execute; /* Whether to execute the function in question or just return - so the sequence can be caught by the calling code */ + * so the sequence can be caught by the calling code. */ struct sc *next; - /* Next in the list */ + /* Next in the list. */ } sc; typedef struct subnfunc { - short scfunc; - /* What function is this */ + void (*scfunc)(void); + /* What function this is. */ int menus; - /* In what menus does this function applu */ + /* In what menus this function applies. */ const char *desc; /* The function's description, e.g. "Page Up". */ #ifndef DISABLE_HELP @@ -448,16 +479,24 @@ typedef struct subnfunc { * text for this function. */ #endif bool viewok; - /* Is this function allowed when in view mode? */ + /* Is this function allowed when in view mode? */ long toggle; - /* If this is a toggle, if nonzero what toggle to set */ + /* If this is a toggle, if nonzero what toggle to set. */ struct subnfunc *next; - /* next item in the list */ + /* Next item in the list. */ } subnfunc; +/* The elements of the interface that can be colored differently. */ +enum +{ + TITLE_BAR = 0, + STATUS_BAR, + KEY_COMBO, + FUNCTION_TAG, + NUMBER_OF_ELEMENTS +}; -/* Enumeration to be used in flags table. See FLAGBIT and FLAGOFF - * definitions. */ +/* Enumeration used in the flags array. See the definition of FLAGMASK. */ enum { DONTUSE, @@ -494,425 +533,53 @@ enum NO_NEWLINES, BOLD_TEXT, QUIET, - UNDOABLE, - SOFTWRAP + SOFTWRAP, + POS_HISTORY, + LOCKING, + NOREAD_MODE }; -/* Flags for which menus in which a given function should be present */ -#define MMAIN (1<<0) -#define MWHEREIS (1<<1) -#define MREPLACE (1<<2) -#define MREPLACE2 (1<<3) -#define MGOTOLINE (1<<4) -#define MWRITEFILE (1<<5) -#define MINSERTFILE (1<<6) -#define MEXTCMD (1<<7) -#define MHELP (1<<8) -#define MSPELL (1<<9) -#define MBROWSER (1<<10) -#define MWHEREISFILE (1<<11) -#define MGOTODIR (1<<12) -#define MYESNO (1<<13) -/* This really isnt all but close enough */ -#define MALL (MMAIN|MWHEREIS|MREPLACE|MREPLACE2|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MSPELL|MBROWSER|MWHEREISFILE|MGOTODIR|MHELP) +/* Flags for the menus in which a given function should be present. */ +#define MMAIN (1<<0) +#define MWHEREIS (1<<1) +#define MREPLACE (1<<2) +#define MREPLACEWITH (1<<3) +#define MGOTOLINE (1<<4) +#define MWRITEFILE (1<<5) +#define MINSERTFILE (1<<6) +#define MEXTCMD (1<<7) +#define MHELP (1<<8) +#define MSPELL (1<<9) +#define MBROWSER (1<<10) +#define MWHEREISFILE (1<<11) +#define MGOTODIR (1<<12) +#define MYESNO (1<<13) +#define MLINTER (1<<14) +/* This is an abbreviation for all menus except Help and YesNo. */ +#define MMOST (MMAIN|MWHEREIS|MREPLACE|MREPLACEWITH|MGOTOLINE|MWRITEFILE|MINSERTFILE|MEXTCMD|MBROWSER|MWHEREISFILE|MGOTODIR|MSPELL|MLINTER) /* Control key sequences. Changing these would be very, very bad. */ #define NANO_CONTROL_SPACE 0 -#define NANO_CONTROL_A 1 -#define NANO_CONTROL_B 2 -#define NANO_CONTROL_C 3 -#define NANO_CONTROL_D 4 -#define NANO_CONTROL_E 5 -#define NANO_CONTROL_F 6 -#define NANO_CONTROL_G 7 -#define NANO_CONTROL_H 8 #define NANO_CONTROL_I 9 -#define NANO_CONTROL_J 10 -#define NANO_CONTROL_K 11 -#define NANO_CONTROL_L 12 -#define NANO_CONTROL_M 13 -#define NANO_CONTROL_N 14 -#define NANO_CONTROL_O 15 -#define NANO_CONTROL_P 16 -#define NANO_CONTROL_Q 17 -#define NANO_CONTROL_R 18 -#define NANO_CONTROL_S 19 -#define NANO_CONTROL_T 20 -#define NANO_CONTROL_U 21 -#define NANO_CONTROL_V 22 -#define NANO_CONTROL_W 23 -#define NANO_CONTROL_X 24 -#define NANO_CONTROL_Y 25 -#define NANO_CONTROL_Z 26 #define NANO_CONTROL_3 27 -#define NANO_CONTROL_4 28 -#define NANO_CONTROL_5 29 -#define NANO_CONTROL_6 30 #define NANO_CONTROL_7 31 #define NANO_CONTROL_8 127 -/* Meta key sequences. */ -#define NANO_META_SPACE ' ' -#define NANO_META_LPARENTHESIS '(' -#define NANO_META_RPARENTHESIS ')' -#define NANO_META_PLUS '+' -#define NANO_META_COMMA ',' -#define NANO_META_MINUS '-' -#define NANO_META_PERIOD '.' -#define NANO_META_SLASH '/' -#define NANO_META_0 '0' -#define NANO_META_6 '6' -#define NANO_META_9 '9' -#define NANO_META_LCARET '<' -#define NANO_META_EQUALS '=' -#define NANO_META_RCARET '>' -#define NANO_META_QUESTION '?' -#define NANO_META_BACKSLASH '\\' -#define NANO_META_RBRACKET ']' -#define NANO_META_CARET '^' -#define NANO_META_UNDERSCORE '_' -#define NANO_META_A 'a' -#define NANO_META_B 'b' -#define NANO_META_C 'c' -#define NANO_META_D 'd' -#define NANO_META_E 'e' -#define NANO_META_F 'f' -#define NANO_META_G 'g' -#define NANO_META_H 'h' -#define NANO_META_I 'i' -#define NANO_META_J 'j' -#define NANO_META_K 'k' -#define NANO_META_L 'l' -#define NANO_META_M 'm' -#define NANO_META_N 'n' -#define NANO_META_O 'o' -#define NANO_META_P 'p' -#define NANO_META_Q 'q' -#define NANO_META_R 'r' -#define NANO_META_S 's' -#define NANO_META_T 't' -#define NANO_META_U 'u' -#define NANO_META_V 'v' -#define NANO_META_W 'w' -#define NANO_META_X 'x' -#define NANO_META_Y 'y' -#define NANO_META_Z 'z' -#define NANO_META_LCURLYBRACKET '{' -#define NANO_META_PIPE '|' -#define NANO_META_RCURLYBRACKET '}' - -/* Some semi-changeable keybindings; don't play with these unless you're - * sure you know what you're doing. Assume ERR is defined as -1. */ - -/* No key at all. */ -#define NANO_NO_KEY -2 - -/* Normal keys. */ -#define NANO_XON_KEY NANO_CONTROL_Q -#define NANO_XOFF_KEY NANO_CONTROL_S -#define NANO_CANCEL_KEY NANO_CONTROL_C -#define NANO_EXIT_KEY NANO_CONTROL_X -#define NANO_EXIT_FKEY KEY_F(2) -#define NANO_INSERTFILE_KEY NANO_CONTROL_R -#define NANO_INSERTFILE_FKEY KEY_F(5) -#define NANO_TOOTHERINSERT_KEY NANO_CONTROL_X -#define NANO_WRITEOUT_KEY NANO_CONTROL_O -#define NANO_WRITEOUT_FKEY KEY_F(3) -#define NANO_GOTOLINE_KEY NANO_CONTROL_7 -#define NANO_GOTOLINE_FKEY KEY_F(13) -#define NANO_GOTOLINE_METAKEY NANO_META_G -#define NANO_GOTODIR_KEY NANO_CONTROL_7 -#define NANO_GOTODIR_FKEY KEY_F(13) -#define NANO_GOTODIR_METAKEY NANO_META_G -#define NANO_TOGOTOLINE_KEY NANO_CONTROL_T -#define NANO_HELP_KEY NANO_CONTROL_G -#define NANO_HELP_FKEY KEY_F(1) -#define NANO_WHEREIS_KEY NANO_CONTROL_W -#define NANO_WHEREIS_FKEY KEY_F(6) -#define NANO_WHEREIS_NEXT_KEY NANO_META_W -#define NANO_WHEREIS_NEXT_FKEY KEY_F(16) -#define NANO_TOOTHERWHEREIS_KEY NANO_CONTROL_T -#define NANO_REGEXP_KEY NANO_META_R -#define NANO_REPLACE_KEY NANO_CONTROL_4 -#define NANO_REPLACE_FKEY KEY_F(14) -#define NANO_REPLACE_METAKEY NANO_META_R -#define NANO_TOOTHERSEARCH_KEY NANO_CONTROL_R -#define NANO_PREVPAGE_KEY NANO_CONTROL_Y -#define NANO_PREVPAGE_FKEY KEY_F(7) -#define NANO_NEXTPAGE_KEY NANO_CONTROL_V -#define NANO_NEXTPAGE_FKEY KEY_F(8) -#define NANO_CUT_KEY NANO_CONTROL_K -#define NANO_CUT_FKEY KEY_F(9) -#define NANO_COPY_KEY NANO_META_CARET -#define NANO_COPY_METAKEY NANO_META_6 -#define NANO_UNCUT_KEY NANO_CONTROL_U -#define NANO_UNCUT_FKEY KEY_F(10) -#define NANO_CURSORPOS_KEY NANO_CONTROL_C -#define NANO_CURSORPOS_FKEY KEY_F(11) -#define NANO_SPELL_KEY NANO_CONTROL_T -#define NANO_SPELL_FKEY KEY_F(12) -#define NANO_FIRSTLINE_KEY NANO_PREVPAGE_KEY -#define NANO_FIRSTLINE_FKEY NANO_PREVPAGE_FKEY -#define NANO_FIRSTLINE_METAKEY NANO_META_BACKSLASH -#define NANO_FIRSTLINE_METAKEY2 NANO_META_PIPE -#define NANO_FIRSTFILE_KEY NANO_FIRSTLINE_KEY -#define NANO_FIRSTFILE_FKEY NANO_FIRSTLINE_FKEY -#define NANO_FIRSTFILE_METAKEY NANO_FIRSTLINE_METAKEY -#define NANO_FIRSTFILE_METAKEY2 NANO_FIRSTLINE_METAKEY2 -#define NANO_LASTLINE_KEY NANO_NEXTPAGE_KEY -#define NANO_LASTLINE_FKEY NANO_NEXTPAGE_FKEY -#define NANO_LASTLINE_METAKEY NANO_META_SLASH -#define NANO_LASTLINE_METAKEY2 NANO_META_QUESTION -#define NANO_LASTFILE_KEY NANO_LASTLINE_KEY -#define NANO_LASTFILE_FKEY NANO_LASTLINE_FKEY -#define NANO_LASTFILE_METAKEY NANO_LASTLINE_METAKEY -#define NANO_LASTFILE_METAKEY2 NANO_LASTLINE_METAKEY2 -#define NANO_REFRESH_KEY NANO_CONTROL_L -#define NANO_JUSTIFY_KEY NANO_CONTROL_J -#define NANO_JUSTIFY_FKEY KEY_F(4) -#define NANO_UNJUSTIFY_KEY NANO_UNCUT_KEY -#define NANO_UNJUSTIFY_FKEY NANO_UNCUT_FKEY -#define NANO_PREVLINE_KEY NANO_CONTROL_P -#define NANO_NEXTLINE_KEY NANO_CONTROL_N -#define NANO_FORWARD_KEY NANO_CONTROL_F -#define NANO_BACK_KEY NANO_CONTROL_B -#define NANO_MARK_KEY NANO_CONTROL_6 -#define NANO_MARK_METAKEY NANO_META_A -#define NANO_MARK_FKEY KEY_F(15) -#define NANO_HOME_KEY NANO_CONTROL_A -#define NANO_END_KEY NANO_CONTROL_E -#define NANO_DELETE_KEY NANO_CONTROL_D -#define NANO_BACKSPACE_KEY NANO_CONTROL_H -#define NANO_TAB_KEY NANO_CONTROL_I -#define NANO_INDENT_KEY NANO_META_RCURLYBRACKET -#define NANO_UNINDENT_KEY NANO_META_LCURLYBRACKET -#define NANO_SUSPEND_KEY NANO_CONTROL_Z -#define NANO_ENTER_KEY NANO_CONTROL_M -#define NANO_TOFILES_KEY NANO_CONTROL_T -#define NANO_APPEND_KEY NANO_META_A -#define NANO_PREPEND_KEY NANO_META_P -#define NANO_PREVFILE_KEY NANO_META_LCARET -#define NANO_PREVFILE_METAKEY NANO_META_COMMA -#define NANO_NEXTFILE_KEY NANO_META_RCARET -#define NANO_NEXTFILE_METAKEY NANO_META_PERIOD -#define NANO_BRACKET_KEY NANO_META_RBRACKET -#define NANO_NEXTWORD_KEY NANO_CONTROL_SPACE -#define NANO_PREVWORD_KEY NANO_META_SPACE -#define NANO_WORDCOUNT_KEY NANO_META_D -#define NANO_SCROLLUP_KEY NANO_META_MINUS -#define NANO_SCROLLDOWN_KEY NANO_META_PLUS -#define NANO_SCROLLUP_METAKEY NANO_META_UNDERSCORE -#define NANO_SCROLLDOWN_METAKEY NANO_META_EQUALS -#define NANO_CUTTILLEND_METAKEY NANO_META_T -#define NANO_PARABEGIN_KEY NANO_CONTROL_W -#define NANO_PARABEGIN_METAKEY NANO_META_LPARENTHESIS -#define NANO_PARABEGIN_METAKEY2 NANO_META_9 -#define NANO_PARAEND_KEY NANO_CONTROL_O -#define NANO_PARAEND_METAKEY NANO_META_RPARENTHESIS -#define NANO_PARAEND_METAKEY2 NANO_META_0 -#define NANO_FULLJUSTIFY_KEY NANO_CONTROL_U -#define NANO_FULLJUSTIFY_METAKEY NANO_META_J -#define NANO_VERBATIM_KEY NANO_META_V - -/* Toggles do not exist if NANO_TINY is defined. */ -#ifndef NANO_TINY - -/* No toggle at all. */ -#define TOGGLE_NO_KEY -2 - -/* Normal toggles. */ -#define TOGGLE_NOHELP_KEY NANO_META_X -#define TOGGLE_CONST_KEY NANO_META_C -#define TOGGLE_MORESPACE_KEY NANO_META_O -#define TOGGLE_SMOOTH_KEY NANO_META_S -#define TOGGLE_WHITESPACE_KEY NANO_META_P -#define TOGGLE_SYNTAX_KEY NANO_META_Y -#define TOGGLE_SMARTHOME_KEY NANO_META_H -#define TOGGLE_AUTOINDENT_KEY NANO_META_I -#define TOGGLE_CUTTOEND_KEY NANO_META_K -#define TOGGLE_WRAP_KEY NANO_META_L -#define TOGGLE_TABSTOSPACES_KEY NANO_META_Q -#define TOGGLE_BACKUP_KEY NANO_META_B -#define TOGGLE_MULTIBUFFER_KEY NANO_META_F -#define TOGGLE_MOUSE_KEY NANO_META_M -#define TOGGLE_NOCONVERT_KEY NANO_META_N -#define TOGGLE_SUSPEND_KEY NANO_META_Z -#define TOGGLE_CASE_KEY NANO_META_C -#define TOGGLE_BACKWARDS_KEY NANO_META_B -#define TOGGLE_DOS_KEY NANO_META_D -#define TOGGLE_MAC_KEY NANO_META_M - -/* Extra bits for the undo function */ -#define UNDO_DEL_DEL (1<<0) -#define UNDO_DEL_BACKSPACE (1<<1) -#define UNDO_SPLIT_MADENEW (1<<2) - -/* Since in ISO C you can't pass around function pointers anymore, - let's make some integer macros for function names, and then I - can go cut my wrists after writing the big switch statement - that will necessitate. */ +/* Codes for "modified" Arrow keys. Chosen like this because some + * terminals produce them, and they are beyond KEY_MAX of ncurses. */ +#define CONTROL_LEFT 539 +#define CONTROL_RIGHT 554 +#ifndef NANO_TINY +/* Extra bits for the undo function. */ +#define UNdel_del (1<<0) +#define UNdel_backspace (1<<1) +#define UNcut_marked_forward (1<<2) +#define UNcut_cutline (1<<3) #endif /* !NANO_TINY */ -#define CASE_SENS_MSG 1 -#define BACKWARDS_MSG 2 -#define REGEXP_MSG 3 -#define WHEREIS_NEXT_MSG 4 -#define FIRST_FILE_MSG 5 -#define LAST_FILE_MSG 6 -#define GOTO_DIR_MSG 7 -#define TOTAL_REFRESH 8 -#define DO_HELP_VOID 9 -#define DO_SEARCH 10 -#define DO_PAGE_UP 11 -#define DO_PAGE_DOWN 12 -#define DO_UP_VOID 13 -#define DO_LEFT 14 -#define DO_DOWN_VOID 15 -#define DO_RIGHT 16 -#define DO_ENTER 17 -#define DO_EXIT 18 -#define NEW_BUFFER_MSG 19 -#define EXT_CMD_MSG 20 -#define TO_FILES_MSG 21 -#define DOS_FORMAT_MSG 23 -#define MAC_FORMAT_MSG 24 -#define BACKUP_FILE_MSG 25 -#define PREPEND_MSG 26 -#define APPEND_MSG 27 -#define DO_FIRST_LINE 28 -#define DO_LAST_LINE 29 -#define DO_TOGGLE 30 -#define GOTOTEXT_MSG 31 -#define NO_REPLACE_MSG 32 -#define DO_BACKSPACE 33 -#define DO_DELETE 34 -#define DO_TAB 35 -#define DO_VERBATIM_INPUT 36 -#define SWITCH_TO_NEXT_BUFFER_VOID 37 -#define SWITCH_TO_PREV_BUFFER_VOID 38 -#define DO_END 39 -#define DO_HOME 40 -#define NEXT_HISTORY_MSG 41 -#define PREV_HISTORY_MSG 42 -#define DO_REDO 43 -#define DO_UNDO 44 -#define DO_WORDLINECHAR_COUNT 45 -#define DO_FIND_BRACKET 46 -#define DO_PREV_WORD_VOID 47 -#define DO_SUSPEND_VOID 48 -#define CANCEL_MSG 49 -#define DO_WRITEOUT_VOID 50 -#define DO_INSERTFILE_VOID 51 -#define DO_CUT_TEXT_VOID 52 -#define DO_UNCUT_TEXT 53 -#define DO_CURSORPOS_VOID 54 -#define DO_GOTOLINECOLUMN_VOID 55 -#define DO_REPLACE 56 -#define DO_JUSTIFY_VOID 57 -#define DO_PARA_BEGIN_VOID 58 -#define DO_PARA_END_VOID 59 -#define DO_FULL_JUSTIFY 60 -#define DO_MARK 61 -#define DO_RESEARCH 62 -#define DO_COPY_TEXT 63 -#define DO_INDENT_VOID 64 -#define DO_UNINDENT 65 -#define DO_SCROLL_UP 66 -#define DO_SCROLL_DOWN 67 -#define DO_NEXT_WORD_VOID 68 -#define DO_CUT_TILL_END 69 -#define NANO_GOTODIR_MSG 70 -#define NANO_LASTFILE_MSG 71 -#define NANO_FIRSTFILE_MSG 72 -#define INSERT_FILE_MSG 73 -#define NANO_MULTIBUFFER_MSG 74 -#define NANO_EXECUTE_MSG 75 -#define NANO_BACKUP_MSG 76 -#define NANO_PREPEND_MSG 77 -#define NANO_APPEND_MSG 78 -#define NANO_MAC_MSG 79 -#define NANO_DOS_MSG 80 -#define NANO_TOFILES_MSG 81 -#define NANO_NEXT_HISTORY_MSG 82 -#define NANO_PREV_HISTORY_MSG 83 -#define NANO_REGEXP_MSG 84 -#define NANO_REVERSE_MSG 85 -#define NANO_CASE_MSG 86 -#define NANO_SUSPEND_MSG 87 -#define SUSPEND_MSG 88 -#define NANO_REFRESH_MSG 89 -#define REFRESH_MSG 90 -#define NANO_WORDCOUNT_MSG 91 -#define NANO_FULLJUSTIFY_MSG 92 -#define FULLJSTIFY_MSG 93 -#define XOFF_COMPLAINT 94 -#define XON_COMPLAINT 95 -#define NANO_CUT_TILL_END_MSG 96 -#define NANO_BACKSPACE_MSG 97 -#define NANO_DELETE_MSG 98 -#define NANO_ENTER_MSG 99 -#define NANO_TAB_MSG 100 -#define NANO_VERBATIM_MSG 101 -#define NANO_NEXTFILE_MSG 102 -#define NANO_PREVFILE_MSG 103 -#define NANO_SCROLLDOWN_MSG 104 -#define NANO_SCROLLUP_MSG 105 -#define NANO_BRACKET_MSG 106 -#define NANO_PARAEND_MSG 107 -#define END_OF_PAR_MSG 108 -#define NANO_PARABEGIN_MSG 109 -#define BEG_OF_PAR_MSG 110 -#define NANO_END_MSG 111 -#define NANO_HOME_MSG 112 -#define NANO_NEXTLINE_MSG 113 -#define NANO_PREVLINE_MSG 114 -#define NANO_PREVWORD_MSG 115 -#define NANO_NEXTWORD_MSG 116 -#define NANO_BACK_MSG 117 -#define NANO_FORWARD_MSG 118 -#define NANO_REDO_MSG 119 -#define NANO_UNDO_MSG 120 -#define NANO_UNINDENT_MSG 121 -#define NANO_INDENT_MSG 122 -#define NANO_COPY_MSG 123 -#define NANO_WHEREIS_NEXT_MSG 124 -#define NANO_MARK_MSG 125 -#define NANO_REPLACE_MSG 126 -#define REPLACE_MSG 127 -#define NANO_GOTOLINE_MSG 128 -#define NANO_LASTLINE_MSG 129 -#define NANO_FIRSTLINE_MSG 130 -#define NANO_SPELL_MSG 131 -#define DO_SPELL 132 -#define NANO_CURSORPOS_MSG 133 -#define NANO_UNCUT_MSG 134 -#define GET_HELP_MSG 135 -#define NANO_HELP_MSG 136 -#define NANO_CANCEL_MSG 137 -#define NANO_EXIT_MSG 138 -#define EXIT_MSG 139 -#define NANO_EXITBROWSER_MSG 140 -#define NANO_WRITEOUT_MSG 141 -#define NANO_DISABLED_MSG 142 -#define NANO_INSERT_MSG 143 -#define WHEREIS_MSG 144 -#define NANO_WHEREIS_MSG 145 -#define NANO_PREVPAGE_MSG 146 -#define NANO_NEXTPAGE_MSG 147 -#define NANO_CUT_MSG 148 -#define DO_CUT_TEXT 149 -#define DO_NEXT_WORD 150 -#define DO_PREV_WORD 151 - - - - -#define VIEW TRUE -#define NOVIEW FALSE - /* The maximum number of entries displayed in the main shortcut list. */ -#define MAIN_VISIBLE 12 +#define MAIN_VISIBLE (((COLS + 40) / 20) * 2) /* The minimum editor window columns and rows required for nano to work * correctly. */ diff --git a/src/prompt.c b/src/prompt.c index afb36d6..e3d4f1f 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -1,9 +1,9 @@ -/* $Id: prompt.c 4475 2010-01-17 05:30:22Z astyanax $ */ +/* $Id: prompt.c 5086 2014-07-31 20:49:32Z bens $ */ /************************************************************************** * prompt.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -42,18 +42,13 @@ static bool reset_statusbar_x = FALSE; * prompt? */ /* Read in a character, interpret it as a shortcut or toggle if - * necessary, and return it. Set meta_key to TRUE if the character is a - * meta sequence, set func_key to TRUE if the character is a function - * key, set have_shortcut to TRUE if the character is a shortcut - * key, set ran_func to TRUE if we ran a function associated with a + * necessary, and return it. + * Set ran_func to TRUE if we ran a function associated with a * shortcut key, and set finished to TRUE if we're done after running - * or trying to run a function associated with a shortcut key. If - * allow_funcs is FALSE, don't actually run any functions associated - * with shortcut keys. refresh_func is the function we will call to - * refresh the edit window. */ -int do_statusbar_input(bool *meta_key, bool *func_key, bool *have_shortcut, - bool *ran_func, bool *finished, bool allow_funcs, void - (*refresh_func)(void)) + * or trying to run a function associated with a shortcut key. + * refresh_func is the function we will call to refresh the edit window. */ +int do_statusbar_input(bool *ran_func, bool *finished, + void (*refresh_func)(void)) { int input; /* The character we read in. */ @@ -62,157 +57,142 @@ int do_statusbar_input(bool *meta_key, bool *func_key, bool *have_shortcut, static size_t kbinput_len = 0; /* The length of the input buffer. */ const sc *s; + bool have_shortcut = FALSE; const subnfunc *f; - *have_shortcut = FALSE; *ran_func = FALSE; *finished = FALSE; /* Read in a character. */ - input = get_kbinput(bottomwin, meta_key, func_key); + input = get_kbinput(bottomwin); #ifndef DISABLE_MOUSE - if (allow_funcs) { - /* If we got a mouse click and it was on a shortcut, read in the - * shortcut character. */ - if (*func_key && input == KEY_MOUSE) { - if (do_statusbar_mouse() == 1) - input = get_kbinput(bottomwin, meta_key, func_key); - else { - *meta_key = FALSE; - *func_key = FALSE; - input = ERR; - } + /* If we got a mouse click and it was on a shortcut, read in the + * shortcut character. */ + if (func_key && input == KEY_MOUSE) { + if (do_statusbar_mouse() == 1) + input = get_kbinput(bottomwin); + else { + meta_key = FALSE; + func_key = FALSE; + input = ERR; } } #endif /* Check for a shortcut in the current list. */ - s = get_shortcut(currmenu, &input, meta_key, func_key); + s = get_shortcut(&input); /* If we got a shortcut from the current list, or a "universal" * statusbar prompt shortcut, set have_shortcut to TRUE. */ - *have_shortcut = (s != NULL); + have_shortcut = (s != NULL); /* If we got a non-high-bit control key, a meta key sequence, or a * function key, and it's not a shortcut or toggle, throw it out. */ - if (!*have_shortcut) { - if (is_ascii_cntrl_char(input) || *meta_key || *func_key) { + if (!have_shortcut) { + if (is_ascii_cntrl_char(input) || meta_key || func_key) { beep(); - *meta_key = FALSE; - *func_key = FALSE; + meta_key = FALSE; + func_key = FALSE; input = ERR; } } - if (allow_funcs) { - /* If we got a character, and it isn't a shortcut or toggle, - * it's a normal text character. Display the warning if we're - * in view mode, or add the character to the input buffer if - * we're not. */ - if (input != ERR && !*have_shortcut) { - /* If we're using restricted mode, the filename isn't blank, - * and we're at the "Write File" prompt, disable text - * input. */ - if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || + /* If we got a character, and it isn't a shortcut or toggle, + * it's a normal text character. Display the warning if we're + * in view mode, or add the character to the input buffer if + * we're not. */ + if (input != ERR && !have_shortcut) { + /* If we're using restricted mode, the filename isn't blank, + * and we're at the "Write File" prompt, disable text input. */ + if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) { - kbinput_len++; - kbinput = (int *)nrealloc(kbinput, kbinput_len * - sizeof(int)); - kbinput[kbinput_len - 1] = input; - } + kbinput_len++; + kbinput = (int *)nrealloc(kbinput, kbinput_len * sizeof(int)); + kbinput[kbinput_len - 1] = input; } - - /* If we got a shortcut, or if there aren't any other characters - * waiting after the one we read in, we need to display all the - * characters in the input buffer if it isn't empty. */ - if (*have_shortcut || get_key_buffer_len() == 0) { - if (kbinput != NULL) { - /* Display all the characters in the input buffer at - * once, filtering out control characters. */ - char *output = charalloc(kbinput_len + 1); - size_t i; - bool got_enter; - /* Whether we got the Enter key. */ - - for (i = 0; i < kbinput_len; i++) - output[i] = (char)kbinput[i]; - output[i] = '\0'; - - do_statusbar_output(output, kbinput_len, &got_enter, - FALSE); - - free(output); - - /* Empty the input buffer. */ - kbinput_len = 0; - free(kbinput); - kbinput = NULL; - } + } + + /* If we got a shortcut, or if there aren't any other characters + * waiting after the one we read in, we need to display all the + * characters in the input buffer if it isn't empty. */ + if (have_shortcut || get_key_buffer_len() == 0) { + if (kbinput != NULL) { + /* Display all the characters in the input buffer at + * once, filtering out control characters. */ + char *output = charalloc(kbinput_len + 1); + size_t i; + bool got_enter; + /* Whether we got the Enter key. */ + + for (i = 0; i < kbinput_len; i++) + output[i] = (char)kbinput[i]; + output[i] = '\0'; + + do_statusbar_output(output, kbinput_len, &got_enter, FALSE); + + free(output); + + /* Empty the input buffer. */ + kbinput_len = 0; + free(kbinput); + kbinput = NULL; } - if (*have_shortcut) { - if (s->scfunc == DO_TAB || s->scfunc == DO_ENTER) + if (have_shortcut) { + if (s->scfunc == do_tab || s->scfunc == do_enter_void) ; - else if (s->scfunc == TOTAL_REFRESH) + else if (s->scfunc == total_refresh) total_statusbar_refresh(refresh_func); - else if (s->scfunc == DO_CUT_TEXT) { + else if (s->scfunc == do_cut_text_void) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Cut. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_cut_text(); - } else if (s->scfunc == DO_RIGHT) - do_statusbar_right(); - else if (s->scfunc == DO_LEFT) + } else if (s->scfunc == do_left) do_statusbar_left(); - + else if (s->scfunc == do_right) + do_statusbar_right(); #ifndef NANO_TINY - else if (s->scfunc == DO_NEXT_WORD) + else if (s->scfunc == do_prev_word_void) + do_statusbar_prev_word(FALSE); + else if (s->scfunc == do_next_word_void) do_statusbar_next_word(FALSE); - else if (s->scfunc == DO_PREV_WORD) - do_statusbar_prev_word(FALSE); -#endif - else if (s->scfunc == DO_HOME) - do_statusbar_home(); - else if (s->scfunc == DO_END) - do_statusbar_end(); - -#ifndef NANO_TINY - else if (s->scfunc == DO_FIND_BRACKET) - do_statusbar_find_bracket(); #endif - else if (s->scfunc == DO_VERBATIM_INPUT) { - /* If we're using restricted mode, the filename - * isn't blank, and we're at the "Write File" - * prompt, disable verbatim input. */ - if (!ISSET(RESTRICTED) || - openfile->filename[0] == '\0' || - currmenu != MWRITEFILE) { - bool got_enter; - /* Whether we got the Enter key. */ - - do_statusbar_verbatim_input(&got_enter); - - /* If we got the Enter key, remove it from - * the input buffer, set input to the key - * value for Enter, and set finished to TRUE - * to indicate that we're done. */ - if (got_enter) { - get_input(NULL, 1); - input = sc_seq_or(DO_ENTER, 0); - *finished = TRUE; - } + else if (s->scfunc == do_home) + do_statusbar_home(); + else if (s->scfunc == do_end) + do_statusbar_end(); + else if (s->scfunc == do_verbatim_input) { + /* If we're using restricted mode, the filename + * isn't blank, and we're at the "Write File" + * prompt, disable verbatim input. */ + if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE || + openfile->filename[0] == '\0') { + bool got_enter; + /* Whether we got the Enter key. */ + + do_statusbar_verbatim_input(&got_enter); + + /* If we got the Enter key, remove it from the input + * buffer, set input to the key value for Enter, and + * set finished to TRUE to indicate that we're done. */ + if (got_enter) { + get_input(NULL, 1); + input = sc_seq_or(do_enter_void, 0); + *finished = TRUE; } - } else if (s->scfunc == DO_DELETE) { + } + } else if (s->scfunc == do_delete) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Delete. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_delete(); - } else if (s->scfunc == DO_BACKSPACE) { + } else if (s->scfunc == do_backspace) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Backspace. */ @@ -220,17 +200,17 @@ int do_statusbar_input(bool *meta_key, bool *func_key, bool *have_shortcut, '\0' || currmenu != MWRITEFILE) do_statusbar_backspace(); } else { - /* Handle the normal statusbar prompt shortcuts, setting - * ran_func to TRUE if we try to run their associated - * functions and setting finished to TRUE to indicate - * that we're done after running or trying to run their - * associated functions. */ - + /* Handle any other shortcut in the current menu, setting + * ran_func to TRUE if we try to run their associated + * functions and setting finished to TRUE to indicate + * that we're done after running or trying to run their + * associated functions. */ f = sctofunc((sc *) s); - if (s->scfunc != 0 && s->execute == TRUE) { - *ran_func = TRUE; - if (f && (!ISSET(VIEW_MODE) || (f->viewok))) - iso_me_harder_funcmap(f->scfunc); + if (s->scfunc != NULL) { + *ran_func = TRUE; + if (f && (!ISSET(VIEW_MODE) || f->viewok) && + f->scfunc != do_gotolinecolumn_void) + f->scfunc(); } *finished = TRUE; } @@ -320,7 +300,7 @@ void do_statusbar_output(char *output, size_t output_len, bool char_buf_len))) continue; - /* More dangerousness fun =) */ + /* More dangerousness fun. =) */ answer = charealloc(answer, answer_len + (char_buf_len * 2)); assert(statusbar_x <= answer_len); @@ -360,13 +340,12 @@ void do_statusbar_home(void) statusbar_x = 0; statusbar_pww = statusbar_xplustabs(); - } else { + } else #endif + { statusbar_x = 0; statusbar_pww = statusbar_xplustabs(); -#ifndef NANO_TINY } -#endif if (need_statusbar_horizontal_update(pww_save)) update_statusbar_line(answer, statusbar_x); @@ -451,14 +430,13 @@ void do_statusbar_cut_text(void) #ifndef NANO_TINY if (ISSET(CUT_TO_END)) null_at(&answer, statusbar_x); - else { + else #endif + { null_at(&answer, 0); statusbar_x = 0; statusbar_pww = statusbar_xplustabs(); -#ifndef NANO_TINY } -#endif update_statusbar_line(answer, statusbar_x); } @@ -651,162 +629,6 @@ void do_statusbar_verbatim_input(bool *got_enter) free(output); } -#ifndef NANO_TINY -/* Search for a match to one of the two characters in bracket_set. If - * reverse is TRUE, search backwards for the leftmost bracket. - * Otherwise, search forwards for the rightmost bracket. Return TRUE if - * we found a match, and FALSE otherwise. */ -bool find_statusbar_bracket_match(bool reverse, const char - *bracket_set) -{ - const char *rev_start = NULL, *found = NULL; - - assert(mbstrlen(bracket_set) == 2); - - /* rev_start might end up 1 character before the start or after the - * end of the line. This won't be a problem because we'll skip over - * it below in that case. */ - rev_start = reverse ? answer + (statusbar_x - 1) : answer + - (statusbar_x + 1); - - while (TRUE) { - /* Look for either of the two characters in bracket_set. - * rev_start can be 1 character before the start or after the - * end of the line. In either case, just act as though no match - * is found. */ - found = ((rev_start > answer && *(rev_start - 1) == '\0') || - rev_start < answer) ? NULL : (reverse ? - mbrevstrpbrk(answer, bracket_set, rev_start) : - mbstrpbrk(rev_start, bracket_set)); - - /* We've found a potential match. */ - if (found != NULL) - break; - - /* We've reached the start or end of the statusbar text, so - * get out. */ - return FALSE; - } - - /* We've definitely found something. */ - statusbar_x = found - answer; - statusbar_pww = statusbar_xplustabs(); - - return TRUE; -} - -/* Search for a match to the bracket at the current cursor position, if - * there is one. */ -void do_statusbar_find_bracket(void) -{ - size_t statusbar_x_save, pww_save; - const char *ch; - /* The location in matchbrackets of the bracket at the current - * cursor position. */ - int ch_len; - /* The length of ch in bytes. */ - const char *wanted_ch; - /* The location in matchbrackets of the bracket complementing - * the bracket at the current cursor position. */ - int wanted_ch_len; - /* The length of wanted_ch in bytes. */ - char *bracket_set; - /* The pair of characters in ch and wanted_ch. */ - size_t i; - /* Generic loop variable. */ - size_t matchhalf; - /* The number of single-byte characters in one half of - * matchbrackets. */ - size_t mbmatchhalf; - /* The number of multibyte characters in one half of - * matchbrackets. */ - size_t count = 1; - /* The initial bracket count. */ - bool reverse; - /* The direction we search. */ - char *found_ch; - /* The character we find. */ - - assert(mbstrlen(matchbrackets) % 2 == 0); - - ch = answer + statusbar_x; - - if (ch == '\0' || (ch = mbstrchr(matchbrackets, ch)) == NULL) - return; - - /* Save where we are. */ - statusbar_x_save = statusbar_x; - pww_save = statusbar_pww; - - /* If we're on an opening bracket, which must be in the first half - * of matchbrackets, we want to search forwards for a closing - * bracket. If we're on a closing bracket, which must be in the - * second half of matchbrackets, we want to search backwards for an - * opening bracket. */ - matchhalf = 0; - mbmatchhalf = mbstrlen(matchbrackets) / 2; - - for (i = 0; i < mbmatchhalf; i++) - matchhalf += parse_mbchar(matchbrackets + matchhalf, NULL, - NULL); - - reverse = ((ch - matchbrackets) >= matchhalf); - - /* If we're on an opening bracket, set wanted_ch to the character - * that's matchhalf characters after ch. If we're on a closing - * bracket, set wanted_ch to the character that's matchhalf - * characters before ch. */ - wanted_ch = ch; - - while (mbmatchhalf > 0) { - if (reverse) - wanted_ch = matchbrackets + move_mbleft(matchbrackets, - wanted_ch - matchbrackets); - else - wanted_ch += move_mbright(wanted_ch, 0); - - mbmatchhalf--; - } - - ch_len = parse_mbchar(ch, NULL, NULL); - wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL); - - /* Fill bracket_set in with the values of ch and wanted_ch. */ - bracket_set = charalloc((mb_cur_max() * 2) + 1); - strncpy(bracket_set, ch, ch_len); - strncpy(bracket_set + ch_len, wanted_ch, wanted_ch_len); - null_at(&bracket_set, ch_len + wanted_ch_len); - - found_ch = charalloc(mb_cur_max() + 1); - - while (TRUE) { - if (find_statusbar_bracket_match(reverse, bracket_set)) { - /* If we found an identical bracket, increment count. If we - * found a complementary bracket, decrement it. */ - parse_mbchar(answer + statusbar_x, found_ch, NULL); - count += (strncmp(found_ch, ch, ch_len) == 0) ? 1 : -1; - - /* If count is zero, we've found a matching bracket. Update - * the statusbar prompt and get out. */ - if (count == 0) { - if (need_statusbar_horizontal_update(pww_save)) - update_statusbar_line(answer, statusbar_x); - break; - } - } else { - /* We didn't find either an opening or closing bracket. - * Restore where we were, and get out. */ - statusbar_x = statusbar_x_save; - statusbar_pww = pww_save; - break; - } - } - - /* Clean up. */ - free(bracket_set); - free(found_ch); -} -#endif /* !NANO_TINY */ /* Return the placewewant associated with statusbar_x, i.e. the * zero-based column position of the cursor. The value will be no @@ -854,7 +676,9 @@ void update_statusbar_line(const char *curranswer, size_t index) index = strnlenpt(curranswer, index); page_start = get_statusbar_page_start(start_col, start_col + index); - wattron(bottomwin, reverse_attr); + if (interface_color_pair[TITLE_BAR].bright) + wattron(bottomwin, A_BOLD); + wattron(bottomwin, interface_color_pair[TITLE_BAR].pairnum); blank_statusbar(); @@ -867,7 +691,8 @@ void update_statusbar_line(const char *curranswer, size_t index) waddstr(bottomwin, expanded); free(expanded); - wattroff(bottomwin, reverse_attr); + wattroff(bottomwin, A_BOLD); + wattroff(bottomwin, interface_color_pair[TITLE_BAR].pairnum); statusbar_pww = statusbar_xplustabs(); reset_statusbar_cursor(); wnoutrefresh(bottomwin); @@ -894,30 +719,26 @@ void total_statusbar_refresh(void (*refresh_func)(void)) /* Get a string of input at the statusbar prompt. This should only be * called from do_prompt(). */ -const sc *get_prompt_string(int *actual, bool allow_tabs, +functionptrtype get_prompt_string(int *actual, bool allow_tabs, #ifndef DISABLE_TABCOMP bool allow_files, + bool *list, #endif const char *curranswer, - bool *meta_key, bool *func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES filestruct **history_list, #endif - void (*refresh_func)(void), int menu -#ifndef DISABLE_TABCOMP - , bool *list -#endif - ) + void (*refresh_func)(void)) { int kbinput = ERR; - bool have_shortcut, ran_func, finished; + bool ran_func, finished; size_t curranswer_len; - const sc *s; + functionptrtype func; #ifndef DISABLE_TABCOMP bool tabbed = FALSE; /* Whether we've pressed Tab. */ #endif -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES char *history = NULL; /* The current history string. */ char *magichistory = NULL; @@ -930,7 +751,7 @@ const sc *get_prompt_string(int *actual, bool allow_tabs, /* The length of the original string that we're trying to * tab complete, if any. */ #endif -#endif /* !NANO_TINY */ +#endif /* !DISABLE_HISTORIES */ answer = mallocstrcpy(answer, curranswer); curranswer_len = strlen(answer); @@ -953,10 +774,8 @@ const sc *get_prompt_string(int *actual, bool allow_tabs, statusbar_pww = statusbar_xplustabs(); } - currmenu = menu; - #ifdef DEBUG -fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answer, (unsigned long) statusbar_x); + fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answer, (unsigned long) statusbar_x); #endif update_statusbar_line(answer, statusbar_x); @@ -971,124 +790,108 @@ fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answe * allow writing to files not specified on the command line. In * this case, disable all keys that would change the text if the * filename isn't blank and we're at the "Write File" prompt. */ - while (1) { - kbinput = do_statusbar_input(meta_key, func_key, &have_shortcut, - &ran_func, &finished, TRUE, refresh_func); + while (TRUE) { + kbinput = do_statusbar_input(&ran_func, &finished, refresh_func); assert(statusbar_x <= strlen(answer)); - s = get_shortcut(currmenu, &kbinput, meta_key, func_key); + func = func_from_key(&kbinput); - if (s) - if (s->scfunc == CANCEL_MSG || s->scfunc == DO_ENTER) - break; + if (func == do_cancel || func == do_enter_void) + break; #ifndef DISABLE_TABCOMP - if (s && s->scfunc != DO_TAB) + if (func != do_tab) tabbed = FALSE; -#endif -#ifndef DISABLE_TABCOMP -#ifndef NANO_TINY - if (s && s->scfunc == DO_TAB) { - if (history_list != NULL) { - if (last_kbinput != sc_seq_or(DO_TAB, NANO_CONTROL_I)) - complete_len = strlen(answer); + if (func == do_tab) { +#ifndef DISABLE_HISTORIES + if (history_list != NULL) { + if (last_kbinput != sc_seq_or(do_tab, NANO_CONTROL_I)) + complete_len = strlen(answer); - if (complete_len > 0) { - answer = mallocstrcpy(answer, + if (complete_len > 0) { + answer = mallocstrcpy(answer, get_history_completion(history_list, - answer, complete_len)); - statusbar_x = strlen(answer); - } - } else -#endif /* !NANO_TINY */ - if (allow_tabs) - answer = input_tab(answer, allow_files, - &statusbar_x, &tabbed, refresh_func, list); + answer, complete_len)); + statusbar_x = strlen(answer); + } + } else +#endif + if (allow_tabs) + answer = input_tab(answer, allow_files, &statusbar_x, + &tabbed, refresh_func, list); - update_statusbar_line(answer, statusbar_x); - } else + update_statusbar_line(answer, statusbar_x); + } else #endif /* !DISABLE_TABCOMP */ -#ifndef NANO_TINY - if (s && s->scfunc == PREV_HISTORY_MSG) { - if (history_list != NULL) { - /* If we're scrolling up at the bottom of the - * history list and answer isn't blank, save answer - * in magichistory. */ - if ((*history_list)->next == NULL && - answer[0] != '\0') - magichistory = mallocstrcpy(magichistory, - answer); - - /* Get the older search from the history list and - * save it in answer. If there is no older search, - * don't do anything. */ - if ((history = - get_history_older(history_list)) != NULL) { - answer = mallocstrcpy(answer, history); - statusbar_x = strlen(answer); - } +#ifndef DISABLE_HISTORIES + if (func == get_history_older_void) { + if (history_list != NULL) { + /* If we're scrolling up at the bottom of the history list + * and answer isn't blank, save answer in magichistory. */ + if ((*history_list)->next == NULL && answer[0] != '\0') + magichistory = mallocstrcpy(magichistory, answer); + + /* Get the older search from the history list and save it in + * answer. If there is no older search, don't do anything. */ + if ((history = get_history_older(history_list)) != NULL) { + answer = mallocstrcpy(answer, history); + statusbar_x = strlen(answer); + } - update_statusbar_line(answer, statusbar_x); + update_statusbar_line(answer, statusbar_x); - /* This key has a shortcut list entry when it's used - * to move to an older search, which means that - * finished has been set to TRUE. Set it back to - * FALSE here, so that we aren't kicked out of the - * statusbar prompt. */ - finished = FALSE; + /* This key has a shortcut-list entry when it's used to + * move to an older search, which means that finished has + * been set to TRUE. Set it back to FALSE here, so that + * we aren't kicked out of the statusbar prompt. */ + finished = FALSE; + } + } else if (func == get_history_newer_void) { + if (history_list != NULL) { + /* Get the newer search from the history list and save it in + * answer. If there is no newer search, don't do anything. */ + if ((history = get_history_newer(history_list)) != NULL) { + answer = mallocstrcpy(answer, history); + statusbar_x = strlen(answer); } - } else if (s && s->scfunc == NEXT_HISTORY_MSG) { - if (history_list != NULL) { - /* Get the newer search from the history list and - * save it in answer. If there is no newer search, - * don't do anything. */ - if ((history = - get_history_newer(history_list)) != NULL) { - answer = mallocstrcpy(answer, history); - statusbar_x = strlen(answer); - } - /* If, after scrolling down, we're at the bottom of - * the history list, answer is blank, and - * magichistory is set, save magichistory in - * answer. */ - if ((*history_list)->next == NULL && - *answer == '\0' && magichistory != NULL) { + /* If, after scrolling down, we're at the bottom of the + * history list, answer is blank, and magichistory is set, + * save magichistory in answer. */ + if ((*history_list)->next == NULL && + *answer == '\0' && magichistory != NULL) { answer = mallocstrcpy(answer, magichistory); statusbar_x = strlen(answer); } - update_statusbar_line(answer, statusbar_x); - - /* This key has a shortcut list entry when it's used - * to move to a newer search, which means that - * finished has been set to TRUE. Set it back to - * FALSE here, so that we aren't kicked out of the - * statusbar prompt. */ - finished = FALSE; - } - } else -#endif /* !NANO_TINY */ - if (s && s->scfunc == DO_HELP_VOID) { update_statusbar_line(answer, statusbar_x); - /* This key has a shortcut list entry when it's used to - * go to the help browser or display a message - * indicating that help is disabled, which means that - * finished has been set to TRUE. Set it back to FALSE - * here, so that we aren't kicked out of the statusbar - * prompt. */ + /* This key has a shortcut-list entry when it's used to + * move to a newer search, which means that finished has + * been set to TRUE. Set it back to FALSE here, so that + * we aren't kicked out of the statusbar prompt. */ finished = FALSE; + } + } else +#endif /* !DISABLE_HISTORIES */ + if (func == do_help_void) { + update_statusbar_line(answer, statusbar_x); + + /* This key has a shortcut-list entry when it's used to go to + * the help browser or display a message indicating that help + * is disabled, which means that finished has been set to TRUE. + * Set it back to FALSE here, so that we aren't kicked out of + * the statusbar prompt. */ + finished = FALSE; } - /* If we have a shortcut with an associated function, break out - * if we're finished after running or trying to run the - * function. */ + /* If we have a shortcut with an associated function, break out if + * we're finished after running or trying to run the function. */ if (finished) break; -#if !defined(NANO_TINY) && !defined(DISABLE_TABCOMP) +#if !defined(DISABLE_HISTORIES) && !defined(DISABLE_TABCOMP) last_kbinput = kbinput; #endif @@ -1096,10 +899,9 @@ fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answe wnoutrefresh(bottomwin); } - -#ifndef NANO_TINY - /* Set the current position in the history list to the bottom and - * free magichistory, if we need to. */ +#ifndef DISABLE_HISTORIES + /* Set the current position in the history list to the bottom, + * and free magichistory if we need to. */ if (history_list != NULL) { history_reset(*history_list); @@ -1108,14 +910,12 @@ fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answe } #endif - /* We've finished putting in an answer or run a normal shortcut's * associated function, so reset statusbar_x and statusbar_pww. If * we've finished putting in an answer, reset the statusbar cursor * position too. */ - if (s) { - if (s->scfunc == CANCEL_MSG || s->scfunc == DO_ENTER || - ran_func) { + if (func) { + if (func == do_cancel || func == do_enter_void || ran_func) { statusbar_x = old_statusbar_x; statusbar_pww = old_pww; @@ -1129,7 +929,8 @@ fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answe } *actual = kbinput; - return s; + + return func; } /* Ask a question on the statusbar. The prompt will be stored in the @@ -1149,15 +950,14 @@ int do_prompt(bool allow_tabs, bool allow_files, #endif int menu, const char *curranswer, - bool *meta_key, bool *func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES filestruct **history_list, #endif void (*refresh_func)(void), const char *msg, ...) { va_list ap; int retval; - const sc *s; + functionptrtype func; #ifndef DISABLE_TABCOMP bool list = FALSE; #endif @@ -1169,6 +969,7 @@ int do_prompt(bool allow_tabs, prompt = charalloc(((COLS - 4) * mb_cur_max()) + 1); + currmenu = menu; bottombars(menu); va_start(ap, msg); @@ -1176,20 +977,16 @@ int do_prompt(bool allow_tabs, va_end(ap); null_at(&prompt, actual_x(prompt, COLS - 4)); - s = get_prompt_string(&retval, allow_tabs, + func = get_prompt_string(&retval, allow_tabs, #ifndef DISABLE_TABCOMP allow_files, + &list, #endif curranswer, - meta_key, func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES history_list, #endif - refresh_func, menu -#ifndef DISABLE_TABCOMP - , &list -#endif - ); + refresh_func); free(prompt); prompt = NULL; @@ -1201,9 +998,9 @@ int do_prompt(bool allow_tabs, /* If we left the prompt via Cancel or Enter, set the return value * properly. */ - if (s && s->scfunc == CANCEL_MSG) + if (func == do_cancel) retval = -1; - else if (s && s->scfunc == DO_ENTER) + else if (func == do_enter_void) retval = (*answer == '\0') ? -2 : 0; blank_statusbar(); @@ -1244,7 +1041,6 @@ int do_yesno_prompt(bool all, const char *msg) const char *yesstr; /* String of Yes characters accepted. */ const char *nostr; /* Same for No. */ const char *allstr; /* And All, surprise! */ - const sc *s; int oldmenu = currmenu; assert(msg != NULL); @@ -1288,12 +1084,15 @@ int do_yesno_prompt(bool all, const char *msg) onekey("^C", _("Cancel"), width); } - wattron(bottomwin, reverse_attr); + if (interface_color_pair[TITLE_BAR].bright) + wattron(bottomwin, A_BOLD); + wattron(bottomwin, interface_color_pair[TITLE_BAR].pairnum); blank_statusbar(); mvwaddnstr(bottomwin, 0, 0, msg, actual_x(msg, COLS - 1)); - wattroff(bottomwin, reverse_attr); + wattroff(bottomwin, A_BOLD); + wattroff(bottomwin, interface_color_pair[TITLE_BAR].pairnum); /* Refresh the edit window and the statusbar before getting * input. */ @@ -1302,16 +1101,16 @@ int do_yesno_prompt(bool all, const char *msg) do { int kbinput; - bool meta_key, func_key; + functionptrtype func; #ifndef DISABLE_MOUSE int mouse_x, mouse_y; #endif currmenu = MYESNO; - kbinput = get_kbinput(bottomwin, &meta_key, &func_key); - s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key); + kbinput = get_kbinput(bottomwin); + func = func_from_key(&kbinput); - if (s && s->scfunc == CANCEL_MSG) + if (func == do_cancel) ok = -1; #ifndef DISABLE_MOUSE else if (kbinput == KEY_MOUSE) { @@ -1343,7 +1142,7 @@ int do_yesno_prompt(bool all, const char *msg) } } #endif /* !DISABLE_MOUSE */ - else if (s && s->scfunc == TOTAL_REFRESH) { + else if (func == total_refresh) { total_redraw(); continue; } else { diff --git a/src/proto.h b/src/proto.h index e05eefe..aa79c56 100644 --- a/src/proto.h +++ b/src/proto.h @@ -1,9 +1,9 @@ -/* $Id: proto.h 4460 2009-12-09 16:51:43Z astyanax $ */ +/* $Id: proto.h 5133 2015-03-08 12:10:52Z bens $ */ /************************************************************************** * proto.h * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -30,9 +30,11 @@ #ifndef NANO_TINY extern sigjmp_buf jump_buf; extern bool jump_buf_main; -extern bool use_undo; #endif +extern bool meta_key; +extern bool func_key; + #ifndef DISABLE_WRAPJUSTIFY extern ssize_t fill; extern ssize_t wrap_at; @@ -60,13 +62,16 @@ extern openfilestruct *openfile; extern char *matchbrackets; #endif -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) extern char *whitespace; extern int whitespace_len[2]; -extern undo_type last_action; #endif +extern const char *exit_tag; +extern const char *close_tag; +extern const char *uncut_tag; #ifndef DISABLE_JUSTIFY +extern const char *unjust_tag; extern char *punct; extern char *brackets; extern char *quotestr; @@ -77,7 +82,8 @@ extern char *quoteerr; #else extern size_t quotelen; #endif -#endif +#endif /* !DISABLE_JUSTIFY */ + extern bool nodelay_mode; extern char *answer; @@ -85,6 +91,8 @@ extern ssize_t tabsize; #ifndef NANO_TINY extern char *backup_dir; +extern const char *locking_prefix; +extern const char *locking_suffix; #endif #ifndef DISABLE_OPERATINGDIR extern char *operating_dir; @@ -95,24 +103,27 @@ extern char *full_operating_dir; extern char *alt_speller; #endif -extern sc *sclist; -extern subnfunc *allfuncs; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR extern syntaxtype *syntaxes; extern char *syntaxstr; #endif extern bool edit_refresh_needed; -extern const shortcut *currshortcut; + extern int currmenu; +extern sc *sclist; +extern subnfunc *allfuncs; +extern subnfunc *exitfunc; +extern subnfunc *uncutfunc; -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES extern filestruct *search_history; extern filestruct *searchage; extern filestruct *searchbot; extern filestruct *replace_history; extern filestruct *replaceage; extern filestruct *replacebot; +extern poshiststruct *poshistory; #endif #ifdef HAVE_REGEX_H @@ -120,16 +131,22 @@ extern regex_t search_regexp; extern regmatch_t regmatches[10]; #endif -extern int reverse_attr; +extern int hilite_attribute; +#ifndef DISABLE_COLOR +extern char* specified_color_combo[NUMBER_OF_ELEMENTS]; +#endif +extern color_pair interface_color_pair[NUMBER_OF_ELEMENTS]; extern char *homedir; +typedef void (*functionptrtype)(void); + /* All functions in browser.c. */ #ifndef DISABLE_BROWSER char *do_browser(char *path, DIR *dir); char *do_browse_from(const char *inpath); void browser_init(const char *path, DIR *dir); -void parse_browser_input(int *kbinput, bool *meta_key, bool *func_key); +functionptrtype parse_browser_input(int *kbinput); void browser_refresh(void); bool browser_select_filename(const char *needle); int filesearch_init(void); @@ -148,6 +165,7 @@ char *striponedir(const char *path); void utf8_init(void); bool using_utf8(void); #endif +char *addstrings(char* str1, size_t len1, char* str2, size_t len2); #ifndef HAVE_ISBLANK bool nisblank(int c); #endif @@ -214,19 +232,19 @@ char *revstrpbrk(const char *s, const char *accept, const char char *mbrevstrpbrk(const char *s, const char *accept, const char *rev_start); #endif -#if defined(ENABLE_NANORC) && (!defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)) +#if !defined(DISABLE_NANORC) && (!defined(NANO_TINY) || !defined(DISABLE_JUSTIFY)) bool has_blank_chars(const char *s); bool has_blank_mbchars(const char *s); #endif #ifdef ENABLE_UTF8 bool is_valid_unicode(wchar_t wc); #endif -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC bool is_valid_mbstring(const char *s); #endif /* All functions in color.c. */ -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR void set_colorpairs(void); void color_init(void); void color_update(void); @@ -234,6 +252,7 @@ void color_update(void); /* All functions in cut.c. */ void cutbuffer_reset(void); +bool keeping_cutbuffer(void); void cut_line(void); #ifndef NANO_TINY void cut_marked(void); @@ -242,7 +261,7 @@ void cut_to_eof(void); #endif void do_cut_text( #ifndef NANO_TINY - bool copy_text, bool cut_till_end, bool undoing + bool copy_text, bool cut_till_eof, bool undoing #else void #endif @@ -250,7 +269,7 @@ void do_cut_text( void do_cut_text_void(void); #ifndef NANO_TINY void do_copy_text(void); -void do_cut_till_end(void); +void do_cut_till_eof(void); #endif void do_uncut_text(void); @@ -263,16 +282,16 @@ void open_buffer(const char *filename, bool undoable); void replace_buffer(const char *filename); #endif void display_buffer(void); -#ifdef ENABLE_MULTIBUFFER -void switch_to_prevnext_buffer(bool next); +#ifndef DISABLE_MULTIBUFFER +void switch_to_prevnext_buffer(bool next, bool quiet); void switch_to_prev_buffer_void(void); void switch_to_next_buffer_void(void); -bool close_buffer(void); +bool close_buffer(bool quiet); #endif filestruct *read_line(char *buf, filestruct *prevnode, bool *first_line_ins, size_t buf_len); void read_file(FILE *f, int fd, const char *filename, bool undoable, bool checkwritable); -int open_file(const char *filename, bool newfie, FILE **f); +int open_file(const char *filename, bool newfie, bool quiet, FILE **f); char *get_next_filename(const char *name, const char *suffix); void do_insertfile( #ifndef NANO_TINY @@ -291,6 +310,8 @@ bool check_operating_dir(const char *currpath, bool allow_tabcomp); #endif #ifndef NANO_TINY void init_backup_dir(void); +int delete_lockfile(const char *lockfilename); +int write_lockfile(const char *lockfilename, const char *origfilename, bool modified); #endif int copy_file(FILE *inn, FILE *out); bool write_file(const char *name, FILE *f_open, bool tmp, append_type @@ -316,46 +337,47 @@ char *input_tab(char *buf, bool allow_files, size_t *place, bool *lastwastab, void (*refresh_func)(void), bool *list); #endif const char *tail(const char *foo); -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#ifndef DISABLE_HISTORIES char *histfilename(void); void load_history(void); bool writehist(FILE *hist, filestruct *histhead); void save_history(void); +int check_dotnano(void); +void load_poshistory(void); +void save_poshistory(void); +void update_poshistory(char *filename, ssize_t lineno, ssize_t xpos); +int check_poshistory(const char *file, ssize_t *line, ssize_t *column); #endif -/* All functions in global.c. */ +/* Some functions in global.c. */ size_t length_of_list(int menu); -#ifndef NANO_TINY -void toggle_init_one(int val -#ifndef DISABLE_HELP - , const char *desc, bool blank_after -#endif - , long flag); -void toggle_init(void); -#endif -void sc_init_one(shortcut **shortcutage, int ctrlval, const char *desc -#ifndef DISABLE_HELP - , const char *help, bool blank_after +key_type strtokeytype(const char *str); +const sc *first_sc_for(int menu, void (*func)(void)); +int sc_seq_or(void (*func)(void), int defaultval); +functionptrtype func_from_key(int *kbinput); +void assign_keyinfo(sc *s); +void print_sclist(void); +void shortcut_init(void); +#ifndef DISABLE_COLOR +void set_lint_or_format_shortcuts(void); +void set_spell_shortcuts(void); #endif - , int metaval, int funcval, int miscval, bool view, void - (*func)(void)); -void shortcut_init(bool unjustify); -void free_shortcutage(shortcut **shortcutage); +const subnfunc *sctofunc(sc *s); +const char *flagtostr(int flag); +sc *strtosc(char *input); +int strtomenu(char *input); #ifdef DEBUG void thanks_for_all_the_fish(void); #endif /* All functions in help.c. */ -#ifndef DISABLE_BROWSER -void do_browser_help(void); -#endif -void do_help_void(void); #ifndef DISABLE_HELP void do_help(void (*refresh_func)(void)); void help_init(void); -void parse_help_input(int *kbinput, bool *meta_key, bool *func_key); +functionptrtype parse_help_input(int *kbinput); size_t help_line_len(const char *ptr); #endif +void do_help_void(void); /* All functions in move.c. */ void do_first_line(void); @@ -416,7 +438,7 @@ partition *partition_filestruct(filestruct *top, size_t top_x, void unpartition_filestruct(partition **p); void move_to_filestruct(filestruct **file_top, filestruct **file_bot, filestruct *top, size_t top_x, filestruct *bot, size_t bot_x); -void copy_from_filestruct(filestruct *file_top, filestruct *file_bot); +void copy_from_filestruct(filestruct *somebuffer); openfilestruct *make_new_opennode(void); void splice_opennode(openfilestruct *begin, openfilestruct *newnode, openfilestruct *end); @@ -446,7 +468,7 @@ void print_opt_full(const char *shortflag , const char *desc); void usage(void); void version(void); -int no_more_space(void); +int more_space(void); int no_help(void); void nano_disabled_msg(void); void do_exit(void); @@ -457,10 +479,9 @@ RETSIGTYPE do_continue(int signal); #ifndef NANO_TINY RETSIGTYPE handle_sigwinch(int signal); void allow_pending_sigwinch(bool allow); -#endif -#ifndef NANO_TINY void do_toggle(int flag); #endif +void do_toggle_void(void); void disable_extended_io(void); #ifdef USE_SLANG void disable_signals(void); @@ -471,17 +492,15 @@ void enable_signals(void); void disable_flow_control(void); void enable_flow_control(void); void terminal_init(void); -int do_input(bool *meta_key, bool *func_key, bool *have_shortcut, bool - *ran_func, bool *finished, bool allow_funcs); +int do_input(bool allow_funcs); #ifndef DISABLE_MOUSE int do_mouse(void); #endif void do_output(char *output, size_t output_len, bool allow_cntrls); /* All functions in prompt.c. */ -int do_statusbar_input(bool *meta_key, bool *func_key, bool *have_shortcut, - bool *ran_func, bool *finished, bool allow_funcs, void - (*refresh_func)(void)); +int do_statusbar_input(bool *ran_func, bool *finished, + void (*refresh_func)(void)); #ifndef DISABLE_MOUSE int do_statusbar_mouse(void); #endif @@ -499,66 +518,59 @@ bool do_statusbar_next_word(bool allow_punct); bool do_statusbar_prev_word(bool allow_punct); #endif void do_statusbar_verbatim_input(bool *got_enter); -#ifndef NANO_TINY -bool find_statusbar_bracket_match(bool reverse, const char - *bracket_set); -void do_statusbar_find_bracket(void); -#endif size_t statusbar_xplustabs(void); size_t get_statusbar_page_start(size_t start_col, size_t column); void reset_statusbar_cursor(void); void update_statusbar_line(const char *curranswer, size_t index); bool need_statusbar_horizontal_update(size_t pww_save); void total_statusbar_refresh(void (*refresh_func)(void)); -const sc *get_prompt_string(int *value, bool allow_tabs, +functionptrtype get_prompt_string(int *value, bool allow_tabs, #ifndef DISABLE_TABCOMP bool allow_files, + bool *list, #endif const char *curranswer, - bool *meta_key, bool *func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES filestruct **history_list, #endif - void (*refresh_func)(void), int menu -#ifndef DISABLE_TABCOMP - , bool *list -#endif - ); + void (*refresh_func)(void)); int do_prompt(bool allow_tabs, #ifndef DISABLE_TABCOMP bool allow_files, #endif int menu, const char *curranswer, - bool *meta_key, bool *func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES filestruct **history_list, #endif void (*refresh_func)(void), const char *msg, ...); void do_prompt_abort(void); int do_yesno_prompt(bool all, const char *msg); -/* All functions in rcfile.c. */ -#ifdef ENABLE_NANORC -void rcfile_error(const char *msg, ...); +/* Most functions in rcfile.c. */ +#if !defined(DISABLE_NANORC) || !defined(DISABLE_HISTORIES) char *parse_next_word(char *ptr); +#endif +#ifndef DISABLE_NANORC +void rcfile_error(const char *msg, ...); char *parse_argument(char *ptr); -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR char *parse_next_regex(char *ptr); bool nregcomp(const char *regex, int eflags); void parse_syntax(char *ptr); void parse_include(char *ptr); short color_to_short(const char *colorname, bool *bright); void parse_colors(char *ptr, bool icase); +bool parse_color_names(char *combostr, short *fg, short *bg, bool *bright); void reset_multis(filestruct *fileptr, bool force); void alloc_multidata_if_needed(filestruct *fileptr); #endif void parse_rcfile(FILE *rcstream -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR , bool syntax_only #endif ); void do_rcfile(void); -#endif +#endif /* !DISABLE_NANORC */ /* All functions in search.c. */ #ifdef HAVE_REGEX_H @@ -577,7 +589,7 @@ bool findnextstr( char *needle, size_t *needle_len); void findnextstr_wrap_reset(void); void do_search(void); -#ifndef NANO_TINY +#if !defined(NANO_TINY) || !defined(DISABLE_BROWSER) void do_research(void); #endif #ifdef HAVE_REGEX_H @@ -598,12 +610,16 @@ void do_gotolinecolumn_void(void); void do_gotopos(ssize_t pos_line, size_t pos_x, ssize_t pos_y, size_t pos_pww); #endif +void goto_line_posx(ssize_t line, size_t pos_x); #ifndef NANO_TINY bool find_bracket_match(bool reverse, const char *bracket_set); void do_find_bracket(void); -#ifdef ENABLE_NANORC -bool history_has_changed(void); +#ifndef DISABLE_TABCOMP +char *get_history_completion(filestruct **h, const char *s, size_t len); +#endif #endif +#ifndef DISABLE_HISTORIES +bool history_has_changed(void); void history_init(void); void history_reset(const filestruct *h); filestruct *find_history(const filestruct *h_start, const filestruct @@ -611,9 +627,8 @@ filestruct *find_history(const filestruct *h_start, const filestruct void update_history(filestruct **h, const char *s); char *get_history_older(filestruct **h); char *get_history_newer(filestruct **h); -#ifndef DISABLE_TABCOMP -char *get_history_completion(filestruct **h, const char *s, size_t len); -#endif +void get_history_older_void(void); +void get_history_newer_void(void); #endif /* All functions in text.c. */ @@ -631,13 +646,14 @@ void do_undo(void); void do_redo(void); #endif void do_enter(bool undoing); +void do_enter_void(void); #ifndef NANO_TINY RETSIGTYPE cancel_command(int signal); bool execute_command(const char *command); #endif #ifndef DISABLE_WRAPPING void wrap_reset(void); -bool do_wrap(filestruct *line, bool undoing); +bool do_wrap(filestruct *line); #endif #if !defined(DISABLE_HELP) || !defined(DISABLE_WRAPJUSTIFY) ssize_t break_line(const char *line, ssize_t goal @@ -670,6 +686,10 @@ const char *do_int_speller(const char *tempfile_name); const char *do_alt_speller(char *tempfile_name); void do_spell(void); #endif +#ifndef DISABLE_COLOR +void do_linter(void); +void do_formatter(void); +#endif #ifndef NANO_TINY void do_wordlinechar_count(void); #endif @@ -684,7 +704,7 @@ void align(char **str); void null_at(char **data, size_t index); void unsunder(char *str, size_t true_len); void sunder(char *str); -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) #ifndef HAVE_GETLINE ssize_t ngetline(char **lineptr, size_t *n, FILE *stream); #endif @@ -731,10 +751,10 @@ void dump_filestruct_reverse(void); void get_key_buffer(WINDOW *win); size_t get_key_buffer_len(void); void unget_input(int *input, size_t input_len); -void unget_kbinput(int kbinput, bool meta_key, bool func_key); +void unget_kbinput(int kbinput, bool metakey, bool funckey); int *get_input(WINDOW *win, size_t input_len); -int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key); -int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key); +int get_kbinput(WINDOW *win); +int parse_kbinput(WINDOW *win); int get_escape_seq_kbinput(const int *seq, size_t seq_len); int get_escape_seq_abcd(int kbinput); int parse_escape_seq_kbinput(WINDOW *win, int kbinput); @@ -750,9 +770,7 @@ int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len); #ifndef DISABLE_MOUSE int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts); #endif -const sc *get_shortcut(int menu, int *kbinput, bool - *meta_key, bool *func_key); -const sc *first_sc_for(int menu, short func); +const sc *get_shortcut(int *kbinput); void blank_line(WINDOW *win, int y, int x, int n); void blank_titlebar(void); void blank_topbar(void); @@ -763,7 +781,7 @@ void check_statusblank(void); char *display_string(const char *buf, size_t start_col, size_t len, bool dollars); void titlebar(const char *path); -void set_modified(void); +extern void set_modified(void); void statusbar(const char *msg, ...); void bottombars(int menu); void onekey(const char *keystroke, const char *desc, size_t len); @@ -783,53 +801,32 @@ void display_main_list(void); void do_cursorpos(bool constant); void do_cursorpos_void(void); void do_replace_highlight(bool highlight, const char *word); -const char *flagtostr(int flag); -const subnfunc *sctofunc(sc *s); -const subnfunc *getfuncfromkey(WINDOW *win); -void print_sclist(void); -sc *strtosc(int menu, char *input); -function_type strtokeytype(const char *str); -int strtomenu(char *input); -void assign_keyinfo(sc *s); void xon_complaint(void); void xoff_complaint(void); -int sc_seq_or (short func, int defaultval); void do_suspend_void(void); - -extern const char *cancel_msg; -#ifndef NANO_TINY -extern const char *case_sens_msg; -extern const char *backwards_msg; -extern const char *prev_history_msg; -extern const char *next_history_msg; -#endif -extern const char *replace_msg; -extern const char *no_replace_msg; -extern const char *go_to_line_msg; -extern const char *whereis_next_msg; -extern const char *first_file_msg; -extern const char *last_file_msg; -extern const char *goto_dir_msg; -extern const char *ext_cmd_msg; -extern const char *to_files_msg; -extern const char *dos_format_msg; -extern const char *mac_format_msg; -extern const char *append_msg; -extern const char *prepend_msg; -extern const char *backup_file_msg; -extern const char *gototext_msg; -extern const char *new_buffer_msg; - -void iso_me_harder_funcmap(short func); void enable_nodelay(void); void disable_nodelay(void); - -#ifdef HAVE_REGEX_H -extern const char *regexp_msg; -#endif - -#ifdef NANO_EXTRA +#ifndef DISABLE_EXTRA void do_credits(void); #endif +/* May as well throw these here, since they are just placeholders. */ +void do_cancel(void); +void do_page_up(void); +void do_page_down(void); +void case_sens_void(void); +void regexp_void(void); +void gototext_void(void); +void to_files_void(void); +void dos_format_void(void); +void mac_format_void(void); +void append_void(void); +void prepend_void(void); +void backup_file_void(void); +void new_buffer_void(void); +void backwards_void(void); +void goto_dir_void(void); +void flip_replace_void(void); +void flip_execute_void(void); + #endif /* !PROTO_H */ diff --git a/src/rcfile.c b/src/rcfile.c index 5aff6d9..a60ea69 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -1,9 +1,9 @@ -/* $Id: rcfile.c 4508 2010-06-21 03:10:10Z astyanax $ */ +/* $Id: rcfile.c 5134 2015-03-08 15:42:52Z bens $ */ /************************************************************************** * rcfile.c * * * - * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 * - * Free Software Foundation, Inc. * + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, * + * 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -23,6 +23,7 @@ #include "proto.h" +#include <glob.h> #include <stdarg.h> #include <string.h> #include <stdio.h> @@ -30,7 +31,7 @@ #include <unistd.h> #include <ctype.h> -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC static const rcoption rcopts[] = { {"boldtext", BOLD_TEXT}, @@ -41,10 +42,13 @@ static const rcoption rcopts[] = { #ifndef DISABLE_WRAPJUSTIFY {"fill", 0}, #endif +#ifndef NANO_TINY + {"locking", LOCKING}, +#endif #ifndef DISABLE_MOUSE {"mouse", USE_MOUSE}, #endif -#ifdef ENABLE_MULTIBUFFER +#ifndef DISABLE_MULTIBUFFER {"multibuffer", MULTIBUFFER}, #endif {"morespace", MORE_SPACE}, @@ -85,16 +89,22 @@ static const rcoption rcopts[] = { {"historylog", HISTORYLOG}, {"matchbrackets", 0}, {"noconvert", NO_CONVERT}, + {"poslog", POS_HISTORY}, {"quiet", QUIET}, {"quickblank", QUICK_BLANK}, {"smarthome", SMART_HOME}, {"smooth", SMOOTH_SCROLL}, {"tabstospaces", TABS_TO_SPACES}, - {"undo", UNDOABLE}, {"whitespace", 0}, {"wordbounds", WORD_BOUNDS}, {"softwrap", SOFTWRAP}, #endif +#ifndef DISABLE_COLOR + {"titlecolor", 0}, + {"statuscolor", 0}, + {"keycolor", 0}, + {"functioncolor", 0}, +#endif {NULL, 0} }; @@ -104,14 +114,11 @@ static size_t lineno = 0; /* If we did, the line number where the last error occurred. */ static char *nanorc = NULL; /* The path to the rcfile we're parsing. */ -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR static syntaxtype *endsyntax = NULL; /* The end of the list of syntaxes. */ -static exttype *endheader = NULL; - /* End of header list */ static colortype *endcolor = NULL; /* The end of the color list for the current syntax. */ - #endif /* We have an error in some part of the rcfile. Print the error message @@ -136,7 +143,9 @@ void rcfile_error(const char *msg, ...) fprintf(stderr, "\n"); } +#endif /* !DISABLE_NANORC */ +#if !defined(DISABLE_NANORC) || !defined(DISABLE_HISTORIES) /* Parse the next word from the string, null-terminate it, and return * a pointer to the first character after the null terminator. The * returned pointer will point to '\0' if we hit the end of the line. */ @@ -156,7 +165,9 @@ char *parse_next_word(char *ptr) return ptr; } +#endif /* !DISABLE_NANORC || !DISABLE_HISTORIES */ +#ifndef DISABLE_NANORC /* Parse an argument, with optional quotes, after a keyword that takes * one. If the next word starts with a ", we say that it ends with the * last " of the line. Otherwise, we interpret it as usual, so that the @@ -193,7 +204,7 @@ char *parse_argument(char *ptr) return ptr; } -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR /* Parse the next regex string from the line at ptr, and return it. */ char *parse_next_regex(char *ptr) { @@ -248,8 +259,8 @@ bool nregcomp(const char *regex, int eflags) void parse_syntax(char *ptr) { const char *fileregptr = NULL, *nameptr = NULL; - syntaxtype *tmpsyntax; - exttype *endext = NULL; + syntaxtype *tmpsyntax, *prev_syntax; + regexlisttype *endext = NULL; /* The end of the extensions list for this syntax. */ assert(ptr != NULL); @@ -275,15 +286,26 @@ void parse_syntax(char *ptr) /* Search for a duplicate syntax name. If we find one, free it, so * that we always use the last syntax with a given name. */ + prev_syntax = NULL; for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) { if (strcmp(nameptr, tmpsyntax->desc) == 0) { - syntaxtype *prev_syntax = tmpsyntax; + syntaxtype *old_syntax = tmpsyntax; + + if (endsyntax == tmpsyntax) + endsyntax = prev_syntax; tmpsyntax = tmpsyntax->next; - free(prev_syntax); + if (prev_syntax != NULL) + prev_syntax->next = tmpsyntax; + else + syntaxes = tmpsyntax; + + free(old_syntax->desc); + free(old_syntax); break; } + prev_syntax = tmpsyntax; } if (syntaxes == NULL) { @@ -300,11 +322,13 @@ void parse_syntax(char *ptr) endsyntax->desc = mallocstrcpy(NULL, nameptr); endsyntax->color = NULL; endcolor = NULL; - endheader = NULL; endsyntax->extensions = NULL; endsyntax->headers = NULL; + endsyntax->magics = NULL; endsyntax->next = NULL; endsyntax->nmultis = 0; + endsyntax->linter = NULL; + endsyntax->formatter = NULL; #ifdef DEBUG fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr); @@ -324,10 +348,9 @@ void parse_syntax(char *ptr) return; } - /* Now load the extensions into their part of the struct. */ + /* Now load the extension regexes into their part of the struct. */ while (*ptr != '\0') { - exttype *newext; - /* The new extension structure. */ + regexlisttype *newext; while (*ptr != '"' && *ptr != '\0') ptr++; @@ -342,7 +365,7 @@ void parse_syntax(char *ptr) if (ptr == NULL) break; - newext = (exttype *)nmalloc(sizeof(exttype)); + newext = (regexlisttype *)nmalloc(sizeof(regexlisttype)); /* Save the extension regex if it's valid. */ if (nregcomp(fileregptr, REG_NOSUB)) { @@ -359,29 +382,53 @@ void parse_syntax(char *ptr) free(newext); } } +#endif /* !DISABLE_COLOR */ int check_bad_binding(sc *s) { #define BADLISTLEN 1 - int badtypes[BADLISTLEN] = {META}; + key_type badtypes[BADLISTLEN] = {META}; int badseqs[BADLISTLEN] = { 91 }; int i; for (i = 0; i < BADLISTLEN; i++) - if (s->type == badtypes[i] && s->seq == badseqs[i]) + if (s->type == badtypes[i] && s->seq == badseqs[i]) return 1; return 0; } -void parse_keybinding(char *ptr) +/* Check whether the given executable function is "universal" (meaning + * any horizontal movement or deletion) and thus is present in almost + * all menus. */ +bool is_universal(void (*func)) +{ + if (func == do_left || func == do_right || + func == do_home || func == do_end || +#ifndef NANO_TINY + func == do_prev_word_void || func == do_next_word_void || +#endif + func == do_verbatim_input || func == do_cut_text_void || + func == do_delete || func == do_backspace || + func == do_tab || func == do_enter) + return TRUE; + else + return FALSE; +} + +/* Bind or unbind a key combo, to or from a function. */ +void parse_binding(char *ptr, bool dobind) { char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL; - sc *s, *newsc; - int i, menu; + sc *s, *newsc = NULL; + int menu; assert(ptr != NULL); +#ifdef DEBUG + fprintf(stderr, "Starting the rebinding code...\n"); +#endif + if (*ptr == '\0') { rcfile_error(N_("Missing key name")); return; @@ -390,206 +437,206 @@ void parse_keybinding(char *ptr) keyptr = ptr; ptr = parse_next_word(ptr); keycopy = mallocstrcpy(NULL, keyptr); - for (i = 0; i < strlen(keycopy); i++) - keycopy[i] = toupper(keycopy[i]); - if (keycopy[0] != 'M' && keycopy[0] != '^' && keycopy[0] != 'F' && keycopy[0] != 'K') { - rcfile_error( - N_("keybindings must begin with \"^\", \"M\", or \"F\"")); + if (strlen(keycopy) < 2) { + rcfile_error(N_("Key name is too short")); return; } - funcptr = ptr; - ptr = parse_next_word(ptr); - - if (!strcmp(funcptr, "")) { - rcfile_error( - N_("Must specify function to bind key to")); - return; + /* Uppercase only the first two or three characters of the key name. */ + keycopy[0] = toupper(keycopy[0]); + keycopy[1] = toupper(keycopy[1]); + if (keycopy[0] == 'M' && keycopy[1] == '-') { + if (strlen(keycopy) > 2) + keycopy[2] = toupper(keycopy[2]); + else { + rcfile_error(N_("Key name is too short")); + return; + } } - menuptr = ptr; - ptr = parse_next_word(ptr); - - if (!strcmp(menuptr, "")) { - rcfile_error( - /* Note to translators, do not translate the word "all" - in the sentence below, everything else is fine */ - N_("Must specify menu to bind key to (or \"all\")")); + /* Allow the codes for Insert and Delete to be rebound, but apart + * from those two only Control, Meta and Function sequences. */ + if (!strcasecmp(keycopy, "Ins") || !strcasecmp(keycopy, "Del")) + keycopy[1] = tolower(keycopy[1]); + else if (keycopy[0] != '^' && keycopy[0] != 'M' && keycopy[0] != 'F') { + rcfile_error(N_("Key name must begin with \"^\", \"M\", or \"F\"")); return; } - menu = strtomenu(menuptr); - newsc = strtosc(menu, funcptr); - if (newsc == NULL) { - rcfile_error( - N_("Could not map name \"%s\" to a function"), funcptr); - return; - } + if (dobind) { + funcptr = ptr; + ptr = parse_next_word(ptr); - if (menu < 1) { - rcfile_error( - N_("Could not map name \"%s\" to a menu"), menuptr); - return; + if (funcptr[0] == '\0') { + rcfile_error(N_("Must specify a function to bind the key to")); + return; + } } + menuptr = ptr; + ptr = parse_next_word(ptr); -#ifdef DEBUG - fprintf(stderr, "newsc now address %d, menu func assigned = %d, menu = %d\n", - &newsc, newsc->scfunc, menu); -#endif - - - newsc->keystr = keycopy; - newsc->menu = menu; - newsc->type = strtokeytype(newsc->keystr); - assign_keyinfo(newsc); -#ifdef DEBUG - fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr); - fprintf(stderr, "s->seq = \"%d\"\n", newsc->seq); -#endif - - if (check_bad_binding(newsc)) { - rcfile_error( - N_("Sorry, keystr \"%s\" is an illegal binding"), newsc->keystr); + if (menuptr[0] == '\0') { + /* TRANSLATORS: Do not translate the word "all". */ + rcfile_error(N_("Must specify a menu (or \"all\") in which to bind/unbind the key")); return; } - /* now let's have some fun. Try and delete the other entries - we found for the same menu, then make this new new - beginning */ - for (s = sclist; s != NULL; s = s->next) { - if (((s->menu & newsc->menu)) && s->seq == newsc->seq) { - s->menu &= ~newsc->menu; -#ifdef DEBUG - fprintf(stderr, "replaced menu entry %d\n", s->menu); -#endif + if (dobind) { + newsc = strtosc(funcptr); + if (newsc == NULL) { + rcfile_error(N_("Cannot map name \"%s\" to a function"), funcptr); + return; } } - newsc->next = sclist; - sclist = newsc; -} - -/* Let user unbind a sequence from a given (or all) menus */ -void parse_unbinding(char *ptr) -{ - char *keyptr = NULL, *keycopy = NULL, *menuptr = NULL; - sc *s; - int i, menu; - assert(ptr != NULL); - - if (*ptr == '\0') { - rcfile_error(N_("Missing key name")); + menu = strtomenu(menuptr); + if (menu < 1) { + rcfile_error(N_("Cannot map name \"%s\" to a menu"), menuptr); return; } - keyptr = ptr; - ptr = parse_next_word(ptr); - keycopy = mallocstrcpy(NULL, keyptr); - for (i = 0; i < strlen(keycopy); i++) - keycopy[i] = toupper(keycopy[i]); - #ifdef DEBUG - fprintf(stderr, "Starting unbinding code"); + if (dobind) + fprintf(stderr, "newsc address is now %ld, assigned func = %ld, menu = %x\n", + (long)&newsc, (long)newsc->scfunc, menu); + else + fprintf(stderr, "unbinding \"%s\" from menu %x\n", keycopy, menu); #endif - if (keycopy[0] != 'M' && keycopy[0] != '^' && keycopy[0] != 'F' && keycopy[0] != 'K') { - rcfile_error( - N_("keybindings must begin with \"^\", \"M\", or \"F\"")); - return; - } + if (dobind) { + subnfunc *f; + int mask = 0; - menuptr = ptr; - ptr = parse_next_word(ptr); + /* Tally up the menus where the function exists. */ + for (f = allfuncs; f != NULL; f = f->next) + if (f->scfunc == newsc->scfunc) + mask = mask | f->menus; - if (!strcmp(menuptr, "")) { - rcfile_error( - /* Note to translators, do not translate the word "all" - in the sentence below, everything else is fine */ - N_("Must specify menu to bind key to (or \"all\")")); - return; - } + /* Handle the special case of the toggles. */ + if (newsc->scfunc == do_toggle_void) + mask = MMAIN; - menu = strtomenu(menuptr); - if (menu < 1) { - rcfile_error( - N_("Could not map name \"%s\" to a menu"), menuptr); - return; - } + /* Now limit the given menu to those where the function exists. */ + if (is_universal(newsc->scfunc)) + menu = menu & MMOST; + else + menu = menu & mask; + if (!menu) { + rcfile_error(N_("Function '%s' does not exist in menu '%s'"), funcptr, menuptr); + free(newsc); + return; + } + newsc->keystr = keycopy; + newsc->menu = menu; + newsc->type = strtokeytype(newsc->keystr); + assign_keyinfo(newsc); #ifdef DEBUG - fprintf(stderr, "unbinding \"%s\" from menu = %d\n", keycopy, menu); + fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr); + fprintf(stderr, "s->seq = \"%d\"\n", newsc->seq); #endif - /* Now find the apropriate entries in the menu to delete */ + if (check_bad_binding(newsc)) { + rcfile_error(N_("Sorry, keystroke \"%s\" may not be rebound"), newsc->keystr); + free(newsc); + return; + } + } + + /* Now find and delete any existing same shortcut in the menu(s). */ for (s = sclist; s != NULL; s = s->next) { - if (((s->menu & menu)) && !strcmp(s->keystr,keycopy)) { - s->menu &= ~menu; + if (((s->menu & menu)) && !strcmp(s->keystr, keycopy)) { #ifdef DEBUG - fprintf(stderr, "deleted menu entry %d\n", s->menu); + fprintf(stderr, "deleting entry from menu %x\n", s->menu); #endif + s->menu &= ~menu; } } + + if (dobind) { + /* Add the new shortcut at the start of the list. */ + newsc->next = sclist; + sclist = newsc; + } } +#ifndef DISABLE_COLOR /* Read and parse additional syntax files. */ -void parse_include(char *ptr) +static void _parse_include(char *file) { struct stat rcinfo; FILE *rcstream; - char *option, *nanorc_save = nanorc, *expanded; - size_t lineno_save = lineno; - option = ptr; - if (*option == '"') - option++; - ptr = parse_argument(ptr); - - /* Can't get the specified file's full path cause it may screw up - our cwd depending on the parent dirs' permissions, (see Savannah bug 25297) */ + /* Can't get the specified file's full path because it may screw up + * our cwd depending on the parent directories' permissions (see + * Savannah bug #25297). */ /* Don't open directories, character files, or block files. */ - if (stat(option, &rcinfo) != -1) { + if (stat(file, &rcinfo) != -1) { if (S_ISDIR(rcinfo.st_mode) || S_ISCHR(rcinfo.st_mode) || S_ISBLK(rcinfo.st_mode)) { rcfile_error(S_ISDIR(rcinfo.st_mode) ? _("\"%s\" is a directory") : - _("\"%s\" is a device file"), option); + _("\"%s\" is a device file"), file); } } - expanded = real_dir_from_tilde(option); - /* Open the new syntax file. */ - if ((rcstream = fopen(expanded, "rb")) == NULL) { - rcfile_error(_("Error reading %s: %s"), expanded, + if ((rcstream = fopen(file, "rb")) == NULL) { + rcfile_error(_("Error reading %s: %s"), file, strerror(errno)); return; } /* Use the name and line number position of the new syntax file * while parsing it, so we can know where any errors in it are. */ - nanorc = expanded; + nanorc = file; lineno = 0; #ifdef DEBUG - fprintf(stderr, "Parsing file \"%s\" (expanded from \"%s\")\n", expanded, option); + fprintf(stderr, "Parsing file \"%s\"\n", file); #endif parse_rcfile(rcstream -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR , TRUE #endif ); +} + +void parse_include(char *ptr) +{ + char *option, *nanorc_save = nanorc, *expanded; + size_t lineno_save = lineno, i; + glob_t files; + + option = ptr; + if (*option == '"') + option++; + ptr = parse_argument(ptr); + + /* Expand tildes first, then the globs. */ + expanded = real_dir_from_tilde(option); + + if (glob(expanded, GLOB_ERR|GLOB_NOSORT, NULL, &files) == 0) { + for (i = 0; i < files.gl_pathc; ++i) + _parse_include(files.gl_pathv[i]); + } else { + rcfile_error(_("Error expanding %s: %s"), option, + strerror(errno)); + } + + globfree(&files); + free(expanded); /* We're done with the new syntax file. Restore the original * filename and line number position. */ nanorc = nanorc_save; lineno = lineno_save; - } /* Return the short value corresponding to the color named in colorname, @@ -637,7 +684,7 @@ short color_to_short(const char *colorname, bool *bright) void parse_colors(char *ptr, bool icase) { short fg, bg; - bool bright = FALSE, no_fgcolor = FALSE; + bool bright = FALSE; char *fgstr; assert(ptr != NULL); @@ -655,36 +702,8 @@ void parse_colors(char *ptr, bool icase) fgstr = ptr; ptr = parse_next_word(ptr); - - if (strchr(fgstr, ',') != NULL) { - char *bgcolorname; - - strtok(fgstr, ","); - bgcolorname = strtok(NULL, ","); - if (bgcolorname == NULL) { - /* If we have a background color without a foreground color, - * parse it properly. */ - bgcolorname = fgstr + 1; - no_fgcolor = TRUE; - } - if (strncasecmp(bgcolorname, "bright", 6) == 0) { - rcfile_error( - N_("Background color \"%s\" cannot be bright"), - bgcolorname); - return; - } - bg = color_to_short(bgcolorname, &bright); - } else - bg = -1; - - if (!no_fgcolor) { - fg = color_to_short(fgstr, &bright); - - /* Don't try to parse screwed-up foreground colors. */ - if (fg == -1) - return; - } else - fg = -1; + if (!parse_color_names(fgstr, &fg, &bg, &bright)) + return; if (*ptr == '\0') { rcfile_error(N_("Missing regex string")); @@ -695,7 +714,7 @@ void parse_colors(char *ptr, bool icase) * in the colorstrings array, woo! */ while (ptr != NULL && *ptr != '\0') { colortype *newcolor; - /* The new color structure. */ + /* The container for a color plus its regexes. */ bool cancelled = FALSE; /* The start expression was bad. */ bool expectend = FALSE; @@ -747,6 +766,10 @@ void parse_colors(char *ptr, bool icase) #ifdef DEBUG fprintf(stderr, "Adding new entry for fg %hd, bg %hd\n", fg, bg); #endif + /* Need to recompute endcolor now so we can extend + * colors to syntaxes. */ + for (endcolor = endsyntax->color; endcolor->next != NULL; endcolor = endcolor->next) + ; endcolor->next = newcolor; } @@ -776,8 +799,8 @@ void parse_colors(char *ptr, bool icase) if (ptr == NULL) break; - /* If the start regex was invalid, skip past the end regex to - * stay in sync. */ + /* If the start regex was invalid, skip past the end regex + * to stay in sync. */ if (cancelled) continue; @@ -785,17 +808,55 @@ void parse_colors(char *ptr, bool icase) newcolor->end_regex = (nregcomp(fgstr, icase ? REG_ICASE : 0)) ? mallocstrcpy(NULL, fgstr) : NULL; - /* Lame way to skip another static counter */ - newcolor->id = endsyntax->nmultis; - endsyntax->nmultis++; + /* Lame way to skip another static counter. */ + newcolor->id = endsyntax->nmultis; + endsyntax->nmultis++; } } } -/* Parse the headers (1st line) of the file which may influence the regex used. */ -void parse_headers(char *ptr) +/* Parse the color name, or pair of color names, in combostr. */ +bool parse_color_names(char *combostr, short *fg, short *bg, bool *bright) { - char *regstr; + bool no_fgcolor = FALSE; + + if (combostr == NULL) + return FALSE; + + if (strchr(combostr, ',') != NULL) { + char *bgcolorname; + strtok(combostr, ","); + bgcolorname = strtok(NULL, ","); + if (bgcolorname == NULL) { + /* If we have a background color without a foreground color, + * parse it properly. */ + bgcolorname = combostr + 1; + no_fgcolor = TRUE; + } + if (strncasecmp(bgcolorname, "bright", 6) == 0) { + rcfile_error(N_("Background color \"%s\" cannot be bright"), bgcolorname); + return FALSE; + } + *bg = color_to_short(bgcolorname, bright); + } else + *bg = -1; + + if (!no_fgcolor) { + *fg = color_to_short(combostr, bright); + + /* Don't try to parse screwed-up foreground colors. */ + if (*fg == -1) + return FALSE; + } else + *fg = -1; + + return TRUE; +} + +/* Parse the header-line regexes that may influence the choice of syntax. */ +void parse_header_exp(char *ptr) +{ + regexlisttype *endheader = NULL; assert(ptr != NULL); @@ -810,11 +871,9 @@ void parse_headers(char *ptr) return; } - /* Now for the fun part. Start adding regexes to individual strings - * in the colorstrings array, woo! */ - while (ptr != NULL && *ptr != '\0') { - exttype *newheader; - /* The new color structure. */ + while (*ptr != '\0') { + const char *regexstring; + regexlisttype *newheader; if (*ptr != '"') { rcfile_error( @@ -825,60 +884,173 @@ void parse_headers(char *ptr) ptr++; - regstr = ptr; + regexstring = ptr; ptr = parse_next_regex(ptr); if (ptr == NULL) break; - newheader = (exttype *)nmalloc(sizeof(exttype)); + newheader = (regexlisttype *)nmalloc(sizeof(regexlisttype)); - /* Save the regex string if it's valid */ - if (nregcomp(regstr, 0)) { - newheader->ext_regex = mallocstrcpy(NULL, regstr); + /* Save the regex string if it's valid. */ + if (nregcomp(regexstring, 0)) { + newheader->ext_regex = mallocstrcpy(NULL, regexstring); newheader->ext = NULL; - newheader->next = NULL; - -#ifdef DEBUG - fprintf(stderr, "Starting a new header entry: %s\n", newheader->ext_regex); -#endif - if (endheader == NULL) { + if (endheader == NULL) endsyntax->headers = newheader; - } else { + else endheader->next = newheader; - } - endheader = newheader; + endheader->next = NULL; } else free(newheader); + } +} + +#ifndef DISABLE_COLOR +/* Parse the magic regexes that may influence the choice of syntax. */ +void parse_magic_exp(char *ptr) +{ +#ifdef HAVE_LIBMAGIC + regexlisttype *endmagic = NULL; + assert(ptr != NULL); + + if (syntaxes == NULL) { + rcfile_error( + N_("Cannot add a magic string regex without a syntax command")); + return; + } + + if (*ptr == '\0') { + rcfile_error(N_("Missing magic string name")); + return; } + + if (*ptr != '"') { + rcfile_error( + N_("Regex strings must begin and end with a \" character")); + return; + } + +#ifdef DEBUG + fprintf(stderr, "Starting a magic type: \"%s\"\n", ptr); +#endif + + /* Now load the magic regexes into their part of the struct. */ + while (*ptr != '\0') { + const char *regexstring; + regexlisttype *newmagic; + + while (*ptr != '"' && *ptr != '\0') + ptr++; + + if (*ptr == '\0') + return; + + ptr++; + + regexstring = ptr; + ptr = parse_next_regex(ptr); + if (ptr == NULL) + break; + + newmagic = (regexlisttype *)nmalloc(sizeof(regexlisttype)); + + /* Save the regex string if it's valid. */ + if (nregcomp(regexstring, REG_NOSUB)) { + newmagic->ext_regex = mallocstrcpy(NULL, regexstring); + newmagic->ext = NULL; + + if (endmagic == NULL) + endsyntax->magics = newmagic; + else + endmagic->next = newmagic; + endmagic = newmagic; + endmagic->next = NULL; + } else + free(newmagic); + } +#endif /* HAVE_LIBMAGIC */ } -#endif /* ENABLE_COLOR */ +#endif /* !DISABLE_COLOR */ + +/* Parse the linter requested for this syntax. Simple? */ +void parse_linter(char *ptr) +{ + assert(ptr != NULL); + + if (syntaxes == NULL) { + rcfile_error( + N_("Cannot add a linter without a syntax command")); + return; + } + + if (*ptr == '\0') { + rcfile_error(N_("Missing linter command")); + return; + } + + if (endsyntax->linter != NULL) + free(endsyntax->linter); + + /* Let them unset the linter by using "". */ + if (!strcmp(ptr, "\"\"")) + endsyntax->linter = NULL; + else + endsyntax->linter = mallocstrcpy(syntaxes->linter, ptr); +} + +void parse_formatter(char *ptr) +{ + assert(ptr != NULL); + + if (syntaxes == NULL) { + rcfile_error( + N_("Cannot add formatter without a syntax command")); + return; + } + + if (*ptr == '\0') { + rcfile_error(N_("Missing formatter command")); + return; + } + + if (endsyntax->formatter != NULL) + free(endsyntax->formatter); + + /* Let them unset the formatter by using "". */ + if (!strcmp(ptr, "\"\"")) + endsyntax->formatter = NULL; + else + endsyntax->formatter = mallocstrcpy(syntaxes->formatter, ptr); +} +#endif /* !DISABLE_COLOR */ /* Check whether the user has unmapped every shortcut for a -sequence we consider 'vital', like the exit function */ + * sequence we consider 'vital', like the exit function. */ static void check_vitals_mapped(void) { subnfunc *f; int v; #define VITALS 5 - short vitals[VITALS] = { DO_EXIT, DO_EXIT, CANCEL_MSG, CANCEL_MSG, CANCEL_MSG }; + void (*vitals[VITALS])(void) = { do_exit, do_exit, do_cancel, do_cancel, do_cancel }; int inmenus[VITALS] = { MMAIN, MHELP, MWHEREIS, MREPLACE, MGOTOLINE }; for (v = 0; v < VITALS; v++) { - for (f = allfuncs; f != NULL; f = f->next) { - if (f->scfunc == vitals[v] && f->menus & inmenus[v]) { - const sc *s = first_sc_for(inmenus[v], f->scfunc); - if (!s) { - rcfile_error(N_("Fatal error: no keys mapped for function \"%s\""), - f->desc); - fprintf(stderr, N_("Exiting. Please use nano with the -I option if needed to adjust your nanorc settings\n")); - exit(1); - } - break; - } - } + for (f = allfuncs; f != NULL; f = f->next) { + if (f->scfunc == vitals[v] && f->menus & inmenus[v]) { + const sc *s = first_sc_for(inmenus[v], f->scfunc); + if (!s) { + fprintf(stderr, _("Fatal error: no keys mapped for function " + "\"%s\". Exiting.\n"), f->desc); + fprintf(stderr, _("If needed, use nano with the -I option " + "to adjust your nanorc settings.\n")); + exit(1); + } + break; + } + } } } @@ -886,7 +1058,7 @@ static void check_vitals_mapped(void) * and close it afterwards. If syntax_only is TRUE, only allow the file * to contain color syntax commands: syntax, color, and icolor. */ void parse_rcfile(FILE *rcstream -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR , bool syntax_only #endif ) @@ -894,6 +1066,9 @@ void parse_rcfile(FILE *rcstream char *buf = NULL; ssize_t len; size_t n = 0; +#ifndef DISABLE_COLOR + syntaxtype *end_syn_save = NULL; +#endif while ((len = getline(&buf, &n, rcstream)) > 0) { char *ptr, *keyword, *option; @@ -918,9 +1093,32 @@ void parse_rcfile(FILE *rcstream keyword = ptr; ptr = parse_next_word(ptr); +#ifndef DISABLE_COLOR + /* Handle extending first... */ + if (strcasecmp(keyword, "extendsyntax") == 0) { + char *syntaxname = ptr; + syntaxtype *ts = NULL; + + ptr = parse_next_word(ptr); + for (ts = syntaxes; ts != NULL; ts = ts->next) + if (!strcmp(ts->desc, syntaxname)) + break; + + if (ts == NULL) { + rcfile_error(N_("Could not find syntax \"%s\" to extend"), syntaxname); + continue; + } else { + end_syn_save = endsyntax; + endsyntax = ts; + keyword = ptr; + ptr = parse_next_word(ptr); + } + } +#endif + /* Try to parse the keyword. */ if (strcasecmp(keyword, "set") == 0) { -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR if (syntax_only) rcfile_error( N_("Command \"%s\" not allowed in included file"), @@ -929,7 +1127,7 @@ void parse_rcfile(FILE *rcstream #endif set = 1; } else if (strcasecmp(keyword, "unset") == 0) { -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR if (syntax_only) rcfile_error( N_("Command \"%s\" not allowed in included file"), @@ -938,7 +1136,7 @@ void parse_rcfile(FILE *rcstream #endif set = -1; } -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR else if (strcasecmp(keyword, "include") == 0) { if (syntax_only) rcfile_error( @@ -951,25 +1149,41 @@ void parse_rcfile(FILE *rcstream rcfile_error(N_("Syntax \"%s\" has no color commands"), endsyntax->desc); parse_syntax(ptr); - } else if (strcasecmp(keyword, "header") == 0) - parse_headers(ptr); + } + else if (strcasecmp(keyword, "magic") == 0) + parse_magic_exp(ptr); + else if (strcasecmp(keyword, "header") == 0) + parse_header_exp(ptr); else if (strcasecmp(keyword, "color") == 0) parse_colors(ptr, FALSE); else if (strcasecmp(keyword, "icolor") == 0) parse_colors(ptr, TRUE); + else if (strcasecmp(keyword, "linter") == 0) + parse_linter(ptr); + else if (strcasecmp(keyword, "formatter") == 0) + parse_formatter(ptr); +#endif /* !DISABLE_COLOR */ else if (strcasecmp(keyword, "bind") == 0) - parse_keybinding(ptr); + parse_binding(ptr, TRUE); else if (strcasecmp(keyword, "unbind") == 0) - parse_unbinding(ptr); -#endif /* ENABLE_COLOR */ + parse_binding(ptr, FALSE); else rcfile_error(N_("Command \"%s\" not understood"), keyword); +#ifndef DISABLE_COLOR + /* If we temporarily reset endsyntax to allow extending, + * restore the value here. */ + if (end_syn_save != NULL) { + endsyntax = end_syn_save; + end_syn_save = NULL; + } +#endif + if (set == 0) continue; if (*ptr == '\0') { - rcfile_error(N_("Missing flag")); + rcfile_error(N_("Missing option")); continue; } @@ -1013,6 +1227,17 @@ void parse_rcfile(FILE *rcstream break; } +#ifndef DISABLE_COLOR + if (strcasecmp(rcopts[i].name, "titlecolor") == 0) + specified_color_combo[TITLE_BAR] = option; + else if (strcasecmp(rcopts[i].name, "statuscolor") == 0) + specified_color_combo[STATUS_BAR] = option; + else if (strcasecmp(rcopts[i].name, "keycolor") == 0) + specified_color_combo[KEY_COMBO] = option; + else if (strcasecmp(rcopts[i].name, "functioncolor") == 0) + specified_color_combo[FUNCTION_TAG] = option; + else +#endif #ifndef DISABLE_OPERATINGDIR if (strcasecmp(rcopts[i].name, "operatingdir") == 0) operating_dir = option; @@ -1111,19 +1336,16 @@ void parse_rcfile(FILE *rcstream } else if (rcopts[i].flag != 0) UNSET(rcopts[i].flag); else - rcfile_error(N_("Cannot unset flag \"%s\""), + rcfile_error(N_("Cannot unset option \"%s\""), rcopts[i].name); - /* Looks like we still need this specific hack for undo */ - if (strcasecmp(rcopts[i].name, "undo") == 0) - shortcut_init(0); break; } } if (rcopts[i].name == NULL) - rcfile_error(N_("Unknown flag \"%s\""), option); + rcfile_error(N_("Unknown option \"%s\""), option); } -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR if (endsyntax != NULL && endcolor == NULL) rcfile_error(N_("Syntax \"%s\" has no color commands"), endsyntax->desc); @@ -1163,7 +1385,7 @@ void do_rcfile(void) rcstream = fopen(nanorc, "rb"); if (rcstream != NULL) parse_rcfile(rcstream -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR , FALSE #endif ); @@ -1205,7 +1427,7 @@ void do_rcfile(void) strerror(errno)); } else parse_rcfile(rcstream -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR , FALSE #endif ); @@ -1221,10 +1443,6 @@ void do_rcfile(void) while (getchar() != '\n') ; } - -#ifdef ENABLE_COLOR - set_colorpairs(); -#endif } -#endif /* ENABLE_NANORC */ +#endif /* !DISABLE_NANORC */ diff --git a/src/search.c b/src/search.c index 4b93045..eb3bfb2 100644 --- a/src/search.c +++ b/src/search.c @@ -1,9 +1,9 @@ -/* $Id: search.c 4472 2010-01-05 23:35:50Z astyanax $ */ +/* $Id: search.c 5148 2015-03-22 11:42:29Z bens $ */ /************************************************************************** * search.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -32,7 +32,7 @@ static bool search_last_line = FALSE; /* Have we gone past the last line while searching? */ -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#ifndef DISABLE_HISTORIES static bool history_changed = FALSE; /* Have any of the history lists changed? */ #endif @@ -137,9 +137,6 @@ int search_init(bool replacing, bool use_answer) { int i = 0; char *buf; - sc *s; - char func = 0; - bool meta_key = FALSE, func_key = FALSE; static char *backupstring = NULL; /* The search string we'll be using. */ @@ -164,8 +161,7 @@ int search_init(bool replacing, bool use_answer) char *disp = display_string(last_search, 0, COLS / 3, FALSE); buf = charalloc(strlen(disp) + 7); - /* We use (COLS / 3) here because we need to see more on the - * line. */ + /* We use (COLS / 3) here because we need to see more on the line. */ sprintf(buf, " [%s%s]", disp, (strlenpt(last_search) > COLS / 3) ? "..." : ""); free(disp); @@ -178,30 +174,26 @@ int search_init(bool replacing, bool use_answer) TRUE, #endif replacing ? MREPLACE : MWHEREIS, backupstring, - &meta_key, &func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES &search_history, #endif + /* TRANSLATORS: This is the main search prompt. */ edit_refresh, "%s%s%s%s%s%s", _("Search"), #ifndef NANO_TINY - /* TRANSLATORS: This string is just a modifier for the search - * prompt; no grammar is implied. */ + /* TRANSLATORS: The next three strings are modifiers of the search prompt. */ ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : #endif "", #ifdef HAVE_REGEX_H - /* TRANSLATORS: This string is just a modifier for the search - * prompt; no grammar is implied. */ ISSET(USE_REGEXP) ? _(" [Regexp]") : #endif "", #ifndef NANO_TINY - /* TRANSLATORS: This string is just a modifier for the search - * prompt; no grammar is implied. */ ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : #endif "", replacing ? #ifndef NANO_TINY + /* TRANSLATORS: The next two strings are modifiers of the search prompt. */ openfile->mark_set ? _(" (to replace) in selection") : #endif _(" (to replace)") : "", buf); @@ -220,11 +212,7 @@ int search_init(bool replacing, bool use_answer) statusbar(_("Cancelled")); return -1; } else { - for (s = sclist; s != NULL; s = s->next) - if ((s->menu & currmenu) && i == s->seq) { - func = s->scfunc; - break; - } + functionptrtype func = func_from_key(&i); if (i == -2 || i == 0 ) { #ifdef HAVE_REGEX_H @@ -236,26 +224,25 @@ int search_init(bool replacing, bool use_answer) #endif ; #ifndef NANO_TINY - } else if (func == CASE_SENS_MSG) { + } else if (func == case_sens_void) { TOGGLE(CASE_SENSITIVE); backupstring = mallocstrcpy(backupstring, answer); return 1; - } else if (func == BACKWARDS_MSG) { + } else if (func == backwards_void) { TOGGLE(BACKWARDS_SEARCH); backupstring = mallocstrcpy(backupstring, answer); return 1; #endif #ifdef HAVE_REGEX_H - } else if (func == REGEXP_MSG) { + } else if (func == regexp_void) { TOGGLE(USE_REGEXP); backupstring = mallocstrcpy(backupstring, answer); return 1; #endif - } else if (func == DO_REPLACE || - func == NO_REPLACE_MSG) { + } else if (func == do_replace || func == flip_replace_void) { backupstring = mallocstrcpy(backupstring, answer); return -2; /* Call the opposite search function. */ - } else if (func == DO_GOTOLINECOLUMN_VOID) { + } else if (func == do_gotolinecolumn_void) { do_gotolinecolumn(openfile->current->lineno, openfile->placewewant + 1, TRUE, TRUE, FALSE, TRUE); @@ -289,7 +276,6 @@ bool findnextstr( ssize_t current_y_find = openfile->current_y; filestruct *fileptr = openfile->current; const char *rev_start = fileptr->data, *found = NULL; - const subnfunc *f; time_t lastkbcheck = time(NULL); /* rev_start might end up 1 character before the start or after the @@ -300,17 +286,19 @@ bool findnextstr( rev_start += #ifndef NANO_TINY ISSET(BACKWARDS_SEARCH) ? - openfile->current_x - 1 : + ((openfile->current_x == 0) ? -1 : move_mbleft(fileptr->data, openfile->current_x)) : #endif - openfile->current_x + 1; + move_mbright(fileptr->data, openfile->current_x); /* Look for needle in the current line we're searching. */ enable_nodelay(); while (TRUE) { - if (time(NULL) - lastkbcheck > 1) { - lastkbcheck = time(NULL); - f = getfuncfromkey(edit); - if (f && f->scfunc == CANCEL_MSG) { + if (time(NULL) - lastkbcheck > 1) { + int input = parse_kbinput(edit); + + lastkbcheck = time(NULL); + + if (input && func_from_key(&input) == do_cancel) { statusbar(_("Cancelled")); return FALSE; } @@ -358,10 +346,10 @@ bool findnextstr( break; } - /* We've finished processing the file, so get out. */ if (search_last_line) { + /* We've finished processing the file, so get out. */ not_found_msg(needle); - disable_nodelay(); + disable_nodelay(); return FALSE; } @@ -378,9 +366,8 @@ bool findnextstr( } #endif - /* We've reached the start or end of the buffer, so wrap - * around. */ if (fileptr == NULL) { + /* We've reached the start or end of the buffer, so wrap around. */ #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) { fileptr = openfile->filebot; @@ -395,8 +382,8 @@ bool findnextstr( statusbar(_("Search Wrapped")); } - /* We've reached the original starting line. */ if (fileptr == begin) + /* We've reached the original starting line. */ search_last_line = TRUE; rev_start = fileptr->data; @@ -456,8 +443,7 @@ void do_search(void) i = search_init(FALSE, FALSE); if (i == -1) - /* Cancel, Go to Line, blank search string, or regcomp() - * failed. */ + /* Cancel, Go to Line, blank search string, or regcomp() failed. */ search_replace_abort(); else if (i == -2) /* Replace. */ @@ -477,7 +463,7 @@ void do_search(void) else last_search = mallocstrcpy(last_search, answer); -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES /* If answer is not "", add this search string to the search history * list. */ if (answer[0] != '\0') @@ -525,7 +511,7 @@ void do_search(void) search_replace_abort(); } -#ifndef NANO_TINY +#if !defined(NANO_TINY) || !defined(DISABLE_BROWSER) /* Search for the last string without prompting. */ void do_research(void) { @@ -573,20 +559,20 @@ void do_research(void) openfile->current_x && !didfind) statusbar(_("This is the only occurrence")); } else { -#endif +#endif /* HAVE_REGEX_H */ statusbar(_("This is the only occurrence")); #ifdef HAVE_REGEX_H } #endif } } else - statusbar(_("No current search pattern")); + statusbar(_("No current search pattern")); openfile->placewewant = xplustabs(); edit_redraw(fileptr, pww_save); search_replace_abort(); } -#endif +#endif /* !NANO_TINY */ #ifdef HAVE_REGEX_H int replace_regexp(char *string, bool create) @@ -636,7 +622,7 @@ int replace_regexp(char *string, bool create) return new_line_size; } -#endif +#endif /* HAVE_REGEX_H */ char *replace_line(const char *needle) { @@ -719,12 +705,12 @@ ssize_t do_replace_loop( filepart = partition_filestruct(top, top_x, bot, bot_x); openfile->edittop = openfile->fileage; openfile->mark_set = FALSE; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR reset_multis(openfile->current, TRUE); #endif edit_refresh(); } -#endif +#endif /* !NANO_TINY */ if (canceled != NULL) *canceled = FALSE; @@ -751,12 +737,10 @@ ssize_t do_replace_loop( * beginning line already, and we're still on the beginning line * after the search, it means that we've wrapped around, so * we're done. */ - if (bol_or_eol && begin_line && openfile->current == - real_current) + if (bol_or_eol && begin_line && openfile->current == real_current) break; /* Otherwise, set the begin_line flag if we've found a match on - * the beginning line, reset the bol_or_eol flag, and - * continue. */ + * the beginning line, reset the bol_or_eol flag, and continue. */ else { if (openfile->current == real_current) begin_line = TRUE; @@ -781,6 +765,7 @@ ssize_t do_replace_loop( do_replace_highlight(TRUE, exp_word); + /* TRANSLATORS: This is a prompt. */ i = do_yesno_prompt(TRUE, _("Replace this instance?")); do_replace_highlight(FALSE, exp_word); @@ -860,18 +845,18 @@ ssize_t do_replace_loop( #endif openfile->current_x += match_len + length_change - 1; - /* Cleanup. */ + /* Clean up. */ openfile->totsize += mbstrlen(copy) - mbstrlen(openfile->current->data); free(openfile->current->data); openfile->current->data = copy; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR reset_multis(openfile->current, TRUE); #endif edit_refresh(); if (!replaceall) { -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR /* If color syntaxes are available and turned on, we * need to call edit_refresh(). */ if (openfile->colorstrings != NULL && @@ -912,7 +897,6 @@ void do_replace(void) { filestruct *edittop_save, *begin; size_t begin_x, pww_save; - bool meta_key = FALSE, func_key = FALSE; ssize_t numreplaced; int i; @@ -924,8 +908,7 @@ void do_replace(void) i = search_init(TRUE, FALSE); if (i == -1) { - /* Cancel, Go to Line, blank search string, or regcomp() - * failed. */ + /* Cancel, Go to Line, blank search string, or regcomp() failed. */ search_replace_abort(); return; } else if (i == -2) { @@ -942,7 +925,7 @@ void do_replace(void) /* If answer is not "", add answer to the search history list and * copy answer into last_search. */ if (answer[0] != '\0') { -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES update_history(&search_history, answer); #endif last_search = mallocstrcpy(last_search, answer); @@ -954,16 +937,15 @@ void do_replace(void) #ifndef DISABLE_TABCOMP TRUE, #endif - MREPLACE2, last_replace, - &meta_key, &func_key, -#ifndef NANO_TINY + MREPLACEWITH, last_replace, +#ifndef DISABLE_HISTORIES &replace_history, #endif + /* TRANSLATORS: This is a prompt. */ edit_refresh, _("Replace with")); -#ifndef NANO_TINY - /* Add this replace string to the replace history list. i == 0 - * means that the string is not "". */ +#ifndef DISABLE_HISTORIES + /* If the replace string is not "", add it to the replace history list. */ if (i == 0) update_history(&replace_history, answer); #endif @@ -1008,6 +990,19 @@ void do_replace(void) search_replace_abort(); } +/* Go to the specified line and x position. */ +void goto_line_posx(ssize_t line, size_t pos_x) +{ + for (openfile->current = openfile->fileage; openfile->current != openfile->filebot && + openfile->current->next != NULL && line > 1; line--) + openfile->current = openfile->current->next; + + openfile->current_x = pos_x; + openfile->placewewant = xplustabs(); + + edit_refresh_needed = TRUE; +} + /* Go to the specified line and column, or ask for them if interactive * is TRUE. Save the x-coordinate and y-coordinate if save_pos is TRUE. * Update the screen afterwards if allow_update is TRUE. Note that both @@ -1015,11 +1010,9 @@ void do_replace(void) void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer, bool interactive, bool save_pos, bool allow_update) { - bool meta_key = FALSE, func_key = FALSE; - const sc *s; - if (interactive) { char *ans = mallocstrcpy(NULL, answer); + functionptrtype func; /* Ask for the line and column. */ int i = do_prompt(FALSE, @@ -1027,10 +1020,10 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer, TRUE, #endif MGOTOLINE, use_answer ? ans : "", - &meta_key, &func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES NULL, #endif + /* TRANSLATORS: This is a prompt. */ edit_refresh, _("Enter line number, column number")); free(ans); @@ -1042,9 +1035,9 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer, return; } + func = func_from_key(&i); - s = get_shortcut(currmenu, &i, &meta_key, &func_key); - if (s && s->scfunc == GOTOTEXT_MSG) { + if (func == gototext_void) { /* Keep answer up on the statusbar. */ search_init(TRUE, TRUE); @@ -1083,10 +1076,10 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer, edit_update(save_pos ? NONE : CENTER); /* If allow_update is TRUE, update the screen. */ - if (allow_update) + if (allow_update) { edit_refresh(); - - display_main_list(); + display_main_list(); + } } /* Go to the specified line and column, asking for them beforehand. */ @@ -1143,8 +1136,8 @@ bool find_bracket_match(bool reverse, const char *bracket_set) mbrevstrpbrk(fileptr->data, bracket_set, rev_start) : mbstrpbrk(rev_start, bracket_set)); - /* We've found a potential match. */ if (found != NULL) + /* We've found a potential match. */ break; if (reverse) { @@ -1155,8 +1148,8 @@ bool find_bracket_match(bool reverse, const char *bracket_set) current_y_find++; } - /* We've reached the start or end of the buffer, so get out. */ if (fileptr == NULL) + /* We've reached the start or end of the buffer, so get out. */ return FALSE; rev_start = fileptr->data; @@ -1290,14 +1283,14 @@ void do_find_bracket(void) free(bracket_set); free(found_ch); } +#endif /* !NANO_TINY */ -#ifdef ENABLE_NANORC +#ifndef DISABLE_HISTORIES /* Indicate whether any of the history lists have changed. */ bool history_has_changed(void) { return history_changed; } -#endif /* Initialize the search and replace history lists. */ void history_init(void) @@ -1372,8 +1365,7 @@ void update_history(filestruct **h, const char *s) bar = p->next; unlink_node(foo); delete_node(foo); - if (bar != NULL) - renumber(bar); + renumber(bar); } /* If the history is full, delete the beginning entry to make room @@ -1394,10 +1386,8 @@ void update_history(filestruct **h, const char *s) *hbot = (*hbot)->next; (*hbot)->data = mallocstrcpy(NULL, ""); -#ifdef ENABLE_NANORC /* Indicate that the history's been changed. */ history_changed = TRUE; -#endif /* Set the current position in the list to the bottom. */ *h = *hbot; @@ -1431,6 +1421,16 @@ char *get_history_newer(filestruct **h) return (*h)->data; } +/* More placeholders. */ +void get_history_newer_void(void) +{ + ; +} +void get_history_older_void(void) +{ + ; +} + #ifndef DISABLE_TABCOMP /* Move h to the next string that's a tab completion of the string s, * looking at only the first len characters of s, and return that @@ -1486,4 +1486,4 @@ char *get_history_completion(filestruct **h, const char *s, size_t len) return (char *)s; } #endif /* !DISABLE_TABCOMP */ -#endif /* !NANO_TINY */ +#endif /* !DISABLE_HISTORIES */ @@ -1,9 +1,9 @@ -/* $Id: text.c 4520 2010-11-12 06:23:14Z astyanax $ */ +/* $Id: text.c 5145 2015-03-21 21:13:03Z bens $ */ /************************************************************************** * text.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -64,12 +64,10 @@ void do_mark(void) #endif /* !NANO_TINY */ /* Delete the character under the cursor. */ -void do_delete(void) +void do_deletion(undo_type action) { - size_t orig_lenpt = 0; - #ifndef NANO_TINY - update_undo(DEL); + size_t orig_lenpt = 0; #endif assert(openfile->current != NULL && openfile->current->data != NULL && openfile->current_x <= strlen(openfile->current->data)); @@ -84,8 +82,12 @@ void do_delete(void) assert(openfile->current_x < strlen(openfile->current->data)); +#ifndef NANO_TINY + update_undo(action); + if (ISSET(SOFTWRAP)) orig_lenpt = strlenpt(openfile->current->data); +#endif /* Let's get dangerous. */ charmove(&openfile->current->data[openfile->current_x], @@ -106,15 +108,17 @@ void do_delete(void) assert(openfile->current_x == strlen(openfile->current->data)); +#ifndef NANO_TINY + add_undo(action); +#endif /* If we're deleting at the end of a line, we need to call * edit_refresh(). */ if (openfile->current->data[openfile->current_x] == '\0') edit_refresh_needed = TRUE; openfile->current->data = charealloc(openfile->current->data, - openfile->current_x + strlen(foo->data) + 1); - strcpy(openfile->current->data + openfile->current_x, - foo->data); + strlen(openfile->current->data) + strlen(foo->data) + 1); + strcat(openfile->current->data, foo->data); #ifndef NANO_TINY if (openfile->mark_set && openfile->mark_begin == openfile->current->next) { @@ -139,16 +143,23 @@ void do_delete(void) } else return; +#ifndef NANO_TINY if (ISSET(SOFTWRAP) && edit_refresh_needed == FALSE) if (strlenpt(openfile->current->data) / COLS != orig_lenpt / COLS) - edit_refresh_needed = TRUE; + edit_refresh_needed = TRUE; +#endif set_modified(); - if (edit_refresh_needed == FALSE) + if (edit_refresh_needed == FALSE) update_line(openfile->current, openfile->current_x); } +void do_delete(void) +{ + do_deletion(DEL); +} + /* Backspace over one character. That is, move the cursor left one * character, and then delete the character under the cursor. */ void do_backspace(void) @@ -156,7 +167,7 @@ void do_backspace(void) if (openfile->current != openfile->fileage || openfile->current_x > 0) { do_left(); - do_delete(); + do_deletion(BACK); } } @@ -216,8 +227,7 @@ void do_indent(ssize_t cols) if (cols == 0) return; - /* If cols is negative, make it positive and set unindent to - * TRUE. */ + /* If cols is negative, make it positive and set unindent to TRUE. */ if (cols < 0) { cols = -cols; unindent = TRUE; @@ -360,99 +370,79 @@ void do_unindent(void) do_indent(-tabsize); } -/* undo a cut, or re-do an uncut */ +#define redo_paste undo_cut +#define undo_paste redo_cut + +/* Undo a cut, or redo an uncut. */ void undo_cut(undo *u) { - /* If we cut the magicline may was well not crash :/ */ + /* If we cut the magicline, we may as well not crash. :/ */ if (!u->cutbuffer) return; - cutbuffer = copy_filestruct(u->cutbuffer); - - /* Compute cutbottom for the uncut using out copy */ - for (cutbottom = cutbuffer; cutbottom->next != NULL; cutbottom = cutbottom->next) - ; - - /* Get to where we need to uncut from */ - if (u->mark_set && u->mark_begin_lineno < u->lineno) - do_gotolinecolumn(u->mark_begin_lineno, u->mark_begin_x+1, FALSE, FALSE, FALSE, FALSE); + /* Get to where we need to uncut from. */ + if (u->xflags == UNcut_cutline) + goto_line_posx(u->mark_begin_lineno, 0); else - do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE); + goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); - copy_from_filestruct(cutbuffer, cutbottom); - free_filestruct(cutbuffer); - cutbuffer = NULL; + copy_from_filestruct(u->cutbuffer); + if (u->xflags != UNcut_marked_forward && u->type != PASTE) + goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); } -/* Re-do a cut, or undo an uncut */ -void redo_cut(undo *u) { - int i; - filestruct *t, *c; - - /* If we cut the magicline may was well not crash :/ */ +/* Redo a cut, or undo an uncut. */ +void redo_cut(undo *u) +{ + /* If we cut the magicline, we may as well not crash. :/ */ if (!u->cutbuffer) return; - do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE); - openfile->mark_set = u->mark_set; - if (cutbuffer) - free(cutbuffer); + filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom; cutbuffer = NULL; + cutbottom = NULL; - /* Move ahead the same # lines we had if a marked cut */ - if (u->mark_set) { - for (i = 1, t = openfile->fileage; i != u->mark_begin_lineno; i++) - t = t->next; - openfile->mark_begin = t; - } else if (!u->to_end) { - /* Here we have a regular old potentially multi-line ^K cut. We'll - need to trick nano into thinking it's a marked cut to cut more - than one line again */ - for (c = u->cutbuffer, t = openfile->current; c->next != NULL && t->next != NULL; ) { + goto_line_posx(u->lineno, u->begin); -#ifdef DEBUG - fprintf(stderr, "Advancing, lineno = %lu, data = \"%s\"\n", (unsigned long) t->lineno, t->data); -#endif - c = c->next; - t = t->next; - } - openfile->mark_begin = t; - openfile->mark_begin_x = 0; - openfile->mark_set = TRUE; + if (ISSET(NO_NEWLINES) && openfile->current->lineno != u->lineno) { + openfile->current_x = strlen(openfile->current->data); + openfile->placewewant = xplustabs(); } - openfile->mark_begin_x = u->mark_begin_x; - do_cut_text(FALSE, u->to_end, TRUE); + openfile->mark_set = TRUE; + openfile->mark_begin = fsfromline(u->mark_begin_lineno); + openfile->mark_begin_x = (u->xflags == UNcut_cutline) ? 0 : u->mark_begin_x; + + do_cut_text(FALSE, FALSE, TRUE); + openfile->mark_set = FALSE; openfile->mark_begin = NULL; openfile->mark_begin_x = 0; edit_refresh_needed = TRUE; + + if (cutbuffer != NULL) + free_filestruct(cutbuffer); + cutbuffer = oldcutbuffer; + cutbottom = oldcutbottom; } -/* Undo the last thing(s) we did */ +/* Undo the last thing(s) we did. */ void do_undo(void) { undo *u = openfile->current_undo; - filestruct *f = openfile->current, *t; - int len = 0; - char *undidmsg, *data; - filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom; + filestruct *t = 0; + size_t len = 0; + char *data, *undidmsg = NULL; if (!u) { statusbar(_("Nothing in undo buffer!")); return; } - - if (u->lineno <= f->lineno) - for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev) - ; - else - for (; f->next != NULL && f->lineno != u->lineno; f = f->next) - ; - if (f->lineno != u->lineno) { - statusbar(_("Internal error: can't match line %d. Please save your work"), u->lineno); + filestruct *f = fsfromline(u->mark_begin_lineno); + if (!f) { + statusbar(_("Internal error: can't match line %d. Please save your work."), u->mark_begin_lineno); return; } #ifdef DEBUG @@ -461,85 +451,94 @@ void do_undo(void) #endif openfile->current_x = u->begin; - switch(u->type) { + switch (u->type) { case ADD: undidmsg = _("text add"); len = strlen(f->data) - strlen(u->strdata) + 1; - data = charalloc(len); - strncpy(data, f->data, u->begin); + data = charalloc(len); + strncpy(data, f->data, u->begin); strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]); free(f->data); f->data = data; + goto_line_posx(u->lineno, u->begin); break; + case BACK: case DEL: undidmsg = _("text delete"); len = strlen(f->data) + strlen(u->strdata) + 1; data = charalloc(len); - strncpy(data, f->data, u->begin); strcpy(&data[u->begin], u->strdata); strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]); free(f->data); f->data = data; - if (u->xflags == UNDO_DEL_BACKSPACE) - openfile->current_x += strlen(u->strdata); + goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); break; #ifndef DISABLE_WRAPPING - case SPLIT: - undidmsg = _("line wrap"); - f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(u->strdata) + 1); - strcpy(&f->data[strlen(f->data) - 1], u->strdata); - if (u->strdata2 != NULL) - f->next->data = mallocstrcpy(f->next->data, u->strdata2); - else { - filestruct *foo = openfile->current->next; - unlink_node(foo); - delete_node(foo); - } - renumber(f); + case SPLIT_END: + goto_line_posx(u->lineno, u->begin); + openfile->current_undo = openfile->current_undo->next; + openfile->last_action = OTHER; + while (openfile->current_undo->type != SPLIT_BEGIN) + do_undo(); + u = openfile->current_undo; + f = openfile->current; + case SPLIT_BEGIN: + undidmsg = _("text add"); break; -#endif /* DISABLE_WRAPPING */ - case UNSPLIT: +#endif /* !DISABLE_WRAPPING */ + case JOIN: undidmsg = _("line join"); t = make_new_node(f); t->data = mallocstrcpy(NULL, u->strdata); - data = mallocstrncpy(NULL, f->data, u->begin); - data[u->begin] = '\0'; + data = mallocstrncpy(NULL, f->data, u->mark_begin_x + 1); + data[u->mark_begin_x] = '\0'; free(f->data); f->data = data; splice_node(f, t, f->next); - renumber(f); + if (f == openfile->filebot) + openfile->filebot = t; + goto_line_posx(u->lineno, u->begin); break; + case CUT_EOF: case CUT: undidmsg = _("text cut"); - undo_cut(u); + undo_cut(u); + f = fsfromline(u->lineno); break; - case UNCUT: + case PASTE: undidmsg = _("text uncut"); - redo_cut(u); + undo_paste(u); + f = fsfromline(u->lineno); break; case ENTER: undidmsg = _("line break"); if (f->next) { filestruct *foo = f->next; - f->data = (char *) nrealloc(f->data, strlen(f->data) + strlen(f->next->data) + 1); - strcat(f->data, f->next->data); + f->data = charealloc(f->data, strlen(f->data) + strlen(&f->next->data[u->mark_begin_x]) + 1); + strcat(f->data, &f->next->data[u->mark_begin_x]); + if (foo == openfile->filebot) + openfile->filebot = f; unlink_node(foo); delete_node(foo); } + goto_line_posx(u->lineno, u->begin); break; case INSERT: undidmsg = _("text insert"); + filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom; cutbuffer = NULL; cutbottom = NULL; - /* When we updated mark_begin_lineno in update_undo, it was effectively how many line - were inserted due to being partitioned before read_file was called. So we - add its value here */ + /* When we updated mark_begin_lineno in update_undo, it was effectively + * how many lines were inserted due to being partitioned before read_file + * was called. So we add its value here. */ openfile->mark_begin = fsfromline(u->lineno + u->mark_begin_lineno - 1); openfile->mark_begin_x = 0; openfile->mark_set = TRUE; - do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE); + goto_line_posx(u->lineno, u->begin); cut_marked(); + if (u->cutbuffer != NULL) + free_filestruct(u->cutbuffer); u->cutbuffer = cutbuffer; u->cutbottom = cutbottom; cutbuffer = oldcutbuffer; @@ -548,29 +547,32 @@ void do_undo(void) break; case REPLACE: undidmsg = _("text replace"); + goto_line_posx(u->lineno, u->begin); data = u->strdata; u->strdata = f->data; f->data = data; break; - default: - undidmsg = _("Internal error: unknown type. Please save your work"); + undidmsg = _("Internal error: unknown type. Please save your work."); break; - } + + if (undidmsg) + statusbar(_("Undid action (%s)"), undidmsg); + renumber(f); - do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE); - statusbar(_("Undid action (%s)"), undidmsg); openfile->current_undo = openfile->current_undo->next; openfile->last_action = OTHER; + openfile->placewewant = xplustabs(); + set_modified(); } +/* Redo the last thing(s) we undid. */ void do_redo(void) { undo *u = openfile->undotop; - filestruct *f = openfile->current; - int len = 0; - char *undidmsg, *data; + size_t len = 0; + char *data, *redidmsg = NULL; for (; u != NULL && u->next != openfile->current_undo; u = u->next) ; @@ -579,18 +581,13 @@ void do_redo(void) return; } if (u->next != openfile->current_undo) { - statusbar(_("Internal error: Redo setup failed. Please save your work")); + statusbar(_("Internal error: cannot set up redo. Please save your work.")); return; } - if (u->lineno <= f->lineno) - for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev) - ; - else - for (; f->next != NULL && f->lineno != u->lineno; f = f->next) - ; - if (f->lineno != u->lineno) { - statusbar(_("Internal error: can't match line %d. Please save your work"), u->lineno); + filestruct *f = fsfromline(u->mark_begin_lineno); + if (!f) { + statusbar(_("Internal error: can't match line %d. Please save your work."), u->mark_begin_lineno); return; } #ifdef DEBUG @@ -598,86 +595,98 @@ void do_redo(void) fprintf(stderr, "Redo running for type %d\n", u->type); #endif - switch(u->type) { + switch (u->type) { case ADD: - undidmsg = _("text add"); + redidmsg = _("text add"); len = strlen(f->data) + strlen(u->strdata) + 1; - data = charalloc(len); + data = charalloc(len); strncpy(data, f->data, u->begin); strcpy(&data[u->begin], u->strdata); strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]); free(f->data); f->data = data; + goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); break; + case BACK: case DEL: - undidmsg = _("text delete"); + redidmsg = _("text delete"); len = strlen(f->data) + strlen(u->strdata) + 1; data = charalloc(len); - strncpy(data, f->data, u->begin); + strncpy(data, f->data, u->begin); strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]); free(f->data); f->data = data; + openfile->current_x = u->begin; + goto_line_posx(u->lineno, u->begin); break; case ENTER: - undidmsg = _("line break"); - do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE); + redidmsg = _("line break"); + goto_line_posx(u->lineno, u->begin); do_enter(TRUE); break; #ifndef DISABLE_WRAPPING - case SPLIT: - undidmsg = _("line wrap"); - if (u->xflags & UNDO_SPLIT_MADENEW) - prepend_wrap = TRUE; - do_wrap(f, TRUE); - renumber(f); + case SPLIT_BEGIN: + goto_line_posx(u->lineno, u->begin); + openfile->current_undo = u; + openfile->last_action = OTHER; + while (openfile->current_undo->type != SPLIT_END) + do_redo(); + u = openfile->current_undo; + goto_line_posx(u->lineno, u->begin); + case SPLIT_END: + redidmsg = _("text add"); break; -#endif /* DISABLE_WRAPPING */ - case UNSPLIT: - undidmsg = _("line join"); - len = strlen(f->data) + strlen(u->strdata + 1); - data = charalloc(len); - strcpy(data, f->data); - strcat(data, u->strdata); - free(f->data); - f->data = data; +#endif /* !DISABLE_WRAPPING */ + case JOIN: + redidmsg = _("line join"); + len = strlen(f->data) + strlen(u->strdata) + 1; + f->data = charealloc(f->data, len); + strcat(f->data, u->strdata); if (f->next != NULL) { filestruct *tmp = f->next; + if (tmp == openfile->filebot) + openfile->filebot = f; unlink_node(tmp); delete_node(tmp); } renumber(f); + goto_line_posx(u->mark_begin_lineno, u->mark_begin_x); break; + case CUT_EOF: case CUT: - undidmsg = _("text cut"); + redidmsg = _("text cut"); redo_cut(u); break; - case UNCUT: - undidmsg = _("text uncut"); - undo_cut(u); + case PASTE: + redidmsg = _("text uncut"); + redo_paste(u); break; case REPLACE: - undidmsg = _("text replace"); + redidmsg = _("text replace"); data = u->strdata; u->strdata = f->data; f->data = data; + goto_line_posx(u->lineno, u->begin); break; case INSERT: - undidmsg = _("text insert"); - do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE); - copy_from_filestruct(u->cutbuffer, u->cutbottom); - openfile->placewewant = xplustabs(); + redidmsg = _("text insert"); + goto_line_posx(u->lineno, u->begin); + copy_from_filestruct(u->cutbuffer); + free_filestruct(u->cutbuffer); + u->cutbuffer = NULL; break; default: - undidmsg = _("Internal error: unknown type. Please save your work"); + redidmsg = _("Internal error: unknown type. Please save your work."); break; - } - do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE); - statusbar(_("Redid action (%s)"), undidmsg); + + if (redidmsg) + statusbar(_("Redid action (%s)"), redidmsg); openfile->current_undo = u; openfile->last_action = OTHER; - + openfile->placewewant = xplustabs(); + set_modified(); } #endif /* !NANO_TINY */ @@ -693,7 +702,6 @@ void do_enter(bool undoing) if (!undoing) add_undo(ENTER); - /* Do auto-indenting, like the neolithic Turbo Pascal editor. */ if (ISSET(AUTOINDENT)) { /* If we are breaking the line in the indentation, the new @@ -711,7 +719,7 @@ void do_enter(bool undoing) #ifndef NANO_TINY if (ISSET(AUTOINDENT)) { strncpy(newnode->data, openfile->current->data, extra); - openfile->totsize += mbstrlen(newnode->data); + openfile->totsize += extra; } #endif null_at(&openfile->current->data, openfile->current_x); @@ -738,9 +746,20 @@ void do_enter(bool undoing) openfile->placewewant = xplustabs(); +#ifndef NANO_TINY + if (!undoing) + update_undo(ENTER); +#endif + edit_refresh_needed = TRUE; } +/* Need this again... */ +void do_enter_void(void) +{ + do_enter(FALSE); +} + #ifndef NANO_TINY /* Send a SIGKILL (unconditional kill) to the forked process in * execute_command(). */ @@ -763,13 +782,12 @@ bool execute_command(const char *command) /* Make our pipes. */ if (pipe(fd) == -1) { - statusbar(_("Could not pipe")); + statusbar(_("Could not create pipe")); return FALSE; } - /* Check $SHELL for the shell to use. If it isn't set, use - * /bin/sh. Note that $SHELL should contain only a path, with no - * arguments. */ + /* Check $SHELL for the shell to use. If it isn't set, use /bin/sh. + * Note that $SHELL should contain only a path, with no arguments. */ shellenv = getenv("SHELL"); if (shellenv == NULL) shellenv = (char *) "/bin/sh"; @@ -835,26 +853,23 @@ bool execute_command(const char *command) return TRUE; } -/* Add a new undo struct to the top of the current pile */ +/* Add a new undo struct to the top of the current pile. */ void add_undo(undo_type current_action) { undo *u; char *data; openfilestruct *fs = openfile; - static undo *last_cutu = NULL; /* Last thing we cut to set up the undo for uncut */ - ssize_t wrap_loc; /* For calculating split beginning */ - - if (!ISSET(UNDOABLE)) - return; + /* Last thing we cut to set up the undo for uncut. */ - /* Ugh, if we were called while cutting not-to-end, non-marked and on the same lineno, - we need to abort here */ + /* Ugh, if we were called while cutting not-to-end, non-marked, and + * on the same lineno, we need to abort here. */ u = fs->current_undo; - if (current_action == CUT && u && u->type == CUT - && !u->mark_set && u->lineno == fs->current->lineno) + if (u && u->mark_begin_lineno == fs->current->lineno && + ((current_action == CUT && u->type == CUT && !u->mark_set && keeping_cutbuffer()) || + (current_action == ADD && u->type == ADD && u->mark_begin_x == fs->current_x))) return; - /* Blow away the old undo stack if we are starting from the middle */ + /* Blow away the old undo stack if we are starting from the middle. */ while (fs->undotop != NULL && fs->undotop != fs->current_undo) { undo *u2 = fs->undotop; fs->undotop = fs->undotop->next; @@ -865,83 +880,101 @@ void add_undo(undo_type current_action) free(u2); } - /* Allocate and initialize a new undo type */ + /* Allocate and initialize a new undo type. */ u = (undo *) nmalloc(sizeof(undo)); u->type = current_action; u->lineno = fs->current->lineno; u->begin = fs->current_x; - u->next = fs->undotop; - fs->undotop = u; - fs->current_undo = u; +#ifndef DISABLE_WRAPPING + if (u->type == SPLIT_BEGIN) { + /* Some action, most likely an ADD, was performed that invoked + * do_wrap(). Rearrange the undo order so that this previous + * action is after the SPLIT_BEGIN undo. */ + u->next = fs->undotop->next ; + fs->undotop->next = u; + } else +#endif + { + u->next = fs->undotop; + fs->undotop = u; + fs->current_undo = u; + } u->strdata = NULL; - u->strdata2 = NULL; u->cutbuffer = NULL; - u->cutbottom = NULL; - u->mark_set = 0; - u->mark_begin_lineno = 0; - u->mark_begin_x = 0; + u->cutbottom = NULL; + u->mark_set = FALSE; + u->mark_begin_lineno = fs->current->lineno; + u->mark_begin_x = fs->current_x; u->xflags = 0; - u->to_end = FALSE; switch (u->type) { - /* We need to start copying data into the undo buffer or we wont be able - to restore it later */ + /* We need to start copying data into the undo buffer + * or we won't be able to restore it later. */ case ADD: - data = charalloc(2); - data[0] = fs->current->data[fs->current_x]; - data[1] = '\0'; - u->strdata = data; break; + case BACK: case DEL: if (u->begin != strlen(fs->current->data)) { - data = mallocstrncpy(NULL, &fs->current->data[u->begin], 2); - data[1] = '\0'; - u->strdata = data; + char *char_buf = charalloc(mb_cur_max() + 1); + int char_buf_len = parse_mbchar(&fs->current->data[u->begin], char_buf, NULL); + null_at(&char_buf, char_buf_len); + u->strdata = char_buf; + if (u->type == BACK) + u->mark_begin_x += char_buf_len; break; } - /* Else purposely fall into unsplit code */ - current_action = u->type = UNSPLIT; - case UNSPLIT: + /* Else purposely fall into the line-joining code. */ + case JOIN: if (fs->current->next) { + if (u->type == BACK) { + u->lineno = fs->current->next->lineno; + u->begin = 0; + } data = mallocstrcpy(NULL, fs->current->next->data); u->strdata = data; } + current_action = u->type = JOIN; break; #ifndef DISABLE_WRAPPING - case SPLIT: - wrap_loc = break_line(openfile->current->data, fill -#ifndef DISABLE_HELP - , FALSE -#endif - ); - u->strdata = mallocstrcpy(NULL, &openfile->current->data[wrap_loc]); - /* Don't both saving the next line if we're not prepending as a new line - will be created */ - if (prepend_wrap) - u->strdata2 = mallocstrcpy(NULL, fs->current->next->data); - u->begin = wrap_loc; + case SPLIT_BEGIN: + current_action = fs->undotop->type; + break; + case SPLIT_END: break; -#endif /* DISABLE_WRAPPING */ +#endif /* !DISABLE_WRAPPING */ case INSERT: + break; case REPLACE: data = mallocstrcpy(NULL, fs->current->data); u->strdata = data; break; + case CUT_EOF: + cutbuffer_reset(); + break; case CUT: + cutbuffer_reset(); u->mark_set = openfile->mark_set; if (u->mark_set) { u->mark_begin_lineno = openfile->mark_begin->lineno; u->mark_begin_x = openfile->mark_begin_x; } - u->to_end = (ISSET(CUT_TO_END)) ? TRUE : FALSE; - last_cutu = u; + else if (!ISSET(CUT_TO_END)) { + /* The entire line is being cut regardless of the cursor position. */ + u->begin = 0; + u->xflags = UNcut_cutline; + } break; - case UNCUT: - if (!last_cutu) - statusbar(_("Internal error: can't setup uncut. Please save your work.")); - else if (last_cutu->type == CUT) { - u->cutbuffer = last_cutu->cutbuffer; - u->cutbottom = last_cutu->cutbottom; + case PASTE: + if (!cutbuffer) + statusbar(_("Internal error: cannot set up uncut. Please save your work.")); + else { + if (u->cutbuffer) + free_filestruct(u->cutbuffer); + u->cutbuffer = copy_filestruct(cutbuffer); + u->mark_begin_lineno = fs->current->lineno; + u->mark_begin_x = fs->current_x; + u->lineno = fs->current->lineno + cutbottom->lineno - cutbuffer->lineno; + u->mark_set = TRUE; } break; case ENTER: @@ -952,43 +985,37 @@ void add_undo(undo_type current_action) } #ifdef DEBUG - fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %d, type = %d\n", - fs->current->data, (unsigned long) fs->current_x, u->begin, current_action); + fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %lu, type = %d\n", + fs->current->data, (unsigned long)fs->current_x, (unsigned long)u->begin, current_action); fprintf(stderr, "left add_undo...\n"); #endif fs->last_action = current_action; } -/* Update an undo item, or determine whether a new one - is really needed and bounce the data to add_undo - instead. The latter functionality just feels - gimmicky and may just be more hassle than - it's worth, so it should be axed if needed. */ +/* Update an undo item, or determine whether a new one is really needed + * and bounce the data to add_undo instead. The latter functionality + * just feels gimmicky and may just be more hassle than it's worth, + * so it should be axed if needed. */ void update_undo(undo_type action) { undo *u; - char *data; - int len = 0; openfilestruct *fs = openfile; - if (!ISSET(UNDOABLE)) - return; - #ifdef DEBUG - fprintf(stderr, "action = %d, fs->last_action = %d, openfile->current->lineno = %lu", - action, fs->last_action, (unsigned long) openfile->current->lineno); +fprintf(stderr, "action = %d, fs->last_action = %d, openfile->current->lineno = %ld", + action, fs->last_action, (long)openfile->current->lineno); if (fs->current_undo) - fprintf(stderr, "fs->current_undo->lineno = %lu\n", (unsigned long) fs->current_undo->lineno); + fprintf(stderr, "fs->current_undo->lineno = %ld\n", (long)fs->current_undo->lineno); else fprintf(stderr, "\n"); #endif /* Change to an add if we're not using the same undo struct - that we should be using */ + * that we should be using. */ if (action != fs->last_action - || (action != CUT && action != INSERT && action != SPLIT + || (action != ENTER && action != CUT && action != INSERT && openfile->current->lineno != fs->current_undo->lineno)) { - add_undo(action); + add_undo(action); return; } @@ -996,103 +1023,103 @@ void update_undo(undo_type action) u = fs->undotop; switch (u->type) { - case ADD: + case ADD: { #ifdef DEBUG - fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %d\n", - fs->current->data, (unsigned long) fs->current_x, u->begin); -#endif - len = strlen(u->strdata) + 2; - data = (char *) nrealloc((void *) u->strdata, len * sizeof(char *)); - data[len-2] = fs->current->data[fs->current_x]; - data[len-1] = '\0'; - u->strdata = (char *) data; + fprintf(stderr, "fs->current->data = \"%s\", current_x = %lu, u->begin = %lu\n", + fs->current->data, (unsigned long)fs->current_x, (unsigned long)u->begin); +#endif + char *char_buf = charalloc(mb_cur_max()); + size_t char_buf_len = parse_mbchar(&fs->current->data[u->mark_begin_x], char_buf, NULL); + u->strdata = addstrings(u->strdata, u->strdata ? strlen(u->strdata) : 0, char_buf, char_buf_len); #ifdef DEBUG fprintf(stderr, "current undo data now \"%s\"\n", u->strdata); #endif + u->mark_begin_lineno = fs->current->lineno; + u->mark_begin_x = fs->current_x; break; - case DEL: - len = strlen(u->strdata) + 2; - assert(len > 2); - if (fs->current_x == u->begin) { - /* They're deleting */ - if (!u->xflags) - u->xflags = UNDO_DEL_DEL; - else if (u->xflags != UNDO_DEL_DEL) { - add_undo(action); - return; - } - data = charalloc(len); - strcpy(data, u->strdata); - data[len-2] = fs->current->data[fs->current_x];; - data[len-1] = '\0'; - free(u->strdata); - u->strdata = data; - } else if (fs->current_x == u->begin - 1) { - /* They're backspacing */ - if (!u->xflags) - u->xflags = UNDO_DEL_BACKSPACE; - else if (u->xflags != UNDO_DEL_BACKSPACE) { - add_undo(action); - return; - } - data = charalloc(len); - data[0] = fs->current->data[fs->current_x]; - strcpy(&data[1], u->strdata); - free(u->strdata); - u->strdata = data; - u->begin--; + } + case BACK: + case DEL: { + char *char_buf = charalloc(mb_cur_max()); + size_t char_buf_len = parse_mbchar(&fs->current->data[fs->current_x], char_buf, NULL); + if (fs->current_x == u->begin) { + /* They're deleting. */ + u->strdata = addstrings(u->strdata, strlen(u->strdata), char_buf, char_buf_len); + u->mark_begin_x = fs->current_x; + } else if (fs->current_x == u->begin - char_buf_len) { + /* They're backspacing. */ + u->strdata = addstrings(char_buf, char_buf_len, u->strdata, strlen(u->strdata)); + u->begin = fs->current_x; } else { - /* They deleted something else on the line */ - add_undo(DEL); + /* They deleted something else on the line. */ + free(char_buf); + add_undo(u->type); return; } #ifdef DEBUG - fprintf(stderr, "current undo data now \"%s\"\nu->begin = %d\n", u->strdata, u->begin); + fprintf(stderr, "current undo data now \"%s\"\nu->begin = %lu\n", u->strdata, (unsigned long)u->begin); #endif break; + } + case CUT_EOF: case CUT: if (!cutbuffer) break; if (u->cutbuffer) - free(u->cutbuffer); + free_filestruct(u->cutbuffer); u->cutbuffer = copy_filestruct(cutbuffer); - /* Compute cutbottom for the uncut using out copy */ - for (u->cutbottom = u->cutbuffer; u->cutbottom->next != NULL; u->cutbottom = u->cutbottom->next) - ; + if (u->mark_set) { + /* If the "marking" operation was from right-->left or + * bottom-->top, then swap the mark points. */ + if ((u->lineno == u->mark_begin_lineno && u->begin < u->mark_begin_x) + || u->lineno < u->mark_begin_lineno) { + size_t x_loc = u->begin; + u->begin = u->mark_begin_x; + u->mark_begin_x = x_loc; + + ssize_t line = u->lineno; + u->lineno = u->mark_begin_lineno; + u->mark_begin_lineno = line; + } else + u->xflags = UNcut_marked_forward; + } else { + /* Compute cutbottom for the uncut using our copy. */ + u->cutbottom = u->cutbuffer; + while (u->cutbottom->next != NULL) + u->cutbottom = u->cutbottom->next; + u->lineno = u->mark_begin_lineno + u->cutbottom->lineno - u->cutbuffer->lineno; + if (ISSET(CUT_TO_END) || u->type == CUT_EOF) { + u->begin = strlen(u->cutbottom->data); + if(u->lineno == u->mark_begin_lineno) + u->begin += u->mark_begin_x; + } + } break; case REPLACE: - case UNCUT: - add_undo(action); + case PASTE: + u->begin = fs->current_x; + u->lineno = openfile->current->lineno; break; case INSERT: u->mark_begin_lineno = openfile->current->lineno; break; -#ifndef DISABLE_WRAPPING - case SPLIT: - /* This will only be called if we made a completely new line, - and as such we should note that so we can destroy it later */ - u->xflags = UNDO_SPLIT_MADENEW; - break; -#endif /* DISABLE_WRAPPING */ - case UNSPLIT: - /* These cases are handled by the earlier check for a new line and action */ case ENTER: + u->mark_begin_x = fs->current_x; + break; +#ifndef DISABLE_WRAPPING + case SPLIT_BEGIN: + case SPLIT_END: +#endif /* !DISABLE_WRAPPING */ + case JOIN: + /* These cases are handled by the earlier check for a new line and action. */ case OTHER: break; } #ifdef DEBUG - fprintf(stderr, "Done in udpate_undo (type was %d)\n", action); -#endif - if (fs->last_action != action) { -#ifdef DEBUG - fprintf(stderr, "Starting add_undo for new action as it does not match last_action\n"); + fprintf(stderr, "Done in update_undo (type was %d)\n", action); #endif - add_undo(action); - } - fs->last_action = action; } - #endif /* !NANO_TINY */ #ifndef DISABLE_WRAPPING @@ -1103,10 +1130,8 @@ void wrap_reset(void) prepend_wrap = FALSE; } -/* We wrap the given line. Precondition: we assume the cursor has been - * moved forward since the last typed character. Return TRUE if we - * wrapped, and FALSE otherwise. */ -bool do_wrap(filestruct *line, bool undoing) +/* Try wrapping the given line. Return TRUE if wrapped, FALSE otherwise. */ +bool do_wrap(filestruct *line) { size_t line_len; /* The length of the line we wrap. */ @@ -1122,16 +1147,10 @@ bool do_wrap(filestruct *line, bool undoing) /* The text after the wrap point. */ size_t after_break_len; /* The length of after_break. */ - bool prepending = FALSE; - /* Do we prepend to the next line? */ const char *next_line = NULL; /* The next line, minus indentation. */ size_t next_line_len = 0; /* The length of next_line. */ - char *new_line = NULL; - /* The line we create. */ - size_t new_line_len = 0; - /* The eventual length of new_line. */ /* There are three steps. First, we decide where to wrap. Then, we * create the new wrap line. Finally, we clean up. */ @@ -1171,9 +1190,6 @@ bool do_wrap(filestruct *line, bool undoing) return FALSE; #ifndef NANO_TINY - if (!undoing) - add_undo(SPLIT); - /* If autoindent is turned on, and we're on the character just after * the indentation, we don't wrap. */ if (ISSET(AUTOINDENT)) { @@ -1184,8 +1200,14 @@ bool do_wrap(filestruct *line, bool undoing) if (wrap_loc == indent_len) return FALSE; } + + add_undo(SPLIT_BEGIN); #endif + size_t old_x = openfile->current_x; + filestruct * oldLine = openfile->current; + openfile->current = line; + /* Step 2, making the new wrap line. It will consist of indentation * followed by the text after the wrap point, optionally followed by * a space (if the text after the wrap point doesn't end in a blank) @@ -1205,9 +1227,15 @@ bool do_wrap(filestruct *line, bool undoing) const char *end = after_break + move_mbleft(after_break, after_break_len); + /* Go to the end of the line. */ + openfile->current_x = line_len; + /* If after_break doesn't end in a blank, make sure it ends in a * space. */ if (!is_blank_mbchar(end)) { +#ifndef NANO_TINY + add_undo(ADD); +#endif line_len++; line->data = charealloc(line->data, line_len + 1); line->data[line_len - 1] = ' '; @@ -1215,126 +1243,42 @@ bool do_wrap(filestruct *line, bool undoing) after_break = line->data + wrap_loc; after_break_len++; openfile->totsize++; + openfile->current_x++; +#ifndef NANO_TINY + update_undo(ADD); +#endif } next_line = line->next->data; next_line_len = strlen(next_line); if (after_break_len + next_line_len <= fill) { - prepending = TRUE; - new_line_len += next_line_len; + /* Delete the LF to join the two lines. */ + do_delete(); + /* Delete any leading blanks from the joined-on line. */ + while (is_blank_mbchar(&line->data[openfile->current_x])) + do_delete(); + renumber(line); } } - /* new_line_len is now the length of the text that will be wrapped - * to the next line, plus (if we're prepending to it) the length of - * the text of the next line. */ - new_line_len += after_break_len; + /* Go to the wrap location and split the line there. */ + openfile->current_x = wrap_loc; + do_enter(FALSE); -#ifndef NANO_TINY - if (ISSET(AUTOINDENT)) { - if (prepending) { - /* If we're prepending, the indentation will come from the - * next line. */ - indent_string = next_line; - indent_len = indent_length(indent_string); - next_line += indent_len; - } else { - /* Otherwise, it will come from this line, in which case - * we should increase new_line_len to make room for it. */ - new_line_len += indent_len; - openfile->totsize += mbstrnlen(indent_string, indent_len); - } - } -#endif - - /* Now we allocate the new line and copy the text into it. */ - new_line = charalloc(new_line_len + 1); - new_line[0] = '\0'; - -#ifndef NANO_TINY - if (ISSET(AUTOINDENT)) { - /* Copy the indentation. */ - strncpy(new_line, indent_string, indent_len); - new_line[indent_len] = '\0'; - new_line_len += indent_len; - } -#endif - - /* Copy all the text after the wrap point of the current line. */ - strcat(new_line, after_break); - - /* Break the current line at the wrap point. */ - null_at(&line->data, wrap_loc); - - if (prepending) { - if (!undoing) - update_undo(SPLIT); - /* If we're prepending, copy the text from the next line, minus - * the indentation that we already copied above. */ - strcat(new_line, next_line); - - free(line->next->data); - line->next->data = new_line; - - /* If the NO_NEWLINES flag isn't set, and text has been added to - * the magicline, make a new magicline. */ - if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0') - new_magicline(); + if (old_x < wrap_loc) { + openfile->current_x = old_x; + openfile->current = oldLine; + prepend_wrap = TRUE; } else { - /* Otherwise, make a new line and copy the text after where we - * broke this line to the beginning of the new line. */ - splice_node(openfile->current, make_new_node(openfile->current), - openfile->current->next); - - /* If the current line is the last line of the file, move the - * last line of the file down to the next line. */ - if (openfile->filebot == openfile->current) - openfile->filebot = openfile->current->next; - - openfile->current->next->data = new_line; - - openfile->totsize++; - } - - /* Step 3, clean up. Reposition the cursor and mark, and do some - * other sundry things. */ - - /* Set the prepend_wrap flag, so that later wraps of this line will - * be prepended to the next line. */ - prepend_wrap = TRUE; - - /* Each line knows its number. We recalculate these if we inserted - * a new line. */ - if (!prepending) - renumber(line); - - /* If the cursor was after the break point, we must move it. We - * also clear the prepend_wrap flag in this case. */ - if (openfile->current_x > wrap_loc) { + openfile->current_x += (old_x - wrap_loc); prepend_wrap = FALSE; - - openfile->current = openfile->current->next; - openfile->current_x -= wrap_loc -#ifndef NANO_TINY - - indent_len -#endif - ; - openfile->placewewant = xplustabs(); } + openfile->placewewant = xplustabs(); + #ifndef NANO_TINY - /* If the mark was on this line after the wrap point, we move it - * down. If it was on the next line and we prepended to that line, - * we move it right. */ - if (openfile->mark_set) { - if (openfile->mark_begin == line && openfile->mark_begin_x > - wrap_loc) { - openfile->mark_begin = line->next; - openfile->mark_begin_x -= wrap_loc - indent_len + 1; - } else if (prepending && openfile->mark_begin == line->next) - openfile->mark_begin_x += after_break_len; - } + add_undo(SPLIT_END); #endif return TRUE; @@ -1346,7 +1290,7 @@ bool do_wrap(filestruct *line, bool undoing) * that the display length to there is at most (goal + 1). If there is * no such blank, then we find the first blank. We then take the last * blank in that group of blanks. The terminating '\0' counts as a - * blank, as does a '\n' if newline is TRUE. */ + * blank, as does a '\n' if newln is TRUE. */ ssize_t break_line(const char *line, ssize_t goal #ifndef DISABLE_HELP , bool newln @@ -1355,17 +1299,18 @@ ssize_t break_line(const char *line, ssize_t goal { ssize_t blank_loc = -1; /* Current tentative return value. Index of the last blank we - * found with short enough display width. */ + * found with short enough display width. */ ssize_t cur_loc = 0; /* Current index in line. */ size_t cur_pos = 0; /* Current column position in line. */ - int line_len; + int char_len = 0; + /* Length of current character, in bytes. */ assert(line != NULL); while (*line != '\0' && goal >= cur_pos) { - line_len = parse_mbchar(line, NULL, &cur_pos); + char_len = parse_mbchar(line, NULL, &cur_pos); if (is_blank_mbchar(line) #ifndef DISABLE_HELP @@ -1380,8 +1325,8 @@ ssize_t break_line(const char *line, ssize_t goal #endif } - line += line_len; - cur_loc += line_len; + line += char_len; + cur_loc += char_len; } if (goal >= cur_pos) @@ -1390,34 +1335,34 @@ ssize_t break_line(const char *line, ssize_t goal #ifndef DISABLE_HELP if (newln && blank_loc <= 0) { - /* If blank was not found or was found only first character, - * force line break. */ - cur_loc -= line_len; - return cur_loc; + /* If no blank was found, or was found only as the first + * character, force a line break. */ + cur_loc -= char_len; + return cur_loc; } #endif if (blank_loc == -1) { - /* No blank was found that was short enough. */ + /* No blank was found within the goal width, + * so now try and find a blank beyond it. */ bool found_blank = FALSE; ssize_t found_blank_loc = 0; while (*line != '\0') { - line_len = parse_mbchar(line, NULL, NULL); + char_len = parse_mbchar(line, NULL, NULL); if (is_blank_mbchar(line) #ifndef DISABLE_HELP || (newln && *line == '\n') #endif ) { - if (!found_blank) - found_blank = TRUE; + found_blank = TRUE; found_blank_loc = cur_loc; } else if (found_blank) return found_blank_loc; - line += line_len; - cur_loc += line_len; + line += char_len; + cur_loc += char_len; } return -1; @@ -1426,23 +1371,14 @@ ssize_t break_line(const char *line, ssize_t goal /* Move to the last blank after blank_loc, if there is one. */ line -= cur_loc; line += blank_loc; - line_len = parse_mbchar(line, NULL, NULL); - line += line_len; - - while (*line != '\0' && (is_blank_mbchar(line) -#ifndef DISABLE_HELP - || (newln && *line == '\n') -#endif - )) { -#ifndef DISABLE_HELP - if (newln && *line == '\n') - break; -#endif + char_len = parse_mbchar(line, NULL, NULL); + line += char_len; - line_len = parse_mbchar(line, NULL, NULL); + while (*line != '\0' && is_blank_mbchar(line)) { + char_len = parse_mbchar(line, NULL, NULL); - line += line_len; - blank_loc += line_len; + line += char_len; + blank_loc += char_len; } return blank_loc; @@ -1804,7 +1740,7 @@ void backup_lines(filestruct *first_line, size_t par_len) /* Copy the paragraph back to the current buffer's filestruct from * the justify buffer. */ - copy_from_filestruct(jusbuffer, jusbottom); + copy_from_filestruct(jusbuffer); /* Move upward from the last line of the paragraph to the first * line, putting first_line, edittop, current, and mark_begin at the @@ -1947,6 +1883,10 @@ void do_justify(bool full_justify) bool filebot_inpar = FALSE; /* Whether the text at filebot is part of the current * paragraph. */ + int kbinput; + /* The first keystroke after a justification. */ + functionptrtype func; + /* The function associated with that keystroke. */ /* We save these variables to be restored if the user * unjustifies. */ @@ -1961,10 +1901,6 @@ void do_justify(bool full_justify) #endif bool modified_save = openfile->modified; - int kbinput; - bool meta_key, func_key, s_or_t, ran_func, finished; - const sc *s; - /* Move to the beginning of the current line, so that justifying at * the end of the last line of the file, if that line isn't blank, * will work the first time through. */ @@ -1974,6 +1910,10 @@ void do_justify(bool full_justify) if (full_justify) openfile->current = openfile->fileage; +#ifndef NANO_TINY + allow_pending_sigwinch(FALSE); +#endif + while (TRUE) { size_t i; /* Generic loop variable. */ @@ -2272,16 +2212,16 @@ void do_justify(bool full_justify) do_cursorpos(TRUE); /* Display the shortcut list with UnJustify. */ - shortcut_init(TRUE); + uncutfunc->desc = unjust_tag; + currmenu = MMAIN; display_main_list(); /* Now get a keystroke and see if it's unjustify. If not, put back * the keystroke and return. */ - kbinput = do_input(&meta_key, &func_key, &s_or_t, &ran_func, - &finished, FALSE); - s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key); + kbinput = do_input(FALSE); + func = func_from_key(&kbinput); - if (s && s->scfunc == DO_UNCUT_TEXT) { + if (func == do_uncut_text) { /* Splice the justify buffer back into the file, but only if we * actually justified something. */ if (first_par_line != NULL) { @@ -2342,8 +2282,12 @@ void do_justify(bool full_justify) blank_statusbar(); /* Display the shortcut list with UnCut. */ - shortcut_init(FALSE); + uncutfunc->desc = uncut_tag; display_main_list(); + +#ifndef NANO_TINY + allow_pending_sigwinch(TRUE); +#endif } /* Justify the current paragraph. */ @@ -2367,7 +2311,6 @@ bool do_int_spell_fix(const char *word) char *save_search, *save_replace; size_t match_len, current_x_save = openfile->current_x; size_t pww_save = openfile->placewewant; - bool meta_key = FALSE, func_key = FALSE; filestruct *edittop_save = openfile->edittop; filestruct *current_save = openfile->current; /* Save where we are. */ @@ -2455,8 +2398,7 @@ bool do_int_spell_fix(const char *word) TRUE, #endif MSPELL, word, - &meta_key, &func_key, -#ifndef NANO_TINY +#ifndef DISABLE_HISTORIES NULL, #endif edit_refresh, _("Edit a replacement")) == -1); @@ -2692,7 +2634,7 @@ const char *do_int_speller(const char *tempfile_name) if (WIFEXITED(spell_status) == 0 || WEXITSTATUS(spell_status)) return _("Error invoking \"spell\""); - if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status)) + if (WIFEXITED(sort_status) == 0 || WEXITSTATUS(sort_status)) return _("Error invoking \"sort -f\""); if (WIFEXITED(uniq_status) == 0 || WEXITSTATUS(uniq_status)) @@ -2719,9 +2661,10 @@ const char *do_alt_speller(char *tempfile_name) { int alt_spell_status; size_t current_x_save = openfile->current_x; - size_t pww_save = openfile->placewewant; ssize_t current_y_save = openfile->current_y; ssize_t lineno_save = openfile->current->lineno; + struct stat spellfileinfo; + __time_t timestamp; pid_t pid_spell; char *ptr; static int arglen = 3; @@ -2730,9 +2673,6 @@ const char *do_alt_speller(char *tempfile_name) bool old_mark_set = openfile->mark_set; bool added_magicline = FALSE; /* Whether we added a magicline after filebot. */ - bool right_side_up = FALSE; - /* TRUE if (mark_begin, mark_begin_x) is the top of the mark, - * FALSE if (current, current_x) is. */ filestruct *top, *bot; size_t top_x, bot_x; ssize_t mb_lineno_save = 0; @@ -2757,6 +2697,10 @@ const char *do_alt_speller(char *tempfile_name) return NULL; } + /* Get the timestamp of the temporary file. */ + stat(tempfile_name, &spellfileinfo); + timestamp = spellfileinfo.st_mtime; + endwin(); /* Set up an argument list to pass execvp(). */ @@ -2834,7 +2778,7 @@ const char *do_alt_speller(char *tempfile_name) * added when we're done correcting misspelled words; and * turn the mark off. */ mark_order((const filestruct **)&top, &top_x, - (const filestruct **)&bot, &bot_x, &right_side_up); + (const filestruct **)&bot, &bot_x, NULL); filepart = partition_filestruct(top, top_x, bot, bot_x); if (!ISSET(NO_NEWLINES)) added_magicline = (openfile->filebot->data[0] != '\0'); @@ -2858,18 +2802,6 @@ const char *do_alt_speller(char *tempfile_name) if (!ISSET(NO_NEWLINES) && added_magicline) remove_magicline(); - /* Put the beginning and the end of the mark at the beginning - * and the end of the spell-checked text. */ - if (openfile->fileage == openfile->filebot) - bot_x += top_x; - if (right_side_up) { - openfile->mark_begin_x = top_x; - current_x_save = bot_x; - } else { - current_x_save = top_x; - openfile->mark_begin_x = bot_x; - } - /* Unpartition the filestruct so that it contains all the text * again. Note that we've replaced the marked text originally * in the partition with the spell-checked marked text in the @@ -2885,8 +2817,7 @@ const char *do_alt_speller(char *tempfile_name) openfile->totsize = totsize_save; /* Assign mark_begin to the line where the mark began before. */ - do_gotopos(mb_lineno_save, openfile->mark_begin_x, - current_y_save, 0); + goto_line_posx(mb_lineno_save, openfile->mark_begin_x); openfile->mark_begin = openfile->current; /* Assign mark_begin_x to the location in mark_begin where the @@ -2899,9 +2830,16 @@ const char *do_alt_speller(char *tempfile_name) } #endif - /* Go back to the old position, and mark the file as modified. */ - do_gotopos(lineno_save, current_x_save, current_y_save, pww_save); - set_modified(); + /* Go back to the old position. */ + goto_line_posx(lineno_save, current_x_save); + openfile->current_y = current_y_save; + edit_update(NONE); + + /* Stat the temporary file again, and mark the buffer as modified only + * if this file was changed since it was written. */ + stat(tempfile_name, &spellfileinfo); + if (spellfileinfo.st_mtime != timestamp) + set_modified(); #ifndef NANO_TINY /* Handle a pending SIGWINCH again. */ @@ -2921,7 +2859,7 @@ void do_spell(void) const char *spell_msg; if (ISSET(RESTRICTED)) { - nano_disabled_msg(); + nano_disabled_msg(); return; } @@ -2943,6 +2881,10 @@ void do_spell(void) return; } + blank_bottombars(); + statusbar(_("Invoking spell checker, please wait")); + doupdate(); + spell_msg = (alt_speller != NULL) ? do_alt_speller(temp) : do_int_speller(temp); unlink(temp); @@ -2966,6 +2908,472 @@ void do_spell(void) } #endif /* !DISABLE_SPELLER */ +#ifndef DISABLE_COLOR +/* Cleanup things to do after leaving the linter. */ +void lint_cleanup(void) +{ + currmenu = MMAIN; + display_main_list(); +} + + +/* Run linter. Based on alt-speller code. Return NULL for normal + * termination, and the error string otherwise. */ +void do_linter(void) +{ + char *read_buff, *read_buff_ptr, *read_buff_word, *ptr; + size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread; + size_t parsesuccess = 0; + int lint_fd[2]; + pid_t pid_lint; + int lint_status; + static int arglen = 3; + static char **lintargs = NULL; + char *lintcopy; + char *convendptr = NULL; + lintstruct *lints = NULL, *tmplint = NULL, *curlint = NULL; + + if (!openfile->syntax || !openfile->syntax->linter) { + statusbar(_("No linter defined for this type of file!")); + return; + } + + if (ISSET(RESTRICTED)) { + nano_disabled_msg(); + return; + } + + if (openfile->modified) { + int i = do_yesno_prompt(FALSE, _("Save modified buffer before linting?")); + if (i == -1) { + statusbar(_("Cancelled")); + lint_cleanup(); + return; + } else if (i == 1) { + if (do_writeout(FALSE) != TRUE) { + lint_cleanup(); + return; + } + } + } + + lintcopy = mallocstrcpy(NULL, openfile->syntax->linter); + /* Create pipe up front. */ + if (pipe(lint_fd) == -1) { + statusbar(_("Could not create pipe")); + lint_cleanup(); + return; + } + + blank_bottombars(); + statusbar(_("Invoking linter, please wait")); + doupdate(); + + /* Set up an argument list to pass execvp(). */ + if (lintargs == NULL) { + lintargs = (char **)nmalloc(arglen * sizeof(char *)); + + lintargs[0] = strtok(lintcopy, " "); + while ((ptr = strtok(NULL, " ")) != NULL) { + arglen++; + lintargs = (char **)nrealloc(lintargs, arglen * + sizeof(char *)); + lintargs[arglen - 3] = ptr; + } + lintargs[arglen - 1] = NULL; + } + lintargs[arglen - 2] = openfile->filename; + + /* A new process to run linter. */ + if ((pid_lint = fork()) == 0) { + + /* Child continues (i.e. future spell process). */ + close(lint_fd[0]); + + /* Send spell's standard output/err to the pipe. */ + if (dup2(lint_fd[1], STDOUT_FILENO) != STDOUT_FILENO) + exit(1); + if (dup2(lint_fd[1], STDERR_FILENO) != STDERR_FILENO) + exit(1); + + close(lint_fd[1]); + + /* Start the linter program; we are using $PATH. */ + execvp(lintargs[0], lintargs); + + /* This should not be reached if linter is found. */ + exit(1); + } + + /* Parent continues here. */ + close(lint_fd[1]); + + /* The child process was not forked successfully. */ + if (pid_lint < 0) { + close(lint_fd[0]); + statusbar(_("Could not fork")); + lint_cleanup(); + return; + } + + /* Get the system pipe buffer size. */ + if ((pipe_buff_size = fpathconf(lint_fd[0], _PC_PIPE_BUF)) < 1) { + close(lint_fd[0]); + statusbar(_("Could not get size of pipe buffer")); + lint_cleanup(); + return; + } + + /* Read in the returned spelling errors. */ + read_buff_read = 0; + read_buff_size = pipe_buff_size + 1; + read_buff = read_buff_ptr = charalloc(read_buff_size); + + while ((bytesread = read(lint_fd[0], read_buff_ptr, + pipe_buff_size)) > 0) { +#ifdef DEBUG + fprintf(stderr, "text.c:do_linter:%ld bytes (%s)\n", (long)bytesread, read_buff_ptr); +#endif + read_buff_read += bytesread; + read_buff_size += pipe_buff_size; + read_buff = read_buff_ptr = charealloc(read_buff, + read_buff_size); + read_buff_ptr += read_buff_read; + } + + *read_buff_ptr = '\0'; + close(lint_fd[0]); + +#ifdef DEBUG + fprintf(stderr, "text.c:do_lint:Raw output: %s\n", read_buff); +#endif + + /* Process output. */ + read_buff_word = read_buff_ptr = read_buff; + + while (*read_buff_ptr != '\0') { + if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) { + *read_buff_ptr = '\0'; + if (read_buff_word != read_buff_ptr) { + char *filename = NULL, *linestr = NULL, *maybecol = NULL; + char *message = mallocstrcpy(NULL, read_buff_word); + + /* At the moment we're assuming the following formats: + * + * filenameorcategory:line:column:message (e.g. splint) + * filenameorcategory:line:message (e.g. pyflakes) + * filenameorcategory:line,col:message (e.g. pylint) + * + * This could be turned into some scanf() based parser, + * but ugh. */ + if ((filename = strtok(read_buff_word, ":")) != NULL) { + if ((linestr = strtok(NULL, ":")) != NULL) { + if ((maybecol = strtok(NULL, ":")) != NULL) { + ssize_t tmplineno = 0, tmpcolno = 0; + char *tmplinecol; + + tmplineno = strtol(linestr, NULL, 10); + if (tmplineno <= 0) { + read_buff_ptr++; + free(message); + continue; + } + + tmpcolno = strtol(maybecol, &convendptr, 10); + if (*convendptr != '\0') { + /* Previous field might still be + * line,col format. */ + strtok(linestr, ","); + if ((tmplinecol = strtok(NULL, ",")) != NULL) + tmpcolno = strtol(tmplinecol, NULL, 10); + } + +#ifdef DEBUG + fprintf(stderr, "text.c:do_lint:Successful parse! %ld:%ld:%s\n", (long)tmplineno, (long)tmpcolno, message); +#endif + /* Nice. We have a lint message we can use. */ + parsesuccess++; + tmplint = curlint; + curlint = nmalloc(sizeof(lintstruct)); + curlint->next = NULL; + curlint->prev = tmplint; + if (curlint->prev != NULL) + curlint->prev->next = curlint; + curlint->msg = mallocstrcpy(NULL, message); + curlint->lineno = tmplineno; + curlint->colno = tmpcolno; + curlint->filename = mallocstrcpy(NULL, filename); + + if (lints == NULL) + lints = curlint; + } + } + } else + free(message); + } + read_buff_word = read_buff_ptr + 1; + } + read_buff_ptr++; + } + + /* Process the end of the lint process. */ + waitpid(pid_lint, &lint_status, 0); + + free(read_buff); + + if (parsesuccess == 0) { + statusbar(_("Got 0 parsable lines from command: %s"), openfile->syntax->linter); + lint_cleanup(); + return; + } + + currmenu = MLINTER; + bottombars(MLINTER); + tmplint = NULL; + curlint = lints; + while (TRUE) { + ssize_t tmpcol = 1; + int kbinput; + functionptrtype func; + + if (curlint->colno > 0) + tmpcol = curlint->colno; + + if (tmplint != curlint) { +#ifndef NANO_TINY + struct stat lintfileinfo; + + new_lint_loop: + if (stat(curlint->filename, &lintfileinfo) != -1) { + if (openfile->current_stat->st_ino != lintfileinfo.st_ino) { + openfilestruct *tmpof = openfile; + while (tmpof != openfile->next) { + if (tmpof->current_stat->st_ino == lintfileinfo.st_ino) + break; + tmpof = tmpof->next; + } + if (tmpof->current_stat->st_ino != lintfileinfo.st_ino) { + char *msg = charalloc(1024 + strlen(curlint->filename)); + int i; + + sprintf(msg, _("This message is for unopened file %s, open it in a new buffer?"), + curlint->filename); + i = do_yesno_prompt(FALSE, msg); + free(msg); + if (i == -1) { + statusbar(_("Cancelled")); + goto free_lints_and_return; + } else if (i == 1) { + SET(MULTIBUFFER); + open_buffer(curlint->filename, FALSE); + } else { + char *dontwantfile = curlint->filename; + + while (curlint != NULL && !strcmp(curlint->filename, dontwantfile)) + curlint = curlint->next; + if (curlint == NULL) { + statusbar("No more errors in un-opened filed, cancelling"); + break; + } else + goto new_lint_loop; + } + } else + openfile = tmpof; + } + } +#endif /* !NANO_TINY */ + do_gotolinecolumn(curlint->lineno, tmpcol, FALSE, FALSE, FALSE, FALSE); + titlebar(NULL); + edit_refresh(); + statusbar(curlint->msg); + bottombars(MLINTER); + } + + kbinput = get_kbinput(bottomwin); + func = func_from_key(&kbinput); + tmplint = curlint; + + if (func == do_cancel) + break; + else if (func == do_help_void) { + tmplint = NULL; + do_help_void(); + } else if (func == do_page_down) { + if (curlint->next != NULL) + curlint = curlint->next; + else + statusbar(_("At last message")); + } else if (func == do_page_up) { + if (curlint->prev != NULL) + curlint = curlint->prev; + else + statusbar(_("At first message")); + } + } + blank_statusbar(); +#ifndef NANO_TINY +free_lints_and_return: +#endif + for (tmplint = lints; tmplint != NULL; tmplint = tmplint->next) { + free(tmplint->msg); + free(tmplint->filename); + free(tmplint); + } + lint_cleanup(); +} + +/* Run a formatter for the given syntax. + * Expects the formatter to be non-interactive and + * operate on a file in-place, which we'll pass it + * on the command line. Another mashup of the speller + * and alt_speller routines. + */ +void do_formatter(void) +{ + bool status; + FILE *temp_file; + char *temp = safe_tempfile(&temp_file); + int format_status; + size_t current_x_save = openfile->current_x; + size_t pww_save = openfile->placewewant; + ssize_t current_y_save = openfile->current_y; + ssize_t lineno_save = openfile->current->lineno; + pid_t pid_format; + char *ptr; + static int arglen = 3; + static char **formatargs = NULL; + char *finalstatus = NULL; + + /* Check whether we're using syntax highlighting + * and the formatter option is set. */ + if (openfile->syntax == NULL || openfile->syntax->formatter == NULL) { + statusbar(_("Error: no formatter defined")); + return; + } + + if (ISSET(RESTRICTED)) { + nano_disabled_msg(); + return; + } + + if (temp == NULL) { + statusbar(_("Error writing temp file: %s"), strerror(errno)); + return; + } + + /* We're not supporting partial formatting, oi vey. */ + openfile->mark_set = FALSE; + status = write_file(temp, temp_file, TRUE, OVERWRITE, FALSE); + + if (!status) { + statusbar(_("Error writing temp file: %s"), strerror(errno)); + free(temp); + return; + } + + if (openfile->totsize == 0) { + statusbar(_("Finished")); + return; + } + + blank_bottombars(); + statusbar(_("Invoking formatter, please wait")); + doupdate(); + + endwin(); + + /* Set up an argument list to pass execvp(). */ + if (formatargs == NULL) { + formatargs = (char **)nmalloc(arglen * sizeof(char *)); + + formatargs[0] = strtok(openfile->syntax->formatter, " "); + while ((ptr = strtok(NULL, " ")) != NULL) { + arglen++; + formatargs = (char **)nrealloc(formatargs, arglen * + sizeof(char *)); + formatargs[arglen - 3] = ptr; + } + formatargs[arglen - 1] = NULL; + } + formatargs[arglen - 2] = temp; + + /* Start a new process for the formatter. */ + if ((pid_format = fork()) == 0) { + /* Start the formatting program; we are using $PATH. */ + execvp(formatargs[0], formatargs); + + /* Should not be reached, if the formatter is found! */ + exit(1); + } + + /* If we couldn't fork, get out. */ + if (pid_format < 0) { + statusbar(_("Could not fork")); + return; + } + +#ifndef NANO_TINY + /* Don't handle a pending SIGWINCH until the alternate format checker + * is finished and we've loaded the format-checked file back in. */ + allow_pending_sigwinch(FALSE); +#endif + + /* Wait for the formatter to finish. */ + wait(&format_status); + + /* Reenter curses mode. */ + doupdate(); + + /* Restore the terminal to its previous state. */ + terminal_init(); + + /* Turn the cursor back on for sure. */ + curs_set(1); + + /* The screen might have been resized. If it has, reinitialize all + * the windows based on the new screen dimensions. */ + window_init(); + + if (!WIFEXITED(format_status) || + WEXITSTATUS(format_status) != 0) { + char *format_error; + char *invoke_error = _("Error invoking \"%s\""); + + format_error = + charalloc(strlen(invoke_error) + + strlen(openfile->syntax->formatter) + 1); + sprintf(format_error, invoke_error, openfile->syntax->formatter); + finalstatus = format_error; + } else { + /* Replace the text of the current buffer with the formatted text. */ + replace_buffer(temp); + + /* Go back to the old position, and mark the file as modified. */ + do_gotopos(lineno_save, current_x_save, current_y_save, pww_save); + set_modified(); + +#ifndef NANO_TINY + /* Handle a pending SIGWINCH again. */ + allow_pending_sigwinch(TRUE); +#endif + + finalstatus = _("Finished formatting"); + } + + unlink(temp); + free(temp); + + currmenu = MMAIN; + + /* If the formatter printed any error messages onscreen, make + * sure that they're cleared off. */ + total_refresh(); + + statusbar(finalstatus); +} + +#endif /* !DISABLE_COLOR */ + #ifndef NANO_TINY /* Our own version of "wc". Note that its character counts are in * multibyte characters instead of single-byte characters. */ @@ -3071,4 +3479,3 @@ void do_verbatim_input(void) free(output); } - diff --git a/src/utils.c b/src/utils.c index ff13a41..bed5f91 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,9 +1,9 @@ -/* $Id: utils.c 4453 2009-12-02 03:36:22Z astyanax $ */ +/* $Id: utils.c 4948 2014-06-09 14:23:53Z bens $ */ /************************************************************************** * utils.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -72,6 +72,10 @@ bool parse_num(const char *str, ssize_t *val) assert(str != NULL); + /* The manual page for strtol() says this is required, and + * it looks like it is! */ + errno = 0; + j = (ssize_t)strtol(str, &first_error, 10); if (errno == ERANGE || *str == '\0' || *first_error != '\0') @@ -183,7 +187,7 @@ void sunder(char *str) * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ -#ifdef ENABLE_NANORC +#ifndef DISABLE_NANORC #ifndef HAVE_GETDELIM /* This function is equivalent to getdelim(). */ @@ -243,7 +247,7 @@ ssize_t ngetline(char **lineptr, size_t *n, FILE *stream) return getdelim(lineptr, n, '\n', stream); } #endif -#endif /* ENABLE_NANORC */ +#endif /* !DISABLE_NANORC */ #ifdef HAVE_REGEX_H /* Do the compiled regex in preg and the regex in string match the @@ -255,9 +259,10 @@ bool regexp_bol_or_eol(const regex_t *preg, const char *string) REG_NOMATCH); } -/* Fix the regex if we're on platforms which requires an adjustment - * from GNU-style to BSD-style word boundaries. */ -const char *fixbounds(const char *r) { +/* Fix the regex if we're on platforms which require an adjustment + * from GNU-style to BSD-style word boundaries. */ +const char *fixbounds(const char *r) +{ #ifndef GNU_WORDBOUNDS int i, j = 0; char *r2 = charalloc(strlen(r) * 5); @@ -268,15 +273,15 @@ const char *fixbounds(const char *r) { #endif for (i = 0; i < strlen(r); i++) { - if (r[i] != '\0' && r[i] == '\\' && (r[i+1] == '>' || r[i+1] == '<')) { - strcpy(&r2[j], "[[:"); - r2[j+3] = r[i+1]; - strcpy(&r2[j+4], ":]]"); - i++; - j += 6; - } else - r2[j] = r[i]; - j++; + if (r[i] != '\0' && r[i] == '\\' && (r[i + 1] == '>' || r[i + 1] == '<')) { + strcpy(&r2[j], "[[:"); + r2[j + 3] = r[i + 1]; + strcpy(&r2[j + 4], ":]]"); + i++; + j += 6; + } else + r2[j] = r[i]; + j++; } r2[j] = '\0'; r3 = mallocstrcpy(NULL, r2); @@ -472,7 +477,10 @@ size_t get_page_start(size_t column) * current_x. */ size_t xplustabs(void) { - return strnlenpt(openfile->current->data, openfile->current_x); + if (openfile->current) + return strnlenpt(openfile->current->data, openfile->current_x); + else + return 0; } /* Return the index in s of the character displayed at the given column, @@ -542,7 +550,7 @@ void new_magicline(void) openfile->filebot->next->prev = openfile->filebot; openfile->filebot->next->next = NULL; openfile->filebot->next->lineno = openfile->filebot->lineno + 1; -#ifdef ENABLE_COLOR +#ifndef DISABLE_COLOR openfile->filebot->next->multidata = NULL; #endif openfile->filebot = openfile->filebot->next; @@ -594,7 +602,7 @@ void mark_order(const filestruct **top, size_t *top_x, const filestruct *right_side_up = FALSE; } } -#endif +#endif /* !NANO_TINY */ /* Calculate the number of characters between begin and end, and return * it. */ @@ -626,7 +634,7 @@ size_t get_totsize(const filestruct *begin, const filestruct *end) return totsize; } -/* Get back a pointer given a line number in the current openfilestruct */ +/* Get back a pointer given a line number in the current openfilestruct. */ filestruct *fsfromline(ssize_t lineno) { filestruct *f = openfile->current; diff --git a/src/winio.c b/src/winio.c index 1aef2a9..086af41 100644 --- a/src/winio.c +++ b/src/winio.c @@ -1,9 +1,9 @@ -/* $Id: winio.c 4484 2010-03-07 19:35:46Z astyanax $ */ +/* $Id: winio.c 5149 2015-03-22 13:23:42Z bens $ */ /************************************************************************** * winio.c * * * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * - * 2008, 2009 Free Software Foundation, Inc. * + * 2008, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3, or (at your option) * @@ -112,7 +112,6 @@ void get_key_buffer(WINDOW *win) if (key_buffer != NULL) return; - /* Read in the first character using blocking input. */ #ifndef NANO_TINY allow_pending_sigwinch(TRUE); #endif @@ -121,10 +120,11 @@ void get_key_buffer(WINDOW *win) * screen updates. */ doupdate(); + /* Read in the first character using whatever mode we're in. */ errcount = 0; if (nodelay_mode) { - if ((input = wgetch(win)) == ERR) - return; + if ((input = wgetch(win)) == ERR) + return; } else while ((input = wgetch(win)) == ERR) { errcount++; @@ -174,7 +174,7 @@ void get_key_buffer(WINDOW *win) #endif } - /* Switch back to non-blocking input. */ + /* Switch back to waiting mode for input. */ nodelay(win, FALSE); #ifdef DEBUG @@ -224,17 +224,17 @@ void unget_input(int *input, size_t input_len) } /* Put back the character stored in kbinput, putting it in byte range - * beforehand. If meta_key is TRUE, put back the Escape character after - * putting back kbinput. If func_key is TRUE, put back the function key + * beforehand. If metakey is TRUE, put back the Escape character after + * putting back kbinput. If funckey is TRUE, put back the function key * (a value outside byte range) without putting it in byte range. */ -void unget_kbinput(int kbinput, bool meta_key, bool func_key) +void unget_kbinput(int kbinput, bool metakey, bool funckey) { - if (!func_key) + if (!funckey) kbinput = (char)kbinput; unget_input(&kbinput, 1); - if (meta_key) { + if (metakey) { kbinput = NANO_CONTROL_3; unget_input(&kbinput, 1); } @@ -298,20 +298,20 @@ int *get_input(WINDOW *win, size_t input_len) /* Read in a single character. If it's ignored, swallow it and go on. * Otherwise, try to translate it from ASCII, meta key sequences, escape - * sequences, and/or extended keypad values. Set meta_key to TRUE when - * we get a meta key sequence, and set func_key to TRUE when we get an - * extended keypad value. Supported extended keypad values consist of + * sequences, and/or extended keypad values. Supported extended keypad + * values consist of * [arrow key], Ctrl-[arrow key], Shift-[arrow key], Enter, Backspace, * the editing keypad (Insert, Delete, Home, End, PageUp, and PageDown), * the function keypad (F1-F16), and the numeric keypad with NumLock - * off. Assume nodelay(win) is FALSE. */ -int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key) + * off. */ +int get_kbinput(WINDOW *win) { int kbinput; /* Read in a character and interpret it. Continue doing this until * we get a recognized value or sequence. */ - while ((kbinput = parse_kbinput(win, meta_key, func_key)) == ERR); + while ((kbinput = parse_kbinput(win)) == ERR) + ; /* If we read from the edit window, blank the statusbar if we need * to. */ @@ -324,14 +324,14 @@ int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key) /* Translate ASCII characters, extended keypad values, and escape * sequences into their corresponding key values. Set meta_key to TRUE * when we get a meta key sequence, and set func_key to TRUE when we get - * a function key. Assume nodelay(win) is FALSE. */ -int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) + * a function key. */ +int parse_kbinput(WINDOW *win) { static int escapes = 0, byte_digits = 0; int *kbinput, retval = ERR; - *meta_key = FALSE; - *func_key = FALSE; + meta_key = FALSE; + func_key = FALSE; /* Read in a character. */ if (nodelay_mode) { @@ -339,7 +339,8 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) if (kbinput == 0) return 0; } else - while ((kbinput = get_input(win, 1)) == NULL); + while ((kbinput = get_input(win, 1)) == NULL) + ; switch (*kbinput) { case ERR: @@ -377,7 +378,7 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) * meta key sequence mode. Set meta_key to * TRUE, and save the lowercase version of the * non-escape character as the result. */ - *meta_key = TRUE; + meta_key = TRUE; retval = tolower(*kbinput); } else /* One escape followed by a non-escape, and @@ -467,7 +468,7 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) * escape counter, set meta_key to TRUE, and * interpret the escape sequence. */ escapes = 0; - *meta_key = TRUE; + meta_key = TRUE; retval = parse_escape_seq_kbinput(win, *kbinput); } @@ -497,36 +498,36 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) if (retval != ERR) { switch (retval) { case NANO_CONTROL_8: - retval = ISSET(REBIND_DELETE) ? sc_seq_or(DO_DELETE, 0) : - sc_seq_or(DO_BACKSPACE, 0); + retval = ISSET(REBIND_DELETE) ? sc_seq_or(do_delete, 0) : + sc_seq_or(do_backspace, 0); break; case KEY_DOWN: #ifdef KEY_SDOWN /* ncurses and Slang don't support KEY_SDOWN. */ case KEY_SDOWN: #endif - retval = sc_seq_or(DO_DOWN_VOID, *kbinput); + retval = sc_seq_or(do_down_void, *kbinput); break; case KEY_UP: #ifdef KEY_SUP /* ncurses and Slang don't support KEY_SUP. */ case KEY_SUP: #endif - retval = sc_seq_or(DO_UP_VOID, *kbinput); + retval = sc_seq_or(do_up_void, *kbinput); break; case KEY_LEFT: #ifdef KEY_SLEFT /* Slang doesn't support KEY_SLEFT. */ case KEY_SLEFT: #endif - retval = sc_seq_or(DO_LEFT, *kbinput); + retval = sc_seq_or(do_left, *kbinput); break; case KEY_RIGHT: #ifdef KEY_SRIGHT /* Slang doesn't support KEY_SRIGHT. */ case KEY_SRIGHT: #endif - retval = sc_seq_or(DO_RIGHT, *kbinput); + retval = sc_seq_or(do_right, *kbinput); break; #ifdef KEY_SHOME /* HP-UX 10-11 and Slang don't support KEY_SHOME. */ @@ -534,36 +535,36 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) #endif case KEY_A1: /* Home (7) on numeric keypad with * NumLock off. */ - retval = sc_seq_or(DO_HOME, *kbinput); + retval = sc_seq_or(do_home, *kbinput); break; case KEY_BACKSPACE: - retval = sc_seq_or(DO_BACKSPACE, *kbinput); + retval = sc_seq_or(do_backspace, *kbinput); break; #ifdef KEY_SDC /* Slang doesn't support KEY_SDC. */ case KEY_SDC: if (ISSET(REBIND_DELETE)) - retval = sc_seq_or(DO_DELETE, *kbinput); + retval = sc_seq_or(do_delete, *kbinput); else - retval = sc_seq_or(DO_BACKSPACE, *kbinput); + retval = sc_seq_or(do_backspace, *kbinput); break; #endif #ifdef KEY_SIC /* Slang doesn't support KEY_SIC. */ case KEY_SIC: - retval = sc_seq_or(DO_INSERTFILE_VOID, *kbinput); + retval = sc_seq_or(do_insertfile_void, *kbinput); break; #endif case KEY_C3: /* PageDown (4) on numeric keypad with * NumLock off. */ - retval = sc_seq_or(DO_PAGE_DOWN, *kbinput); + retval = sc_seq_or(do_page_down, *kbinput); break; case KEY_A3: /* PageUp (9) on numeric keypad with * NumLock off. */ - retval = sc_seq_or(DO_PAGE_UP, *kbinput); + retval = sc_seq_or(do_page_up, *kbinput); break; case KEY_ENTER: - retval = sc_seq_or(DO_ENTER, *kbinput); + retval = sc_seq_or(do_enter_void, *kbinput); break; case KEY_B2: /* Center (5) on numeric keypad with * NumLock off. */ @@ -575,7 +576,7 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) /* HP-UX 10-11 and Slang don't support KEY_SEND. */ case KEY_SEND: #endif - retval = sc_seq_or(DO_END, *kbinput); + retval = sc_seq_or(do_end, *kbinput); break; #ifdef KEY_BEG /* Slang doesn't support KEY_BEG. */ @@ -591,7 +592,7 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) /* Slang doesn't support KEY_SCANCEL. */ case KEY_SCANCEL: #endif - retval = first_sc_for(currmenu, CANCEL_MSG)->seq; + retval = first_sc_for(currmenu, do_cancel)->seq; break; #endif #ifdef KEY_SBEG @@ -604,13 +605,13 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) #ifdef KEY_SSUSPEND /* Slang doesn't support KEY_SSUSPEND. */ case KEY_SSUSPEND: - retval = sc_seq_or(DO_SUSPEND_VOID, 0); + retval = sc_seq_or(do_suspend_void, 0); break; #endif #ifdef KEY_SUSPEND /* Slang doesn't support KEY_SUSPEND. */ case KEY_SUSPEND: - retval = sc_seq_or(DO_SUSPEND_VOID, 0); + retval = sc_seq_or(do_suspend_void, 0); break; #endif #ifdef PDCURSES @@ -632,16 +633,26 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key) retval = ERR; break; #endif + case CONTROL_LEFT: +#ifndef NANO_TINY + retval = sc_seq_or(do_prev_word_void, 0); +#endif + break; + case CONTROL_RIGHT: +#ifndef NANO_TINY + retval = sc_seq_or(do_next_word_void, 0); +#endif + break; } /* If our result is an extended keypad value (i.e. a value * outside of byte range), set func_key to TRUE. */ if (retval != ERR) - *func_key = !is_byte(retval); + func_key = !is_byte(retval); } #ifdef DEBUG - fprintf(stderr, "parse_kbinput(): kbinput = %d, meta_key = %s, func_key = %s, escapes = %d, byte_digits = %d, retval = %d\n", *kbinput, *meta_key ? "TRUE" : "FALSE", *func_key ? "TRUE" : "FALSE", escapes, byte_digits, retval); + fprintf(stderr, "parse_kbinput(): kbinput = %d, meta_key = %s, func_key = %s, escapes = %d, byte_digits = %d, retval = %d\n", *kbinput, meta_key ? "TRUE" : "FALSE", func_key ? "TRUE" : "FALSE", escapes, byte_digits, retval); #endif free(kbinput); @@ -707,11 +718,15 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) * Terminal. */ case 'B': /* Esc O 1 ; 5 B == Ctrl-Down on * Terminal. */ + retval = get_escape_seq_abcd(seq[4]); + break; case 'C': /* Esc O 1 ; 5 C == Ctrl-Right on * Terminal. */ + retval = CONTROL_RIGHT; + break; case 'D': /* Esc O 1 ; 5 D == Ctrl-Left on * Terminal. */ - retval = get_escape_seq_abcd(seq[4]); + retval = CONTROL_LEFT; break; } } @@ -758,15 +773,15 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) retval = KEY_B2; break; case 'F': /* Esc O F == End on xterm/Terminal. */ - retval = sc_seq_or(DO_END, 0); + retval = sc_seq_or(do_end, 0); break; case 'H': /* Esc O H == Home on xterm/Terminal. */ - retval = sc_seq_or(DO_HOME, 0);; + retval = sc_seq_or(do_home, 0); break; case 'M': /* Esc O M == Enter on numeric keypad with * NumLock off on VT100/VT220/VT320/xterm/ * rxvt/Eterm. */ - retval = sc_seq_or(DO_HOME, 0);; + retval = sc_seq_or(do_home, 0); break; case 'P': /* Esc O P == F1 on VT100/VT220/VT320/Mach * console. */ @@ -804,9 +819,13 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) break; case 'a': /* Esc O a == Ctrl-Up on rxvt. */ case 'b': /* Esc O b == Ctrl-Down on rxvt. */ + retval = get_escape_seq_abcd(seq[1]); + break; case 'c': /* Esc O c == Ctrl-Right on rxvt. */ + retval = CONTROL_RIGHT; + break; case 'd': /* Esc O d == Ctrl-Left on rxvt. */ - retval = get_escape_seq_abcd(seq[1]); + retval = CONTROL_LEFT; break; case 'j': /* Esc O j == '*' on numeric keypad with * NumLock off on VT100/VT220/VT320/xterm/ @@ -831,7 +850,7 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) case 'n': /* Esc O n == Delete (.) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * xterm/rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_DELETE, 0);; + retval = sc_seq_or(do_delete, 0); break; case 'o': /* Esc O o == '/' on numeric keypad with * NumLock off on VT100/VT220/VT320/xterm/ @@ -841,27 +860,27 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) case 'p': /* Esc O p == Insert (0) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_INSERTFILE_VOID, 0);; + retval = sc_seq_or(do_insertfile_void, 0); break; case 'q': /* Esc O q == End (1) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_END, 0);; + retval = sc_seq_or(do_end, 0); break; case 'r': /* Esc O r == Down (2) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_DOWN_VOID, 0);; + retval = sc_seq_or(do_down_void, 0); break; case 's': /* Esc O s == PageDown (3) on numeric * keypad with NumLock off on VT100/VT220/ * VT320/rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_PAGE_DOWN, 0);; + retval = sc_seq_or(do_page_down, 0); break; case 't': /* Esc O t == Left (4) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_LEFT, 0);; + retval = sc_seq_or(do_left, 0); break; case 'u': /* Esc O u == Center (5) on numeric keypad * with NumLock off on VT100/VT220/VT320/ @@ -871,22 +890,22 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) case 'v': /* Esc O v == Right (6) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_RIGHT, 0); + retval = sc_seq_or(do_right, 0); break; case 'w': /* Esc O w == Home (7) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_HOME, 0); + retval = sc_seq_or(do_home, 0); break; case 'x': /* Esc O x == Up (8) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_UP_VOID, 0); + retval = sc_seq_or(do_up_void, 0); break; case 'y': /* Esc O y == PageUp (9) on numeric keypad * with NumLock off on VT100/VT220/VT320/ * rxvt/Eterm/Terminal. */ - retval = sc_seq_or(DO_PAGE_UP, 0); + retval = sc_seq_or(do_page_up, 0); break; } break; @@ -894,9 +913,13 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) switch (seq[1]) { case 'a': /* Esc o a == Ctrl-Up on Eterm. */ case 'b': /* Esc o b == Ctrl-Down on Eterm. */ + retval = get_escape_seq_abcd(seq[1]); + break; case 'c': /* Esc o c == Ctrl-Right on Eterm. */ + retval = CONTROL_RIGHT; + break; case 'd': /* Esc o d == Ctrl-Left on Eterm. */ - retval = get_escape_seq_abcd(seq[1]); + retval = CONTROL_LEFT; break; } break; @@ -966,11 +989,15 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) * xterm. */ case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on * xterm. */ + retval = get_escape_seq_abcd(seq[4]); + break; case 'C': /* Esc [ 1 ; 5 C == Ctrl-Right on * xterm. */ + retval = CONTROL_RIGHT; + break; case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on * xterm. */ - retval = get_escape_seq_abcd(seq[4]); + retval = CONTROL_LEFT; break; } } @@ -980,7 +1007,7 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) break; default: /* Esc [ 1 ~ == Home on * VT320/Linux console. */ - retval = sc_seq_or(DO_HOME, 0);; + retval = sc_seq_or(do_home, 0); break; } } @@ -1031,40 +1058,40 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) default: /* Esc [ 2 ~ == Insert on * VT220/VT320/Linux console/ * xterm/Terminal. */ - retval = sc_seq_or(DO_INSERTFILE_VOID, 0);; + retval = sc_seq_or(do_insertfile_void, 0); break; } } break; case '3': /* Esc [ 3 ~ == Delete on VT220/VT320/ * Linux console/xterm/Terminal. */ - retval = sc_seq_or(DO_DELETE, 0);; + retval = sc_seq_or(do_delete, 0); break; case '4': /* Esc [ 4 ~ == End on VT220/VT320/Linux * console/xterm. */ - retval = sc_seq_or(DO_END, 0);; + retval = sc_seq_or(do_end, 0); break; case '5': /* Esc [ 5 ~ == PageUp on VT220/VT320/ * Linux console/xterm/Terminal; * Esc [ 5 ^ == PageUp on Eterm. */ - retval = sc_seq_or(DO_PAGE_UP, 0);; + retval = sc_seq_or(do_page_up, 0); break; case '6': /* Esc [ 6 ~ == PageDown on VT220/VT320/ * Linux console/xterm/Terminal; - * Esc [ 6 ^ == PageDown on Eterm. */ - retval = sc_seq_or(DO_PAGE_DOWN, 0);; + * Esc [ 6 ^ == PageDown on Eterm. */ + retval = sc_seq_or(do_page_down, 0); break; case '7': /* Esc [ 7 ~ == Home on rxvt. */ - retval = sc_seq_or(DO_HOME, 0); + retval = sc_seq_or(do_home, 0); break; case '8': /* Esc [ 8 ~ == End on rxvt. */ - retval = sc_seq_or(DO_END, 0); + retval = sc_seq_or(do_end, 0); break; case '9': /* Esc [ 9 == Delete on Mach console. */ - retval = sc_seq_or(DO_DELETE, 0);; + retval = sc_seq_or(do_delete, 0); break; case '@': /* Esc [ @ == Insert on Mach console. */ - retval = sc_seq_or(DO_INSERTFILE_VOID, 0);; + retval = sc_seq_or(do_insertfile_void, 0); break; case 'A': /* Esc [ A == Up on ANSI/VT220/Linux * console/FreeBSD console/Mach console/ @@ -1087,23 +1114,23 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) break; case 'F': /* Esc [ F == End on FreeBSD * console/Eterm. */ - retval = sc_seq_or(DO_END, 0); + retval = sc_seq_or(do_end, 0); break; case 'G': /* Esc [ G == PageDown on FreeBSD * console. */ - retval = sc_seq_or(DO_PAGE_DOWN, 0); + retval = sc_seq_or(do_page_down, 0); break; case 'H': /* Esc [ H == Home on ANSI/VT220/FreeBSD * console/Mach console/Eterm. */ - retval = sc_seq_or(DO_HOME, 0); + retval = sc_seq_or(do_home, 0); break; case 'I': /* Esc [ I == PageUp on FreeBSD * console. */ - retval = sc_seq_or(DO_PAGE_UP, 0); + retval = sc_seq_or(do_page_up, 0); break; case 'L': /* Esc [ L == Insert on ANSI/FreeBSD * console. */ - retval = sc_seq_or(DO_INSERTFILE_VOID, 0); + retval = sc_seq_or(do_insertfile_void, 0); break; case 'M': /* Esc [ M == F1 on FreeBSD console. */ retval = KEY_F(1); @@ -1151,10 +1178,10 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) retval = KEY_F(8); break; case 'U': /* Esc [ U == PageDown on Mach console. */ - retval = sc_seq_or(DO_PAGE_DOWN, 0); + retval = sc_seq_or(do_page_down, 0); break; case 'V': /* Esc [ V == PageUp on Mach console. */ - retval = sc_seq_or(DO_PAGE_UP, 0); + retval = sc_seq_or(do_page_up, 0); break; case 'W': /* Esc [ W == F11 on FreeBSD console. */ retval = KEY_F(11); @@ -1163,7 +1190,7 @@ int get_escape_seq_kbinput(const int *seq, size_t seq_len) retval = KEY_F(12); break; case 'Y': /* Esc [ Y == End on Mach console. */ - retval = sc_seq_or(DO_END, 0); + retval = sc_seq_or(do_end, 0); break; case 'Z': /* Esc [ Z == F14 on FreeBSD console. */ retval = KEY_F(14); @@ -1220,13 +1247,13 @@ int get_escape_seq_abcd(int kbinput) { switch (tolower(kbinput)) { case 'a': - return sc_seq_or(DO_UP_VOID, 0);; + return sc_seq_or(do_up_void, 0); case 'b': - return sc_seq_or(DO_DOWN_VOID, 0);; + return sc_seq_or(do_down_void, 0); case 'c': - return sc_seq_or(DO_RIGHT, 0);; + return sc_seq_or(do_right, 0); case 'd': - return sc_seq_or(DO_LEFT, 0);; + return sc_seq_or(do_left, 0); default: return ERR; } @@ -1301,15 +1328,13 @@ int get_byte_kbinput(int kbinput) break; case 3: /* Third digit: This must be from zero to five if the first - * was two and the second was between zero and five, and may - * be any decimal value if the first was zero or one and the - * second was between six and nine. Put it in the 1's - * position of the byte sequence holder. */ + * was two and the second was five, and may be any decimal + * value otherwise. Put it in the 1's position of the byte + * sequence holder. */ if (('0' <= kbinput && kbinput <= '5') || (byte < 250 && '6' <= kbinput && kbinput <= '9')) { byte += kbinput - '0'; - /* If this character is a valid decimal value, then the - * byte sequence is complete. */ + /* The byte sequence is complete. */ retval = byte; } else /* This isn't the third digit of a byte sequence. @@ -1531,7 +1556,8 @@ int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len) int *kbinput, *retval; /* Read in the first keystroke. */ - while ((kbinput = get_input(win, 1)) == NULL); + while ((kbinput = get_input(win, 1)) == NULL) + ; #ifdef ENABLE_UTF8 if (using_utf8()) { @@ -1557,8 +1583,8 @@ int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len) statusbar(_("Unicode Input")); while (uni == ERR) { - while ((kbinput = get_input(win, 1)) == NULL); - + while ((kbinput = get_input(win, 1)) == NULL) + ; uni = get_unicode_kbinput(*kbinput); } @@ -1638,8 +1664,7 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts) /* The width of all the shortcuts, except for the last * two, in the shortcut list in bottomwin. */ int j; - /* The y-coordinate relative to the beginning of the - * shortcut list in bottomwin. */ + /* The calculated index number of the clicked item. */ size_t currslen; /* The number of shortcuts in the current shortcut * list. */ @@ -1659,10 +1684,6 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts) return 0; } - /* Calculate the y-coordinate relative to the beginning of - * the shortcut list in bottomwin. */ - j = *mouse_y - 1; - /* Get the shortcut lists' length. */ if (currmenu == MMAIN) currslen = MAIN_VISIBLE; @@ -1683,44 +1704,46 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts) else i = COLS / ((currslen / 2) + (currslen % 2)); - /* Calculate the x-coordinate relative to the beginning of - * the shortcut list in bottomwin, and add it to j. j - * should now be the index in the shortcut list of the - * shortcut we released/clicked on. */ - j = (*mouse_x / i) * 2 + j; + /* Calculate the one-based index in the shortcut list. */ + j = (*mouse_x / i) * 2 + *mouse_y; - /* Adjust j if we released on the last two shortcuts. */ - if ((j >= currslen) && (*mouse_x % i < COLS % i)) + /* Adjust the index if we hit the last two wider ones. */ + if ((j > currslen) && (*mouse_x % i < COLS % i)) j -= 2; - +#ifdef DEBUG + fprintf(stderr, "Calculated %i as index in shortcut list, currmenu = %x.\n", j, currmenu); +#endif /* Ignore releases/clicks of the first mouse button beyond * the last shortcut. */ - if (j >= currslen) + if (j > currslen) return 2; - /* Go through the shortcut list to determine which shortcut - * we released/clicked on. */ - f = allfuncs; - - for (; j > 0; j--) { - if (f->next != NULL) - f = f->next; - - while (f->next != NULL && ((f->menus & currmenu) == 0 + /* Go through the list of functions to determine which + * shortcut in the current menu we released/clicked on. */ + for (f = allfuncs; f != NULL; f = f->next) { + if ((f->menus & currmenu) == 0) + continue; #ifndef DISABLE_HELP - || strlen(f->help) == 0 + if (!f->help || strlen(f->help) == 0) + continue; #endif - )) - f = f->next; + if (first_sc_for(currmenu, f->scfunc) == NULL) + continue; + /* Tick off an actually shown shortcut. */ + j -= 1; + if (j == 0) + break; } +#ifdef DEBUG + fprintf(stderr, "Stopped on func %ld present in menus %x\n", (long)f->scfunc, f->menus); +#endif - - /* And put back the equivalent key. */ + /* And put the corresponding key into the keyboard buffer. */ if (f != NULL) { - const sc *s = first_sc_for(currmenu, f->scfunc); - if (s != NULL) - unget_kbinput(s->seq, s->type == META, FALSE); + const sc *s = first_sc_for(currmenu, f->scfunc); + unget_kbinput(s->seq, s->type == META, s->type == FKEY); } + return 1; } else /* Handle releases/clicks of the first mouse button that * aren't on the current shortcut list elsewhere. */ @@ -1746,8 +1769,8 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts) * wheel is equivalent to moving down three lines. */ for (i = 0; i < 3; i++) unget_kbinput((mevent.bstate & BUTTON4_PRESSED) ? - sc_seq_or(DO_UP_VOID, 0) : sc_seq_or(DO_DOWN_VOID, 0), FALSE, - FALSE); + sc_seq_or(do_up_void, 0) : sc_seq_or(do_down_void, 0), + FALSE, FALSE); return 1; } else @@ -1763,67 +1786,35 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts) } #endif /* !DISABLE_MOUSE */ -/* Return the shortcut corresponding to the values of kbinput (the key - * itself), meta_key (whether the key is a meta sequence), and func_key - * (whether the key is a function key), if any. The shortcut will be - * the first one in the list (control key, meta key sequence, function - * key, other meta key sequence) for the corresponding function. For - * example, passing in a meta key sequence that corresponds to a - * function with a control key, a function key, and a meta key sequence - * will return the control key corresponding to that function. */ -const sc *get_shortcut(int menu, int *kbinput, bool - *meta_key, bool *func_key) +/* Return the shortcut that corresponds to the values of kbinput (the + * key itself) and meta_key (whether the key is a meta sequence). The + * returned shortcut will be the first in the list that corresponds to + * the given sequence. */ +const sc *get_shortcut(int *kbinput) { sc *s; #ifdef DEBUG - fprintf(stderr, "get_shortcut(): kbinput = %d, meta_key = %s, func_key = %s\n", *kbinput, *meta_key ? "TRUE" : "FALSE", *func_key ? "TRUE" : "FALSE"); + fprintf(stderr, "get_shortcut(): kbinput = %d, meta_key = %s -- ", *kbinput, meta_key ? "TRUE" : "FALSE"); #endif - /* Check for shortcuts. */ for (s = sclist; s != NULL; s = s->next) { - if ((menu & s->menu) - && ((s->type == META && *meta_key == TRUE && *kbinput == s->seq) - || (s->type != META && *kbinput == s->seq))) { + if ((currmenu & s->menu) && *kbinput == s->seq + && meta_key == (s->type == META)) { #ifdef DEBUG - fprintf (stderr, "matched seq \"%s\" and btw meta was %d (menus %d = %d)\n", s->keystr, *meta_key, menu, s->menu); + fprintf (stderr, "matched seq \"%s\", and btw meta was %d (menu is %x from %x)\n", + s->keystr, meta_key, currmenu, s->menu); #endif return s; } } #ifdef DEBUG - fprintf (stderr, "matched nothing btw meta was %d\n", *meta_key); + fprintf (stderr, "matched nothing, btw meta was %d\n", meta_key); #endif return NULL; } - -/* Try to get a function back from a window. Just a wrapper so - functions to need to create function_key meta_key blah blah - mmenu - what menu name to look through for valid funcs */ -const subnfunc *getfuncfromkey(WINDOW *win) -{ - int kbinput; - bool func_key = FALSE, meta_key = FALSE; - const sc *s; - const subnfunc *f; - - kbinput = parse_kbinput(win, &meta_key, &func_key); - if (kbinput == 0) - return NULL; - - s = get_shortcut(currmenu, &kbinput, &meta_key, &func_key); - if (!s) - return NULL; - - f = sctofunc((sc *) s); - return f; - -} - - - /* Move to (x, y) in win, and display a line of n spaces with the * current attributes. */ void blank_line(WINDOW *win, int y, int x, int n) @@ -1999,7 +1990,7 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool /* If buf contains a tab character, interpret it. */ if (*buf_mb == '\t') { -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) if (ISSET(WHITESPACE_DISPLAY)) { int i; @@ -2015,7 +2006,7 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool } /* If buf contains a control character, interpret it. If buf * contains an invalid multibyte control character, display it - * as such.*/ + * as such. */ } else if (is_cntrl_mbchar(buf_mb)) { char *ctrl_buf_mb = charalloc(mb_cur_max()); int ctrl_buf_mb_len, i; @@ -2034,7 +2025,7 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool free(ctrl_buf_mb); /* If buf contains a space character, interpret it. */ } else if (*buf_mb == ' ') { -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) if (ISSET(WHITESPACE_DISPLAY)) { int i; @@ -2113,7 +2104,9 @@ void titlebar(const char *path) assert(path != NULL || openfile->filename != NULL); - wattron(topwin, reverse_attr); + if (interface_color_pair[TITLE_BAR].bright) + wattron(topwin, A_BOLD); + wattron(topwin, interface_color_pair[TITLE_BAR].pairnum); blank_titlebar(); @@ -2244,7 +2237,8 @@ void titlebar(const char *path) } } - wattroff(topwin, reverse_attr); + wattroff(topwin, A_BOLD); + wattroff(topwin, interface_color_pair[TITLE_BAR].pairnum); wnoutrefresh(topwin); reset_cursor(); @@ -2258,6 +2252,19 @@ void set_modified(void) if (!openfile->modified) { openfile->modified = TRUE; titlebar(NULL); +#ifndef NANO_TINY + if (ISSET(LOCKING)) { + if (openfile->filename[0] == '\0') + return; + else if (openfile->lock_filename == NULL) { + /* TRANSLATORS: Try to keep this at most 76 characters. */ + statusbar(_("Warning: Modifying a file which is not locked, check directory permission?")); + } else { + write_lockfile(openfile->lock_filename, + get_full_path(openfile->filename), TRUE); + } + } +#endif } } @@ -2268,8 +2275,8 @@ void statusbar(const char *msg, ...) { va_list ap; char *bar, *foo; - size_t start_x, foo_len; -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) + size_t start_x; +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) bool old_whitespace; #endif @@ -2285,7 +2292,7 @@ void statusbar(const char *msg, ...) blank_statusbar(); -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) old_whitespace = ISSET(WHITESPACE_DISPLAY); UNSET(WHITESPACE_DISPLAY); #endif @@ -2293,21 +2300,23 @@ void statusbar(const char *msg, ...) vsnprintf(bar, mb_cur_max() * (COLS - 3), msg, ap); va_end(ap); foo = display_string(bar, 0, COLS - 4, FALSE); -#if !defined(NANO_TINY) && defined(ENABLE_NANORC) + free(bar); +#if !defined(NANO_TINY) && !defined(DISABLE_NANORC) if (old_whitespace) SET(WHITESPACE_DISPLAY); #endif - free(bar); - foo_len = strlenpt(foo); - start_x = (COLS - foo_len - 4) / 2; + start_x = (COLS - strlenpt(foo) - 4) / 2; wmove(bottomwin, 0, start_x); - wattron(bottomwin, reverse_attr); + if (interface_color_pair[STATUS_BAR].bright) + wattron(bottomwin, A_BOLD); + wattron(bottomwin, interface_color_pair[STATUS_BAR].pairnum); waddstr(bottomwin, "[ "); waddstr(bottomwin, foo); free(foo); waddstr(bottomwin, " ]"); - wattroff(bottomwin, reverse_attr); + wattroff(bottomwin, A_BOLD); + wattroff(bottomwin, interface_color_pair[STATUS_BAR].pairnum); wnoutrefresh(bottomwin); reset_cursor(); wnoutrefresh(edit); @@ -2365,30 +2374,27 @@ void bottombars(int menu) for (f = allfuncs, i = 0; i < slen && f != NULL; f = f->next) { #ifdef DEBUG - fprintf(stderr, "Checking menu items...."); + fprintf(stderr, "Checking menu items...."); #endif - if ((f->menus & menu) == 0) - continue; - - if (!f->desc || strlen(f->desc) == 0) + if ((f->menus & menu) == 0) continue; #ifdef DEBUG - fprintf(stderr, "found one! f->menus = %d, desc = \"%s\"\n", f->menus, f->desc); + fprintf(stderr, "found one! f->menus = %x, desc = \"%s\"\n", f->menus, f->desc); #endif - s = first_sc_for(menu, f->scfunc); - if (s == NULL) { + s = first_sc_for(menu, f->scfunc); + if (s == NULL) { #ifdef DEBUG fprintf(stderr, "Whoops, guess not, no shortcut key found for func!\n"); #endif - continue; - } + continue; + } wmove(bottomwin, 1 + i % 2, (i / 2) * colwidth); #ifdef DEBUG - fprintf(stderr, "Calling onekey with keystr \"%s\" and desc \"%s\"\n", s->keystr, f->desc); + fprintf(stderr, "Calling onekey with keystr \"%s\" and desc \"%s\"\n", s->keystr, f->desc); #endif onekey(s->keystr, _(f->desc), colwidth + (COLS % colwidth)); - i++; + i++; } wnoutrefresh(bottomwin); @@ -2407,9 +2413,12 @@ void onekey(const char *keystroke, const char *desc, size_t len) assert(keystroke != NULL && desc != NULL); - wattron(bottomwin, reverse_attr); + if (interface_color_pair[KEY_COMBO].bright) + wattron(bottomwin, A_BOLD); + wattron(bottomwin, interface_color_pair[KEY_COMBO].pairnum); waddnstr(bottomwin, keystroke, actual_x(keystroke, len)); - wattroff(bottomwin, reverse_attr); + wattroff(bottomwin, A_BOLD); + wattroff(bottomwin, interface_color_pair[KEY_COMBO].pairnum); if (len > keystroke_len) len -= keystroke_len; @@ -2418,7 +2427,12 @@ void onekey(const char *keystroke, const char *desc, size_t len) if (len > 0) { waddch(bottomwin, ' '); + if (interface_color_pair[FUNCTION_TAG].bright) + wattron(bottomwin, A_BOLD); + wattron(bottomwin, interface_color_pair[FUNCTION_TAG].pairnum); waddnstr(bottomwin, desc, actual_x(desc, len)); + wattroff(bottomwin, A_BOLD); + wattroff(bottomwin, interface_color_pair[FUNCTION_TAG].pairnum); } } @@ -2436,17 +2450,20 @@ void reset_cursor(void) xpt = xplustabs(); +#ifndef NANO_TINY if (ISSET(SOFTWRAP)) { filestruct *tmp; openfile->current_y = 0; for (tmp = openfile->edittop; tmp && tmp != openfile->current; tmp = tmp->next) - openfile->current_y += 1 + strlenpt(tmp->data) / COLS; + openfile->current_y += (strlenpt(tmp->data) / COLS) + 1; openfile->current_y += xplustabs() / COLS; if (openfile->current_y < editwinrows) wmove(edit, openfile->current_y, xpt % COLS); - } else { + } else +#endif + { openfile->current_y = openfile->current->lineno - openfile->edittop->lineno; @@ -2466,7 +2483,7 @@ void reset_cursor(void) void edit_draw(filestruct *fileptr, const char *converted, int line, size_t start) { -#if !defined(NANO_TINY) || defined(ENABLE_COLOR) +#if !defined(NANO_TINY) || !defined(DISABLE_COLOR) size_t startpos = actual_x(fileptr->data, start); /* The position in fileptr->data of the leftmost character * that displays at least partially on the window. */ @@ -2481,23 +2498,32 @@ void edit_draw(filestruct *fileptr, const char *converted, int assert(openfile != NULL && fileptr != NULL && converted != NULL); assert(strlenpt(converted) <= COLS); - /* Just paint the string in any case (we'll add color or reverse on - * just the text that needs it). */ + /* First simply paint the line -- then we'll add colors or the + * marking highlight on just the pieces that need it. */ mvwaddstr(edit, line, 0, converted); -#ifdef ENABLE_COLOR +#ifndef USE_SLANG + /* Tell ncurses to really redraw the line without trying to optimize + * for what it thinks is already there, because it gets it wrong in + * the case of a wide character in column zero. See bug #31743. */ + wredrawln(edit, line, 1); +#endif + +#ifndef DISABLE_COLOR /* If color syntaxes are available and turned on, we need to display * them. */ if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) { const colortype *tmpcolor = openfile->colorstrings; - /* Set up multi-line color data for this line if it's not yet calculated */ - if (fileptr->multidata == NULL && openfile->syntax + /* Set up multi-line color data for this line if it's not yet + * calculated. */ + if (fileptr->multidata == NULL && openfile->syntax && openfile->syntax->nmultis > 0) { - int i; - fileptr->multidata = (short *) nmalloc(openfile->syntax->nmultis * sizeof(short)); - for (i = 0; i < openfile->syntax->nmultis; i++) - fileptr->multidata[i] = -1; /* Assue this applies until we know otherwise */ + int i; + fileptr->multidata = (short *)nmalloc(openfile->syntax->nmultis * sizeof(short)); + for (i = 0; i < openfile->syntax->nmultis; i++) + /* Assume this applies until we know otherwise. */ + fileptr->multidata[i] = -1; } for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) { int x_start; @@ -2584,18 +2610,19 @@ void edit_draw(filestruct *fileptr, const char *converted, int short md = fileptr->multidata[tmpcolor->id]; if (md == -1) - fileptr->multidata[tmpcolor->id] = CNONE; /* until we find out otherwise */ + /* Assume this until we know otherwise. */ + fileptr->multidata[tmpcolor->id] = CNONE; else if (md == CNONE) - continue; + goto end_of_loop; else if (md == CWHOLELINE) { mvwaddnstr(edit, line, 0, converted, -1); - continue; + goto end_of_loop; } else if (md == CBEGINBEFORE) { regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0); paintlen = actual_x(converted, strnlenpt(fileptr->data, endmatch.rm_eo) - start); mvwaddnstr(edit, line, 0, converted, paintlen); - continue; + goto end_of_loop; } while (start_line != NULL && regexec(tmpcolor->start, @@ -2745,12 +2772,12 @@ void edit_draw(filestruct *fileptr, const char *converted, int } } } - + end_of_loop: wattroff(edit, A_BOLD); wattroff(edit, COLOR_PAIR(tmpcolor->pairnum)); } } -#endif /* ENABLE_COLOR */ +#endif /* !DISABLE_COLOR */ #ifndef NANO_TINY /* If the mark is on, we need to display it. */ @@ -2815,10 +2842,10 @@ void edit_draw(filestruct *fileptr, const char *converted, int if (paintlen > 0) paintlen = actual_x(converted + index, paintlen); - wattron(edit, reverse_attr); + wattron(edit, hilite_attribute); mvwaddnstr(edit, line, x_start, converted + index, paintlen); - wattroff(edit, reverse_attr); + wattroff(edit, hilite_attribute); } } #endif /* !NANO_TINY */ @@ -2827,26 +2854,27 @@ void edit_draw(filestruct *fileptr, const char *converted, int /* Just update one line in the edit buffer. This is basically a wrapper * for edit_draw(). The line will be displayed starting with * fileptr->data[index]. Likely arguments are current_x or zero. - * Returns: Number of additiona lines consumed (needed for SOFTWRAP) - */ + * Returns: Number of additional lines consumed (needed for SOFTWRAP). */ int update_line(filestruct *fileptr, size_t index) { int line = 0; - int extralinesused = 0; /* The line in the edit window that we want to update. */ + int extralinesused = 0; char *converted; /* fileptr->data converted to have tabs and control characters * expanded. */ size_t page_start; - filestruct *tmp; assert(fileptr != NULL); +#ifndef NANO_TINY if (ISSET(SOFTWRAP)) { - for (tmp = openfile->edittop; tmp && tmp != fileptr; tmp = tmp->next) { - line += 1 + (strlenpt(tmp->data) / COLS); - } + filestruct *tmp; + + for (tmp = openfile->edittop; tmp && tmp != fileptr; tmp = tmp->next) + line += (strlenpt(tmp->data) / COLS) + 1; } else +#endif line = fileptr->lineno - openfile->edittop->lineno; if (line < 0 || line >= editwinrows) @@ -2857,42 +2885,49 @@ int update_line(filestruct *fileptr, size_t index) /* Next, convert variables that index the line to their equivalent * positions in the expanded line. */ +#ifndef NANO_TINY if (ISSET(SOFTWRAP)) index = 0; else +#endif index = strnlenpt(fileptr->data, index); page_start = get_page_start(index); /* Expand the line, replacing tabs with spaces, and control * characters with their displayed forms. */ +#ifdef NANO_TINY + converted = display_string(fileptr->data, page_start, COLS, TRUE); +#else converted = display_string(fileptr->data, page_start, COLS, !ISSET(SOFTWRAP)); - #ifdef DEBUG if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2) - fprintf(stderr, "update_line(): converted(1) line = %s\n", converted); + fprintf(stderr, "update_line(): converted(1) line = %s\n", converted); #endif - +#endif /* !NANO_TINY */ /* Paint the line. */ edit_draw(fileptr, converted, line, page_start); free(converted); +#ifndef NANO_TINY if (!ISSET(SOFTWRAP)) { +#endif if (page_start > 0) mvwaddch(edit, line, 0, '$'); if (strlenpt(fileptr->data) > page_start + COLS) mvwaddch(edit, line, COLS - 1, '$'); +#ifndef NANO_TINY } else { - int full_length = strlenpt(fileptr->data); + size_t full_length = strlenpt(fileptr->data); for (index += COLS; index <= full_length && line < editwinrows; index += COLS) { line++; #ifdef DEBUG - fprintf(stderr, "update_line(): Softwrap code, moving to %d index %lu\n", line, (unsigned long) index); + fprintf(stderr, "update_line(): softwrap code, moving to %d index %lu\n", line, (unsigned long)index); #endif - blank_line(edit, line, 0, COLS); + blank_line(edit, line, 0, COLS); /* Expand the line, replacing tabs with spaces, and control - * characters with their displayed forms. */ + * characters with their displayed forms. */ converted = display_string(fileptr->data, index, COLS, !ISSET(SOFTWRAP)); #ifdef DEBUG if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2) @@ -2901,10 +2936,11 @@ int update_line(filestruct *fileptr, size_t index) /* Paint the line. */ edit_draw(fileptr, converted, line, index); - free(converted); + free(converted); extralinesused++; } } +#endif /* !NANO_TINY */ return extralinesused; } @@ -2935,8 +2971,7 @@ bool need_vertical_update(size_t pww_save) } /* When edittop changes, try and figure out how many lines - * we really have to work with (i.e. set maxrows) - */ + * we really have to work with (i.e. set maxrows). */ void compute_maxrows(void) { int n; @@ -2949,7 +2984,7 @@ void compute_maxrows(void) maxrows = 0; for (n = 0; n < editwinrows && foo; n++) { - maxrows ++; + maxrows++; n += strlenpt(foo->data) / COLS; foo = foo->next; } @@ -2958,20 +2993,20 @@ void compute_maxrows(void) maxrows += editwinrows - n; #ifdef DEBUG - fprintf(stderr, "compute_maxrows(): maxrows = %ld\n", maxrows); + fprintf(stderr, "compute_maxrows(): maxrows = %d\n", maxrows); #endif } /* Scroll the edit window in the given direction and the given number * of lines, and draw new lines on the blank lines left after the - * scrolling. direction is the direction to scroll, either UP_DIR or - * DOWN_DIR, and nlines is the number of lines to scroll. We change + * scrolling. direction is the direction to scroll, either UPWARD or + * DOWNWARD, and nlines is the number of lines to scroll. We change * edittop, and assume that current and current_x are up to date. We * also assume that scrollok(edit) is FALSE. */ void edit_scroll(scroll_dir direction, ssize_t nlines) { + ssize_t i; filestruct *foo; - ssize_t i, extracuzsoft = 0; bool do_redraw = FALSE; /* Don't bother scrolling less than one line. */ @@ -2981,36 +3016,6 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) if (need_vertical_update(0)) do_redraw = TRUE; - - /* If using soft wrapping, we want to scroll down enough to display the entire next - line, if possible... */ - if (ISSET(SOFTWRAP) && direction == DOWN_DIR) { -#ifdef DEBUG - fprintf(stderr, "Softwrap: Entering check for extracuzsoft\n"); -#endif - for (i = maxrows, foo = openfile->edittop; foo && i > 0; i--, foo = foo->next) - ; - - if (foo) { - extracuzsoft += strlenpt(foo->data) / COLS; -#ifdef DEBUG - fprintf(stderr, "Setting extracuzsoft to %lu due to strlen %lu of line %lu\n", (unsigned long) extracuzsoft, - (unsigned long) strlenpt(foo->data), (unsigned long) foo->lineno); -#endif - - /* Now account for whether the edittop line itself is >COLS, if scrolling down */ - for (foo = openfile->edittop; foo && extracuzsoft > 0; nlines++) { - extracuzsoft -= 1 + strlenpt(foo->data) / COLS; -#ifdef DEBUG - fprintf(stderr, "Edittop adjustment, setting nlines to %lu\n", (unsigned long) nlines); -#endif - if (foo == openfile->filebot) - break; - foo = foo->next; - } - } - } - /* Part 1: nlines is the number of lines we're going to scroll the * text of the edit window. */ @@ -3018,7 +3023,7 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) * value of direction) nlines lines, or as many lines as we can if * there are fewer than nlines lines available. */ for (i = nlines; i > 0; i--) { - if (direction == UP_DIR) { + if (direction == UPWARD) { if (openfile->edittop == openfile->fileage) break; openfile->edittop = openfile->edittop->prev; @@ -3027,13 +3032,16 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) break; openfile->edittop = openfile->edittop->next; } - /* Don't over-scroll on long lines */ - if (ISSET(SOFTWRAP)) { + +#ifndef NANO_TINY + /* Don't over-scroll on long lines. */ + if (ISSET(SOFTWRAP) && direction == UPWARD) { ssize_t len = strlenpt(openfile->edittop->data) / COLS; - i -= len; + i -= len; if (len > 0) do_redraw = TRUE; } +#endif } /* Limit nlines to the number of lines we could scroll. */ @@ -3051,7 +3059,7 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) /* Scroll the text of the edit window up or down nlines lines, * depending on the value of direction. */ scrollok(edit, TRUE); - wscrl(edit, (direction == UP_DIR) ? -nlines : nlines); + wscrl(edit, (direction == UPWARD) ? -nlines : nlines); scrollok(edit, FALSE); /* Part 2: nlines is the number of lines in the scrolled region of @@ -3059,8 +3067,8 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) /* If the top or bottom line of the file is now visible in the edit * window, we need to draw the entire edit window. */ - if ((direction == UP_DIR && openfile->edittop == - openfile->fileage) || (direction == DOWN_DIR && + if ((direction == UPWARD && openfile->edittop == + openfile->fileage) || (direction == DOWNWARD && openfile->edittop->lineno + editwinrows - 1 >= openfile->filebot->lineno)) nlines = editwinrows; @@ -3081,7 +3089,7 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) /* If we scrolled down, move down to the line before the scrolled * region. */ - if (direction == DOWN_DIR) { + if (direction == DOWNWARD) { for (i = editwinrows - nlines; i > 0 && foo != NULL; i--) foo = foo->next; } @@ -3092,8 +3100,8 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) * blank, so we don't need to draw it unless the mark is on or we're * not on the first page. */ for (i = nlines; i > 0 && foo != NULL; i--) { - if ((i == nlines && direction == DOWN_DIR) || (i == 1 && - direction == UP_DIR)) { + if ((i == nlines && direction == DOWNWARD) || (i == 1 && + direction == UPWARD)) { if (do_redraw) update_line(foo, (foo == openfile->current) ? openfile->current_x : 0); @@ -3102,6 +3110,7 @@ void edit_scroll(scroll_dir direction, ssize_t nlines) openfile->current_x : 0); foo = foo->next; } + compute_maxrows(); } /* Update any lines between old_current and current that need to be @@ -3119,13 +3128,10 @@ void edit_redraw(filestruct *old_current, size_t pww_save) maxrows || openfile->current->lineno < openfile->edittop->lineno || openfile->current->lineno >= openfile->edittop->lineno + maxrows) { - #ifdef DEBUG - fprintf(stderr, "edit_redraw(): line %lu was offscreen, oldcurrent = %lu edittop = %lu", openfile->current->lineno, - old_current->lineno, openfile->edittop->lineno); + fprintf(stderr, "edit_redraw(): line %ld was offscreen, oldcurrent = %ld edittop = %ld", + (long)openfile->current->lineno, (long)old_current->lineno, (long)openfile->edittop->lineno); #endif - filestruct *old_edittop = openfile->edittop; - ssize_t nlines; #ifndef NANO_TINY /* If the mark is on, update all the lines between old_current @@ -3133,6 +3139,7 @@ void edit_redraw(filestruct *old_current, size_t pww_save) * whether we've scrolled up or down) of the edit window. */ if (openfile->mark_set) { ssize_t old_lineno; + filestruct *old_edittop = openfile->edittop; if (old_edittop->lineno < openfile->edittop->lineno) old_lineno = old_edittop->lineno; @@ -3153,10 +3160,11 @@ void edit_redraw(filestruct *old_current, size_t pww_save) } #endif /* !NANO_TINY */ - /* Put edittop in range of current, get the difference in lines - * between the original edittop and the current edittop, and - * then restore the original edittop. */ - edit_update(CENTER); + /* Make sure the current line is on the screen. */ + if (ISSET(SMOOTH_SCROLL)) + edit_update(NONE); + else + edit_update(CENTER); /* Update old_current if we're not on the same page as * before. */ @@ -3211,19 +3219,18 @@ void edit_refresh(void) filestruct *foo; int nlines; - /* Figure out what maxrows should really be */ + /* Figure out what maxrows should really be. */ compute_maxrows(); if (openfile->current->lineno < openfile->edittop->lineno || openfile->current->lineno >= openfile->edittop->lineno + maxrows) { - #ifdef DEBUG - fprintf(stderr, "edit_refresh(): line = %d, edittop %d + maxrows %d\n", openfile->current->lineno, openfile->edittop->lineno, maxrows); + fprintf(stderr, "edit_refresh(): line = %ld, edittop %ld + maxrows %d\n", + (long)openfile->current->lineno, (long)openfile->edittop->lineno, maxrows); #endif - /* Put the top line of the edit window in range of the current - * line. */ + /* Make sure the current line is on the screen. */ edit_update(CENTER); } @@ -3275,12 +3282,14 @@ void edit_update(update_type location) for (; goal > 0 && foo->prev != NULL; goal--) { foo = foo->prev; +#ifndef NANO_TINY if (ISSET(SOFTWRAP) && foo) goal -= strlenpt(foo->data) / COLS; +#endif } openfile->edittop = foo; #ifdef DEBUG - fprintf(stderr, "edit_udpate(), setting edittop to lineno %d\n", openfile->edittop->lineno); + fprintf(stderr, "edit_update(): setting edittop to lineno %ld\n", (long)openfile->edittop->lineno); #endif compute_maxrows(); edit_refresh_needed = TRUE; @@ -3313,6 +3322,14 @@ void total_refresh(void) * portion of the window. */ void display_main_list(void) { +#ifndef DISABLE_COLOR + if (openfile->syntax + && (openfile->syntax->formatter || openfile->syntax->linter)) + set_lint_or_format_shortcuts(); + else + set_spell_shortcuts(); +#endif + bottombars(MMAIN); } @@ -3374,17 +3391,16 @@ void do_cursorpos_void(void) void enable_nodelay(void) { - nodelay_mode = TRUE; - nodelay(edit, TRUE); + nodelay_mode = TRUE; + nodelay(edit, TRUE); } void disable_nodelay(void) { - nodelay_mode = FALSE; - nodelay(edit, FALSE); + nodelay_mode = FALSE; + nodelay(edit, FALSE); } - /* Highlight the current word being replaced or spell checked. We * expect word to have tabs and control characters expanded. */ void do_replace_highlight(bool highlight, const char *word) @@ -3404,7 +3420,7 @@ void do_replace_highlight(bool highlight, const char *word) wnoutrefresh(edit); if (highlight) - wattron(edit, reverse_attr); + wattron(edit, hilite_attribute); /* This is so we can show zero-length matches. */ if (word_len == 0) @@ -3416,12 +3432,12 @@ void do_replace_highlight(bool highlight, const char *word) waddch(edit, '$'); if (highlight) - wattroff(edit, reverse_attr); + wattroff(edit, hilite_attribute); } -#ifdef NANO_EXTRA -#define CREDIT_LEN 55 -#define XLCREDIT_LEN 8 +#ifndef DISABLE_EXTRA +#define CREDIT_LEN 54 +#define XLCREDIT_LEN 9 /* Easter egg: Display credits. Assume nodelay(edit) and scrollok(edit) * are FALSE. */ @@ -3443,14 +3459,11 @@ void do_credits(void) "Rocco Corsi", "David Lawrence Ramsey", "David Benbennick", + "Mark Majeres", "Mike Frysinger", + "Benno Schulenberg", "Ken Tyler", "Sven Guckes", - NULL, /* credits[15], handled below. */ - "Pauli Virtanen", - "Daniele Medri", - "Clement Laforet", - "Tedi Heriyanto", "Bill Soudan", "Christian Weisgerber", "Erik Andersen", @@ -3460,6 +3473,7 @@ void do_credits(void) "Albert Chin", "", NULL, /* "Special thanks to:" */ + "Monique, Brielle & Joseph", "Plattsburgh State University", "Benet Laboratories", "Amy Allegretta", @@ -3468,6 +3482,7 @@ void do_credits(void) "Richard Kolb II", NULL, /* "The Free Software Foundation" */ "Linus Torvalds", + NULL, /* "the many translators and the TP" */ NULL, /* "For ncurses:" */ "Thomas Dickey", "Pavel Curtis", @@ -3479,7 +3494,7 @@ void do_credits(void) "", "", "", - "(C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007", + "(C) 1999 - 2015", "Free Software Foundation, Inc.", "", "", @@ -3494,20 +3509,12 @@ void do_credits(void) N_("Brought to you by:"), N_("Special thanks to:"), N_("The Free Software Foundation"), + N_("the many translators and the TP"), N_("For ncurses:"), N_("and anyone else we forgot..."), N_("Thank you for using nano!") }; - /* credits[15]: Make sure this name is displayed properly, since we - * can't dynamically assign it above, using Unicode 00F6 (Latin - * Small Letter O with Diaresis) if applicable. */ - credits[15] = -#ifdef ENABLE_UTF8 - using_utf8() ? "Florian K\xC3\xB6nig" : -#endif - "Florian K\xF6nig"; - if (!old_more_space || !old_no_help) { SET(MORE_SPACE); SET(NO_HELP); @@ -3584,4 +3591,4 @@ void do_credits(void) total_refresh(); } -#endif /* NANO_EXTRA */ +#endif /* !DISABLE_EXTRA */ |